// ═══ GENESIS BUILD saude-m12-grupos-canonicos · 2026-07-12 ═══

// ═══════════ 🧩 FITKIT — raiz de componentes de fitness compartilhados ═══════════
// Consumido pelo Saúde (aluno) E pelo Coach (pré-visualização do professor).
// Regra da casa: mudou aqui, mudou nos dois módulos. Nada de hardcodar em cada um.

const fitFmtDescanso = seg => `${Math.floor(seg / 60)}m ${String(seg % 60).padStart(2, '0')}s`;

// ─── 🧍 FitMapaMuscular: corpo clicável (estilo MuscleWiki) pra filtrar exercícios ───
// grupos canônicos do banco — espelham as regiões do boneco (mesma lista do backend)
const FIT_GRUPOS = ['Peito', 'Costas', 'Ombros', 'Bíceps', 'Tríceps', 'Antebraço', 'Core', 'Glúteos', 'Quadríceps', 'Posteriores', 'Panturrilha', 'Cardio'];
const FIT_REGIOES = [
  { id: 'ombros',       nome: 'Ombros',        rx: /deltoide|ombro/i },
  { id: 'peito',        nome: 'Peito',         rx: /peitoral|peito/i },
  { id: 'biceps',       nome: 'Bíceps',        rx: /b[íi]ceps|braquial/i },
  { id: 'triceps',      nome: 'Tríceps',       rx: /tr[íi]ceps/i },
  { id: 'antebraco',    nome: 'Antebraço',     rx: /antebra[çc]o|punho|preens[ãa]o/i },
  { id: 'core',         nome: 'Core / Abdômen',rx: /abd[ôo]men|core|lombar|oblíquo/i },
  { id: 'costas',       nome: 'Costas',        rx: /dorsal|trap[ée]zio|costas|remada/i },
  { id: 'gluteos',      nome: 'Glúteos',       rx: /gl[úu]teo/i },
  { id: 'quadriceps',   nome: 'Quadríceps',    rx: /quadr[íi]ceps|perna(?!.*post)/i },
  { id: 'posteriores',  nome: 'Posteriores',   rx: /posterior|isquio/i },
  { id: 'panturrilha',  nome: 'Panturrilha',   rx: /panturrilha/i },
];
const fitRegioesDe = (ex) => {
  const txt = `${(ex && ex.grupo) || ''} ${(ex && ex.musculo) || ''} ${(ex && ex.nome) || ''}`;
  return FIT_REGIOES.filter(r => r.rx.test(txt)).map(r => r.id);
};

// hotspots traçados sobre as imagens anatômicas (tidal/corpo-frente.png 390×768 · tidal/corpo-costas.png 378×768)
const FIT_HOTSPOTS = {
  frente: { img: 'tidal/corpo-frente.png', w: 390, h: 768, regioes: {
    ombros:      [[[96,150],[130,138],[148,152],[140,178],[108,182],[92,166]], [[294,150],[260,138],[242,152],[250,178],[282,182],[298,166]]],
    peito:       [[[148,158],[195,166],[195,232],[150,224],[132,196]], [[242,158],[195,166],[195,232],[240,224],[258,196]]],
    biceps:      [[[96,186],[126,190],[122,258],[96,262],[84,228]], [[294,186],[264,190],[268,258],[294,262],[306,228]]],
    antebraco:   [[[80,268],[112,266],[96,352],[66,346]], [[310,268],[278,266],[294,352],[324,346]]],
    core:        [[[158,238],[232,238],[238,318],[212,352],[178,352],[152,318]]],
    quadriceps:  [[[140,392],[186,384],[190,512],[150,522],[126,470]], [[250,392],[204,384],[200,512],[240,522],[264,470]]],
    panturrilha: [[[140,548],[180,545],[176,650],[146,652]], [[250,548],[210,545],[214,650],[244,652]]],
  }},
  costas: { img: 'tidal/corpo-costas.png', w: 378, h: 768, regioes: {
    costas:      [[[150,120],[228,120],[240,168],[230,262],[189,296],[148,262],[138,168]]],
    triceps:     [[[94,182],[124,186],[120,258],[92,262],[82,224]], [[284,182],[254,186],[258,258],[286,262],[296,224]]],
    antebraco:   [[[78,268],[110,266],[94,352],[64,346]], [[300,268],[268,266],[284,352],[314,346]]],
    gluteos:     [[[146,330],[188,326],[188,398],[146,394],[132,362]], [[232,330],[190,326],[190,398],[232,394],[246,362]]],
    posteriores: [[[142,412],[184,408],[186,520],[150,526],[128,472]], [[236,412],[194,408],[192,520],[228,526],[250,472]]],
    panturrilha: [[[142,548],[182,545],[176,655],[146,656]], [[236,548],[196,545],[202,655],[232,656]]],
  }},
};

const FitMapaMuscular = ({ selecionadas, onToggle, lang }) => {
  const [hover, setHover] = React.useState(null);
  const [semImg, setSemImg] = React.useState(false);
  const sel = selecionadas || [];
  const nomes = sel.map(id => (FIT_REGIOES.find(r => r.id === id) || {}).nome).filter(Boolean);
  const figura = (lado) => {
    const F = FIT_HOTSPOTS[lado];
    return (
      <div key={lado} style={{ flex: '1 1 150px', maxWidth: 210, minWidth: 130 }}>
      <div style={{ position: 'relative' }}>{/* container SÓ da arte: overlays alinham 1:1, sem o rótulo esticar nada */}
        <img src={F.img} alt="" onError={() => setSemImg(true)} style={{ width: '100%', height: 'auto', display: 'block' }} />
        {/* camadas pixel-perfect: o MÚSCULO DO DESENHO acende (máscaras mm-*.png geradas da própria arte) */}
        {Object.keys(F.regioes).map(id => {
          const on = sel.includes(id), hv = hover === id;
          return (
            <img key={id} src={`tidal/mm-${lado}-${id}.png`} alt="" style={{
              position: 'absolute', inset: 0, width: '100%', height: '100%',
              opacity: on ? 1 : hv ? 0.5 : 0, transition: 'opacity .18s', pointerEvents: 'none',
            }} />
          );
        })}
        {/* áreas de clique (invisíveis) */}
        <svg viewBox={`0 0 ${F.w} ${F.h}`} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
          {Object.keys(F.regioes).map(id => (
            <g key={id} style={{ cursor: 'pointer' }}
              onClick={() => onToggle(id)} onMouseEnter={() => setHover(id)} onMouseLeave={() => setHover(null)}>
              {F.regioes[id].map((pts, i) => (
                <polygon key={i} points={pts.map(p => p.join(',')).join(' ')} fill="rgba(0,0,0,0)" style={{ pointerEvents: 'all' }} />
              ))}
            </g>
          ))}
        </svg>
      </div>
        <div style={{ textAlign: 'center', fontFamily: 'var(--fm)', fontSize: 9, letterSpacing: 1.2, color: 'var(--muted)', marginTop: 2 }}>{lado === 'frente' ? 'FRENTE' : 'COSTAS'}</div>
      </div>
    );
  };
  return (
    <div style={{ textAlign: 'center' }}>
      <span style={{ display: 'inline-block', padding: '5px 14px', borderRadius: 999, background: 'var(--surface)', border: '1px solid var(--line-soft)', fontFamily: 'var(--fm)', fontSize: 10.5, color: sel.length || hover ? 'var(--rose)' : 'var(--muted)', fontWeight: sel.length ? 700 : 400, marginBottom: 8 }}>
        {hover ? (FIT_REGIOES.find(r => r.id === hover) || {}).nome
          : nomes.length ? nomes.join(' · ')
          : (lang === 'pt' ? 'Nenhum músculo selecionado — clica no corpo' : 'No muscle selected — tap the body')}
      </span>
      {semImg ? (
        <div className="empty" style={{ padding: 16, fontSize: 12 }}>
          🖼 {lang === 'pt' ? 'faltam as imagens do corpo: sobe corpo-frente.png e corpo-costas.png na pasta public/tidal/ do NAS.' : 'upload corpo-frente.png and corpo-costas.png to public/tidal/.'}
        </div>
      ) : (
        <div style={{ display: 'flex', gap: 14, justifyContent: 'center', flexWrap: 'wrap' }}>
          {figura('frente')}{figura('costas')}
        </div>
      )}
    </div>
  );
};

// ─── FitTreinoDoDia: faixa de dias + título + carrossel de cards de exercício ───
// props: week, dayName (hoje), selDia, setSelDia, bank, prsMap, lang, atualizadoEm,
//        onCardClick(ex), onIniciar (botão 🤳 só aparece se selDia === hoje e onIniciar existir)
const FitTreinoDoDia = ({ week, dayName, selDia, setSelDia, bank, prsMap, lang, atualizadoEm, onCardClick, onIniciar }) => {
  const card = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };
  return (
    <div style={{ ...card, borderTop: '3px solid var(--accent)', overflow: 'hidden' }}>
        {/* ── faixa de dias (Dom → Sáb, selecionado preenchido) ── */}
        <div style={{ display: 'flex', gap: 6, marginBottom: 16, overflowX: 'auto', paddingBottom: 2 }}>
          {['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'].map(d => {
            const on = d === selDia;
            const ehHoje = d === dayName;
            const wd = week.find(x => x.day === d) || {};
            const tem = (wd.exercises || []).length > 0;
            return (
              <button key={d} onClick={() => setSelDia(d)} style={{
                flex: '1 0 auto', minWidth: 52, border: on ? 'none' : '1px solid var(--line)', cursor: 'pointer',
                borderRadius: 12, padding: '9px 6px 7px', textAlign: 'center', position: 'relative',
                background: on ? 'var(--teal)' : 'var(--surface)', color: on ? '#fff' : 'var(--teal)',
                fontFamily: 'var(--fm)', fontSize: 12, fontWeight: 700, letterSpacing: 0.8, textTransform: 'uppercase',
                boxShadow: on ? '0 4px 14px rgba(31,87,85,0.3)' : 'none',
              }}>
                {d}
                <div style={{ height: 4, marginTop: 3, display: 'flex', justifyContent: 'center', gap: 3 }}>
                  {tem ? <span style={{ width: 4, height: 4, borderRadius: '50%', background: on ? '#fff' : 'var(--accent)' }} /> : null}
                  {ehHoje ? <span style={{ width: 4, height: 4, borderRadius: '50%', background: on ? 'var(--sun)' : 'var(--sun)' }} /> : null}
                </div>
              </button>
            );
          })}
        </div>

        {/* ── título do dia ── */}
        {(() => {
          const dp = week.find(x => x.day === selDia) || { focus: '', exercises: [] };
          const exs = dp.exercises || [];
          const ehHoje = selDia === dayName;
          const repsDe = ex => {
            if (Array.isArray(ex.sets) && ex.sets.length) {
              const rs = ex.sets.map(st => String(st.reps || '').trim()).filter(Boolean);
              const nums = rs.map(r => parseInt(r)).filter(n => !isNaN(n));
              if (nums.length === rs.length && nums.length) { const mn = Math.min(...nums), mx = Math.max(...nums); return mn === mx ? String(mn) : `${mn}-${mx}`; }
              return rs[0] || '—';
            }
            return String(ex.reps || '—');
          };
          const seriesDe = ex => (Array.isArray(ex.sets) && ex.sets.length) ? ex.sets.length : (Number(ex.series) || '—');
          const ultimoDe = ex => { const v = prsMap[(ex.nome || '').toLowerCase()]; return v != null ? v : null; };
          const linhaInfo = (rot, val, sub) => (
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '5px 0', borderBottom: '1px solid rgba(255,255,255,0.14)' }}>
              <span style={{ fontFamily: 'var(--fm)', fontSize: 8.5, letterSpacing: 1, textTransform: 'uppercase', color: 'rgba(255,255,255,0.75)' }}>{rot}</span>
              <span style={{ color: '#fff', fontFamily: 'var(--fm)', fontSize: 15, fontWeight: 700, lineHeight: 1 }}>{val}{sub ? <span style={{ fontSize: 9, fontWeight: 400, color: 'rgba(255,255,255,0.65)' }}> {sub}</span> : null}</span>
            </div>
          );
          return (
            <React.Fragment>
              <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'treino do dia' : "day's workout"}</div>
              <div style={{ fontFamily: 'var(--fs)', fontSize: 27, letterSpacing: '-0.5px', marginTop: 2, marginBottom: 2 }}>
                {dp.focus || (lang === 'pt' ? 'Descanso' : 'Rest')} <span style={{ fontSize: 15, color: 'var(--muted)', fontStyle: 'italic' }}>({selDia.toUpperCase()}{ehHoje ? (lang === 'pt' ? ' · hoje' : ' · today') : ''})</span>
              </div>
              {dp.nota ? <div style={{ fontSize: 12, color: 'var(--muted)', marginBottom: 10 }}>📝 {dp.nota}</div> : null}
              {dp.descanso ? <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', marginBottom: 10 }}>⏱ {lang === 'pt' ? 'descanso entre séries' : 'rest'}: <b style={{ color: 'var(--teal)' }}>{Math.floor(dp.descanso / 60)}m {String(dp.descanso % 60).padStart(2, '0')}s</b></div> : null}

              {exs.length > 0 && ehHoje && onIniciar ? (
                <button onClick={onIniciar} style={{
                  width: '100%', marginBottom: 14, border: 'none', cursor: 'pointer', borderRadius: 14, padding: '15px',
                  background: 'linear-gradient(135deg, var(--accent), var(--accent-2))', color: '#fff',
                  fontFamily: 'var(--fs)', fontSize: 16, fontWeight: 700, boxShadow: '0 6px 22px rgba(217,105,75,0.35)',
                }}>🤳 {lang === 'pt' ? 'Iniciar treino' : 'Start workout'}</button>
              ) : null}

              {!exs.length ? (
                <div className="empty" style={{ padding: 26, textAlign: 'center' }}>{lang === 'pt' ? 'descanso. recupera que o mar continua aí amanhã 🌙' : 'rest day 🌙'}</div>
              ) : (
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, overflowX: 'auto', padding: '4px 2px 10px', scrollSnapType: 'x proximity' }}>
                  {exs.map((ex, i) => {
                    const be = bank.find(b => (ex.exercise_id && b.id === ex.exercise_id) || b.nome.toLowerCase() === (ex.nome || '').toLowerCase()) || {};
                    const ultimo = ultimoDe(ex);
                    return (
                      <React.Fragment key={i}>
                        <button onClick={() => onCardClick && onCardClick(ex)} style={{
                          position: 'relative', flexShrink: 0, width: 192, height: 296, borderRadius: 18, overflow: 'hidden',
                          border: 'none', cursor: 'pointer', padding: 0, textAlign: 'left', scrollSnapAlign: 'start',
                          background: 'linear-gradient(160deg, var(--teal), var(--sky))', boxShadow: 'var(--shadow-sm)',
                        }}>
                          {be.image_url ? (
                            <img src={be.image_url} alt="" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
                          ) : be.media_url ? (
                            <video src={be.media_url} muted loop playsInline autoPlay preload="metadata" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
                          ) : (
                            <span style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', fontSize: 62, opacity: 0.35 }}>🏋️</span>
                          )}
                          {/* nome no topo */}
                          <div style={{ position: 'absolute', top: 0, left: 0, right: 0, padding: '12px 12px 26px', background: 'linear-gradient(180deg, rgba(10,16,18,0.78), transparent)' }}>
                            <div style={{ color: '#fff', fontFamily: 'var(--fs)', fontSize: 16.5, fontWeight: 700, lineHeight: 1.15, textTransform: 'uppercase', letterSpacing: 0.3, textShadow: '0 1px 6px rgba(0,0,0,0.5)' }}>{ex.nome}</div>
                          </div>
                          {/* número da sequência */}
                          <span style={{ position: 'absolute', top: 10, right: 10, width: 24, height: 24, borderRadius: '50%', background: 'var(--accent)', color: '#fff', display: 'grid', placeItems: 'center', fontFamily: 'var(--fm)', fontSize: 11.5, fontWeight: 700, boxShadow: '0 2px 8px rgba(0,0,0,0.35)' }}>{i + 1}</span>
                          {/* painel translúcido inferior */}
                          <div style={{ position: 'absolute', left: 8, right: 8, bottom: 8, background: 'rgba(12,17,19,0.80)', backdropFilter: 'blur(3px)', borderRadius: 13, padding: '4px 12px 8px' }}>
                            {linhaInfo(lang === 'pt' ? 'séries' : 'sets', seriesDe(ex))}
                            {linhaInfo(lang === 'pt' ? 'repetições' : 'reps', repsDe(ex))}
                            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '5px 0 1px' }}>
                              <span style={{ fontFamily: 'var(--fm)', fontSize: 8.5, letterSpacing: 1, textTransform: 'uppercase', color: 'rgba(255,255,255,0.75)' }}>{lang === 'pt' ? 'último peso' : 'last weight'}</span>
                              <span style={{ color: '#fff', fontFamily: 'var(--fm)', fontSize: 15, fontWeight: 700, lineHeight: 1 }}>{ultimo != null ? ultimo : '—'}<span style={{ fontSize: 9, fontWeight: 400, color: 'rgba(255,255,255,0.65)' }}> kg 🏋️</span></span>
                            </div>
                          </div>
                        </button>
                        {i < exs.length - 1 ? (
                          <span style={{ flexShrink: 0, width: 26, height: 26, borderRadius: '50%', background: 'var(--surface)', border: '1px solid var(--line)', display: 'grid', placeItems: 'center', color: 'var(--teal)', fontSize: 13, boxShadow: 'var(--shadow-sm)' }}>➜</span>
                        ) : null}
                      </React.Fragment>
                    );
                  })}
                </div>
              )}
              {atualizadoEm ? <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)', marginTop: 6 }}>{lang === 'pt' ? 'programa atualizado em' : 'updated'} {new Date(atualizadoEm).toLocaleDateString('pt-BR')}</div> : null}
            </React.Fragment>
          );
        })()}
      </div>
  );
};


// ═══ GENESIS BUILD saude-viva-ui · 2026-07-11 ═══
// Tidal — Saúde · privacy-first health hub
// Privacidade radical: só EU + Prof. de EF (state.health.coach) veem métricas pessoais.
// Operação/admin/comunidade nunca veem peso, dieta, diário, treinos pessoais.
// Comunidade vê apenas: Cardápio, aulas em grupo (sem inscritos), banco de habilidades.

const COACH_ROLE = (state) => state.health?.coach;
const IS_COACH = (state) => {
  const me = state.users.find(u => u.role === state.role) || state.users[0];
  return me.id === state.health?.coach;
};
const IS_ME = (state) => {
  const me = state.users.find(u => u.role === state.role) || state.users[0];
  return me.id === state.health?.me;
};

// ─── Treino e dieta (ligado ao backend /api/saude) ───
const SAUDE_TK = () => localStorage.getItem('genesis_token');

// ═══ AVAL — motor de cálculo da avaliação física (fórmulas da planilha PetroRio Wellness) ═══
const AVAL = {
  n: v => { const x = parseFloat(String(v ?? '').replace(',', '.')); return isNaN(x) ? null : x; },
  idade: nasc => { if (!nasc) return null; const d = new Date(nasc); if (isNaN(d)) return null; const h = new Date(); let i = h.getFullYear() - d.getFullYear(); const m = h.getMonth() - d.getMonth(); if (m < 0 || (m === 0 && h.getDate() < d.getDate())) i--; return i; },
  imc: (peso, est) => { const p = AVAL.n(peso), e = AVAL.n(est); return p && e ? p / (e * e) : null; },
  classifIMC: imc => imc == null ? null : imc < 18.5 ? ['Abaixo do peso', 'sun'] : imc < 25 ? ['Peso normal', 'leaf'] : imc < 30 ? ['Acima do peso', 'sun'] : imc < 35 ? ['Obesidade 1', 'rose'] : imc < 40 ? ['Obesidade 2', 'rose'] : ['Obesidade 3', 'rose'],
  fcmaxInbar: idade => idade == null ? null : 205.8 - 0.685 * idade,
  fcmaxTanaka: idade => idade == null ? null : 208 - 0.7 * idade,
  zonasFC: (fcRep, fcMax) => { const r = AVAL.n(fcRep), m = AVAL.n(fcMax); if (r == null || m == null) return []; return [60, 70, 80, 90, 100].map(p => ({ pct: p, fc: r + (p / 100) * (m - r) })); },
  // dobras: protocolos clássicos → densidade → %MG (Siri). O professor escolhe o protocolo (ou informa %MG direto).
  densidade: (protocolo, dobras, idade, sexo) => {
    const d = k => AVAL.n(dobras[k]) || 0;
    const log10 = x => Math.log(x) / Math.LN10;
    if (protocolo === 'pollock3') {
      const S = sexo === 'F' ? d('triceps') + d('suprailiaca') + d('coxa') : d('peitoral') + d('abdominal') + d('coxa');
      if (!S || idade == null) return null;
      return sexo === 'F'
        ? 1.0994921 - 0.0009929 * S + 0.0000023 * S * S - 0.0001392 * idade
        : 1.10938 - 0.0008267 * S + 0.0000016 * S * S - 0.0002574 * idade;
    }
    if (protocolo === 'pollock7') {
      const S = d('peitoral') + d('axilar') + d('triceps') + d('subescapular') + d('abdominal') + d('suprailiaca') + d('coxa');
      if (!S || idade == null) return null;
      return sexo === 'F'
        ? 1.097 - 0.00046971 * S + 0.00000056 * S * S - 0.00012828 * idade
        : 1.112 - 0.00043499 * S + 0.00000055 * S * S - 0.00028826 * idade;
    }
    if (protocolo === 'durnin') {
      const S = d('biceps') + d('triceps') + d('subescapular') + d('suprailiaca');
      if (!S || idade == null) return null;
      const t = sexo === 'F'
        ? (idade < 17 ? [1.1369, 0.0598] : idade < 20 ? [1.1549, 0.0678] : idade < 30 ? [1.1599, 0.0717] : idade < 40 ? [1.1423, 0.0632] : idade < 50 ? [1.1333, 0.0612] : [1.1339, 0.0645])
        : (idade < 17 ? [1.1533, 0.0643] : idade < 20 ? [1.1620, 0.0630] : idade < 30 ? [1.1631, 0.0632] : idade < 40 ? [1.1422, 0.0544] : idade < 50 ? [1.1620, 0.0700] : [1.1715, 0.0779]);
      return t[0] - t[1] * log10(S);
    }
    return null;
  },
  pctMG: dens => dens ? (495 / dens - 450) : null,
  somaDobras: dobras => Object.values(dobras || {}).reduce((a, v) => a + (AVAL.n(v) || 0), 0),
  rcq: (cintura, quadril) => { const c = AVAL.n(cintura), q = AVAL.n(quadril); return c && q ? c / q : null; },
  classifRCQ: (rcq, sexo) => rcq == null ? null : (sexo === 'F' ? (rcq <= 0.85 ? ['Normal', 'leaf'] : ['Acima do normal', 'rose']) : (rcq <= 0.90 ? ['Normal', 'leaf'] : ['Acima do normal', 'rose'])),
  classifCircAbd: (ca, sexo) => { const c = AVAL.n(ca); if (c == null) return null; const lim = sexo === 'F' ? [80, 88] : [94, 102]; return c < lim[0] ? ['Normal', 'leaf'] : c < lim[1] ? ['Aumentado', 'sun'] : ['Substancialmente aumentado', 'rose']; },
  fmt: (v, casas) => v == null ? '—' : Number(v).toFixed(casas == null ? 1 : casas),
};

// campos das seções da avaliação (rótulos e chaves — a planilha em forma de dados)
const AVAL_DOBRAS = [['peitoral','Peitoral'],['axilar','Axilar média'],['triceps','Tríceps'],['subescapular','Subescapular'],['abdominal','Abdominal'],['suprailiaca','Supra-ilíaca'],['coxa','Coxa'],['biceps','Bíceps'],['perna','Perna']];
const AVAL_PERIMETROS = [['per_braco_d','Braço D'],['per_braco_e','Braço E'],['per_peitoral','Peitoral'],['per_cintura','Cintura'],['per_abdomen','Abdômen'],['per_quadril','Quadril'],['per_coxa_d','Coxa D'],['per_coxa_e','Coxa E'],['per_perna_d','Perna D'],['per_perna_e','Perna E']];
const AVAL_FORCA = [['forca_preensao_d','Preensão mão D (kg)'],['forca_preensao_e','Preensão mão E (kg)'],['forca_flexao_bracos','Flexão de braços 60s'],['forca_flexao_tronco','Flexão de tronco 60s'],['forca_salto','Salto vertical (cm)']];
const AVAL_SQUAT = [['sq_nao_agacha','Não consegue agachar'],['sq_lado','Agacha mais pra um lado'],['sq_valgo','Valgo dos joelhos'],['sq_rot_pes','Rot. externa dos pés'],['sq_bracos_frente','Queda dos braços à frente'],['sq_flexao_tronco','Flexão excessiva do tronco'],['sq_bascula','Báscula de quadril'],['sq_pronacao','Pronação dos tornozelos']];
const AVAL_FLEX = [['flex_isquios','Ísquios tibiais'],['flex_rot_ext_quadril','Rot. externa quadril'],['flex_adutores','Adutores do quadril'],['flex_ext_quadril','Extensão do quadril'],['flex_quadriceps','Quadríceps'],['flex_rot_int_quadril','Rot. interna quadril'],['flex_ombros','Flexão dos ombros'],['flex_peitoral','Peitoral'],['flex_rot_ext_ombro','Rot. externa ombro'],['flex_back','Back stretch']];

// ─── ⚡ Prontidão do dia — o número da manhã (estilo Whoop, sem pulseira) ───
const ProntidaoCard = ({ lang }) => {
  const [p, setP] = useState(null);
  useEffect(() => {
    fetch('/api/treino/prontidao', { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : null).then(setP).catch(() => {});
  }, []);
  if (!p) return null;
  if (p.sem_checkin) return (
    <div style={{ background: 'var(--cream)', border: '1px dashed var(--line)', borderRadius: 20, padding: '16px 20px', marginBottom: 16, fontSize: 13, color: 'var(--muted)' }}>
      ⚡ {lang === 'pt' ? 'Faz o check-in do dia (sono, energia, humor) e eu te digo a tua prontidão pro treino.' : 'Do your daily check-in to see your training readiness.'}
    </div>
  );
  const cor = p.score >= 75 ? 'var(--leaf)' : p.score >= 50 ? 'var(--sun)' : 'var(--rose)';
  const R = 34, C = 2 * Math.PI * R;
  const ROTULOS = { sono: lang === 'pt' ? 'sono' : 'sleep', energia: 'energia', humor: 'humor', agua: 'água', descanso: 'descanso' };
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderTop: `3px solid ${cor}`, borderRadius: 20, padding: '18px 20px', boxShadow: 'var(--shadow-sm)', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 18, flexWrap: 'wrap' }}>
      <svg width="84" height="84" viewBox="0 0 84 84" style={{ flexShrink: 0 }}>
        <circle cx="42" cy="42" r={R} fill="none" stroke="var(--cream-3)" strokeWidth="8" />
        <circle cx="42" cy="42" r={R} fill="none" stroke={cor} strokeWidth="8" strokeLinecap="round"
          strokeDasharray={`${C * p.score / 100} ${C}`} transform="rotate(-90 42 42)" />
        <text x="42" y="48" textAnchor="middle" style={{ fontFamily: 'var(--fs)', fontSize: 24, fontWeight: 700, fill: 'var(--ink)' }}>{p.score}</text>
      </svg>
      <div style={{ flex: 1, minWidth: 200 }}>
        <div className="t-eyebrow" style={{ color: cor, marginBottom: 3 }}>⚡ {lang === 'pt' ? 'prontidão do dia' : 'readiness'}</div>
        <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 8 }}>{p.recomendacao.emoji} {p.recomendacao.frase}</div>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
          {Object.entries(p.fatores).map(([k, v]) => (
            <span key={k} style={{ background: 'var(--cream-2)', borderRadius: 8, padding: '3px 9px', fontFamily: 'var(--fm)', fontSize: 11, color: v >= 70 ? 'var(--ink)' : 'var(--rose)' }}>{ROTULOS[k] || k} {v}</span>
          ))}
        </div>
      </div>
    </div>
  );
};

// ─── 🕸 Radar de força — volume por grupo muscular (30d) com evolução de carga ───
const RadarForca = ({ userId, lang }) => {
  const [radar, setRadar] = useState(null);
  useEffect(() => {
    fetch(`/api/treino/radar/${userId || 'me'}`, { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : null).then(setRadar).catch(() => {});
  }, [userId]);
  const grupos = (radar && radar.grupos) || [];
  if (grupos.length < 3) return null;   // radar pede pelo menos 3 eixos
  const top = grupos.slice(0, 6);
  const maxS = Math.max(...top.map(g => g.series)) || 1;
  const CX = 110, CY = 100, RMAX = 72;
  const ponto = (i, frac) => {
    const ang = (Math.PI * 2 * i / top.length) - Math.PI / 2;
    return [CX + Math.cos(ang) * RMAX * frac, CY + Math.sin(ang) * RMAX * frac];
  };
  const poly = top.map((g, i) => ponto(i, Math.max(0.08, g.series / maxS)).join(',')).join(' ');
  const teia = [0.33, 0.66, 1].map(f => top.map((g, i) => ponto(i, f).join(',')).join(' '));
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderTop: '3px solid var(--teal)', borderRadius: 20, padding: '18px 20px', boxShadow: 'var(--shadow-sm)', marginBottom: 18 }}>
      <div className="t-eyebrow" style={{ color: 'var(--teal)', marginBottom: 2 }}>🕸 {lang === 'pt' ? 'radar de força · 30 dias' : 'strength radar · 30d'}</div>
      <div style={{ fontSize: 12, color: 'var(--muted)', marginBottom: 10 }}>{lang === 'pt' ? 'Volume de séries por grupo — o buraco na teia é o ponto fraco.' : 'Set volume by muscle group.'}</div>
      <div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap' }}>
        <svg width="220" height="200" viewBox="0 0 220 200" style={{ flexShrink: 0 }}>
          {teia.map((t, i) => <polygon key={i} points={t} fill="none" stroke="var(--line-soft)" strokeWidth="1" />)}
          {top.map((g, i) => { const [x, y] = ponto(i, 1); return <line key={i} x1={CX} y1={CY} x2={x} y2={y} stroke="var(--line-soft)" strokeWidth="1" />; })}
          <polygon points={poly} fill="rgba(31,87,85,0.22)" stroke="var(--teal)" strokeWidth="2" strokeLinejoin="round" />
          {top.map((g, i) => {
            const [x, y] = ponto(i, 1.16);
            return <text key={i} x={x} y={y + 3} textAnchor="middle" style={{ fontFamily: 'var(--fm)', fontSize: 9.5, fill: 'var(--muted)' }}>{g.grupo.length > 11 ? g.grupo.slice(0, 10) + '…' : g.grupo}</text>;
          })}
        </svg>
        <div style={{ flex: 1, minWidth: 180, display: 'flex', flexDirection: 'column', gap: 6 }}>
          {top.map(g => {
            const evol = g.carga_max != null && g.carga_anterior != null ? g.carga_max - g.carga_anterior : null;
            return (
              <div key={g.grupo} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', fontSize: 12.5 }}>
                <span>{g.grupo} <span style={{ color: 'var(--muted)', fontFamily: 'var(--fm)', fontSize: 11 }}>· {g.series} série{g.series > 1 ? 's' : ''}</span></span>
                <span style={{ fontFamily: 'var(--fm)', fontSize: 11.5 }}>
                  {g.carga_max != null ? `${g.carga_max}kg` : '—'}
                  {evol != null && evol !== 0 ? <span style={{ color: evol > 0 ? 'var(--leaf)' : 'var(--rose)', fontWeight: 700, marginLeft: 5 }}>{evol > 0 ? '▲' : '▼'}{Math.abs(evol)}</span> : null}
                </span>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

// ─── 🏠 Foco em Terra — o código do aluno + treinos de casa validados ───
const CasaCard = ({ state, lang }) => {
  const [casa, setCasa] = useState([]);
  const gid = (state.currentUser && state.currentUser.genesis_id) || '';
  const codigo = gid ? `GYM-${gid}` : null;
  useEffect(() => {
    fetch('/api/treino/casa/me', { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setCasa(Array.isArray(d) ? d : [])).catch(() => {});
  }, []);
  if (!codigo) return null;
  const copiar = () => { try { navigator.clipboard.writeText(codigo); } catch (e) {} };
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderTop: '3px solid var(--teal)', borderRadius: 20, padding: '18px 20px', boxShadow: 'var(--shadow-sm)', marginTop: 16 }}>
      <div className="t-eyebrow" style={{ color: 'var(--teal)', marginBottom: 4 }}>🏠 {lang === 'pt' ? 'foco em terra' : 'home training'}</div>
      <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 12 }}>{lang === 'pt' ? 'De folga? Treina, tira foto e manda com teu código pro professor (WhatsApp). Ele valida aqui e o dia conta pro streak 🔥 e pra conquista 🏠.' : 'On leave? Train, snap a photo and send it with your code to the coach.'}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
        <span style={{ fontFamily: 'var(--fm)', fontSize: 20, letterSpacing: 2, fontWeight: 700, background: 'var(--cream-2)', borderRadius: 12, padding: '10px 18px' }}>{codigo}</span>
        <button className="btn btn-sm" onClick={copiar}>⧉ {lang === 'pt' ? 'copiar' : 'copy'}</button>
        {casa.length ? <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--teal)' }}>✓ {casa.length} {lang === 'pt' ? 'treino(s) em terra validados' : 'validated'}</span> : null}
      </div>
      {casa.length ? (
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 12 }}>
          {casa.slice(0, 10).map(c => (
            <span key={c.id} title={c.nota || ''} style={{ background: 'var(--cream-2)', borderRadius: 8, padding: '4px 10px', fontFamily: 'var(--fm)', fontSize: 11 }}>🏠 {new Date(String(c.dia).split('T')[0] + 'T12:00').toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' })}</span>
          ))}
        </div>
      ) : null}
    </div>
  );
};

// ─── vídeo em tela grande (toca na janelinha → expande) ───
const SaudeVideoZoom = ({ src, poster, nome, onClose }) => (
  <div onClick={e => { e.stopPropagation(); onClose(); }} style={{ position: 'fixed', inset: 0, zIndex: 900, background: 'rgba(10,14,16,0.92)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 14 }}>
    <video src={src} autoPlay loop muted playsInline controls poster={poster || undefined} onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 720, maxHeight: '78vh', borderRadius: 16, background: '#000' }} />
    <div style={{ color: '#fff', fontFamily: 'var(--fs)', fontSize: 17, marginTop: 14 }}>{nome}</div>
    <button onClick={e => { e.stopPropagation(); onClose(); }} style={{ marginTop: 12, background: 'rgba(255,255,255,0.15)', color: '#fff', border: 'none', borderRadius: 999, padding: '9px 22px', cursor: 'pointer', fontFamily: 'var(--fm)', fontSize: 13 }}>✕ fechar</button>
  </div>
);

const WeightProgress = ({ hist }) => {
  const data = hist.slice().reverse().map(h => Number(h.carga)).filter(n => !isNaN(n));
  if (data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data), range = (max - min) || 1;
  const W = 300, H = 50, pad = 4;
  const pts = data.map((v, i) => `${pad + i / (data.length - 1) * (W - 2 * pad)},${pad + (1 - (v - min) / range) * (H - 2 * pad)}`).join(' ');
  const delta = data[data.length - 1] - data[0];
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ flex: 1, height: 50 }}><polyline points={pts} fill="none" stroke="var(--leaf)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>
      <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: delta >= 0 ? 'var(--leaf)' : 'var(--accent)' }}>{delta >= 0 ? '+' : ''}{delta.toFixed(1)} kg</span>
    </div>
  );
};

const ExerciseModal = ({ ex, bank, lang, onClose, onLogged }) => {
  const [videoZoom, setVideoZoom] = useState(false);
  const be = bank.find(b => (ex.exercise_id && b.id === ex.exercise_id) || b.nome.toLowerCase() === (ex.nome || '').toLowerCase());
  const [carga, setCarga] = useState('');
  const [reps, setReps] = useState(ex.reps || (be && be.def_reps) || '');
  const [nota, setNota] = useState('');
  const [hist, setHist] = useState([]);
  const [saving, setSaving] = useState(false);
  useEffect(() => {
    if (!be) return;
    fetch(`/api/saude/weightlog?exercise_id=${be.id}&limit=12`, { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setHist(Array.isArray(d) ? d : [])).catch(() => {});
  }, [be && be.id]);
  const save = async () => {
    if (!carga) return; setSaving(true);
    try {
      const res = await fetch('/api/saude/weightlog', { method: 'POST', headers: { Authorization: `Bearer ${SAUDE_TK()}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ exercise_id: be ? be.id : null, exercise_nome: ex.nome, carga, reps, nota }) });
      if (res.ok) { const row = await res.json(); setHist(h => [row, ...h]); setCarga(''); setNota(''); onLogged && onLogged(); }
    } catch (e) { } finally { setSaving(false); }
  };
  const inp = { width: '100%', boxSizing: 'border-box', minWidth: 0 };
  return (
    <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: '5vh 16px', overflowY: 'auto' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 520, background: 'var(--cream)', borderRadius: 22, boxShadow: 'var(--shadow-lg)', border: '1px solid var(--line-soft)', overflow: 'hidden', animation: 'slideIn .25s cubic-bezier(.2,.7,.3,1) both' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '18px 22px', borderBottom: '1px solid var(--line-soft)' }}>
          <div style={{ minWidth: 0 }}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{(be && be.grupo) || (lang === 'pt' ? 'exercício' : 'exercise')}</div>
            <div style={{ fontFamily: 'var(--fs)', fontSize: 22, letterSpacing: '-0.4px' }}>{ex.nome}</div>
          </div>
          <button className="btn ghost btn-sm" onClick={onClose}><Icon n="x" size={14} /></button>
        </div>
        <div style={{ padding: 22, display: 'flex', flexDirection: 'column', gap: 16 }}>
          {be && be.media_url ? (
            <div onClick={() => setVideoZoom(true)} title={lang === 'pt' ? 'Toca pra ampliar' : 'Tap to enlarge'} style={{ position: 'relative', cursor: 'zoom-in' }}>
              <video src={be.media_url} autoPlay loop muted playsInline poster={be.image_url || undefined} style={{ width: '100%', borderRadius: 14, maxHeight: 320, objectFit: 'cover', background: 'var(--cream-2)', display: 'block' }} />
              <span style={{ position: 'absolute', right: 10, bottom: 10, background: 'rgba(16,22,25,0.65)', color: '#fff', borderRadius: 999, padding: '5px 11px', fontSize: 11, fontFamily: 'var(--fm)' }}>⤢ {lang === 'pt' ? 'ampliar' : 'enlarge'}</span>
            </div>
          ) : be && be.image_url ? (
            <img src={be.image_url} alt="" style={{ width: '100%', borderRadius: 14, maxHeight: 280, objectFit: 'cover', background: 'var(--cream-2)' }} />
          ) : (
            <div className="empty" style={{ padding: '30px 16px', textAlign: 'center' }}>🏋️<div style={{ marginTop: 6, fontSize: 12 }}>{lang === 'pt' ? 'Sem mídia de execução ainda.' : 'No demo media yet.'}</div></div>
          )}
          {be && be.musculo && <div style={{ fontSize: 12, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'Músculo' : 'Muscle'}: {be.musculo}</div>}
          {be && be.instrucao && <div style={{ fontSize: 13, lineHeight: 1.5, color: 'var(--ink-2)' }}>{be.instrucao}</div>}
          {be && be.video_url && <a href={be.video_url} target="_blank" rel="noreferrer" className="btn btn-sm" style={{ alignSelf: 'flex-start' }}>▶ {lang === 'pt' ? 'Ver vídeo' : 'Watch video'}</a>}
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <span style={{ padding: '6px 12px', borderRadius: 10, background: 'var(--cream-2)', fontFamily: 'var(--fm)', fontSize: 12 }}>{ex.series}×{ex.reps}</span>
            <span style={{ padding: '6px 12px', borderRadius: 10, background: 'var(--cream-2)', fontFamily: 'var(--fm)', fontSize: 12 }}>{lang === 'pt' ? 'prescrito' : 'target'}: {ex.carga || '-'}</span>
          </div>
          <div style={{ borderTop: '1px solid var(--line-soft)', paddingTop: 14 }}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 10 }}>{lang === 'pt' ? 'registrar carga de hoje' : "log today's weight"}</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 8 }}>
              <div><label className="label">{lang === 'pt' ? 'Carga (kg)' : 'Weight (kg)'}</label><input className="input" type="number" step="0.5" style={inp} value={carga} onChange={e => setCarga(e.target.value)} /></div>
              <div><label className="label">Reps</label><input className="input" style={inp} value={reps} onChange={e => setReps(e.target.value)} /></div>
            </div>
            <input className="input" style={{ ...inp, marginBottom: 8 }} placeholder={lang === 'pt' ? 'nota (opcional)' : 'note (optional)'} value={nota} onChange={e => setNota(e.target.value)} />
            <button className="btn btn-primary" style={{ width: '100%' }} onClick={save} disabled={saving || !carga}>{saving ? '…' : (lang === 'pt' ? 'Salvar carga' : 'Save')}</button>
          </div>
          {hist.length > 0 && (
            <div>
              <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 8 }}>{lang === 'pt' ? 'histórico' : 'history'}</div>
              <WeightProgress hist={hist} />
              <div style={{ display: 'flex', flexDirection: 'column', marginTop: 8 }}>
                {hist.slice(0, 6).map(h => (
                  <div key={h.id} style={{ display: 'flex', justifyContent: 'space-between', padding: '6px 0', borderBottom: '1px solid var(--line-soft)', fontSize: 12, fontFamily: 'var(--fm)' }}>
                    <span style={{ color: 'var(--muted)' }}>{new Date(h.data).toLocaleDateString('pt-BR')}</span>
                    <span>{h.carga} kg{h.reps ? ` · ${h.reps}` : ''}</span>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      </div>
      {videoZoom && be && be.media_url ? <SaudeVideoZoom src={be.media_url} poster={be.image_url} nome={ex.nome} onClose={() => setVideoZoom(false)} /> : null}
    </div>
  );
};

const TreinoDietaView = ({ state, setPage, lang, toast, me }) => {
  const [plan, setPlan] = useState(null);
  const [bank, setBank] = useState([]);
  const [loading, setLoading] = useState(true);
  const [modalEx, setModalEx] = useState(null);
  const [diet, setDiet] = useState(null);
  const [dlog, setDlog] = useState({ consumidas: [], agua: 0 });
  const [openSub, setOpenSub] = useState(null);
  const [selDia, setSelDia] = useState(['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'][new Date().getDay()]);
  const [prsMap, setPrsMap] = useState({});

  const load = async () => {
    try {
      const hdr = { headers: { Authorization: `Bearer ${SAUDE_TK()}` } };
      const [pRes, bRes, dRes, lRes] = await Promise.all([
        fetch('/api/saude/plan/me', hdr),
        fetch('/api/saude/exercises', hdr),
        fetch('/api/saude/diet/me', hdr),
        fetch('/api/saude/dietlog', hdr),
      ]);
      if (pRes.ok) setPlan(await pRes.json());
      if (bRes.ok) { const b = await bRes.json(); setBank(Array.isArray(b) ? b : []); }
      if (dRes.ok) setDiet(await dRes.json());
      if (lRes.ok) setDlog(await lRes.json());
    } catch (e) { console.error(e); } finally { setLoading(false); }
  };
  useEffect(() => { load(); }, []);
  useEffect(() => {
    fetch('/api/treino/prs/me', { headers: { Authorization: `Bearer ${SAUDE_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(() => {});
  }, []);

  const today = new Date();
  const dayName = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'][today.getDay()];
  const week = (plan && plan.week) || [];
  const todayPlan = week.find(d => d.day === dayName) || week[0] || { focus: '', exercises: [] };
  const card = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };

  // dieta (backend)
  const todayISO = today.toISOString().split('T')[0];
  const refeicoes = (diet && diet.refeicoes) || [];
  const consumidas = dlog.consumidas || [];
  const metaKcal = (diet && diet.meta_kcal) || 0;
  const consumedKcal = refeicoes.reduce((s, r, i) => s + (consumidas.includes(i) ? (r.kcal || 0) : 0), 0);
  const macroMeta = (diet && diet.macros) || { proteina: 0, carbo: 0, gordura: 0 };
  const macroTot = refeicoes.reduce((a, r, i) => { if (consumidas.includes(i) && r.macros) { a.p += r.macros.p || 0; a.c += r.macros.c || 0; a.f += r.macros.f || 0; } return a; }, { p: 0, c: 0, f: 0 });
  const saveDlog = async (next) => {
    setDlog(next);
    try { await fetch('/api/saude/dietlog', { method: 'PUT', headers: { Authorization: `Bearer ${SAUDE_TK()}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ dia: todayISO, consumidas: next.consumidas, agua: next.agua }) }); } catch (e) { }
  };
  const toggleMeal = (i) => { const c = consumidas.includes(i) ? consumidas.filter(x => x !== i) : [...consumidas, i]; saveDlog({ ...dlog, consumidas: c }); };
  const setWater = (delta) => saveDlog({ ...dlog, agua: Math.max(0, Math.round((dlog.agua + delta) * 4) / 4) });

  if (loading) return <div className="empty" style={{ padding: 50 }}>{lang === 'pt' ? 'carregando…' : 'loading…'}</div>;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      {plan && plan.demo && (
        <div style={{ ...card, padding: '12px 16px', background: 'rgba(198,138,31,0.12)', fontSize: 12, color: 'var(--ink-2)' }}>
          ℹ️ {lang === 'pt' ? 'Plano de demonstração — seu professor ainda não montou o treino oficial.' : "Demo plan — your coach hasn't set your program yet."}
        </div>
      )}

      <FitTreinoDoDia
        week={week} dayName={dayName} selDia={selDia} setSelDia={setSelDia}
        bank={bank} prsMap={prsMap} lang={lang}
        atualizadoEm={plan && plan.updated_at}
        onCardClick={ex => setModalEx(ex)}
        onIniciar={setPage ? () => setPage('treino') : null}
      />

      <CasaCard state={state} lang={lang} />

      {diet && (
        <div style={{ ...card, borderTop: '3px solid var(--sun)' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6, flexWrap: 'wrap', gap: 6 }}>
            <div className="t-eyebrow" style={{ color: 'var(--sun)' }}>{lang === 'pt' ? 'dieta · hoje' : 'diet · today'}</div>
            <div style={{ fontFamily: 'var(--fm)', fontSize: 13 }}>{lang === 'pt' ? 'consumido' : 'eaten'} {consumedKcal} <span style={{ color: 'var(--muted)' }}>/ {metaKcal} kcal</span></div>
          </div>
          <div style={{ height: 6, background: 'var(--cream-2)', borderRadius: 3, overflow: 'hidden', marginBottom: 14 }}>
            <div style={{ width: `${Math.min(100, metaKcal ? consumedKcal / metaKcal * 100 : 0)}%`, height: '100%', background: 'var(--leaf)', borderRadius: 3 }} />
          </div>
          {/* macros */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10, marginBottom: 16 }}>
            {[[lang === 'pt' ? 'Proteína' : 'Protein', macroTot.p, macroMeta.proteina, 'var(--accent)'], [lang === 'pt' ? 'Carbo' : 'Carbs', macroTot.c, macroMeta.carbo, 'var(--sun)'], [lang === 'pt' ? 'Gordura' : 'Fat', macroTot.f, macroMeta.gordura, 'var(--teal)']].map(([lb, v, m, col]) => (
              <div key={lb}>
                <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10.5, fontFamily: 'var(--fm)', marginBottom: 3 }}><span style={{ color: 'var(--muted)' }}>{lb}</span><span>{v}/{m}g</span></div>
                <div style={{ height: 4, background: 'var(--cream-2)', borderRadius: 2, overflow: 'hidden' }}><div style={{ width: `${Math.min(100, m ? v / m * 100 : 0)}%`, height: '100%', background: col, borderRadius: 2 }} /></div>
              </div>
            ))}
          </div>
          {/* refeições */}
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            {refeicoes.map((r, i) => {
              const on = consumidas.includes(i);
              return (
                <div key={i} style={{ borderBottom: i < refeicoes.length - 1 ? '1px solid var(--line-soft)' : 'none', padding: '11px 0' }}>
                  <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
                    <button onClick={() => toggleMeal(i)} style={{ cursor: 'pointer', background: 'transparent', border: 'none', padding: 0, flexShrink: 0 }} aria-label={lang === 'pt' ? 'marcar consumida' : 'mark eaten'}>
                      <span style={{ width: 20, height: 20, borderRadius: 6, display: 'grid', placeItems: 'center', background: on ? 'var(--leaf)' : 'transparent', border: on ? 'none' : '2px solid var(--line)', color: '#fff', fontSize: 11 }}>{on ? '✓' : ''}</span>
                    </button>
                    <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--accent)', minWidth: 42 }}>{r.hora || ''}</span>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontFamily: 'var(--fs)', fontStyle: 'italic', fontSize: 15 }}>{r.refeicao}</div>
                      <div style={{ fontSize: 12, color: 'var(--muted)' }}>{(r.alimentos || []).join(', ')}</div>
                    </div>
                    <div style={{ textAlign: 'right', flexShrink: 0 }}>
                      <div style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--ink-2)' }}>{r.kcal} kcal</div>
                      {r.macros && <div style={{ fontSize: 9.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>P{r.macros.p} C{r.macros.c} G{r.macros.f}</div>}
                    </div>
                  </div>
                  {r.substituicoes && r.substituicoes.length > 0 && (
                    <div style={{ marginLeft: 32, marginTop: 4 }}>
                      <button onClick={() => setOpenSub(openSub === i ? null : i)} style={{ background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--accent)', padding: 0 }}>{openSub === i ? '▾' : '▸'} {lang === 'pt' ? 'substituições' : 'swaps'}</button>
                      {openSub === i && <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 4 }}>{r.substituicoes.join('  ·  ')}</div>}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          {/* água */}
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 14, paddingTop: 14, borderTop: '1px solid var(--line-soft)', gap: 12, flexWrap: 'wrap' }}>
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>💧 {lang === 'pt' ? 'Hidratação' : 'Hydration'}</div>
              <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{dlog.agua}L / {diet.agua_meta || 0}L</div>
            </div>
            <div style={{ display: 'flex', gap: 6 }}>
              <button className="btn btn-sm" onClick={() => setWater(-0.25)}>−250ml</button>
              <button className="btn btn-sm" onClick={() => setWater(0.25)}>+250ml</button>
            </div>
          </div>
          {diet.demo && <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 12, fontFamily: 'var(--fm)' }}>ℹ️ {lang === 'pt' ? 'Dieta de demonstração — seu professor ainda não montou a oficial.' : "Demo diet — your coach hasn't set the official one yet."}</div>}
        </div>
      )}

      {modalEx && <ExerciseModal ex={modalEx} bank={bank} lang={lang} onClose={() => setModalEx(null)} onLogged={() => toast.push({ icon: 'check', title: lang === 'pt' ? 'Carga registrada' : 'Weight logged' })} />}
    </div>
  );
};

// gráfico de evolução por sessão de medição
const MEASURE_META = {
  peso:        { l: 'Peso',        u: 'kg', color: 'var(--accent)', lowerBetter: true },
  gordura:     { l: 'Gordura',     u: '%',  color: 'var(--sun)',    lowerBetter: true },
  massa_magra: { l: 'Massa magra', u: 'kg', color: 'var(--leaf)',   lowerBetter: false },
  cintura:     { l: 'Cintura',     u: 'cm', color: 'var(--teal)',   lowerBetter: true },
  peitoral:    { l: 'Peitoral',    u: 'cm', color: '#8A6FB0',       lowerBetter: false },
  braco:       { l: 'Braço',       u: 'cm', color: '#B0795C',       lowerBetter: false },
  coxa:        { l: 'Coxa',        u: 'cm', color: '#5C8AB8',       lowerBetter: false },
};
const dmBR = iso => (iso || '').slice(5).split('-').reverse().join('/');

// ─── 📈 motor de gráfico de verdade: eixo, grade, área, valores e faixa de referência ───
const SaudeChartSVG = ({ pts, meta, genero }) => {
  const W = 360, H = 178, padL = 38, padR = 12, padT = 16, padB = 22;
  const vals = pts.map(p => p.v);
  const faixa = meta.faixa ? meta.faixa(genero || 'M') : null;
  let minV = Math.min(...vals), maxV = Math.max(...vals);
  if (faixa) { minV = Math.min(minV, faixa[0]); maxV = Math.max(maxV, faixa[1]); }
  const folga = (maxV - minV) * 0.12 || Math.abs(maxV) * 0.05 || 1;
  minV -= folga; maxV += folga;
  const range = maxV - minV || 1;
  const x = i => padL + (pts.length === 1 ? 0.5 : i / (pts.length - 1)) * (W - padL - padR);
  const y = v => padT + (1 - (v - minV) / range) * (H - padT - padB);
  const fmtY = v => Math.abs(v) >= 100 ? Math.round(v) : Number(v.toFixed(1));
  const grid = [0, 1, 2, 3].map(i => minV + (range * i) / 3);
  const poly = pts.map((p, i) => `${x(i)},${y(p.v)}`).join(' ');
  const area = `${padL},${y(pts[0].v)} ${poly} ${x(pts.length - 1)},${H - padB} ${padL},${H - padB}`;
  const rotularPonto = i => pts.length <= 7 || i === 0 || i === pts.length - 1 || pts[i].v === Math.max(...vals) || pts[i].v === Math.min(...vals);
  const xLabels = pts.length <= 6 ? pts.map((p, i) => i) : [0, Math.round((pts.length - 1) / 3), Math.round(((pts.length - 1) * 2) / 3), pts.length - 1];
  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto', display: 'block' }}>
      {faixa ? (
        <g>
          <rect x={padL} y={y(faixa[1])} width={W - padL - padR} height={Math.max(0, y(faixa[0]) - y(faixa[1]))} fill="var(--leaf)" fillOpacity="0.09" />
          <text x={W - padR - 2} y={y(faixa[1]) + 9} textAnchor="end" fontSize="7" fill="var(--leaf)" fontFamily="var(--fm)">faixa saudável</text>
        </g>
      ) : null}
      {grid.map((g, i) => (
        <g key={i}>
          <line x1={padL} y1={y(g)} x2={W - padR} y2={y(g)} stroke="var(--line-soft)" strokeWidth="1" strokeDasharray={i === 0 ? '' : '3,4'} />
          <text x={padL - 5} y={y(g) + 3} textAnchor="end" fontSize="8" fill="var(--muted)" fontFamily="var(--fm)">{fmtY(g)}</text>
        </g>
      ))}
      <polygon points={area} fill={meta.color} fillOpacity="0.10" />
      <polyline points={poly} fill="none" stroke={meta.color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
      {pts.map((p, i) => (
        <g key={i}>
          <circle cx={x(i)} cy={y(p.v)} r={i === pts.length - 1 ? 4.5 : 2.8} fill={i === pts.length - 1 ? meta.color : 'var(--surface)'} stroke={meta.color} strokeWidth="1.6" />
          {rotularPonto(i) ? <text x={x(i)} y={y(p.v) - 7} textAnchor="middle" fontSize="8.5" fontWeight="700" fill={meta.color} fontFamily="var(--fm)">{p.v}</text> : null}
        </g>
      ))}
      {xLabels.map(i => (
        <text key={i} x={x(i)} y={H - 6} textAnchor="middle" fontSize="8" fill="var(--muted)" fontFamily="var(--fm)">{dmBR(pts[i].dia)}</text>
      ))}
    </svg>
  );
};

// séries derivadas da AVALIAÇÃO COMPLETA — TUDO que a gente cobra no modal, plotável
const AVAL_GRUPOS = [['comp', '🧬 Composição'], ['peri', '📏 Perímetros'], ['forca', '💪 Força'], ['cardio', '❤️ Cardio']];
const AVAL_SERIES = {
  // composição
  peso_aval:     { g: 'comp', l: 'Peso', u: 'kg', color: 'var(--accent)', lowerBetter: true, calc: d => AVAL.n(d.peso) },
  imc:           { g: 'comp', l: 'IMC', u: '', color: '#8A6FB0', lowerBetter: true, calc: d => { const v = AVAL.imc(d.peso, d.estatura); return v != null ? Number(v.toFixed(1)) : null; } },
  pct_mg:        { g: 'comp', l: '% gordura', u: '%', color: 'var(--sun)', lowerBetter: true, faixa: g => g === 'F' ? [18, 28] : [10, 20],
    calc: d => { const idade = AVAL.idade(d.nascimento); const dens = d.protocolo && d.protocolo !== 'manual' ? AVAL.densidade(d.protocolo, d.dobras || {}, idade, d.sexo || 'M') : null; const v = d.protocolo === 'manual' ? AVAL.n(d.pct_mg) : AVAL.pctMG(dens); return v != null ? Number(Number(v).toFixed(1)) : null; } },
  massa_magra_a: { g: 'comp', l: 'Massa magra', u: 'kg', color: 'var(--leaf)', lowerBetter: false, calc: d => AVAL.n(d.massa_magra) },
  soma_dobras:   { g: 'comp', l: 'Soma de dobras', u: 'mm', color: '#B0795C', lowerBetter: true, calc: d => { const v = AVAL.somaDobras(d.dobras); return v || null; } },
  // perímetros
  per_peitoral:  { g: 'peri', l: 'Peitoral', u: 'cm', color: '#8A6FB0', lowerBetter: false, calc: d => AVAL.n(d.per_peitoral) },
  per_cintura:   { g: 'peri', l: 'Cintura', u: 'cm', color: 'var(--teal)', lowerBetter: true, calc: d => AVAL.n(d.per_cintura) },
  per_abdomen:   { g: 'peri', l: 'Abdômen', u: 'cm', color: '#5C8AB8', lowerBetter: true, calc: d => AVAL.n(d.per_abdomen) },
  per_quadril:   { g: 'peri', l: 'Quadril', u: 'cm', color: 'var(--rose)', lowerBetter: true, calc: d => AVAL.n(d.per_quadril) },
  rcq:           { g: 'peri', l: 'RCQ', u: '', color: '#8A6FB0', lowerBetter: true, calc: d => { const v = AVAL.rcq(d.per_cintura, d.per_quadril); return v != null ? Number(v.toFixed(2)) : null; } },
  per_braco_d:   { g: 'peri', l: 'Braço D', u: 'cm', color: '#B0795C', lowerBetter: false, calc: d => AVAL.n(d.per_braco_d) },
  per_braco_e:   { g: 'peri', l: 'Braço E', u: 'cm', color: '#B0795C', lowerBetter: false, calc: d => AVAL.n(d.per_braco_e) },
  per_coxa_d:    { g: 'peri', l: 'Coxa D', u: 'cm', color: '#5C8AB8', lowerBetter: false, calc: d => AVAL.n(d.per_coxa_d) },
  per_coxa_e:    { g: 'peri', l: 'Coxa E', u: 'cm', color: '#5C8AB8', lowerBetter: false, calc: d => AVAL.n(d.per_coxa_e) },
  per_perna_d:   { g: 'peri', l: 'Perna D', u: 'cm', color: 'var(--teal)', lowerBetter: false, calc: d => AVAL.n(d.per_perna_d) },
  per_perna_e:   { g: 'peri', l: 'Perna E', u: 'cm', color: 'var(--teal)', lowerBetter: false, calc: d => AVAL.n(d.per_perna_e) },
  // força
  preensao_d:    { g: 'forca', l: 'Preensão mão D', u: 'kg', color: 'var(--accent)', lowerBetter: false, calc: d => AVAL.n(d.forca_preensao_d) },
  preensao_e:    { g: 'forca', l: 'Preensão mão E', u: 'kg', color: 'var(--accent-2)', lowerBetter: false, calc: d => AVAL.n(d.forca_preensao_e) },
  flexao_bracos: { g: 'forca', l: 'Flexões 60s', u: '', color: 'var(--leaf)', lowerBetter: false, calc: d => AVAL.n(d.forca_flexao_bracos) },
  flexao_tronco: { g: 'forca', l: 'Abdominais 60s', u: '', color: '#5C8AB8', lowerBetter: false, calc: d => AVAL.n(d.forca_flexao_tronco) },
  salto:         { g: 'forca', l: 'Salto vertical', u: 'cm', color: 'var(--rose)', lowerBetter: false, calc: d => AVAL.n(d.forca_salto) },
  // cardio
  fc_repouso:    { g: 'cardio', l: 'FC de repouso', u: 'bpm', color: 'var(--rose)', lowerBetter: true, calc: d => AVAL.n(d.fc_repouso) },
  fc_max:        { g: 'cardio', l: 'FC máxima', u: 'bpm', color: 'var(--accent)', lowerBetter: false, calc: d => { const v = AVAL.n(d.fc_max) || AVAL.fcmaxTanaka(AVAL.idade(d.nascimento)); return v != null ? Math.round(v) : null; } },
};
// faixa saudável também nas medições de gordura
MEASURE_META.gordura.faixa = g => g === 'F' ? [18, 28] : [10, 20];

const MeasureChart = ({ sessions, lang, me, userId }) => {
  const [fonte, setFonte] = useState('med');     // med · aval
  const [grupo, setGrupo] = useState('comp');
  const [sel, setSel] = useState('peso');
  const [avals, setAvals] = useState([]);
  useEffect(() => {
    fetch(`/api/saude/avaliacoes/${userId || 'me'}`, { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setAvals(Array.isArray(d) ? d : [])).catch(() => {});
  }, [userId]);
  const doGrupo = Object.fromEntries(Object.entries(AVAL_SERIES).filter(([k, v]) => v.g === grupo));
  const metas = fonte === 'med' ? MEASURE_META : doGrupo;
  const m = metas[sel] || metas[Object.keys(metas)[0]];
  const chave = metas[sel] ? sel : Object.keys(metas)[0];

  const pts = fonte === 'med'
    ? sessions.map(s => ({ dia: String(s.dia).split('T')[0], v: s[chave] == null ? null : Number(s[chave]) })).filter(p => p.v != null && !isNaN(p.v))
    : avals.slice().sort((a, b) => String(a.dia) < String(b.dia) ? -1 : 1)
        .map(a => { const v = m.calc(a.data || {}); return { dia: String(a.dia).split('T')[0], v: v != null ? Number(Number(v).toFixed(1)) : null }; })
        .filter(p => p.v != null && !isNaN(p.v));

  const card = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };
  const vals = pts.map(p => p.v);
  const last = vals[vals.length - 1];
  const dPeriodo = vals.length >= 2 ? last - vals[0] : null;
  const dUltima = vals.length >= 2 ? last - vals[vals.length - 2] : null;
  const chipDelta = (d, rotulo) => {
    if (d == null || d === 0) return null;
    const bom = m.lowerBetter ? d < 0 : d > 0;
    return (
      <span style={{ fontFamily: 'var(--fm)', fontSize: 10.5, fontWeight: 700, padding: '3px 9px', borderRadius: 999,
        background: `color-mix(in srgb, var(--${bom ? 'leaf' : 'rose'}) 14%, transparent)`, color: `var(--${bom ? 'leaf' : 'rose'})` }}>
        {d > 0 ? '▲' : '▼'} {Math.abs(d).toFixed(1)}{m.u} {rotulo}
      </span>
    );
  };
  return (
    <div style={{ ...card, borderTop: '3px solid var(--rose)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, flexWrap: 'wrap' }}>
        <div className="t-eyebrow" style={{ color: 'var(--rose)', flex: 1 }}>{lang === 'pt' ? 'evolução' : 'evolution'}</div>
        <div style={{ display: 'flex', gap: 2, background: 'var(--cream-2)', borderRadius: 10, padding: 2 }}>
          {[['med', lang === 'pt' ? '⚖ Medições' : '⚖ Sessions'], ['aval', lang === 'pt' ? '🩺 Avaliações' : '🩺 Assessments']].map(([id, rot]) => (
            <button key={id} onClick={() => { setFonte(id); setSel(id === 'med' ? 'peso' : 'pct_mg'); }}
              style={{ border: 'none', cursor: 'pointer', padding: '6px 11px', borderRadius: 8, fontSize: 11, fontFamily: 'var(--f)', fontWeight: fonte === id ? 700 : 400, background: fonte === id ? 'var(--surface)' : 'transparent', color: fonte === id ? 'var(--teal)' : 'var(--muted)', boxShadow: fonte === id ? 'var(--shadow-sm)' : 'none' }}>{rot}</button>
          ))}
        </div>
      </div>
      {fonte === 'aval' ? (
        <div style={{ display: 'flex', gap: 6, marginBottom: 8, flexWrap: 'wrap' }}>
          {AVAL_GRUPOS.map(([id, rot]) => (
            <button key={id} onClick={() => { setGrupo(id); const primeiro = Object.keys(AVAL_SERIES).find(k => AVAL_SERIES[k].g === id); setSel(primeiro); }}
              style={{ border: 'none', cursor: 'pointer', padding: '5px 11px', borderRadius: 999, fontSize: 11, fontFamily: 'var(--fm)', fontWeight: grupo === id ? 700 : 400,
                background: grupo === id ? 'var(--teal)' : 'var(--cream-2)', color: grupo === id ? '#fff' : 'var(--muted)' }}>{rot}</button>
          ))}
        </div>
      ) : null}
      <div style={{ display: 'flex', gap: 6, marginBottom: 12, flexWrap: 'wrap' }}>
        {Object.keys(metas).map(k => (
          <button key={k} onClick={() => setSel(k)} className={chave === k ? 'btn btn-primary btn-sm' : 'btn btn-sm'} style={{ fontSize: 11 }}>{metas[k].l}</button>
        ))}
      </div>
      {!pts.length ? (
        <div className="empty" style={{ padding: 24 }}>{fonte === 'aval' ? (lang === 'pt' ? 'sem avaliações com esse dado ainda — o professor lança na próxima avaliação física.' : 'no assessments yet.') : (lang === 'pt' ? 'sem medições ainda.' : 'no data')}</div>
      ) : (
        <React.Fragment>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6, flexWrap: 'wrap' }}>
            <span style={{ fontFamily: 'var(--fs)', fontSize: 28, letterSpacing: '-0.5px' }}>{last} <em style={{ fontSize: 13, color: 'var(--muted)' }}>{m.u}</em></span>
            {chipDelta(dUltima, lang === 'pt' ? 'vs anterior' : 'vs last')}
            {chipDelta(dPeriodo, lang === 'pt' ? 'no período' : 'period')}
          </div>
          <SaudeChartSVG pts={pts} meta={m} genero={(me && me.genero) || 'M'} />
          <div style={{ fontFamily: 'var(--fm)', fontSize: 9, color: 'var(--muted)', marginTop: 6 }}>
            {pts.length} {fonte === 'aval' ? (lang === 'pt' ? 'avaliações' : 'assessments') : (lang === 'pt' ? 'medições' : 'sessions')}{m.faixa ? ` · ${lang === 'pt' ? 'faixa verde = referência saudável' : 'green band = healthy range'}` : ''}
          </div>
        </React.Fragment>
      )}
    </div>
  );
};

// ─── delta com setinha (verde melhorou · vermelho piorou · direção do "bom" configurável) ───// ─── delta com setinha (verde melhorou · vermelho piorou · direção do "bom" configurável) ───
const AvalDelta = ({ atual, anterior, unidade, bomQuandoDesce }) => {
  const a = AVAL.n(atual), b = AVAL.n(anterior);
  if (a == null || b == null || a === b) return <span style={{ color: 'var(--muted)', fontFamily: 'var(--fm)', fontSize: 11 }}>{a === b && a != null ? '=' : ''}</span>;
  const desceu = a < b;
  const bom = bomQuandoDesce ? desceu : !desceu;
  return <span style={{ color: bom ? 'var(--leaf)' : 'var(--rose)', fontFamily: 'var(--fm)', fontSize: 12, fontWeight: 700 }}>{desceu ? '▼' : '▲'} {Math.abs(a - b).toFixed(1)}{unidade || ''}</span>;
};

// ─── sparkline SVG (série de pontos → linhazinha) ───
const AvalSpark = ({ valores, cor }) => {
  const vs = (valores || []).map(AVAL.n).filter(v => v != null);
  if (vs.length < 2) return null;
  const min = Math.min(...vs), max = Math.max(...vs), rng = (max - min) || 1;
  const W = 120, H = 34;
  const pts = vs.map((v, i) => `${(i / (vs.length - 1)) * W},${H - 4 - ((v - min) / rng) * (H - 8)}`).join(' ');
  return (
    <svg width={W} height={H} style={{ display: 'block' }}>
      <polyline points={pts} fill="none" stroke={cor || 'var(--teal)'} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={W} cy={H - 4 - ((vs[vs.length - 1] - min) / rng) * (H - 8)} r="3" fill={cor || 'var(--teal)'} />
    </svg>
  );
};

// ─── pill de classificação colorida ───
const AvalPill = ({ classif }) => classif ? (
  <span style={{ background: `color-mix(in srgb, var(--${classif[1]}) 16%, transparent)`, color: `var(--${classif[1]})`, borderRadius: 999, padding: '3px 10px', fontFamily: 'var(--fm)', fontSize: 11, fontWeight: 700, whiteSpace: 'nowrap' }}>{classif[0]}</span>
) : null;

// ─── avaliação completa em modo leitura (aluno) ───
const AvalDetalheModal = ({ aval, me, onClose }) => {
  const d = aval.data || {};
  const idade = AVAL.idade(d.nascimento || (me && me.data_nascimento));
  const sexo = d.sexo || 'M';
  const imc = AVAL.imc(d.peso, d.estatura);
  const dens = d.protocolo && d.protocolo !== 'manual' ? AVAL.densidade(d.protocolo, d.dobras || {}, idade, sexo) : 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 linha = (rot, val, extra) => (val == null || val === '' ) ? null : (
    <div key={rot} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '7px 0', borderBottom: '1px dashed var(--line-soft)', gap: 10 }}>
      <span style={{ fontSize: 13, color: 'var(--muted)' }}>{rot}</span>
      <span style={{ fontSize: 13, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 8 }}>{val}{extra}</span>
    </div>
  );
  const cab = t => <div style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 1.2, textTransform: 'uppercase', color: 'var(--accent)', margin: '16px 0 4px' }}>{t}</div>;
  return (
    <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 14px', overflowY: 'auto' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', maxWidth: 560, background: 'var(--cream)', borderRadius: 22, boxShadow: 'var(--shadow-lg)', border: '1px solid var(--line-soft)', padding: '22px 24px 26px', marginBottom: 40 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>avaliação física</div>
            <div style={{ fontFamily: 'var(--fs)', fontSize: 24 }}>{new Date(aval.dia + 'T12:00').toLocaleDateString('pt-BR')}</div>
          </div>
          <button className="btn ghost btn-sm" onClick={onClose}>✕</button>
        </div>
        {d.meta ? <div style={{ marginTop: 6, fontSize: 13, color: 'var(--muted)' }}>🎯 Meta: <b style={{ color: 'var(--ink)' }}>{d.meta}</b></div> : null}
        {cab('composição corporal')}
        {linha('Peso', d.peso ? `${d.peso} kg` : null)}
        {linha('Estatura', d.estatura ? `${d.estatura} m` : null)}
        {linha('IMC', imc ? AVAL.fmt(imc) : null, <AvalPill classif={AVAL.classifIMC(imc)} />)}
        {linha('% de gordura', pctMG != null ? `${AVAL.fmt(pctMG)}%` : null)}
        {pctMG != null && d.peso ? linha('Massa gorda', `${AVAL.fmt(AVAL.n(d.peso) * pctMG / 100)} kg`) : null}
        {pctMG != null && d.peso ? linha('Massa magra', `${AVAL.fmt(AVAL.n(d.peso) * (1 - pctMG / 100))} kg`) : null}
        {cab('parâmetros fisiológicos')}
        {linha('FC de repouso', d.fc_repouso ? `${d.fc_repouso} bpm` : null)}
        {linha('SpO²', d.spo2 ? `${d.spo2}%` : null)}
        {linha('Pressão arterial', d.pa_sist && d.pa_diast ? `${d.pa_sist}/${d.pa_diast} mmHg` : null)}
        {linha('FC máxima', fcmax ? `${AVAL.fmt(fcmax, 0)} bpm` : null)}
        {zonas.length ? (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', margin: '8px 0 2px' }}>
            {zonas.map(z => <span key={z.pct} style={{ background: 'var(--cream-2)', borderRadius: 8, padding: '4px 9px', fontFamily: 'var(--fm)', fontSize: 11 }}>{z.pct}% → <b>{Math.round(z.fc)}</b></span>)}
          </div>
        ) : null}
        {cab('perímetros e riscos')}
        {AVAL_PERIMETROS.map(([k, rot]) => linha(rot, d[k] ? `${d[k]} cm` : null))}
        {linha('Cintura/Quadril', rcq ? AVAL.fmt(rcq, 2) : null, <AvalPill classif={AVAL.classifRCQ(rcq, sexo)} />)}
        {linha('Circunf. abdominal', d.per_abdomen ? `${d.per_abdomen} cm` : null, <AvalPill classif={AVAL.classifCircAbd(d.per_abdomen, sexo)} />)}
        {cab('força')}
        {AVAL_FORCA.map(([k, rot]) => linha(rot, d[k] || null))}
        {(d.squat && Object.values(d.squat).some(Boolean)) || (d.flex && Object.values(d.flex).some(v => v)) ? cab('postura e mobilidade') : null}
        {d.squat ? AVAL_SQUAT.filter(([k]) => d.squat[k]).map(([k, rot]) => linha(rot, 'Presente')) : null}
        {d.flex ? AVAL_FLEX.filter(([k]) => d.flex[k]).map(([k, rot]) => linha(rot, d.flex[k])) : null}
        {d.wells ? linha('Banco de Wells', `${d.wells} cm`) : null}
        {d.obs ? <div style={{ marginTop: 14, background: 'var(--cream-2)', borderRadius: 12, padding: '10px 14px', fontSize: 13 }}>📝 {d.obs}</div> : null}
      </div>
    </div>
  );
};

// ─── linha do tempo das avaliações (dentro da aba métricas do aluno) ───
const AvalTimeline = ({ me, lang }) => {
  const [avals, setAvals] = useState([]);
  const [aberta, setAberta] = useState(null);
  useEffect(() => {
    fetch('/api/saude/avaliacoes/me', { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setAvals(Array.isArray(d) ? d : [])).catch(() => {});
  }, []);
  if (!avals.length) return null;
  const ord = [...avals].sort((a, b) => a.dia < b.dia ? -1 : 1);   // cronológica pros sparks
  const serie = k => ord.map(a => (a.data || {})[k]);
  const pct = a => {
    const d = a.data || {};
    if (d.protocolo === 'manual') return AVAL.n(d.pct_mg);
    const dens = AVAL.densidade(d.protocolo, d.dobras || {}, AVAL.idade(d.nascimento || (me && me.data_nascimento)), d.sexo || 'M');
    return AVAL.pctMG(dens);
  };
  const seriePct = ord.map(pct);
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderTop: '3px solid var(--accent)', borderRadius: 20, padding: '20px 22px', boxShadow: 'var(--shadow-sm)', marginBottom: 18 }}>
      <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 4 }}>{lang === 'pt' ? 'avaliações do professor' : 'coach assessments'}</div>
      <div style={{ fontFamily: 'var(--fs)', fontSize: 22, marginBottom: 14 }}>{lang === 'pt' ? 'Minha evolução' : 'My evolution'}</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px,1fr))', gap: 12, marginBottom: 16 }}>
        {[['peso', lang === 'pt' ? 'Peso (kg)' : 'Weight', serie('peso'), true, 'var(--teal)'],
          ['mg', '% gordura', seriePct, true, 'var(--accent)'],
          ['cintura', 'Cintura (cm)', serie('per_cintura'), true, 'var(--sun)'],
        ].map(([k, rot, vs, desceBom, cor]) => {
          const nums = vs.map(AVAL.n).filter(v => v != null);
          if (!nums.length) return null;
          return (
            <div key={k} style={{ background: 'var(--cream-2)', borderRadius: 14, padding: '12px 14px' }}>
              <div style={{ fontFamily: 'var(--fm)', fontSize: 10, letterSpacing: 1, textTransform: 'uppercase', color: 'var(--muted)' }}>{rot}</div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, margin: '4px 0 6px' }}>
                <span style={{ fontFamily: 'var(--fs)', fontSize: 24, fontWeight: 700 }}>{AVAL.fmt(nums[nums.length - 1])}</span>
                {nums.length > 1 ? <AvalDelta atual={nums[nums.length - 1]} anterior={nums[nums.length - 2]} bomQuandoDesce={desceBom} /> : null}
              </div>
              <AvalSpark valores={vs} cor={cor} />
            </div>
          );
        })}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {avals.map(a => (
          <button key={a.id} onClick={() => setAberta(a)} style={{ textAlign: 'left', cursor: 'pointer', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '11px 15px', background: 'var(--cream-2)', border: '1px solid var(--line-soft)', borderRadius: 12 }}>
            <span style={{ fontSize: 14, fontWeight: 500 }}>📋 {new Date(a.dia + 'T12:00').toLocaleDateString('pt-BR')}{(a.data || {}).meta ? <span style={{ color: 'var(--muted)', fontWeight: 400 }}> · {a.data.meta}</span> : ''}</span>
            <span style={{ fontSize: 11, color: 'var(--accent)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'ver completa ›' : 'view ›'}</span>
          </button>
        ))}
      </div>
      {aberta ? <AvalDetalheModal aval={aberta} me={me} onClose={() => setAberta(null)} /> : null}
    </div>
  );
};

const MetricasView = ({ state, lang, me }) => {
  const h = state.health;
  const [sessions, setSessions] = useState([]);
  const [loading, setLoading] = useState(true);
  const card = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };
  useEffect(() => {
    fetch('/api/saude/measurements/me', { headers: { Authorization: `Bearer ${SAUDE_TK()}` } })
      .then(r => r.ok ? r.json() : []).then(d => setSessions(Array.isArray(d) ? d : [])).catch(() => {}).finally(() => setLoading(false));
  }, []);

  const hasPhoto = s => s && s.fotos && (s.fotos.frente || s.fotos.lado || s.fotos.costas);
  const comPhotos = sessions.filter(hasPhoto);
  const latest = sessions[sessions.length - 1];
  const prev = sessions[sessions.length - 2];

  const exportPDF = () => {
    if (!sessions.length) return;
    const cols = [['dia', 'Data'], ['peso', 'Peso (kg)'], ['gordura', 'Gordura (%)'], ['massa_magra', 'Massa magra (kg)'], ['cintura', 'Cintura (cm)'], ['peitoral', 'Peitoral (cm)'], ['braco', 'Braço (cm)'], ['coxa', 'Coxa (cm)']];
    const head = cols.map(c => `<th>${c[1]}</th>`).join('');
    const body = sessions.map(s => '<tr>' + cols.map(c => `<td>${c[0] === 'dia' ? dmBR(s.dia) : (s[c[0]] != null ? s[c[0]] : '—')}</td>`).join('') + (s.nota ? `</tr><tr><td colspan="8" class="nota">Nota: ${(s.nota || '').replace(/</g, '&lt;')}</td>` : '') + '</tr>').join('');
    const nome = (state.currentUser && state.currentUser.nome) || '';
    const w = window.open('', '_blank');
    w.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Relatório de evolução</title>
<style>@page{size:A4 portrait;margin:14mm}*{font-family:Arial,sans-serif;box-sizing:border-box}body{color:#1f2a2e}
h1{font-size:18px;margin:0 0 2px}.sub{color:#666;font-size:12px;margin-bottom:16px}
table{width:100%;border-collapse:collapse;font-size:11px}th,td{border:1px solid #ccc;padding:6px 8px;text-align:center}th{background:#f3efe6}
td.nota{text-align:left;color:#555;font-style:italic;background:#faf8f2}</style></head><body>
<h1>Relatório de evolução — Genesis I</h1><div class="sub">${nome ? nome + ' · ' : ''}gerado em ${new Date().toLocaleDateString('pt-BR')}</div>
<table><thead><tr>${head}</tr></thead><tbody>${body}</tbody></table>
<script>window.onload=function(){setTimeout(function(){window.print()},300)}<\/script></body></html>`);
    w.document.close();
  };

  if (loading) return <div className="empty" style={{ padding: 50 }}>{lang === 'pt' ? 'carregando…' : 'loading…'}</div>;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <AvalTimeline me={me} lang={lang} />
      <RadarForca lang={lang} />
      <div className="section-h" style={{ marginBottom: 0 }}>
        <h2 style={{ fontFamily: 'var(--fs)', fontSize: 24, letterSpacing: '-0.5px', fontWeight: 400 }}>{lang === 'pt' ? 'Métricas e ' : 'Metrics & '}<em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>{lang === 'pt' ? 'evolução.' : 'evolution.'}</em></h2>
        {sessions.length > 0 && <button className="btn-icone" onClick={exportPDF} title={lang === 'pt' ? 'exportar PDF' : 'export PDF'}>📄</button>}
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1.3fr) minmax(0,1fr)', gap: 18 }} className="saude-dash-grid">
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0 }}>
          <MeasureChart sessions={sessions} lang={lang} me={me} />

          {/* Histórico de sessões */}
          <div style={{ ...card, borderTop: '3px solid var(--rose)' }}>
            <div className="t-eyebrow" style={{ color: 'var(--rose)', marginBottom: 14 }}>{lang === 'pt' ? 'histórico de medições' : 'measurement history'}</div>
            {!sessions.length ? (
              <div className="empty" style={{ padding: 24 }}>{lang === 'pt' ? 'Nenhuma sessão de medição ainda.' : 'No measurement sessions yet.'}</div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column' }}>
                {sessions.slice().reverse().map((s, i) => (
                  <div key={s.id || i} style={{ padding: '11px 0', borderBottom: i < sessions.length - 1 ? '1px solid var(--line-soft)' : 'none' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8, flexWrap: 'wrap' }}>
                      <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--accent)' }}>{dmBR(s.dia)}</span>
                      <span style={{ fontFamily: 'var(--fm)', fontSize: 12 }}>{s.peso}kg · {s.gordura}% · {s.cintura}cm {lang === 'pt' ? 'cintura' : 'waist'}</span>
                    </div>
                    {s.nota && <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 4, fontStyle: 'italic' }}>{s.nota}</div>}
                  </div>
                ))}
              </div>
            )}
          </div>

          {/* Métricas diárias (seed) */}
          <div style={{ ...card, borderTop: '3px solid var(--teal)' }}>
            <div className="t-eyebrow" style={{ color: 'var(--teal)', marginBottom: 14 }}>{lang === 'pt' ? 'métricas diárias · 14 dias' : 'daily metrics · 14 days'}</div>
            <Sparkline label={lang === 'pt' ? 'sono (h)' : 'sleep (h)'} data={h.metrics.sleep} color="var(--teal)" suffix="h" />
            <Sparkline label={lang === 'pt' ? 'humor' : 'mood'} data={h.metrics.mood} color="var(--sun)" max={5} />
            <Sparkline label={lang === 'pt' ? 'energia' : 'energy'} data={h.metrics.energy} color="var(--leaf)" max={5} />
            {h.metrics.hydration && <Sparkline label={lang === 'pt' ? 'hidratação (L)' : 'hydration (L)'} data={h.metrics.hydration} color="#5C8AB8" suffix="L" />}
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0 }}>
          {/* Medidas atuais + variação vs sessão anterior */}
          <div style={card}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14, flexWrap: 'wrap', gap: 6 }}>
              <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'medidas atuais' : 'current measures'}</div>
              {latest && <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{dmBR(latest.dia)}</div>}
            </div>
            {!latest ? (
              <div className="empty" style={{ padding: 24 }}>{lang === 'pt' ? 'sem medições' : 'no measures'}</div>
            ) : (
              <div style={{ display: 'flex', flexDirection: 'column' }}>
                {Object.keys(MEASURE_META).map((k, i, arr) => {
                  const meta = MEASURE_META[k];
                  const v = latest[k], pv = prev ? prev[k] : null;
                  const d = (v != null && pv != null) ? (Number(v) - Number(pv)) : null;
                  const good = d != null && (meta.lowerBetter ? d < 0 : d > 0);
                  return (
                    <div key={k} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0', borderBottom: i < arr.length - 1 ? '1px solid var(--line-soft)' : 'none' }}>
                      <span style={{ fontSize: 13, color: 'var(--ink-2)' }}>{meta.l}</span>
                      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
                        <span style={{ fontFamily: 'var(--fm)', fontSize: 13 }}>{v != null ? v : '—'} <span style={{ color: 'var(--muted)', fontSize: 11 }}>{meta.u}</span></span>
                        {d != null && d !== 0 && <span style={{ fontFamily: 'var(--fm)', fontSize: 11, minWidth: 46, textAlign: 'right', color: good ? 'var(--leaf)' : 'var(--accent)' }}>{d > 0 ? '+' : ''}{d.toFixed(1)} {meta.u}</span>}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>

          {/* Fotos: comparador antes/depois */}
          <div style={card}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'fotos · antes / depois' : 'photos · before / after'}</div>
            {comPhotos.length < 1 ? (
              <div className="empty" style={{ padding: '28px 16px', textAlign: 'center' }}>📷
                <div style={{ marginTop: 8, fontSize: 13 }}>{lang === 'pt' ? 'Sem fotos ainda.' : 'No photos yet.'}</div>
                <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 4, fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'As fotos de cada sessão de medição com o professor aparecerão aqui para comparar evolução.' : 'Photos from each session with the coach will appear here.'}</div>
              </div>
            ) : (
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                {[comPhotos[0], comPhotos[comPhotos.length - 1]].map((s, idx) => (
                  <div key={idx}>
                    <div style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)', marginBottom: 6 }}>{idx === 0 ? (lang === 'pt' ? 'Antes' : 'Before') : (lang === 'pt' ? 'Depois' : 'After')} · {dmBR(s.dia)}</div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                      {['frente', 'lado', 'costas'].map(p => s.fotos[p] && (
                        <img key={p} src={s.fotos[p]} alt={p} style={{ width: '100%', borderRadius: 10, background: 'var(--cream-2)' }} />
                      ))}
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
      <style>{`@media (max-width:820px){.saude-dash-grid{grid-template-columns:1fr !important;}}`}</style>
    </div>
  );
};

const Saude = ({state, setState, setPage}) => {
  const tt = useT();
  const lang = tt.lang;
  const toast = useToast();
  const [tab, setTab] = useState('geral');

  const me = state.users.find(u => u.role === state.role) || state.users[0];
  const isCoach = me.id === state.health?.coach;
  const consented = state.health?.consent || false;

  // tabs depend on role
  const tabs = [
    {id:'geral',    pt:'visão geral',         en:'overview',  show: !isCoach, gated:!consented},
    {id:'treino',   pt:'treino e dieta',      en:'training',  show: !isCoach, gated:!consented},
    {id:'metricas', pt:'métricas e evolução', en:'metrics',   show: !isCoach, gated:!consented},
    {id:'coach',    pt:'turma',               en:'class',     show: isCoach},
  ].filter(t => t.show);

  return (
    <main style={{padding:'26px 20px 56px', flex:1, maxWidth:1180, margin:'0 auto', width:'100%', boxSizing:'border-box'}}>
      {/* Privacy banner */}
      <PrivacyBanner state={state} setState={setState} lang={lang} toast={toast} consented={consented} isCoach={isCoach}/>

      {/* Tabs */}
      <div style={{display:'flex',gap:6,marginBottom:24,borderBottom:'1px solid var(--line-soft)'}}>
        {tabs.map(t => (
          <button key={t.id} onClick={()=>setTab(t.id)}
            style={{
              background:'transparent',border:'none',padding:'10px 18px',
              fontFamily:'var(--fs)',fontStyle:'italic',fontSize:18,
              color: tab===t.id ? 'var(--accent)' : 'var(--muted)',
              borderBottom: tab===t.id ? '2px solid var(--accent)' : '2px solid transparent',
              cursor:'pointer',marginBottom:-1,transition:'all .15s',
              opacity: t.gated ? 0.5 : 1
            }}>
            {lang==='pt'?t.pt:t.en}
            {t.gated && <Icon n="lock" size={11} stroke={1.4} />}
          </button>
        ))}
      </div>

      {!consented && tab !== 'coach' ? (
        <ConsentScreen state={state} setState={setState} lang={lang}/>
      ) : (
        <>
          {tab==='geral' && <PersonalView state={state} setState={setState} setPage={setPage} lang={lang} toast={toast} me={me}/>}
          {tab==='treino' && <TreinoDietaView state={state} setPage={setPage} lang={lang} toast={toast} me={me}/>}
          {tab==='metricas' && <MetricasView state={state} lang={lang} me={me}/>}
          {tab==='coach' && <Coach state={state}/>}{/* mesa nova (coach.jsx) — CoachView antigo aposentado */}
        </>
      )}
    </main>
  );
};

// ─── Privacy banner (always visible) ───
const PrivacyBanner = ({state, setState, lang, toast, consented, isCoach}) => {
  if (isCoach) return (
    <div style={{
      padding:'12px 18px',background:'var(--accent-soft)',border:'1px solid var(--accent)',
      borderRadius:14,marginBottom:20,display:'flex',alignItems:'center',gap:12,fontSize:13
    }}>
      <Icon n="lock" size={16} stroke={1.5}/>
      <div style={{flex:1}}>
        <strong style={{color:'var(--accent)'}}>{lang==='pt'?'Acesso de Prof. de EF':'EF Coach access'}</strong>
        {' · '}
        <span style={{color:'var(--ink-2)'}}>
          {lang==='pt'
            ? 'você vê apenas adesão e último treino dos atletas que consentiram. Diário, dieta e mente continuam privados.'
            : 'you see only adherence and last workout of consenting athletes. Journal, diet and mind stay private.'}
        </span>
      </div>
    </div>
  );

  return (
    <div style={{
      padding:'14px 18px',background:'#FDF7EE',border:'1px solid var(--line-soft)',
      borderRadius:14,marginBottom:20,display:'flex',alignItems:'center',gap:14,fontSize:13
    }}>
      <div style={{
        width:32,height:32,borderRadius:'50%',background:'var(--accent-soft)',color:'var(--accent)',
        display:'grid',placeItems:'center',flexShrink:0
      }}>
        <Icon n="lock" size={15} stroke={1.6}/>
      </div>
      <div style={{flex:1,lineHeight:1.5}}>
        <div style={{fontWeight:500,marginBottom:2}}>
          {lang==='pt'?'só você e o Prof. de EF veem isso aqui.':'only you and the EF coach see this.'}
        </div>
        <div style={{color:'var(--muted)',fontSize:12}}>
          {lang==='pt'
            ? 'Operação, comando e colegas nunca acessam suas métricas. Este app não substitui acompanhamento médico.'
            : 'Ops, command and crew never see your metrics. This app does not replace medical care.'}
        </div>
      </div>
      {consented && (
        <button className="btn btn-ghost" onClick={()=>{
          if (confirm(lang==='pt'?'Revogar consentimento? Suas métricas voltarão a ficar bloqueadas.':'Revoke consent? Your metrics will be locked again.')) {
            setState(s => ({...s, health:{...s.health, consent:false}}));
            toast.push({icon:'lock', title:lang==='pt'?'Consentimento revogado':'Consent revoked'});
          }
        }} style={{fontSize:11}}>
          {lang==='pt'?'Revogar':'Revoke'}
        </button>
      )}
    </div>
  );
};

// ─── Consent screen (gate) ───
const ConsentScreen = ({state, setState, lang}) => {
  const coachUser = state.users.find(u => u.id === state.health?.coach);
  return (
    <div style={{maxWidth:600,margin:'40px auto',background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:24,padding:'40px 44px'}}>
      <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:14}}>
        {lang==='pt'?'Termos de uso · saúde':'Health · terms of use'}
      </div>
      <div style={{fontFamily:'var(--fs)',fontSize:32,letterSpacing:'-0.5px',lineHeight:1.15,marginBottom:18}}>
        {lang==='pt'?'antes de começar,':'before you start,'} <em style={{color:'var(--muted-2)'}}>{lang==='pt'?'leia com calma.':'read it carefully.'}</em>
      </div>
      <div style={{fontSize:14,lineHeight:1.7,color:'var(--ink-2)',marginBottom:24}}>
        {lang==='pt' ? (
          <>
            <p style={{marginBottom:14}}>O Portal Genesis cria um espaço pessoal e privado para cuidar do seu corpo e mente durante o embarque.</p>
            <p style={{marginBottom:14}}>Aqui você compartilha métricas (peso, sono, humor), seu plano de treino e o diário <em>somente com</em> o Prof. de EF responsável pela equipe — atualmente <strong>{coachUser?.nome || 'definir'}</strong>.</p>
            <p style={{marginBottom:14}}>O comando, a operação e o restante da tripulação nunca acessam seus dados, nem em painéis agregados.</p>
            <p style={{marginBottom:14}}>Você pode revogar o consentimento a qualquer momento — seus dados ficam bloqueados imediatamente, mas permanecem armazenados localmente para o caso de você reconsiderar.</p>
            <p style={{marginBottom:0,padding:14,background:'var(--cream-2)',borderRadius:10,fontSize:13}}>
              <strong>Limites do app.</strong> Esta ferramenta apoia hábitos saudáveis a bordo. Não diagnostica nem trata condições médicas. Em caso de sintomas, procure a enfermaria.
            </p>
          </>
        ) : (
          <>
            <p style={{marginBottom:14}}>Portal Genesis creates a personal, private space to care for your body and mind on board.</p>
            <p style={{marginBottom:14}}>You share metrics (weight, sleep, mood), training plan and journal <em>only with</em> the EF coach in charge of the team — currently <strong>{coachUser?.nome || 'tbd'}</strong>.</p>
            <p style={{marginBottom:14}}>Command, ops and the rest of the crew never see your data, not even in aggregate.</p>
            <p style={{marginBottom:14}}>You can revoke consent any time — data is locked immediately and kept locally in case you change your mind.</p>
            <p style={{marginBottom:0,padding:14,background:'var(--cream-2)',borderRadius:10,fontSize:13}}>
              <strong>App limits.</strong> This tool supports healthy habits on board. It does not diagnose or treat medical conditions. For symptoms, see the infirmary.
            </p>
          </>
        )}
      </div>
      <button className="btn btn-primary" style={{width:'100%',padding:'14px'}}
        onClick={()=>setState(s => ({...s, health:{...s.health, consent:true}}))}>
        <Icon n="check" size={14}/>
        {lang==='pt'?'Aceito e quero começar':'I accept and want to start'}
      </button>
    </div>
  );
};

// ─── PERSONAL: training plan + diet + metrics + journal ───
// ─── Dashboard pessoal de saúde (estilo painel) ───
const saudacaoPT = () => { const h = new Date().getHours(); return h < 12 ? 'Bom dia' : h < 18 ? 'Boa tarde' : 'Boa noite'; };
const saudacaoEN = () => { const h = new Date().getHours(); return h < 12 ? 'Good morning' : h < 18 ? 'Good afternoon' : 'Good evening'; };
const arrLast = a => (a && a.length) ? a[a.length - 1] : 0;
const arrAvg = a => (a && a.length) ? a.reduce((s, x) => s + x, 0) / a.length : 0;
const arrDelta = a => (a && a.length >= 8) ? (a[a.length - 1] - a[a.length - 8]) : 0;
const METAPESO = 78.0, METAGORDURA = 15.0;

const KpiCard = ({ emoji, label, value, unit, sub, delta, deltaGood, tone }) => (
  <div style={{ background: 'var(--surface)', border: '1px solid var(--line-soft)', borderTop: `3px solid ${tone || 'var(--line-soft)'}`, borderRadius: 14, padding: '13px 15px', display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0, boxShadow: 'var(--shadow-sm)' }}>
    <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--muted)' }}>
      <span style={{ fontSize: 15 }}>{emoji}</span>
      <span style={{ fontFamily: 'var(--fm)', fontSize: 11, letterSpacing: 0.3 }}>{label}</span>
    </div>
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap' }}>
      <span style={{ fontFamily: 'var(--fs)', fontSize: 28, letterSpacing: '-0.6px', lineHeight: 1 }}>{value}</span>
      {unit && <span style={{ fontSize: 12, color: 'var(--muted)' }}>{unit}</span>}
      {delta != null && delta !== 0 && (
        <span style={{ fontSize: 11, fontFamily: 'var(--fm)', color: deltaGood ? 'var(--leaf)' : 'var(--accent)' }}>
          {delta > 0 ? '↑' : '↓'} {Math.abs(delta).toFixed(1)}
        </span>
      )}
    </div>
    {sub && <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{sub}</div>}
    <div style={{ height: 4, borderRadius: 2, background: 'var(--cream-2)', overflow: 'hidden', marginTop: 2 }}>
      <div style={{ height: '100%', width: '60%', background: tone || 'var(--accent)', borderRadius: 2 }} />
    </div>
  </div>
);

const ScoreCard = ({ score, lang }) => {
  const r = 30, c = 2 * Math.PI * r, off = c * (1 - score / 100);
  const band = score >= 85 ? (lang === 'pt' ? 'Muito bom' : 'Excellent') : score >= 70 ? (lang === 'pt' ? 'Bom' : 'Good') : score >= 50 ? (lang === 'pt' ? 'Regular' : 'Fair') : (lang === 'pt' ? 'Atenção' : 'Low');
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderRadius: 18, padding: '15px 17px', display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center', boxShadow: 'var(--shadow-sm)', minWidth: 0 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: 'var(--muted)', alignSelf: 'flex-start' }}>
        <span style={{ fontSize: 15 }}>❤️</span>
        <span style={{ fontFamily: 'var(--fm)', fontSize: 11 }}>Health Score</span>
      </div>
      <svg width="78" height="78" viewBox="0 0 84 84">
        <circle cx="42" cy="42" r={r} fill="none" stroke="var(--cream-2)" strokeWidth="8" />
        <circle cx="42" cy="42" r={r} fill="none" stroke="var(--leaf)" strokeWidth="8" strokeLinecap="round" strokeDasharray={c} strokeDashoffset={off} transform="rotate(-90 42 42)" />
        <text x="42" y="44" textAnchor="middle" fontFamily="var(--fs)" fontSize="22" fill="var(--ink)">{score}</text>
        <text x="42" y="58" textAnchor="middle" fontFamily="var(--fm)" fontSize="8" fill="var(--muted)">/100</text>
      </svg>
      <div style={{ fontSize: 11, color: 'var(--leaf)', fontFamily: 'var(--fm)' }}>{band}</div>
    </div>
  );
};

const EvoChart = ({ h, lang }) => {
  const series = {
    weight:   { label: lang === 'pt' ? 'Peso' : 'Weight', data: h.metrics.weight, unit: 'kg', color: 'var(--accent)', meta: METAPESO },
    bodyfat:  { label: lang === 'pt' ? 'Gordura' : 'Body fat', data: h.metrics.bodyfat, unit: '%', color: 'var(--sun)' },
    leanmass: { label: lang === 'pt' ? 'Massa magra' : 'Lean mass', data: h.metrics.leanmass, unit: 'kg', color: 'var(--leaf)' },
    waist:    { label: lang === 'pt' ? 'Cintura' : 'Waist', data: h.metrics.waist, unit: 'cm', color: 'var(--teal)' },
  };
  const [sel, setSel] = useState('weight');
  const s = series[sel];
  const data = s.data || [];
  const minV = Math.min(...data, s.meta || Infinity);
  const maxV = Math.max(...data, s.meta || -Infinity);
  const range = (maxV - minV) || 1;
  const W = 300, H = 120, pad = 8;
  const x = i => pad + (i / (data.length - 1)) * (W - pad * 2);
  const y = v => pad + (1 - (v - minV) / range) * (H - pad * 2);
  const pts = data.map((v, i) => `${x(i)},${y(v)}`).join(' ');
  const last = arrLast(data), first = data[0] || 0, delta = last - first;
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderRadius: 20, padding: '20px 22px', boxShadow: 'var(--shadow-sm)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 12, flexWrap: 'wrap', gap: 8 }}>
        <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'evolução corporal' : 'body evolution'}</div>
        <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'últimos 14 dias' : 'last 14 days'}</div>
      </div>
      <div style={{ display: 'flex', gap: 6, marginBottom: 14, flexWrap: 'wrap' }}>
        {Object.keys(series).map(k => (
          <button key={k} onClick={() => setSel(k)} className={sel === k ? 'btn btn-primary btn-sm' : 'btn btn-sm'} style={{ fontSize: 11 }}>{series[k].label}</button>
        ))}
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 6 }}>
        <span style={{ fontFamily: 'var(--fs)', fontSize: 28, letterSpacing: '-0.5px' }}>{last.toFixed(1)} <em style={{ fontSize: 13, color: 'var(--muted)' }}>{s.unit}</em></span>
        <span style={{ fontSize: 12, fontFamily: 'var(--fm)', color: delta < 0 ? 'var(--leaf)' : delta > 0 ? 'var(--accent)' : 'var(--muted)' }}>{delta > 0 ? '↑' : delta < 0 ? '↓' : ''} {Math.abs(delta).toFixed(1)} {s.unit}</span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 'auto' }}>
        {s.meta != null && (
          <g>
            <line x1={pad} y1={y(s.meta)} x2={W - pad} y2={y(s.meta)} stroke="var(--accent)" strokeWidth="1" strokeDasharray="4 4" opacity="0.5" />
            <text x={pad + 2} y={y(s.meta) - 4} fontFamily="var(--fm)" fontSize="8" fill="var(--accent)">{lang === 'pt' ? 'Meta' : 'Goal'} {s.meta}</text>
          </g>
        )}
        <polyline points={pts} fill="none" stroke={s.color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
        {data.map((v, i) => <circle key={i} cx={x(i)} cy={y(v)} r={i === data.length - 1 ? 3.5 : 1.6} fill={s.color} />)}
      </svg>
    </div>
  );
};

const MeasuresCard = ({ h, lang }) => {
  const m = h.measures;
  if (!m) return null;
  return (
    <div style={{ background: 'var(--cream)', border: '1px solid var(--line-soft)', borderRadius: 20, padding: '20px 22px', boxShadow: 'var(--shadow-sm)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14, flexWrap: 'wrap', gap: 6 }}>
        <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'medidas corporais' : 'body measures'}</div>
        <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{m.data}</div>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column' }}>
        {m.itens.map((it, i) => (
          <div key={i} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0', borderBottom: i < m.itens.length - 1 ? '1px solid var(--line-soft)' : 'none' }}>
            <span style={{ fontSize: 13, color: 'var(--ink-2)' }}>{it.label}</span>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
              <span style={{ fontFamily: 'var(--fm)', fontSize: 13 }}>{it.v} <span style={{ color: 'var(--muted)', fontSize: 11 }}>{it.unit}</span></span>
              {it.delta != null && it.delta !== 0 && (
                <span style={{ fontFamily: 'var(--fm)', fontSize: 11, minWidth: 42, textAlign: 'right', color: it.delta < 0 ? 'var(--leaf)' : 'var(--accent)' }}>{it.delta > 0 ? '+' : ''}{it.delta} {it.unit}</span>
              )}
            </div>
          </div>
        ))}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8, marginTop: 14, paddingTop: 14, borderTop: '1px solid var(--line-soft)' }}>
        {[
          { l: lang === 'pt' ? 'Peso inicial' : 'Start', v: m.pesoInicial + ' kg' },
          { l: lang === 'pt' ? 'Menor peso' : 'Lowest', v: m.pesoMenor + ' kg' },
          { l: lang === 'pt' ? 'Variação' : 'Change', v: (m.variacao > 0 ? '+' : '') + m.variacao + ' kg', tone: m.variacao < 0 ? 'var(--leaf)' : 'var(--accent)' },
        ].map((b, i) => (
          <div key={i}>
            <div style={{ fontSize: 10, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{b.l}</div>
            <div style={{ fontFamily: 'var(--fs)', fontSize: 18, color: b.tone || 'var(--ink)' }}>{b.v}</div>
          </div>
        ))}
      </div>
    </div>
  );
};

const PersonalView = ({ state, setState, setPage, lang, toast, me }) => {
  const h = state.health;
  const today = new Date();
  const dayName = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'][today.getDay()];
  const coach = state.users.find(u => u.id === h.coach);
  const firstName = ((state.currentUser && state.currentUser.nome) || me?.nome || '').split(' ')[0];

  // dados reais do backend
  const [bk, setBk] = useState(null); // { plan, diet, dlog, sessions, checkins }
  const loadBk = () => {
    const hdr = { headers: { Authorization: `Bearer ${SAUDE_TK()}` } };
    return Promise.all([
      fetch('/api/saude/plan/me', hdr).then(r => r.ok ? r.json() : null),
      fetch('/api/saude/diet/me', hdr).then(r => r.ok ? r.json() : null),
      fetch('/api/saude/dietlog', hdr).then(r => r.ok ? r.json() : { consumidas: [], agua: 0 }),
      fetch('/api/saude/measurements/me', hdr).then(r => r.ok ? r.json() : []),
      fetch('/api/saude/checkins?days=21', hdr).then(r => r.ok ? r.json() : []),
    ]).then(([plan, diet, dlog, sessions, checkins]) => setBk({ plan, diet, dlog, sessions: Array.isArray(sessions) ? sessions : [], checkins: Array.isArray(checkins) ? checkins : [] })).catch(() => setBk({}));
  };
  useEffect(() => { loadBk(); }, []);

  // 📸 check-in da academia (validado pelo professor) + jornada (streak/ano)
  const [gymSt, setGymSt] = useState(null);
  const [jogoGym, setJogoGym] = useState(null);
  const [ckModal, setCkModal] = useState(false);
  const loadGym = () => {
    const hdr = { headers: { Authorization: `Bearer ${SAUDE_TK()}` } };
    fetch('/api/users/gym-checkin/meu-status', hdr).then(r => r.ok ? r.json() : null).then(d => setGymSt(d)).catch(() => {});
    const uid = (state.currentUser && state.currentUser.id) || (me && me.id);
    if (uid) fetch(`/api/users/conquistas/${uid}`, hdr).then(r => r.ok ? r.json() : null).then(d => setJogoGym(d)).catch(() => {});
  };
  useEffect(() => { loadGym(); }, []);

  // check-in diário (backend → fallback seed)
  const checkins = (bk && bk.checkins) || [];
  const ckVals = key => checkins.map(c => c[key]).filter(v => v != null).map(Number);
  const dSleep = checkins.length && ckVals('sono').length ? ckVals('sono') : h.metrics.sleep;
  const dMood = checkins.length && ckVals('humor').length ? ckVals('humor') : h.metrics.mood;
  const dEnergy = checkins.length && ckVals('energia').length ? ckVals('energia') : h.metrics.energy;
  const dHydra = checkins.length && ckVals('hidratacao').length ? ckVals('hidratacao') : h.metrics.hydration;

  // treino (backend → fallback seed)
  const plan = (bk && bk.plan) || h.plan;
  const week = (plan && plan.week) || [];
  const todayPlan = week.find(d => d.day === dayName) || week[0] || { focus: '', exercises: [] };
  const [done, setDone] = useState({});
  const totalEx = todayPlan.exercises.length;
  const doneCount = todayPlan.exercises.filter((_, i) => done[i]).length;
  const pct = totalEx ? Math.round(doneCount / totalEx * 100) : 0;

  // medições (backend → fallback seed)
  const sessions = (bk && bk.sessions) || [];
  const latest = sessions[sessions.length - 1];
  const prevS = sessions[sessions.length - 2];
  const mDelta = k => (latest && prevS && latest[k] != null && prevS[k] != null) ? (Number(latest[k]) - Number(prevS[k])) : null;
  const weightLast = latest ? Number(latest.peso) : arrLast(h.metrics.weight);
  const weightDelta = mDelta('peso') != null ? mDelta('peso') : arrDelta(h.metrics.weight);
  const bfLast = latest ? Number(latest.gordura) : arrLast(h.metrics.bodyfat);
  const bfDelta = mDelta('gordura') != null ? mDelta('gordura') : arrDelta(h.metrics.bodyfat);

  // dieta (backend → fallback seed)
  const diet = (bk && bk.diet) || null;
  const refeicoes = diet ? diet.refeicoes : h.diet.hoje;
  const metaKcal = diet ? diet.meta_kcal : h.diet.meta;
  const consumidas = (bk && bk.dlog && bk.dlog.consumidas) || [];
  const consumedKcal = refeicoes.reduce((s, r, i) => s + (consumidas.includes(i) ? (r.kcal || 0) : 0), 0);
  const restantes = Math.max(0, metaKcal - consumedKcal);

  // sono + health score (check-in real → fallback seed)
  const sleepLast = arrLast(dSleep), sleepAvg = arrAvg(dSleep);
  const score = Math.round((Math.min(1, sleepAvg / 8) * 0.3 + (arrAvg(dMood) / 5) * 0.25 + (arrAvg(dEnergy) / 5) * 0.25 + Math.min(1, h.diet.total / h.diet.meta) * 0.2) * 100);

  // fotos: última sessão com fotos
  const fotoSession = sessions.slice().reverse().find(s => s.fotos && (s.fotos.frente || s.fotos.lado || s.fotos.costas));

  const card = { background: 'var(--surface)', border: '1px solid var(--line-soft)', borderRadius: 16, padding: '15px 17px', boxShadow: 'var(--shadow-sm)' };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      {/* Saudação */}
      <div>
        <h2 style={{ fontFamily: 'var(--fs)', fontSize: 26, letterSpacing: '-0.6px', fontWeight: 400 }}>
          {lang === 'pt' ? saudacaoPT() : saudacaoEN()}, <em style={{ fontStyle: 'italic', color: 'var(--accent)' }}>{firstName}.</em> 👋
        </h2>
        <div style={{ fontSize: 13, color: 'var(--muted)', marginTop: 2 }}>{lang === 'pt' ? 'Aqui está o seu resumo de hoje.' : "Here's your summary for today."}</div>
      </div>

      {/* ═══ 🌅 MEU DIA: treino de hoje · check-in · jornada ═══ */}
      <div style={{ ...card, borderTop: '3px solid var(--accent)', padding: '16px 18px' }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1.3fr) minmax(0,1fr) minmax(0,1fr)', gap: 14, alignItems: 'stretch' }} className="saude-meudia-grid">

          {/* treino de hoje */}
          <div style={{ minWidth: 0 }}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 4 }}>🏋️ {lang === 'pt' ? 'treino de hoje' : "today's workout"}</div>
            <div style={{ fontFamily: 'var(--fs)', fontSize: 23, letterSpacing: '-0.5px', lineHeight: 1.1 }}>{todayPlan.focus || (lang === 'pt' ? 'Descanso' : 'Rest day')}</div>
            <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', marginTop: 3, marginBottom: 10 }}>
              {totalEx ? `${totalEx} ${lang === 'pt' ? 'exercícios' : 'exercises'}` : (lang === 'pt' ? 'recupera que amanhã tem mais' : 'recover — more tomorrow')}
            </div>
            {totalEx > 0 && setPage ? (
              <button onClick={() => setPage('treino')} style={{ border: 'none', cursor: 'pointer', borderRadius: 12, padding: '11px 18px', background: 'linear-gradient(135deg, var(--accent), var(--accent-2))', color: '#fff', fontFamily: 'var(--fs)', fontSize: 14.5, fontWeight: 700, boxShadow: '0 5px 18px rgba(217,105,75,0.3)' }}>
                🤳 {lang === 'pt' ? 'Iniciar treino' : 'Start workout'}
              </button>
            ) : null}
          </div>

          {/* check-in validado */}
          <div style={{ minWidth: 0, borderLeft: '1px solid var(--line-soft)', paddingLeft: 14 }} className="saude-meudia-sep">
            <div className="t-eyebrow" style={{ color: 'var(--leaf)', marginBottom: 4 }}>📸 check-in</div>
            {gymSt && gymSt.hoje === 'validado' ? (
              <React.Fragment>
                <div style={{ fontFamily: 'var(--fs)', fontSize: 21, color: 'var(--leaf)' }}>✓ {lang === 'pt' ? 'Validado!' : 'Validated!'}</div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', marginTop: 3 }}>{lang === 'pt' ? 'treino de hoje na conta 💪' : 'today counted 💪'}</div>
              </React.Fragment>
            ) : gymSt && gymSt.hoje === 'pendente' ? (
              <React.Fragment>
                <div style={{ fontFamily: 'var(--fs)', fontSize: 21, color: 'var(--sun)' }}>⏳ {lang === 'pt' ? 'Enviado' : 'Sent'}</div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 10.5, color: 'var(--muted)', marginTop: 3 }}>{lang === 'pt' ? 'aguardando o professor validar' : 'awaiting coach'}</div>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <div style={{ fontSize: 11.5, color: 'var(--muted)', marginBottom: 8, lineHeight: 1.4 }}>{lang === 'pt' ? 'foi na academia? manda a foto que o professor valida.' : 'at the gym? send a photo for validation.'}</div>
                <button className="btn btn-primary btn-sm" onClick={() => setCkModal(true)}>📸 {lang === 'pt' ? 'Fazer check-in' : 'Check in'}</button>
                {gymSt && gymSt.hoje === 'recusado' ? <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--rose)', marginTop: 6 }}>✗ {lang === 'pt' ? 'recusado' : 'declined'}{gymSt.motivo ? `: ${gymSt.motivo}` : ''}</div> : null}
              </React.Fragment>
            )}
          </div>

          {/* jornada */}
          <div style={{ minWidth: 0, borderLeft: '1px solid var(--line-soft)', paddingLeft: 14 }} className="saude-meudia-sep">
            <div className="t-eyebrow" style={{ color: 'var(--teal)', marginBottom: 4 }}>⚓ {lang === 'pt' ? 'jornada' : 'journey'}</div>
            <div style={{ display: 'flex', gap: 16 }}>
              <div>
                <div style={{ fontFamily: 'var(--fs)', fontSize: 23, color: 'var(--rose)' }}>🔥 {jogoGym && jogoGym.gym ? jogoGym.gym.streak : '—'}</div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)' }}>{lang === 'pt' ? 'dias seguidos' : 'day streak'}</div>
              </div>
              <div>
                <div style={{ fontFamily: 'var(--fs)', fontSize: 23, color: 'var(--teal)' }}>🏋️ {jogoGym && jogoGym.gym ? jogoGym.gym.ano : '—'}</div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 9.5, color: 'var(--muted)' }}>{lang === 'pt' ? 'no ano' : 'this year'}</div>
              </div>
            </div>
            {jogoGym && jogoGym.pontos != null ? <div style={{ fontFamily: 'var(--fm)', fontSize: 10, color: 'var(--muted)', marginTop: 8 }}>⭐ {jogoGym.pontos.toLocaleString('pt-BR')} {lang === 'pt' ? 'pontos' : 'points'}</div> : null}
          </div>
        </div>
        <style>{`@media (max-width:860px){.saude-meudia-grid{grid-template-columns:1fr !important;}.saude-meudia-sep{border-left:none !important;padding-left:0 !important;border-top:1px solid var(--line-soft);padding-top:12px;}}`}</style>
      </div>
      {ckModal ? <CheckinFotoModal lang={lang} toast={toast} onClose={() => setCkModal(false)} onEnviado={loadGym} /> : null}

      <ProntidaoCard lang={lang} />

      {/* KPIs */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))', gap: 12 }}>
        <KpiCard emoji="🌙" label={lang === 'pt' ? 'Sono' : 'Sleep'} value={sleepLast.toFixed(1)} unit="h" delta={arrDelta(dSleep)} deltaGood={arrDelta(dSleep) >= 0} tone="var(--teal)" sub={`${lang === 'pt' ? 'Qualidade' : 'Quality'}: ${sleepAvg >= 7.5 ? (lang === 'pt' ? 'Boa' : 'Good') : (lang === 'pt' ? 'Regular' : 'Fair')}`} />
        <KpiCard emoji="⚖️" label={lang === 'pt' ? 'Peso' : 'Weight'} value={weightLast.toFixed(1)} unit="kg" delta={weightDelta} deltaGood={weightDelta <= 0} tone="var(--accent)" sub={`${lang === 'pt' ? 'Meta' : 'Goal'}: ${METAPESO.toFixed(1)} kg`} />
        <KpiCard emoji="📊" label={lang === 'pt' ? 'Gordura corporal' : 'Body fat'} value={bfLast.toFixed(1)} unit="%" delta={bfDelta} deltaGood={bfDelta <= 0} tone="var(--sun)" sub={`${lang === 'pt' ? 'Meta' : 'Goal'}: ${METAGORDURA.toFixed(1)}%`} />
        <KpiCard emoji="🔥" label={lang === 'pt' ? 'Calorias' : 'Calories'} value={consumedKcal.toLocaleString('pt-BR')} unit={`/ ${(metaKcal || 0).toLocaleString('pt-BR')}`} tone="var(--leaf)" sub={`${lang === 'pt' ? 'Restantes' : 'Remaining'}: ${restantes} kcal`} />
        <ScoreCard score={score} lang={lang} />
      </div>

      {/* Corpo do dashboard */}
      <div style={{ display: 'grid', gridTemplateColumns: 'minmax(0,1.3fr) minmax(0,1fr)', gap: 18 }} className="saude-dash-grid">
        {/* COLUNA ESQUERDA */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0 }}>
          {/* Treino de hoje */}
          <div style={card}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 12, flexWrap: 'wrap' }}>
              <div style={{ flex: 1, minWidth: 120 }}>
                <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'treino · hoje' : 'workout · today'}</div>
                <div style={{ fontFamily: 'var(--fs)', fontSize: 26, letterSpacing: '-0.5px', marginTop: 2 }}>{todayPlan.focus || (lang === 'pt' ? 'descanso' : 'rest')}</div>
              </div>
              {totalEx > 0 && (
                <div style={{ textAlign: 'right' }}>
                  <div style={{ display: 'inline-block', background: 'var(--accent)', color: 'var(--cream)', borderRadius: 20, padding: '4px 12px', fontFamily: 'var(--fm)', fontSize: 12 }}>{pct}% {lang === 'pt' ? 'concluído' : 'done'}</div>
                  <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)', marginTop: 4 }}>{doneCount} {lang === 'pt' ? 'de' : 'of'} {totalEx} {lang === 'pt' ? 'exercícios' : 'exercises'}</div>
                </div>
              )}
            </div>
            {totalEx > 0 ? (
              <div style={{ display: 'grid', gap: 8 }}>
                {todayPlan.exercises.map((ex, i) => (
                  <button key={i} onClick={() => setDone(d => ({ ...d, [i]: !d[i] }))}
                    style={{ textAlign: 'left', cursor: 'pointer', border: '1px solid var(--line-soft)', display: 'flex', alignItems: 'center', gap: 12, padding: '11px 14px', background: done[i] ? 'var(--leaf-soft)' : 'var(--cream-2)', borderRadius: 12 }}>
                    <span style={{ width: 22, height: 22, borderRadius: '50%', flexShrink: 0, display: 'grid', placeItems: 'center', background: done[i] ? 'var(--leaf)' : 'transparent', border: done[i] ? 'none' : '2px solid var(--line)', color: '#fff', fontSize: 12 }}>{done[i] ? '✓' : ''}</span>
                    <span style={{ flex: 1, fontSize: 13, fontWeight: 500, textDecoration: done[i] ? 'line-through' : 'none', color: done[i] ? 'var(--muted)' : 'var(--ink)' }}>{ex.nome}</span>
                    <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)' }}>{ex.series}×{ex.reps} · {ex.carga}</span>
                  </button>
                ))}
              </div>
            ) : (
              <div className="empty" style={{ padding: 24, textAlign: 'center' }}>{lang === 'pt' ? 'descanso programado. corpo agradece.' : 'rest day. your body thanks you.'}</div>
            )}
          </div>

          {/* Dieta do dia */}
          <div style={card}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
              <div className="t-eyebrow" style={{ color: 'var(--accent)', flex: 1 }}>{lang === 'pt' ? 'dieta · hoje' : 'diet · today'}</div>
              <div style={{ fontFamily: 'var(--fm)', fontSize: 13 }}>{consumedKcal.toLocaleString('pt-BR')} <span style={{ color: 'var(--muted)' }}>/ {(metaKcal || 0).toLocaleString('pt-BR')} kcal</span></div>
            </div>
            <div style={{ height: 6, background: 'var(--cream-2)', borderRadius: 3, overflow: 'hidden', marginBottom: 14 }}>
              <div style={{ width: `${Math.min(100, metaKcal ? consumedKcal / metaKcal * 100 : 0)}%`, height: '100%', background: 'var(--leaf)', borderRadius: 3 }} />
            </div>
            <div style={{ display: 'flex', flexDirection: 'column' }}>
              {refeicoes.map((r, i) => (
                <div key={i} style={{ display: 'flex', gap: 14, padding: '11px 0', borderBottom: i < refeicoes.length - 1 ? '1px solid var(--line-soft)' : 'none', alignItems: 'baseline', opacity: consumidas.includes(i) ? 0.6 : 1 }}>
                  <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--accent)', minWidth: 42 }}>{r.hora || ''}</span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontFamily: 'var(--fs)', fontStyle: 'italic', fontSize: 15, color: 'var(--ink)' }}>{consumidas.includes(i) ? '✓ ' : ''}{r.refeicao}</div>
                    <div style={{ fontSize: 12, color: 'var(--muted)', lineHeight: 1.5 }}>{(r.alimentos || []).join(', ')}</div>
                  </div>
                  <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--ink-2)' }}>{r.kcal} kcal</span>
                </div>
              ))}
            </div>
          </div>

          {/* Métricas diárias (check-in real → fallback seed) */}
          <div style={card}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'métricas diárias' : 'daily metrics'}</div>
            <Sparkline label={lang === 'pt' ? 'sono (h)' : 'sleep (h)'} data={dSleep} color="var(--teal)" suffix="h" />
            <Sparkline label={lang === 'pt' ? 'humor' : 'mood'} data={dMood} color="var(--sun)" max={5} />
            <Sparkline label={lang === 'pt' ? 'energia' : 'energy'} data={dEnergy} color="var(--leaf)" max={5} />
            {dHydra && <Sparkline label={lang === 'pt' ? 'hidratação (L)' : 'hydration (L)'} data={dHydra} color="#5C8AB8" suffix="L" />}
          </div>

          {/* Diário de bordo / check-in */}
          <div style={card}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'diário de bordo' : 'logbook'}</div>
            <CheckinJournal checkins={checkins} onSaved={loadBk} lang={lang} />
          </div>
        </div>

        {/* COLUNA DIREITA */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0 }}>
          {sessions.length > 0 ? <MeasureChart sessions={sessions} lang={lang} me={me} /> : <EvoChart h={h} lang={lang} />}

          {/* Medidas atuais (backend → fallback seed) */}
          {latest ? (
            <div style={card}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14, flexWrap: 'wrap', gap: 6 }}>
                <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'medidas atuais' : 'current measures'}</div>
                <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{dmBR(latest.dia)}</div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column' }}>
                {Object.keys(MEASURE_META).map((k, i, arr) => {
                  const meta = MEASURE_META[k], v = latest[k], d = mDelta(k);
                  const good = d != null && (meta.lowerBetter ? d < 0 : d > 0);
                  return (
                    <div key={k} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '9px 0', borderBottom: i < arr.length - 1 ? '1px solid var(--line-soft)' : 'none' }}>
                      <span style={{ fontSize: 13, color: 'var(--ink-2)' }}>{meta.l}</span>
                      <div style={{ display: 'flex', alignItems: 'baseline', gap: 10 }}>
                        <span style={{ fontFamily: 'var(--fm)', fontSize: 13 }}>{v != null ? v : '—'} <span style={{ color: 'var(--muted)', fontSize: 11 }}>{meta.u}</span></span>
                        {d != null && d !== 0 && <span style={{ fontFamily: 'var(--fm)', fontSize: 11, minWidth: 46, textAlign: 'right', color: good ? 'var(--leaf)' : 'var(--accent)' }}>{d > 0 ? '+' : ''}{d.toFixed(1)} {meta.u}</span>}
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          ) : <MeasuresCard h={h} lang={lang} />}

          {/* Desafios ativos */}
          {h.challenges && h.challenges.length > 0 && (
            <div style={card}>
              <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'desafios ativos' : 'active challenges'}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
                {h.challenges.map((c, i) => (
                  <div key={i}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
                      <div>
                        <div style={{ fontSize: 13, fontWeight: 500 }}>{c.nome}</div>
                        <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{c.desc}</div>
                      </div>
                      <div style={{ fontFamily: 'var(--fs)', fontSize: 20, color: 'var(--accent)' }}>{c.meta ? `${Math.round(c.valor / c.meta * 100)}%` : `${c.valor}`}<span style={{ fontSize: 11, color: 'var(--muted)' }}>{c.meta ? '' : ` ${c.unidade}`}</span></div>
                    </div>
                    {c.meta ? (
                      <div style={{ height: 6, background: 'var(--cream-2)', borderRadius: 3, overflow: 'hidden' }}>
                        <div style={{ width: `${Math.min(100, c.valor / c.meta * 100)}%`, height: '100%', background: 'var(--leaf)', borderRadius: 3 }} />
                      </div>
                    ) : (
                      <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'sequência atual' : 'current streak'}</div>
                    )}
                    {c.meta && <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)', marginTop: 4 }}>{c.valor} / {c.meta} {c.unidade}</div>}
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Ranking saudável */}
          {h.ranking && h.ranking.length > 0 && (
            <div style={card}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 12 }}>
                <div className="t-eyebrow" style={{ color: 'var(--accent)' }}>{lang === 'pt' ? 'ranking saudável' : 'healthy ranking'}</div>
                <div style={{ fontSize: 10.5, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'mês atual' : 'this month'}</div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column' }}>
                {h.ranking.map((r, i) => (
                  <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '9px 10px', borderRadius: 10, background: r.eu ? 'var(--accent-soft)' : 'transparent' }}>
                    <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--muted)', width: 16 }}>{i + 1}</span>
                    <span style={{ width: 28, height: 28, borderRadius: '50%', background: 'var(--cream-2)', display: 'grid', placeItems: 'center', fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)' }}>{r.nome.split(' ').map(w => w[0]).slice(0, 2).join('')}</span>
                    <span style={{ flex: 1, fontSize: 13, fontWeight: r.eu ? 600 : 400 }}>{r.nome}{r.eu ? (lang === 'pt' ? ' (você)' : ' (you)') : ''}</span>
                    <span style={{ fontFamily: 'var(--fm)', fontSize: 12, color: 'var(--leaf)' }}>+{r.pts.toFixed(1)} pts</span>
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* Profissional responsável */}
          {coach && (
            <div style={card}>
              <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'profissional responsável' : 'your coach'}</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                <Avatar user={coach} size="md" />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 14, fontWeight: 500 }}>{coach.nome}</div>
                  <div style={{ fontSize: 11, color: 'var(--muted)', fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'Prof. de Educação Física' : 'Physical Education'}</div>
                </div>
                <button className="btn btn-sm"><Icon n="chat" size={14} />{lang === 'pt' ? 'Mensagem' : 'Message'}</button>
              </div>
            </div>
          )}

          {/* Evolução em fotos (última sessão com fotos) */}
          <div style={card}>
            <div className="t-eyebrow" style={{ color: 'var(--accent)', marginBottom: 14 }}>{lang === 'pt' ? 'evolução em fotos' : 'photo progress'}</div>
            {fotoSession ? (
              <div>
                <div style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--muted)', marginBottom: 8 }}>{dmBR(fotoSession.dia)}</div>
                <div style={{ display: 'flex', gap: 8 }}>
                  {['frente', 'lado', 'costas'].map(p => fotoSession.fotos[p] && <img key={p} src={fotoSession.fotos[p]} alt={p} style={{ flex: 1, minWidth: 0, borderRadius: 10, objectFit: 'cover', background: 'var(--cream-2)' }} />)}
                </div>
              </div>
            ) : (
              <div className="empty" style={{ padding: '28px 16px', textAlign: 'center', fontSize: 13 }}>
                📷<div style={{ marginTop: 8 }}>{lang === 'pt' ? 'Nenhuma foto ainda.' : 'No photos yet.'}</div>
                <div style={{ fontSize: 11, color: 'var(--muted)', marginTop: 4, fontFamily: 'var(--fm)' }}>{lang === 'pt' ? 'As fotos das sessões com o professor aparecem aqui.' : 'Photos from coach sessions appear here.'}</div>
              </div>
            )}
          </div>
        </div>
      </div>

      <style>{`@media (max-width: 820px){ .saude-dash-grid{ grid-template-columns: 1fr !important; } }`}</style>
    </div>
  );
};

const Sparkline = ({label, data, color, suffix='', max}) => {
  const minV = Math.min(...data);
  const maxV = max || Math.max(...data);
  const range = maxV - minV || 1;
  const last = data[data.length-1];
  const prev = data[data.length-8] || data[0];
  const delta = last - prev;
  const w = 240, h = 40;
  const pts = data.map((v,i) => `${i/(data.length-1)*w},${h - ((v-minV)/range)*h}`).join(' ');
  return (
    <div style={{display:'flex',alignItems:'center',gap:14,padding:'10px 0',borderBottom:'1px solid var(--line-soft)'}}>
      <div style={{minWidth:90,fontSize:11.5,color:'var(--muted)',fontFamily:'var(--fm)',letterSpacing:0.3,textTransform:'lowercase'}}>{label}</div>
      <svg width={w} height={h} style={{flex:1,maxWidth:w}}>
        <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
        <circle cx={w} cy={h - ((last-minV)/range)*h} r="3" fill={color}/>
      </svg>
      <div style={{textAlign:'right',minWidth:60}}>
        <div style={{fontSize:14,fontWeight:500,fontFamily:'var(--fm)'}}>{typeof last === 'number' ? last.toFixed(suffix==='kg'||suffix==='h'?1:0) : last}{suffix && ` ${suffix}`}</div>
        <div style={{fontSize:10,color: delta > 0 ? '#7BB67E' : delta < 0 ? '#D9694B' : 'var(--muted)',fontFamily:'var(--fm)'}}>
          {delta > 0 ? '↑' : delta < 0 ? '↓' : '·'} {Math.abs(delta).toFixed(1)}
        </div>
      </div>
    </div>
  );
};

const CheckinJournal = ({ checkins, onSaved, lang }) => {
  const todayISO = new Date().toISOString().split('T')[0];
  const todayCk = checkins.find(c => (c.dia || '').slice(0, 10) === todayISO) || {};
  const [f, setF] = useState({ sono: '', humor: '', energia: '', hidratacao: '', peso: '', nota: '' });
  const [open, setOpen] = useState(false);
  const [saving, setSaving] = useState(false);
  useEffect(() => { setF({ sono: todayCk.sono ?? '', humor: todayCk.humor ?? '', energia: todayCk.energia ?? '', hidratacao: todayCk.hidratacao ?? '', peso: todayCk.peso ?? '', nota: todayCk.nota ?? '' }); }, [checkins.length]);
  const moodEmoji = m => m >= 5 ? '😄' : m >= 4 ? '🙂' : m >= 3 ? '😐' : m >= 2 ? '😕' : '😣';
  const save = async () => {
    setSaving(true);
    try { await fetch('/api/saude/checkin', { method: 'PUT', headers: { Authorization: `Bearer ${SAUDE_TK()}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ dia: todayISO, ...f }) }); if (onSaved) await onSaved(); setOpen(false); } catch (e) { } finally { setSaving(false); }
  };
  const recent = checkins.slice().reverse().slice(0, 6);
  const inp = { width: '100%', boxSizing: 'border-box' };
  return (
    <div>
      {!open ? (
        <button className="btn-tidal" style={{ marginBottom: 12 }} onClick={() => setOpen(true)}>＋ {todayCk.dia ? (lang === 'pt' ? 'Editar check-in' : 'Edit check-in') : (lang === 'pt' ? 'Check-in de hoje' : "Today's check-in")}</button>
      ) : (
        <div style={{ border: '1px solid var(--line-soft)', borderRadius: 12, padding: 14, marginBottom: 12 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(88px,1fr))', gap: 8, marginBottom: 8 }}>
            <div><label className="label">{lang === 'pt' ? 'Sono (h)' : 'Sleep (h)'}</label><input className="input" type="number" step="0.1" style={inp} value={f.sono} onChange={e => setF(s => ({ ...s, sono: e.target.value }))} /></div>
            <div><label className="label">{lang === 'pt' ? 'Humor 1-5' : 'Mood 1-5'}</label><input className="input" type="number" min="1" max="5" style={inp} value={f.humor} onChange={e => setF(s => ({ ...s, humor: e.target.value }))} /></div>
            <div><label className="label">{lang === 'pt' ? 'Energia 1-5' : 'Energy 1-5'}</label><input className="input" type="number" min="1" max="5" style={inp} value={f.energia} onChange={e => setF(s => ({ ...s, energia: e.target.value }))} /></div>
            <div><label className="label">{lang === 'pt' ? 'Água (L)' : 'Water (L)'}</label><input className="input" type="number" step="0.1" style={inp} value={f.hidratacao} onChange={e => setF(s => ({ ...s, hidratacao: e.target.value }))} /></div>
            <div><label className="label">{lang === 'pt' ? 'Peso (kg)' : 'Weight (kg)'}</label><input className="input" type="number" step="0.1" style={inp} value={f.peso} onChange={e => setF(s => ({ ...s, peso: e.target.value }))} /></div>
          </div>
          <textarea className="input" rows={2} style={{ ...inp, marginBottom: 8 }} placeholder={lang === 'pt' ? 'como foi o dia?' : 'how was your day?'} value={f.nota} onChange={e => setF(s => ({ ...s, nota: e.target.value }))} />
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
            <button className="btn btn-sm" onClick={() => setOpen(false)}>{lang === 'pt' ? 'Cancelar' : 'Cancel'}</button>
            <button className="btn btn-primary btn-sm" onClick={save} disabled={saving}>{saving ? '…' : (lang === 'pt' ? 'Salvar' : 'Save')}</button>
          </div>
        </div>
      )}
      {recent.length === 0 ? (
        <div className="empty" style={{ padding: 20, textAlign: 'center', fontSize: 13 }}>{lang === 'pt' ? 'Sem registros ainda. Faça seu primeiro check-in.' : 'No entries yet.'}</div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column' }}>
          {recent.map((c, i) => (
            <div key={i} style={{ display: 'flex', gap: 10, padding: '9px 0', borderBottom: i < recent.length - 1 ? '1px solid var(--line-soft)' : 'none' }}>
              <span style={{ fontFamily: 'var(--fm)', fontSize: 11, color: 'var(--accent)', minWidth: 42 }}>{(c.dia || '').slice(5).split('-').reverse().join('/')}</span>
              {c.humor != null && <span style={{ fontSize: 14 }}>{moodEmoji(Number(c.humor))}</span>}
              <div style={{ flex: 1, minWidth: 0, fontSize: 13, color: c.nota ? 'var(--ink)' : 'var(--muted)' }}>{c.nota || '—'}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

const Journal = ({h, setState, lang}) => {
  const [adding, setAdding] = useState(false);
  const [draft, setDraft] = useState({mood:4, energy:4, sleep:7, note:''});
  const sorted = [...h.journal].sort((a,b) => b.date.localeCompare(a.date));

  const submit = () => {
    setState(s => ({...s, health:{...s.health, journal:[{date:new Date().toISOString().split('T')[0], ...draft}, ...s.health.journal]}}));
    setAdding(false);
    setDraft({mood:4, energy:4, sleep:7, note:''});
  };

  if (adding) return (
    <div>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:10,marginBottom:10}}>
        <div>
          <div style={{fontSize:10,color:'var(--muted)',fontFamily:'var(--fm)',letterSpacing:1,textTransform:'uppercase',marginBottom:4}}>{lang==='pt'?'humor':'mood'}</div>
          <Stars value={draft.mood} onChange={v=>setDraft(d=>({...d,mood:v}))}/>
        </div>
        <div>
          <div style={{fontSize:10,color:'var(--muted)',fontFamily:'var(--fm)',letterSpacing:1,textTransform:'uppercase',marginBottom:4}}>{lang==='pt'?'energia':'energy'}</div>
          <Stars value={draft.energy} onChange={v=>setDraft(d=>({...d,energy:v}))}/>
        </div>
      </div>
      <div style={{marginBottom:10}}>
        <div style={{fontSize:10,color:'var(--muted)',fontFamily:'var(--fm)',letterSpacing:1,textTransform:'uppercase',marginBottom:4}}>{lang==='pt'?'sono (h)':'sleep (h)'}</div>
        <input type="number" step="0.1" className="input" value={draft.sleep} onChange={e=>setDraft(d=>({...d,sleep:+e.target.value}))} style={{width:'100%'}}/>
      </div>
      <textarea className="input" value={draft.note} onChange={e=>setDraft(d=>({...d,note:e.target.value}))}
        rows={3} placeholder={lang==='pt'?'como foi o dia?':'how was your day?'} style={{width:'100%',resize:'vertical',fontFamily:'inherit',marginBottom:10}}/>
      <div style={{display:'flex',gap:8}}>
        <button className="btn" onClick={()=>setAdding(false)}>{lang==='pt'?'Cancelar':'Cancel'}</button>
        <button className="btn btn-primary" style={{flex:1}} onClick={submit}><Icon n="check" size={13}/>{lang==='pt'?'Salvar':'Save'}</button>
      </div>
    </div>
  );

  return (
    <div>
      <button className="btn btn-primary" style={{width:'100%',marginBottom:14}} onClick={()=>setAdding(true)}>
        <Icon n="plus" size={13}/>{lang==='pt'?'Entrada de hoje':'Today\'s entry'}
      </button>
      {sorted.slice(0,5).map((j,i) => (
        <div key={i} style={{padding:'10px 0',borderBottom: i<4?'1px solid var(--line-soft)':'none',fontSize:13}}>
          <div style={{display:'flex',gap:8,alignItems:'baseline',marginBottom:4}}>
            <span style={{fontFamily:'var(--fm)',fontSize:10.5,color:'var(--muted)',letterSpacing:0.5}}>{j.date}</span>
            <span style={{color:'#C8A24A'}}>{'★'.repeat(j.mood)}{'☆'.repeat(5-j.mood)}</span>
            <span style={{color:'var(--muted)',fontFamily:'var(--fm)',fontSize:10.5}}>· {j.sleep}h sono</span>
          </div>
          {j.note && <div style={{color:'var(--ink-2)',lineHeight:1.5,fontSize:12.5}}>{j.note}</div>}
        </div>
      ))}
    </div>
  );
};

const Stars = ({value, onChange}) => (
  <div style={{display:'flex',gap:4}}>
    {[1,2,3,4,5].map(n => (
      <button key={n} type="button" onClick={()=>onChange(n)}
        style={{background:'none',border:'none',cursor:'pointer',color:n<=value?'#C8A24A':'var(--muted-2)',fontSize:22,padding:2}}>★</button>
    ))}
  </div>
);

// ─── GROUP: classes (signup), duos, ship gym occupancy ───
const GroupView = ({state, setState, lang, toast, me, isCoach}) => {
  const h = state.health;
  const usersById = useMemo(() => Object.fromEntries(state.users.map(u=>[u.id,u])), [state.users]);

  const toggleSignup = (cls) => {
    setState(s => ({
      ...s,
      health: {
        ...s.health,
        classes: s.health.classes.map(c => {
          if (c.id !== cls.id) return c;
          const isIn = c.inscritos.includes(me.id);
          if (!isIn && c.inscritos.length >= c.cap) {
            toast.push({icon:'lock', title:lang==='pt'?'Aula lotada':'Class full'});
            return c;
          }
          return {...c, inscritos: isIn ? c.inscritos.filter(i=>i!==me.id) : [...c.inscritos, me.id]};
        })
      }
    }));
  };

  return (
    <div style={{display:'grid',gridTemplateColumns:'1.4fr 1fr',gap:18}}>
      <div>
        <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:14}}>{lang==='pt'?'aulas em grupo':'group classes'}</div>
        <div style={{display:'grid',gap:12}}>
          {h.classes.map(cls => {
            const coach = usersById[cls.coach];
            const isIn = cls.inscritos.includes(me.id);
            const pct = cls.inscritos.length / cls.cap;
            return (
              <div key={cls.id} style={{
                background:'var(--cream)',border:`1px solid ${isIn?'var(--accent)':'var(--line-soft)'}`,
                borderRadius:18,padding:'18px 22px',display:'flex',alignItems:'center',gap:18
              }}>
                <div style={{
                  width:60,minWidth:60,padding:'10px 0',borderRadius:12,background:isIn?'var(--accent)':'var(--cream-2)',
                  color:isIn?'var(--cream)':'var(--ink-2)',textAlign:'center'
                }}>
                  <div style={{fontFamily:'var(--fm)',fontSize:9.5,letterSpacing:1.2,textTransform:'uppercase',opacity:0.7}}>
                    {new Date(cls.dia).toLocaleDateString('pt-BR',{weekday:'short'})}
                  </div>
                  <div style={{fontFamily:'var(--fs)',fontSize:22,letterSpacing:'-0.5px',lineHeight:1.1,marginTop:2}}>
                    {cls.hora.split(':')[0]}<span style={{fontSize:14}}>:{cls.hora.split(':')[1]}</span>
                  </div>
                </div>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{fontFamily:'var(--fs)',fontSize:20,letterSpacing:'-0.3px',marginBottom:3}}>{cls.titulo}</div>
                  <div style={{fontSize:12,color:'var(--muted)',fontFamily:'var(--fm)',display:'flex',alignItems:'center',gap:8}}>
                    {coach && <Avatar user={coach} size="xs"/>}
                    <span>{coach?.nome.split(' ')[0]} · {cls.local}</span>
                  </div>
                  <div style={{marginTop:8,display:'flex',alignItems:'center',gap:10}}>
                    <div style={{flex:1,height:5,background:'var(--cream-2)',borderRadius:3,overflow:'hidden',maxWidth:200}}>
                      <div style={{width:`${pct*100}%`,height:'100%',background: pct>0.85?'var(--coral-2)':'var(--accent)'}}/>
                    </div>
                    <span style={{fontSize:11,fontFamily:'var(--fm)',color:'var(--muted)'}}>{cls.inscritos.length}/{cls.cap}</span>
                  </div>
                </div>
                <button onClick={()=>toggleSignup(cls)}
                  className={isIn?'btn':'btn btn-primary'}
                  style={isIn?{borderColor:'var(--accent)',color:'var(--accent)'}:{}}>
                  <Icon n={isIn?'check':'plus'} size={13}/>
                  {isIn ? (lang==='pt'?'Inscrito':'Joined') : (lang==='pt'?'Inscrever':'Join')}
                </button>
              </div>
            );
          })}
        </div>
      </div>

      <div style={{display:'flex',flexDirection:'column',gap:18}}>
        <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,padding:'22px 24px'}}>
          <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:12}}>{lang==='pt'?'academia · agora':'gym · now'}</div>
          <div style={{display:'flex',alignItems:'baseline',gap:8,marginBottom:8}}>
            <div style={{fontFamily:'var(--fs)',fontSize:48,letterSpacing:'-1px',color:'var(--accent)',lineHeight:1}}>4</div>
            <div style={{fontSize:14,color:'var(--muted)'}}>{lang==='pt'?'pessoas treinando':'people training'}</div>
          </div>
          <div style={{height:6,background:'var(--cream-2)',borderRadius:3,overflow:'hidden',marginBottom:14}}>
            <div style={{width:'33%',height:'100%',background:'var(--accent)'}}/>
          </div>
          <div style={{fontSize:11.5,color:'var(--muted)',fontFamily:'var(--fm)',lineHeight:1.6}}>
            {lang==='pt'?'pico hoje 06:30 (8 pessoas) · 18:00 (7) — janelas calmas: 10–11h e 14–16h':'today peak 06:30 (8) · 18:00 (7) — quiet windows: 10–11h, 14–16h'}
          </div>
        </div>

        <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,padding:'22px 24px'}}>
          <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:12}}>{lang==='pt'?'mensagem do coach':'message from coach'}</div>
          <div style={{fontSize:13.5,lineHeight:1.6,color:'var(--ink-2)',fontStyle:'italic',fontFamily:'var(--fs)'}}>
            "{lang==='pt'?'turma — semana de mar mais agitado, alivia o cardio externo e usa a esteira nos picos de movimento. quem precisar de plano de recuperação fala comigo direto.':'team — rough seas this week, ease off outdoor cardio and use the treadmill during pitch peaks. ping me direct if you need a recovery plan.'}"
          </div>
          <div style={{marginTop:10,fontSize:11,color:'var(--muted)',fontFamily:'var(--fm)'}}>
            — {state.users.find(u => u.id === h.coach)?.nome}
          </div>
        </div>
      </div>
    </div>
  );
};

// ─── WELLNESS (mental check-in + private notes) ───
const WellnessView = ({state, setState, lang, toast, me}) => {
  const [checkin, setCheckin] = useState(null);
  const checkins = [
    {emoji:'😌', pt:'em paz',     en:'at peace',  v:'calm'},
    {emoji:'🙂', pt:'tranquilo',  en:'fine',      v:'fine'},
    {emoji:'😐', pt:'neutro',     en:'neutral',   v:'neutral'},
    {emoji:'😣', pt:'tenso',      en:'tense',     v:'tense'},
    {emoji:'😢', pt:'pra baixo',  en:'low',       v:'low'},
  ];
  const submit = () => {
    if (!checkin) return;
    toast.push({icon:'heart', title:lang==='pt'?'check-in registrado':'check-in saved', sub:lang==='pt'?'só você vê isso.':'only you see this.'});
    setCheckin(null);
  };

  return (
    <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:18}}>
      <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,padding:'28px 32px'}}>
        <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:14}}>{lang==='pt'?'check-in mental · 30s':'mind check-in · 30s'}</div>
        <div style={{fontFamily:'var(--fs)',fontSize:26,letterSpacing:'-0.4px',marginBottom:24,lineHeight:1.2}}>
          {lang==='pt'?'como você está agora,':'how are you right now,'} <em style={{color:'var(--muted-2)'}}>{lang==='pt'?'só por dentro?':'just inside?'}</em>
        </div>
        <div style={{display:'grid',gridTemplateColumns:'repeat(5, 1fr)',gap:8,marginBottom:24}}>
          {checkins.map(c => (
            <button key={c.v} onClick={()=>setCheckin(c.v)}
              style={{
                padding:'18px 8px',borderRadius:14,
                background: checkin===c.v ? 'var(--accent-soft)' : 'var(--cream-2)',
                border: `1px solid ${checkin===c.v?'var(--accent)':'transparent'}`,
                cursor:'pointer',transition:'all .15s',
                display:'flex',flexDirection:'column',alignItems:'center',gap:6
              }}>
              <span style={{fontSize:28}}>{c.emoji}</span>
              <span style={{fontSize:11,fontFamily:'var(--fm)',color:checkin===c.v?'var(--accent)':'var(--muted)'}}>
                {lang==='pt'?c.pt:c.en}
              </span>
            </button>
          ))}
        </div>
        <button className="btn btn-primary" style={{width:'100%'}} disabled={!checkin} onClick={submit}>
          <Icon n="check" size={14}/>{lang==='pt'?'Registrar (privado)':'Save (private)'}
        </button>
        <div style={{marginTop:14,fontSize:11.5,color:'var(--muted)',lineHeight:1.5}}>
          {lang==='pt'
            ? 'check-ins não são compartilhados com o coach nem com a operação. servem como sinal pra você mesmo. se você marcar "pra baixo" 3 vezes em 7 dias, sugerimos uma conversa com a enfermaria — a decisão é sua.'
            : 'check-ins are not shared with coach or ops. they\'re a signal for yourself. if you mark "low" 3× in 7 days we suggest reaching the infirmary — your call.'}
        </div>
      </div>

      <div style={{display:'flex',flexDirection:'column',gap:18}}>
        <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,padding:'22px 24px'}}>
          <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:14}}>{lang==='pt'?'turno · ritmo':'shift · rhythm'}</div>
          <div style={{fontSize:13.5,lineHeight:1.7,color:'var(--ink-2)'}}>
            {lang==='pt' ? (
              <>
                <p style={{marginBottom:10}}>seu turno: <strong>00:00–12:00</strong>. nas primeiras 48h depois de virar turno, evite cafeína após 16h e priorize sono escuro entre 14–22h.</p>
                <p style={{marginBottom:0}}>treinos pesados rendem mais para você nos primeiros 2h após acordar. dieta sugerida atualizada para esse padrão.</p>
              </>
            ) : (
              <>
                <p style={{marginBottom:10}}>shift: <strong>00:00–12:00</strong>. in the first 48h after a shift switch, avoid caffeine after 16h and prioritize dark sleep 14–22h.</p>
                <p style={{marginBottom:0}}>heavy workouts pay off best in the first 2h after waking. diet suggestions are tuned to this pattern.</p>
              </>
            )}
          </div>
        </div>

        <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,padding:'22px 24px'}}>
          <div className="t-eyebrow" style={{color:'var(--accent)',marginBottom:14}}>{lang==='pt'?'recursos':'resources'}</div>
          <div style={{display:'grid',gap:10}}>
            {[
              {pt:'Conversa com a enfermaria',  en:'Talk to infirmary',     icon:'health',  type:'urgent'},
              {pt:'Falar com o capelão',         en:'Chat with chaplain',    icon:'heart',  type:'soft'},
              {pt:'Linha de apoio em terra',     en:'Onshore support line',  icon:'radio',  type:'soft'},
              {pt:'Áudio · 5 min de respiração', en:'Audio · 5 min breath',  icon:'play',   type:'self'},
            ].map((r,i) => (
              <button key={i} className="btn" style={{justifyContent:'flex-start',padding:'12px 14px',borderColor: r.type==='urgent'?'var(--coral-2)':'var(--line-soft)',color: r.type==='urgent'?'var(--coral-2)':'var(--ink-2)'}}>
                <Icon n={r.icon} size={14}/>
                <span style={{flex:1,textAlign:'left'}}>{lang==='pt'?r.pt:r.en}</span>
                <Icon n="chev_r" size={13}/>
              </button>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
};

// ─── MENU (community / public) ───
const MenuView = ({state, setState, lang, toast, isAdmin}) => {
  const m = state.menu;
  const chef = state.users.find(u => u.id === m.chef);
  const [day, setDay] = useState('hoje');
  const [editing, setEditing] = useState(false);

  if (editing) {
    return <MenuEditor state={state} setState={setState} onClose={()=>setEditing(false)} lang={lang} toast={toast}/>;
  }
  const today = day === 'hoje' ? m.hoje : m.amanha;
  return (
    <div>
      <div style={{display:'flex',alignItems:'baseline',gap:14,marginBottom:18}}>
        <div style={{display:'flex',gap:6}}>
          <button onClick={()=>setDay('hoje')} className={day==='hoje'?'btn btn-primary':'btn'}>
            {lang==='pt'?'hoje':'today'}
          </button>
          <button onClick={()=>setDay('amanha')} className={day==='amanha'?'btn btn-primary':'btn'}>
            {lang==='pt'?'amanhã':'tomorrow'}
          </button>
        </div>
        <div style={{flex:1}}/>
        {chef && (
          <div style={{fontSize:12,color:'var(--muted)',fontFamily:'var(--fm)',display:'flex',alignItems:'center',gap:8}}>
            <Avatar user={chef} size="xs"/>
            <span>{lang==='pt'?'chef':'chef'} {chef.nome.split(' ')[0]}</span>
          </div>
        )}
        {isAdmin && (
          <button className="btn" onClick={()=>setEditing(true)}><Icon n="edit" size={13}/>{lang==='pt'?'Editar cardápio':'Edit menu'}</button>
        )}
      </div>

      <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(280px,1fr))',gap:14}}>
        {Object.entries(today).map(([k,v]) => {
          const labels = {cafe:{pt:'café',en:'breakfast'}, lanche_manha:{pt:'lanche manhã',en:'morning snack'}, almoco:{pt:'almoço',en:'lunch'}, lanche:{pt:'lanche',en:'snack'}, jantar:{pt:'jantar',en:'dinner'}, ceia:{pt:'ceia',en:'late'}, madrugada:{pt:'madrugada',en:'overnight'}};
          const fallback = v.nome || k;
          return (
            <div key={k} style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:18,padding:'20px 22px'}}>
              <div style={{display:'flex',alignItems:'baseline',gap:8,marginBottom:10}}>
                <div style={{fontFamily:'var(--fs)',fontSize:24,letterSpacing:'-0.4px',color:'var(--accent)'}}>{v.nome || (labels[k]?(lang==='pt'?labels[k].pt:labels[k].en):k)}</div>
                <div style={{flex:1}}/>
                <div style={{fontFamily:'var(--fm)',fontSize:11,color:'var(--muted)',letterSpacing:0.4}}>{v.hora}</div>
              </div>
              <ul style={{listStyle:'none',padding:0,margin:0,display:'flex',flexDirection:'column',gap:6}}>
                {v.pratos.map((p,i) => (
                  <li key={i} style={{fontSize:13.5,color:'var(--ink-2)',padding:'4px 0',display:'flex',alignItems:'baseline',gap:8}}>
                    <span style={{width:3,height:3,borderRadius:'50%',background:'var(--accent)',display:'inline-block',marginTop:7}}/>
                    {p}
                  </li>
                ))}
              </ul>
            </div>
          );
        })}
      </div>

      <div style={{marginTop:18,padding:'14px 18px',background:'var(--cream-2)',borderRadius:12,fontSize:12.5,color:'var(--muted)',fontStyle:'italic',fontFamily:'var(--fs)',lineHeight:1.5}}>
        {m.obs}
      </div>
    </div>
  );
};

// ─── COACH VIEW (only EF coach sees this; aggregate, no diet/journal) ───
const CoachView = ({state, setState, lang, toast}) => {
  const h = state.health;
  const usersById = useMemo(() => Object.fromEntries(state.users.map(u=>[u.id,u])), [state.users]);
  const [editing, setEditing] = useState(null);

  return (
    <>
    {editing && <AthleteEditDrawer athleteId={editing} state={state} setState={setState} onClose={()=>setEditing(null)} lang={lang} toast={toast}/>}
    <div>
      <div style={{display:'grid',gridTemplateColumns:'repeat(3, 1fr)',gap:12,marginBottom:20}}>
        <Stat label={lang==='pt'?'atletas ativos':'active athletes'} value={h.coachView.length} sub={lang==='pt'?'consentimento ok':'consent ok'}/>
        <Stat label={lang==='pt'?'adesão média':'avg adherence'} value={`${Math.round(h.coachView.reduce((a,c)=>a+c.adesao,0)/h.coachView.length*100)}%`} sub={lang==='pt'?'7 dias':'7 days'}/>
        <Stat label={lang==='pt'?'alertas':'alerts'} value={h.coachView.filter(c=>c.alerta).length} sub={lang==='pt'?'precisam de conversa':'need a chat'} tone={h.coachView.filter(c=>c.alerta).length>0?'warn':'ok'}/>
      </div>

      <div style={{background:'var(--cream)',border:'1px solid var(--line-soft)',borderRadius:20,overflow:'hidden'}}>
        <div style={{display:'grid',gridTemplateColumns:'2fr 1.5fr 1.2fr 1.5fr 80px',padding:'14px 22px',background:'var(--cream-2)',fontFamily:'var(--fm)',fontSize:10.5,letterSpacing:1.2,textTransform:'uppercase',color:'var(--muted)'}}>
          <div>{lang==='pt'?'atleta':'athlete'}</div><div>{lang==='pt'?'adesão · 7d':'adherence · 7d'}</div><div>{lang==='pt'?'último treino':'last workout'}</div><div>{lang==='pt'?'alerta':'alert'}</div><div></div>
        </div>
        {h.coachView.map((c,i) => {
          const u = usersById[c.user];
          if (!u) return null;
          const plan = h.athletePlans?.[c.user];
          return (
            <div key={i} style={{display:'grid',gridTemplateColumns:'2fr 1.5fr 1.2fr 1.5fr 80px',padding:'14px 22px',alignItems:'center',borderTop:'1px solid var(--line-soft)',cursor:'pointer',transition:'background .12s'}}
              onMouseEnter={e=>e.currentTarget.style.background='var(--cream-2)'}
              onMouseLeave={e=>e.currentTarget.style.background='transparent'}
              onClick={()=>setEditing(c.user)}>
              <div style={{display:'flex',alignItems:'center',gap:11}}>
                <Avatar user={u} size="sm"/>
                <div>
                  <div style={{fontSize:13.5,fontWeight:500}}>{u.nome}</div>
                  <div style={{fontSize:11,color:'var(--muted)',fontFamily:'var(--fm)'}}>{u.funcao}</div>
                </div>
              </div>
              <div style={{display:'flex',alignItems:'center',gap:10}}>
                <div style={{flex:1,maxWidth:120,height:5,background:'var(--cream-2)',borderRadius:3,overflow:'hidden'}}>
                  <div style={{width:`${c.adesao*100}%`,height:'100%',background:c.adesao>0.7?'#7BB67E':c.adesao>0.5?'#C8A24A':'#D9694B'}}/>
                </div>
                <span style={{fontFamily:'var(--fm)',fontSize:12}}>{Math.round(c.adesao*100)}%</span>
              </div>
              <div style={{fontFamily:'var(--fm)',fontSize:12,color:'var(--muted)'}}>{c.ultimoTreino}</div>
              <div>
                {c.alerta ? (
                  <span style={{display:'inline-flex',alignItems:'center',gap:6,padding:'4px 10px',borderRadius:8,background:'rgba(217,105,75,0.12)',color:'var(--coral-2)',fontSize:11,fontFamily:'var(--fm)'}}>
                    <span style={{width:5,height:5,borderRadius:'50%',background:'var(--coral-2)'}}/>
                    {c.alerta}
                  </span>
                ) : <span style={{color:'var(--muted)',fontSize:11,fontFamily:'var(--fm)'}}>—</span>}
              </div>
              <div style={{display:'flex',gap:6,justifyContent:'flex-end'}}>
                <button className="btn btn-ghost" style={{padding:'4px 8px'}} title={lang==='pt'?'Editar ficha':'Edit plan'} onClick={(e)=>{e.stopPropagation();setEditing(c.user);}}><Icon n="edit" size={14}/></button>
                <button className="btn btn-ghost" style={{padding:'4px 8px'}} title={lang==='pt'?'Conversar':'Chat'} onClick={(e)=>e.stopPropagation()}><Icon n="chat" size={14}/></button>
              </div>
            </div>
          );
        })}
      </div>

      <div style={{marginTop:16,padding:'14px 18px',background:'var(--cream-2)',borderRadius:12,fontSize:12,color:'var(--muted)',lineHeight:1.6}}>
        {lang==='pt'
          ? 'clique em qualquer atleta para editar treino, dieta e notas. você só vê adesão (treinos completados ÷ planejados) e data do último treino. dieta efetiva, peso, humor e diário do atleta ficam invisíveis para você.'
          : 'click any athlete to edit training, diet and notes. you only see adherence (completed ÷ planned) and last workout. their actual diet intake, weight, mood and journal stay invisible.'}
      </div>
    </div>
    </>
  );
};

const Stat = ({label, value, sub, tone}) => (
  <div style={{
    background:'var(--cream)',border:`1px solid ${tone==='warn'?'var(--coral-2)':'var(--line-soft)'}`,
    borderRadius:18,padding:'18px 22px'
  }}>
    <div className="t-eyebrow" style={{color: tone==='warn'?'var(--coral-2)':'var(--accent)',marginBottom:6}}>{label}</div>
    <div style={{fontFamily:'var(--fs)',fontSize:36,letterSpacing:'-0.6px',color: tone==='warn'?'var(--coral-2)':'var(--ink)',lineHeight:1}}>{value}</div>
    {sub && <div style={{fontSize:11.5,color:'var(--muted)',fontFamily:'var(--fm)',marginTop:4}}>{sub}</div>}
  </div>
);

Object.assign(window, {Saude});
