Skip to content

JuKennedy/apexfit.com.br

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 

Repository files navigation

apexfit.index.html.html

<title>ApexFit — Plataforma de Avaliação Física</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script> <style> *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} :root{ --brand:#00D4AA;--brand2:#7C3AED;--accent:#F59E0B; --danger:#EF4444;--success:#10B981;--info:#3B82F6; --bg:#0A0E1A;--bg2:#111827;--bg3:#1C2333;--bg4:#242D40;--bg5:#2D3748; --border:rgba(255,255,255,0.07);--border2:rgba(0,212,170,0.3); --text:#F1F5F9;--text2:#94A3B8;--text3:#64748B; --font:'Sora',sans-serif;--mono:'JetBrains Mono',monospace; --rad:10px;--rad2:16px;--rad3:24px; } body{font-family:var(--font);background:var(--bg);color:var(--text);min-height:100vh;overflow-x:hidden} /* ── SCROLLBAR ── */ ::-webkit-scrollbar{width:4px;height:4px} ::-webkit-scrollbar-track{background:transparent} ::-webkit-scrollbar-thumb{background:var(--bg5);border-radius:2px}

/* ══════════════════════════════════════ LOGIN SCREEN ══════════════════════════════════════ */ #loginScreen{ position:fixed;inset:0;z-index:9999; display:flex;align-items:center;justify-content:center; background:var(--bg); background-image: radial-gradient(ellipse 60% 50% at 20% 30%, rgba(0,212,170,0.08) 0%, transparent 70%), radial-gradient(ellipse 40% 60% at 80% 70%, rgba(124,58,237,0.08) 0%, transparent 70%); } .login-card{ width:380px;padding:48px 40px; background:var(--bg2); border:1px solid var(--border); border-radius:var(--rad3); position:relative;overflow:hidden; } .login-card::before{ content:'';position:absolute;top:0;left:0;right:0;height:2px; background:linear-gradient(90deg,transparent,var(--brand),var(--brand2),transparent); } .login-logo{text-align:center;margin-bottom:36px} .login-logo-icon{ width:56px;height:56px;border-radius:16px; background:linear-gradient(135deg,var(--brand),var(--brand2)); display:flex;align-items:center;justify-content:center; font-size:26px;margin:0 auto 14px; box-shadow:0 8px 32px rgba(0,212,170,0.3); } .login-title{font-size:22px;font-weight:700;letter-spacing:-0.5px} .login-title span{color:var(--brand)} .login-sub{font-size:12px;color:var(--text3);margin-top:4px} .login-field{margin-bottom:16px} .login-label{font-size:11px;color:var(--text3);font-weight:500;margin-bottom:6px;display:block;letter-spacing:0.5px} .login-input{ width:100%;padding:11px 14px; background:var(--bg3);border:1px solid var(--border); border-radius:var(--rad);color:var(--text); font-family:var(--font);font-size:14px;outline:none; transition:all .2s; } .login-input:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(0,212,170,0.1)} .login-btn{ width:100%;padding:12px;margin-top:8px; background:linear-gradient(135deg,var(--brand),#00A890); border:none;border-radius:var(--rad); color:#0A0E1A;font-family:var(--font);font-size:14px;font-weight:700; cursor:pointer;transition:all .2s;letter-spacing:0.3px; } .login-btn:hover{transform:translateY(-1px);box-shadow:0 8px 24px rgba(0,212,170,0.4)} .login-btn:active{transform:translateY(0)} .login-error{ color:var(--danger);font-size:12px;text-align:center; margin-top:10px;display:none; background:rgba(239,68,68,0.1);padding:8px;border-radius:var(--rad); } .login-hint{font-size:11px;color:var(--text3);text-align:center;margin-top:16px}

/* ══════════════════════════════════════ MAIN APP ══════════════════════════════════════ */ #app{display:none;min-height:100vh;flex-direction:column}

/* ── TOPBAR ── */ .topbar{ display:flex;align-items:center;justify-content:space-between; padding:10px 20px;background:var(--bg2); border-bottom:1px solid var(--border); position:sticky;top:0;z-index:100; flex-shrink:0; } .logo{display:flex;align-items:center;gap:9px;cursor:pointer} .logo-icon{ width:30px;height:30px;border-radius:8px; background:linear-gradient(135deg,var(--brand),var(--brand2)); display:flex;align-items:center;justify-content:center;font-size:14px; } .logo-text{font-size:14px;font-weight:700;letter-spacing:-0.3px} .logo-text span{color:var(--brand)}

.topnav{display:flex;gap:2px;background:var(--bg3);border-radius:var(--rad);padding:3px} .tnav{ padding:5px 13px;border-radius:7px;border:none; background:transparent;color:var(--text2); font-family:var(--font);font-size:12px;font-weight:500; cursor:pointer;transition:all .2s;white-space:nowrap; } .tnav.active{background:var(--bg4);color:var(--brand);box-shadow:0 1px 4px rgba(0,0,0,.4)} .tnav:hover:not(.active){color:var(--text)}

.topbar-right{display:flex;align-items:center;gap:10px} .user-pill{ display:flex;align-items:center;gap:8px; background:var(--bg3);border:1px solid var(--border); border-radius:20px;padding:4px 12px 4px 4px; } .avatar{ width:24px;height:24px;border-radius:50%; background:linear-gradient(135deg,var(--brand),var(--brand2)); display:flex;align-items:center;justify-content:center; font-size:10px;font-weight:700;color:#0A0E1A; } .user-pill span{font-size:11px;color:var(--text2)} .logout-btn{ padding:5px 12px;border-radius:var(--rad);border:1px solid rgba(239,68,68,0.3); background:transparent;color:var(--danger); font-family:var(--font);font-size:11px;cursor:pointer;transition:all .2s; } .logout-btn:hover{background:rgba(239,68,68,0.1)}

/* ── LAYOUT ── */ .app-body{display:flex;flex:1;min-height:0} .sidebar{ width:220px;flex-shrink:0; background:var(--bg2);border-right:1px solid var(--border); padding:16px 10px;overflow-y:auto; } .main-content{flex:1;overflow-y:auto;padding:20px}

.sidebar-label{ font-size:9px;letter-spacing:1.5px;font-weight:600; color:var(--text3);text-transform:uppercase; padding:0 8px;margin:16px 0 6px; } .sidebar-label:first-child{margin-top:0} .slink{ display:flex;align-items:center;gap:9px; padding:8px 10px;border-radius:var(--rad); border:none;background:transparent;color:var(--text2); font-family:var(--font);font-size:12px;font-weight:500; cursor:pointer;transition:all .15s;width:100%;text-align:left; } .slink:hover{background:var(--bg3);color:var(--text)} .slink.active{background:rgba(0,212,170,0.1);color:var(--brand);border:1px solid rgba(0,212,170,0.15)} .slink-icon{font-size:14px;width:18px;text-align:center}

/* ── PAGES ── */ .page{display:none}.page.active{display:block}

/* ── CARDS ── */ .card{ background:var(--bg2);border:1px solid var(--border); border-radius:var(--rad2);padding:18px;position:relative;overflow:hidden; } .card::before{ content:'';position:absolute;top:0;left:0;right:0;height:1px; background:linear-gradient(90deg,transparent,rgba(0,212,170,0.2),transparent); } .card-title{ font-size:10px;font-weight:600;letter-spacing:1px; text-transform:uppercase;color:var(--text3);margin-bottom:14px; } .card-title.c{color:var(--brand)}

/* ── GRIDS ── */ .g2{display:grid;grid-template-columns:1fr 1fr;gap:14px} .g3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px} .g4{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}

/* ── BUTTONS ── */ .btn{ display:inline-flex;align-items:center;gap:6px; padding:8px 16px;border-radius:var(--rad);border:none; font-family:var(--font);font-size:12px;font-weight:600; cursor:pointer;transition:all .2s;text-decoration:none; } .btn-primary{background:var(--brand);color:#0A0E1A} .btn-primary:hover{background:#00FFCC;transform:translateY(-1px)} .btn-secondary{background:var(--brand2);color:#fff} .btn-secondary:hover{background:#6D28D9} .btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)} .btn-ghost:hover{background:var(--bg3);color:var(--text)} .btn-danger{background:rgba(239,68,68,0.15);color:var(--danger);border:1px solid rgba(239,68,68,0.3)} .btn-danger:hover{background:rgba(239,68,68,0.25)} .btn-sm{padding:5px 10px;font-size:11px} .btn-xs{padding:3px 8px;font-size:10px}

/* ── INPUTS ── */ .fg{margin-bottom:12px} .fl{font-size:10px;color:var(--text3);margin-bottom:4px;display:block;font-weight:500;letter-spacing:0.3px} .fi,.fs,.fta{ width:100%;padding:8px 11px; background:var(--bg3);border:1px solid var(--border); border-radius:var(--rad);color:var(--text); font-family:var(--font);font-size:13px;outline:none;transition:border .2s; } .fi:focus,.fs:focus,.fta:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(0,212,170,0.08)} .fs option{background:var(--bg2)} .fta{resize:vertical}

/* ── SECTION HEADER ── */ .sh{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px} .st{font-size:16px;font-weight:700;letter-spacing:-0.3px} .ss{font-size:11px;color:var(--text3);margin-top:2px}

/* ── BADGES ── */ .badge{font-size:9px;font-weight:700;padding:3px 8px;border-radius:20px;text-transform:uppercase;letter-spacing:0.5px} .bb{background:rgba(0,212,170,0.12);color:var(--brand);border:1px solid rgba(0,212,170,0.2)} .bp{background:rgba(124,58,237,0.12);color:#A78BFA;border:1px solid rgba(124,58,237,0.2)} .ba{background:rgba(245,158,11,0.12);color:var(--accent);border:1px solid rgba(245,158,11,0.2)} .bd{background:rgba(239,68,68,0.12);color:var(--danger);border:1px solid rgba(239,68,68,0.2)} .bg-s{background:rgba(16,185,129,0.12);color:var(--success);border:1px solid rgba(16,185,129,0.2)}

/* ── METRIC CARDS ── */ .metric{ background:var(--bg3);border:1px solid var(--border); border-radius:var(--rad);padding:12px 14px; } .ml{font-size:10px;color:var(--text3);margin-bottom:3px} .mv{font-size:20px;font-weight:700;font-family:var(--mono)} .md{font-size:10px;margin-top:2px} .md.pos{color:var(--success)}.md.neg{color:var(--danger)}.md.neu{color:var(--text3)} .mbar{margin-top:7px;height:3px;background:var(--bg4);border-radius:2px;overflow:hidden} .mbf{height:100%;border-radius:2px;background:linear-gradient(90deg,var(--brand),var(--brand2));transition:width .6s}

/* ── ALERTS ── */ .alert{padding:9px 12px;border-radius:var(--rad);font-size:11px;display:flex;align-items:flex-start;gap:8px;margin-bottom:8px} .aw{background:rgba(245,158,11,0.08);border:1px solid rgba(245,158,11,0.2);color:#FCD34D} .ai{background:rgba(0,212,170,0.06);border:1px solid rgba(0,212,170,0.15);color:var(--brand)} .ad{background:rgba(239,68,68,0.08);border:1px solid rgba(239,68,68,0.2);color:#FCA5A5} .as-{background:rgba(16,185,129,0.08);border:1px solid rgba(16,185,129,0.2);color:#6EE7B7}

/* ── SLIDER ── */ .eval-slider{width:100%;appearance:none;height:4px;background:var(--bg5);border-radius:2px;outline:none} .eval-slider::-webkit-slider-thumb{appearance:none;width:14px;height:14px;border-radius:50%;background:var(--brand);cursor:pointer;box-shadow:0 0 6px rgba(0,212,170,0.5)}

/* ── TABLE ── */ .tbl{width:100%;border-collapse:collapse;font-size:12px} .tbl th{text-align:left;padding:8px 10px;font-size:9px;font-weight:600;letter-spacing:0.8px;color:var(--text3);text-transform:uppercase;border-bottom:1px solid var(--border)} .tbl td{padding:9px 10px;border-bottom:1px solid var(--border);color:var(--text2);vertical-align:middle} .tbl tr:last-child td{border-bottom:none} .tbl tr:hover td{background:rgba(255,255,255,0.02);color:var(--text)} .tbl-clickable{cursor:pointer}

/* ── TABS ── */ .subtabs{display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap} .stab{ padding:5px 13px;border-radius:20px; border:1px solid var(--border);background:transparent; color:var(--text2);font-family:var(--font);font-size:11px;cursor:pointer;transition:all .2s; } .stab.active{background:rgba(0,212,170,0.08);border-color:rgba(0,212,170,0.3);color:var(--brand)}

/* ── MODAL ── */ .modal-overlay{ position:fixed;inset:0;z-index:500; background:rgba(0,0,0,0.7);backdrop-filter:blur(4px); display:none;align-items:center;justify-content:center;padding:20px; } .modal-overlay.open{display:flex} .modal{ background:var(--bg2);border:1px solid var(--border); border-radius:var(--rad3);padding:28px; width:100%;max-width:680px;max-height:90vh;overflow-y:auto; position:relative; } .modal::before{ content:'';position:absolute;top:0;left:0;right:0;height:2px; background:linear-gradient(90deg,transparent,var(--brand),var(--brand2),transparent); } .modal-title{font-size:17px;font-weight:700;margin-bottom:20px;display:flex;align-items:center;gap:10px} .modal-close{ position:absolute;top:18px;right:18px; background:var(--bg3);border:1px solid var(--border); border-radius:50%;width:30px;height:30px; display:flex;align-items:center;justify-content:center; cursor:pointer;color:var(--text2);font-size:14px;transition:all .2s; } .modal-close:hover{background:var(--bg4);color:var(--text)}

/* ── TIMELINE ── */ .tl{position:relative;padding-left:22px} .tl::before{content:'';position:absolute;left:7px;top:0;bottom:0;width:1px;background:var(--border)} .tl-item{position:relative;padding-bottom:16px} .tl-dot{position:absolute;left:-18px;top:3px;width:9px;height:9px;border-radius:50%;background:var(--brand);border:2px solid var(--bg)} .tl-dot.old{background:var(--text3)} .tl-date{font-size:9px;color:var(--text3);font-family:var(--mono)} .tl-title{font-size:12px;font-weight:600;margin-top:1px} .tl-sub{font-size:11px;color:var(--text3);margin-top:1px}

/* ── ALUNO CARD ── */ .aluno-card{ background:var(--bg3);border:1px solid var(--border); border-radius:var(--rad2);padding:14px 16px; display:flex;align-items:center;gap:14px; cursor:pointer;transition:all .2s;margin-bottom:8px; } .aluno-card:hover{border-color:var(--brand);background:rgba(0,212,170,0.04)} .aluno-av{ width:42px;height:42px;border-radius:50%;flex-shrink:0; display:flex;align-items:center;justify-content:center; font-size:15px;font-weight:700;color:#0A0E1A; } .aluno-info{flex:1;min-width:0} .aluno-name{font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .aluno-meta{font-size:11px;color:var(--text3);margin-top:2px} .aluno-actions{display:flex;gap:6px;flex-shrink:0}

/* ── EXERCISE EDITOR ── */ .ex-row{ display:flex;align-items:center;gap:8px; padding:8px 10px;background:var(--bg3); border:1px solid var(--border);border-radius:var(--rad); margin-bottom:6px; } .ex-drag{color:var(--text3);cursor:grab;font-size:14px} .ex-name-input{ flex:2;padding:4px 8px;background:var(--bg4);border:1px solid var(--border); border-radius:6px;color:var(--text);font-family:var(--font);font-size:12px;outline:none; } .ex-num-input{ width:52px;padding:4px 6px;background:var(--bg4);border:1px solid var(--border); border-radius:6px;color:var(--text);font-family:var(--mono);font-size:12px;outline:none;text-align:center; } .ex-del{background:none;border:none;color:var(--text3);cursor:pointer;font-size:14px;padding:2px 4px} .ex-del:hover{color:var(--danger)}

/* ── CHART WRAP ── */ .chart-wrap{position:relative;width:100%;background:var(--bg3);border-radius:var(--rad);padding:10px}

/* ── BODY SVG ── */ .bp{cursor:pointer;transition:all .2s;fill:var(--bg4);stroke:rgba(255,255,255,0.1);stroke-width:1} .bp:hover{fill:rgba(0,212,170,0.3)!important;filter:drop-shadow(0 0 4px rgba(0,212,170,0.5))} .bp.pain{fill:rgba(239,68,68,0.5)!important;stroke:var(--danger)!important;filter:drop-shadow(0 0 5px rgba(239,68,68,0.6))} .bp.selected-part{fill:rgba(0,212,170,0.4)!important;stroke:var(--brand)!important}

/* ── PROGRESS BAR ── */ .prog-bar{height:6px;background:var(--bg4);border-radius:3px;overflow:hidden;margin-top:4px} .prog-fill{height:100%;border-radius:3px;transition:width .6s ease}

/* ── ANIMATIONS ── */ @keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}} @keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}} @keyframes blink{0%,100%{opacity:.2}50%{opacity:1}} .fade-in{animation:fadeIn .3s ease} .typing span{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--brand);margin:0 1px;animation:blink 1.2s infinite} .typing span:nth-child(2){animation-delay:.2s} .typing span:nth-child(3){animation-delay:.4s}

/* ── CHAT ── */ .ia-chat{height:300px;overflow-y:auto;display:flex;flex-direction:column;gap:8px;padding-right:4px} .msg{max-width:85%;padding:9px 12px;border-radius:14px;font-size:12px;line-height:1.5} .msg.user{align-self:flex-end;background:var(--brand2);color:#fff;border-bottom-right-radius:3px} .msg.ia{align-self:flex-start;background:var(--bg3);border:1px solid var(--border);border-bottom-left-radius:3px} .msg.ia .mh{font-size:9px;color:var(--brand);font-weight:700;margin-bottom:3px;letter-spacing:0.5px} .msg-input-wrap{display:flex;gap:8px;margin-top:10px} .msg-input{flex:1;padding:8px 11px;background:var(--bg3);border:1px solid var(--border);border-radius:var(--rad);color:var(--text);font-family:var(--font);font-size:12px;outline:none} .msg-input:focus{border-color:var(--brand)}

/* ── STEP WIZARD ── */ .wizard-steps{display:flex;gap:0;margin-bottom:24px;background:var(--bg3);border-radius:var(--rad);overflow:hidden} .wizard-step{ flex:1;padding:10px 8px;text-align:center; font-size:11px;color:var(--text3);font-weight:500; border-right:1px solid var(--border);cursor:pointer;transition:all .2s; } .wizard-step:last-child{border-right:none} .wizard-step.active{background:rgba(0,212,170,0.1);color:var(--brand)} .wizard-step.done{background:rgba(16,185,129,0.08);color:var(--success)} .wstep-num{ width:18px;height:18px;border-radius:50%; background:var(--bg5);color:var(--text3); font-size:10px;font-weight:700; display:flex;align-items:center;justify-content:center; margin:0 auto 4px; } .wizard-step.active .wstep-num{background:var(--brand);color:#0A0E1A} .wizard-step.done .wstep-num{background:var(--success);color:#fff}

/* ── NOTIFICATION DOT ── */ .notif-dot{ width:6px;height:6px;border-radius:50%; background:var(--danger);display:inline-block;margin-left:4px; animation:pulse 2s infinite; }

/* ── RESPONSIVE ── */ @media(max-width:768px){ .sidebar{display:none} .g2,.g3,.g4{grid-template-columns:1fr} .topnav{overflow-x:auto} }

/* ── RISK SCORE BAR ── */ .risk-bar-wrap{display:flex;align-items:center;gap:8px} .risk-bar{flex:1;height:6px;background:var(--bg5);border-radius:3px;overflow:hidden} .risk-bar-fill{height:100%;border-radius:3px} </style>

APEXFIT
Plataforma Profissional de Avaliação Física
LOGIN
SENHA
ENTRAR →
Login ou senha incorretos. Tente novamente.
Credenciais: Teste / 123
APEXFIT
Dashboard Alunos Avaliação Treinos Histórico IA
P
Prof. Teste
Sair
Principal
📊Dashboard 👥Alunos
  <div class="sidebar-label">Ferramentas</div>
  <button class="slink" data-slink="avaliacao" onclick="navTo('avaliacao')"><span class="slink-icon">📏</span>Nova Avaliação</button>
  <button class="slink" data-slink="treinos" onclick="navTo('treinos')"><span class="slink-icon">🏋</span>Treinos</button>
  <button class="slink" data-slink="historico" onclick="navTo('historico')"><span class="slink-icon">📈</span>Histórico</button>
  <button class="slink" data-slink="ia" onclick="navTo('ia')"><span class="slink-icon">🧠</span>Assistente IA</button>

  <div class="sidebar-label">Alunos Recentes</div>
  <div id="sidebarAlunos"></div>
</div>

<!-- MAIN -->
<div class="main-content" id="mainContent">

  <!-- ════════ DASHBOARD ════════ -->
  <div class="page active" id="page-dashboard">
    <div class="sh">
      <div>
        <div class="st">Dashboard Profissional</div>
        <div class="ss" id="dash-date"></div>
      </div>
      <button class="btn btn-primary" onclick="openModal('modalNovoAluno')">+ Novo Aluno</button>
    </div>

    <!-- STATS -->
    <div class="g4" style="margin-bottom:16px" id="dashStats">
      <div class="metric"><div class="ml">Total de Alunos</div><div class="mv" id="statTotal" style="color:var(--brand)">0</div><div class="md neu">cadastrados</div></div>
      <div class="metric"><div class="ml">Avaliações Hoje</div><div class="mv" id="statHoje" style="color:var(--accent)">0</div><div class="md neu">registradas</div></div>
      <div class="metric"><div class="ml">Alertas Ativos</div><div class="mv" id="statAlertas" style="color:var(--danger)">0</div><div class="md neu">requerem atenção</div></div>
      <div class="metric"><div class="ml">Treinos Ativos</div><div class="mv" id="statTreinos" style="color:var(--success)">0</div><div class="md neu">em andamento</div></div>
    </div>

    <div class="g2">
      <!-- LISTA ALUNOS -->
      <div class="card">
        <div class="card-title c">Alunos Cadastrados</div>
        <div id="dashAlunosList">
          <div style="text-align:center;padding:30px;color:var(--text3);font-size:13px;">
            Nenhum aluno cadastrado.<br>Clique em <strong style="color:var(--brand)">+ Novo Aluno</strong> para começar.
          </div>
        </div>
      </div>

      <!-- ALERTAS -->
      <div class="card">
        <div class="card-title c">Alertas & Notificações</div>
        <div id="dashAlertas">
          <div class="alert ai"><span>✦</span><div>Sistema pronto. Cadastre alunos para ver alertas inteligentes da IA.</div></div>
        </div>
        <div class="card-title c" style="margin-top:16px;">Atividade Recente</div>
        <div id="dashAtividade">
          <div style="color:var(--text3);font-size:12px;">Nenhuma atividade registrada.</div>
        </div>
      </div>
    </div>

    <!-- GRAFICO GERAL -->
    <div class="card" style="margin-top:14px;">
      <div class="card-title c">Evolução Geral da Turma</div>
      <div class="chart-wrap" style="height:180px"><canvas id="chartGeral"></canvas></div>
    </div>
  </div>

  <!-- ════════ ALUNOS ════════ -->
  <div class="page" id="page-alunos">
    <div class="sh">
      <div>
        <div class="st">Gerenciar Alunos</div>
        <div class="ss" id="alunosCount">0 alunos cadastrados</div>
      </div>
      <button class="btn btn-primary" onclick="openModal('modalNovoAluno')">+ Novo Aluno</button>
    </div>

    <!-- BUSCA -->
    <div style="margin-bottom:14px">
      <input class="fi" id="searchAluno" placeholder="Buscar aluno por nome..." oninput="renderAlunosList()" style="max-width:320px"/>
    </div>

    <div id="alunosGrid"></div>

    <!-- DETALHE ALUNO (hidden) -->
    <div id="alunoDetail" style="display:none">
      <button class="btn btn-ghost btn-sm" onclick="fecharDetalhe()" style="margin-bottom:14px">← Voltar</button>

      <div class="sh">
        <div style="display:flex;align-items:center;gap:14px">
          <div class="aluno-av" id="detAv" style="width:56px;height:56px;font-size:22px"></div>
          <div>
            <div class="st" id="detNome"></div>
            <div class="ss" id="detMeta"></div>
          </div>
        </div>
        <div style="display:flex;gap:8px">
          <button class="btn btn-primary" onclick="novaAvaliacaoParaAluno()">+ Nova Avaliação</button>
          <button class="btn btn-secondary btn-sm" onclick="verHistoricoAluno()">📈 Histórico</button>
          <button class="btn btn-ghost btn-sm" onclick="editarAluno()">✏️ Editar</button>
          <button class="btn btn-danger btn-sm" onclick="excluirAluno()">🗑 Excluir</button>
        </div>
      </div>

      <div class="g3" id="detMetrics" style="margin-bottom:14px"></div>

      <div class="g2">
        <div class="card">
          <div class="card-title c">Dados do Aluno</div>
          <table class="tbl" id="detTabela"></table>
        </div>
        <div class="card">
          <div class="card-title c">Última Bioimpedância</div>
          <div id="detBio"></div>
        </div>
      </div>

      <div class="card" style="margin-top:14px">
        <div class="card-title c">Avaliações Registradas</div>
        <div id="detAvaliacoes"></div>
      </div>

      <div class="card" style="margin-top:14px">
        <div class="card-title c">Evolução — Peso & % Gordura</div>
        <div class="chart-wrap" style="height:200px"><canvas id="chartDetAluno"></canvas></div>
      </div>
    </div>
  </div>

  <!-- ════════ AVALIAÇÃO ════════ -->
  <div class="page" id="page-avaliacao">
    <div class="sh">
      <div>
        <div class="st">Nova Avaliação</div>
        <div class="ss">Registrar dados completos de avaliação</div>
      </div>
      <span class="badge bb" id="avalAluno">Selecione um aluno</span>
    </div>

    <!-- SELECIONA ALUNO -->
    <div class="card" id="avalSelecionaAluno" style="margin-bottom:14px">
      <div class="card-title">Selecionar Aluno</div>
      <div style="display:flex;gap:10px;align-items:center">
        <select class="fs" id="avalAlunoSelect" style="max-width:300px" onchange="selecionarAlunoAval()">
          <option value="">— Selecione —</option>
        </select>
        <button class="btn btn-ghost btn-sm" onclick="openModal('modalNovoAluno')">+ Cadastrar Novo</button>
      </div>
    </div>

    <!-- WIZARD -->
    <div class="wizard-steps" id="avalWizard">
      <div class="wizard-step active" onclick="goStep(0)"><div class="wstep-num">1</div>Geral</div>
      <div class="wizard-step" onclick="goStep(1)"><div class="wstep-num">2</div>Medidas</div>
      <div class="wizard-step" onclick="goStep(2)"><div class="wstep-num">3</div>Bioimpedância</div>
      <div class="wizard-step" onclick="goStep(3)"><div class="wstep-num">4</div>Postura & Dor</div>
      <div class="wizard-step" onclick="goStep(4)"><div class="wstep-num">5</div>Funcional</div>
    </div>

    <!-- STEP 0: GERAL -->
    <div id="avalStep0" class="fade-in">
      <div class="g2">
        <div class="card">
          <div class="card-title">Dados Gerais</div>
          <div class="fg"><label class="fl">Data da Avaliação</label><input class="fi" id="avalData" type="date"/></div>
          <div class="fg"><label class="fl">Peso Atual (kg)</label><input class="fi" id="avalPeso" type="number" step="0.1" placeholder="ex: 72.5"/></div>
          <div class="fg"><label class="fl">Altura (cm)</label><input class="fi" id="avalAltura" type="number" placeholder="ex: 170"/></div>
          <div class="fg"><label class="fl">Pressão Arterial</label><input class="fi" id="avalPA" placeholder="ex: 120/80"/></div>
          <div class="fg"><label class="fl">Frequência Cardíaca (bpm)</label><input class="fi" id="avalFC" type="number" placeholder="ex: 72"/></div>
          <div class="fg" style="margin-bottom:0"><label class="fl">Observações Gerais</label><textarea class="fta" id="avalObs" rows="3" placeholder="Observações da sessão..."></textarea></div>
        </div>
        <div class="card">
          <div class="card-title">Resultados Automáticos</div>
          <div id="avalCalcs">
            <div style="color:var(--text3);font-size:12px;text-align:center;padding:20px 0">Preencha peso e altura para ver IMC e classificação.</div>
          </div>
          <div style="margin-top:14px">
            <div class="card-title">Nível de Dor Geral (0–10)</div>
            <div style="display:flex;align-items:center;gap:12px;margin-top:8px">
              <input type="range" min="0" max="10" value="0" class="eval-slider" id="avalDor" oninput="updateDorLabel()"/>
              <span id="avalDorVal" style="font-family:var(--mono);font-size:16px;color:var(--danger);min-width:20px">0</span>
            </div>
          </div>
        </div>
      </div>
      <div style="display:flex;justify-content:flex-end;margin-top:12px">
        <button class="btn btn-primary" onclick="goStep(1)">Próximo →</button>
      </div>
    </div>

    <!-- STEP 1: MEDIDAS -->
    <div id="avalStep1" style="display:none" class="fade-in">
      <div class="g2">
        <div class="card">
          <div class="card-title">Circunferências (cm)</div>
          <div class="g2">
            <div class="fg"><label class="fl">Cintura</label><input class="fi" id="mCintura" type="number"/></div>
            <div class="fg"><label class="fl">Quadril</label><input class="fi" id="mQuadril" type="number"/></div>
            <div class="fg"><label class="fl">Braço D</label><input class="fi" id="mBracoD" type="number"/></div>
            <div class="fg"><label class="fl">Braço E</label><input class="fi" id="mBracoE" type="number"/></div>
            <div class="fg"><label class="fl">Coxa D</label><input class="fi" id="mCoxaD" type="number"/></div>
            <div class="fg"><label class="fl">Coxa E</label><input class="fi" id="mCoxaE" type="number"/></div>
            <div class="fg"><label class="fl">Panturrilha D</label><input class="fi" id="mPantD" type="number"/></div>
            <div class="fg"><label class="fl">Pescoço</label><input class="fi" id="mPescoco" type="number"/></div>
          </div>
        </div>
        <div class="card">
          <div class="card-title">Dobras Cutâneas (mm)</div>
          <div class="g2">
            <div class="fg"><label class="fl">Tríceps</label><input class="fi" id="dTriceps" type="number"/></div>
            <div class="fg"><label class="fl">Subescapular</label><input class="fi" id="dSubesc" type="number"/></div>
            <div class="fg"><label class="fl">Peitoral</label><input class="fi" id="dPeitoral" type="number"/></div>
            <div class="fg"><label class="fl">Axilar Médio</label><input class="fi" id="dAxilar" type="number"/></div>
            <div class="fg"><label class="fl">Suprailíaco</label><input class="fi" id="dSuprail" type="number"/></div>
            <div class="fg"><label class="fl">Abdominal</label><input class="fi" id="dAbdom" type="number"/></div>
            <div class="fg"><label class="fl">Coxa</label><input class="fi" id="dCoxa" type="number"/></div>
            <div class="fg"><label class="fl">Protocolo</label>
              <select class="fs" id="dProtocolo">
                <option>Pollock 7 dobras</option>
                <option>Pollock 3 dobras</option>
                <option>Jackson-Pollock</option>
              </select>
            </div>
          </div>
        </div>
      </div>
      <div style="display:flex;justify-content:space-between;margin-top:12px">
        <button class="btn btn-ghost" onclick="goStep(0)">← Anterior</button>
        <button class="btn btn-primary" onclick="goStep(2)">Próximo →</button>
      </div>
    </div>

    <!-- STEP 2: BIOIMPEDÂNCIA -->
    <div id="avalStep2" style="display:none" class="fade-in">
      <div class="g2">
        <div class="card">
          <div class="card-title">Dados de Bioimpedância</div>
          <div class="g2">
            <div class="fg"><label class="fl">% Gordura Corporal</label><input class="fi" id="bioGord" type="number" step="0.1" placeholder="ex: 22.5"/></div>
            <div class="fg"><label class="fl">Massa Muscular (kg)</label><input class="fi" id="bioMusc" type="number" step="0.1" placeholder="ex: 30.2"/></div>
            <div class="fg"><label class="fl">Massa Magra (kg)</label><input class="fi" id="bioMagra" type="number" step="0.1" placeholder="ex: 52.0"/></div>
            <div class="fg"><label class="fl">Água Corporal (%)</label><input class="fi" id="bioAgua" type="number" step="0.1" placeholder="ex: 58.0"/></div>
            <div class="fg"><label class="fl">TMB (kcal/dia)</label><input class="fi" id="bioTMB" type="number" placeholder="ex: 1450"/></div>
            <div class="fg"><label class="fl">Gordura Visceral (índice)</label><input class="fi" id="bioVisceral" type="number" placeholder="ex: 5 (ideal &lt;10)"/></div>
          </div>
        </div>
        <div class="card">
          <div class="card-title">Referências</div>
          <table class="tbl">
            <tr><th>Indicador</th><th>Ideal (F)</th><th>Ideal (M)</th></tr>
            <tr><td>% Gordura</td><td>18–25%</td><td>10–18%</td></tr>
            <tr><td>Água Corporal</td><td>45–60%</td><td>50–65%</td></tr>
            <tr><td>Gordura Visceral</td><td colspan="2">&lt; 10</td></tr>
            <tr><td>TMB Média</td><td>~1400</td><td>~1700</td></tr>
          </table>
          <div class="alert ai" style="margin-top:12px;margin-bottom:0">
            <span>ℹ</span><div>Os valores de bioimpedância devem ser coletados em equipamento calibrado, preferencialmente em jejum.</div>
          </div>
        </div>
      </div>
      <div style="display:flex;justify-content:space-between;margin-top:12px">
        <button class="btn btn-ghost" onclick="goStep(1)">← Anterior</button>
        <button class="btn btn-primary" onclick="goStep(3)">Próximo →</button>
      </div>
    </div>

    <!-- STEP 3: POSTURA & DOR -->
    <div id="avalStep3" style="display:none" class="fade-in">
      <div class="g2">
        <div class="card">
          <div class="card-title">Mapa de Dor Corporal</div>
          <div style="display:flex;gap:14px;align-items:flex-start">
            <svg viewBox="0 0 120 340" width="130" height="300" style="flex-shrink:0">
              <ellipse class="bp" id="bp-head" cx="60" cy="22" rx="18" ry="20" onclick="selectBP('Cabeça','bp-head')"/>
              <rect class="bp" id="bp-neck" x="53" y="42" width="14" height="14" rx="3" onclick="selectBP('Pescoço','bp-neck')"/>
              <rect class="bp" id="bp-torso" x="35" y="56" width="50" height="65" rx="6" onclick="selectBP('Tórax/Abdômen','bp-torso')"/>
              <ellipse class="bp" id="bp-shl" cx="28" cy="68" rx="12" ry="10" onclick="selectBP('Ombro Esq.','bp-shl')"/>
              <ellipse class="bp" id="bp-shr" cx="92" cy="68" rx="12" ry="10" onclick="selectBP('Ombro Dir.','bp-shr')"/>
              <rect class="bp" id="bp-arml" x="12" y="76" width="18" height="45" rx="6" onclick="selectBP('Braço Esq.','bp-arml')"/>
              <rect class="bp" id="bp-armr" x="90" y="76" width="18" height="45" rx="6" onclick="selectBP('Braço Dir.','bp-armr')"/>
              <rect class="bp" id="bp-forl" x="14" y="123" width="14" height="36" rx="5" onclick="selectBP('Antebraço Esq.','bp-forl')"/>
              <rect class="bp" id="bp-forr" x="92" y="123" width="14" height="36" rx="5" onclick="selectBP('Antebraço Dir.','bp-forr')"/>
              <rect class="bp" id="bp-pelvis" x="38" y="121" width="44" height="28" rx="5" onclick="selectBP('Lombar/Pelve','bp-pelvis')"/>
              <rect class="bp" id="bp-thl" x="37" y="150" width="20" height="54" rx="6" onclick="selectBP('Coxa Esq.','bp-thl')"/>
              <rect class="bp" id="bp-thr" x="62" y="150" width="20" height="54" rx="6" onclick="selectBP('Coxa Dir.','bp-thr')"/>
              <ellipse class="bp" id="bp-knl" cx="47" cy="210" rx="10" ry="8" onclick="selectBP('Joelho Esq.','bp-knl')"/>
              <ellipse class="bp" id="bp-knr" cx="72" cy="210" rx="10" ry="8" onclick="selectBP('Joelho Dir.','bp-knr')"/>
              <rect class="bp" id="bp-shl2" x="39" y="218" width="16" height="52" rx="5" onclick="selectBP('Perna Esq.','bp-shl2')"/>
              <rect class="bp" id="bp-shr2" x="64" y="218" width="16" height="52" rx="5" onclick="selectBP('Perna Dir.','bp-shr2')"/>
              <ellipse class="bp" id="bp-ftl" cx="47" cy="278" rx="12" ry="8" onclick="selectBP('Pé Esq.','bp-ftl')"/>
              <ellipse class="bp" id="bp-ftr" cx="72" cy="278" rx="12" ry="8" onclick="selectBP('Pé Dir.','bp-ftr')"/>
            </svg>
            <div style="flex:1">
              <div id="bpInfo" style="background:var(--bg3);border-radius:var(--rad);padding:12px;margin-bottom:10px;font-size:12px;color:var(--text3)">
                Clique em uma região do corpo para registrar dor.
              </div>
              <div id="painEntries"></div>
            </div>
          </div>
        </div>
        <div class="card">
          <div class="card-title">Desvios Posturais</div>
          <div id="postureDeviations">
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-lordose" style="accent-color:var(--brand)"> Hiperlordose Lombar
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-cifose"> Cifose Torácica
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-escoliose"> Escoliose
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-antero"> Anteroversão de Pelve
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-valgo"> Joelho Valgo
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid var(--border);cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-cabeca"> Cabeça Anteriorizada
            </label>
            <label style="display:flex;align-items:center;gap:8px;padding:7px 0;cursor:pointer;font-size:12px">
              <input type="checkbox" id="dev-ombros"> Protrusão de Ombros
            </label>
          </div>
          <div class="fg" style="margin-top:14px;margin-bottom:0">
            <label class="fl">Observações Posturais</label>
            <textarea class="fta" id="postureObs" rows="4" placeholder="Descreva desvios observados, compensações..."></textarea>
          </div>
        </div>
      </div>
      <div style="display:flex;justify-content:space-between;margin-top:12px">
        <button class="btn btn-ghost" onclick="goStep(2)">← Anterior</button>
        <button class="btn btn-primary" onclick="goStep(4)">Próximo →</button>
      </div>
    </div>

    <!-- STEP 4: FUNCIONAL -->
    <div id="avalStep4" style="display:none" class="fade-in">
      <div class="g2">
        <div class="card">
          <div class="card-title">Testes Funcionais</div>
          <div style="margin-bottom:12px">
            <label class="fl">Agachamento Overhead (FMS 0–3)</label>
            <select class="fs" id="fmsAga"><option value="3">3 — Padrão correto</option><option value="2" selected>2 — Compensação</option><option value="1">1 — Dor presente</option><option value="0">0 — N/R</option></select>
          </div>
          <div style="margin-bottom:12px">
            <label class="fl">Prancha Isométrica (seg)</label>
            <input class="fi" id="funcPrancha" type="number" placeholder="ex: 60"/>
          </div>
          <div style="margin-bottom:12px">
            <label class="fl">Flexão de Tronco (cm além dos pés)</label>
            <input class="fi" id="funcFlex" placeholder="ex: +5 ou -3"/>
          </div>
          <div style="margin-bottom:12px">
            <label class="fl">VO₂ Estimado (ml/kg/min)</label>
            <input class="fi" id="funcVO2" type="number" placeholder="ex: 35"/>
          </div>
          <div>
            <label class="fl">Observações Funcionais</label>
            <textarea class="fta" id="funcObs" rows="3" placeholder="Padrões de movimento, compensações..."></textarea>
          </div>
        </div>
        <div class="card">
          <div class="card-title">Resumo da Avaliação</div>
          <div id="avalSummary" style="font-size:12px;color:var(--text2);">
            Complete os passos anteriores para ver o resumo.
          </div>
        </div>
      </div>
      <div style="display:flex;justify-content:space-between;margin-top:12px">
        <button class="btn btn-ghost" onclick="goStep(3)">← Anterior</button>
        <button class="btn btn-primary" onclick="salvarAvaliacao()">✓ Salvar Avaliação</button>
      </div>
    </div>
  </div>

  <!-- ════════ TREINOS ════════ -->
  <div class="page" id="page-treinos">
    <div class="sh">
      <div>
        <div class="st">Gerenciar Treinos</div>
        <div class="ss">Criar, editar e personalizar treinos</div>
      </div>
      <div style="display:flex;gap:8px">
        <button class="btn btn-secondary" onclick="gerarTreinoIA()">🧠 Gerar com IA</button>
        <button class="btn btn-primary" onclick="novoTreinoManual()">+ Criar Manual</button>
      </div>
    </div>

    <!-- SELECIONA ALUNO -->
    <div class="card" style="margin-bottom:14px">
      <div style="display:flex;align-items:center;gap:12px">
        <label class="fl" style="margin-bottom:0;white-space:nowrap">Aluno:</label>
        <select class="fs" id="treinoAlunoSelect" onchange="carregarTreinosAluno()" style="max-width:300px">
          <option value="">— Selecione —</option>
        </select>
      </div>
    </div>

    <div id="treinosContainer">
      <div style="text-align:center;padding:40px;color:var(--text3)">
        Selecione um aluno para ver e gerenciar seus treinos.
      </div>
    </div>
  </div>

  <!-- ════════ HISTÓRICO ════════ -->
  <div class="page" id="page-historico">
    <div class="sh">
      <div>
        <div class="st">Histórico Evolutivo</div>
        <div class="ss">Acompanhe a evolução detalhada de cada aluno</div>
      </div>
      <button class="btn btn-ghost" onclick="exportarHistorico()">📄 Exportar Relatório</button>
    </div>

    <div class="card" style="margin-bottom:14px">
      <div style="display:flex;align-items:center;gap:12px">
        <label class="fl" style="margin-bottom:0;white-space:nowrap">Aluno:</label>
        <select class="fs" id="histAlunoSelect" onchange="carregarHistoricoAluno()" style="max-width:300px">
          <option value="">— Selecione —</option>
        </select>
      </div>
    </div>

    <div id="histContainer">
      <div style="text-align:center;padding:40px;color:var(--text3)">
        Selecione um aluno para visualizar o histórico.
      </div>
    </div>
  </div>

  <!-- ════════ IA ════════ -->
  <div class="page" id="page-ia">
    <div class="sh">
      <div>
        <div class="st">Assistente IA</div>
        <div class="ss">Análise inteligente, insights e recomendações</div>
      </div>
      <span class="badge bb">● Online</span>
    </div>

    <div class="g2">
      <div class="card" style="display:flex;flex-direction:column">
        <div class="card-title c">Chat Inteligente</div>
        <div class="ia-chat" id="iaChat">
          <div class="msg ia">
            <div class="mh">⚡ APEX IA</div>
            Olá, Prof. Teste! Estou pronto para analisar seus alunos e fornecer insights inteligentes. Você pode perguntar sobre qualquer aluno, solicitar análise de risco de lesão, sugestões de treino ou interpretação de bioimpedância.
          </div>
        </div>
        <div class="msg-input-wrap">
          <input class="msg-input" id="iaInput" placeholder="Pergunte sobre alunos, avaliações, lesões..." onkeydown="if(event.key==='Enter')enviarIA()"/>
          <button class="btn btn-primary btn-sm" onclick="enviarIA()">Enviar</button>
        </div>
      </div>

      <div>
        <div class="card" style="margin-bottom:14px">
          <div class="card-title c">Análise Rápida por Aluno</div>
          <select class="fs" id="iaAlunoSelect" onchange="analisarAluno()" style="margin-bottom:12px">
            <option value="">— Selecione um aluno —</option>
          </select>
          <div id="iaAnalise">
            <div style="color:var(--text3);font-size:12px">Selecione um aluno para análise automática.</div>
          </div>
        </div>

        <div class="card">
          <div class="card-title c">Riscos Detectados</div>
          <div id="iaRiscos">
            <div style="color:var(--text3);font-size:12px">Nenhum risco identificado ainda.</div>
          </div>
        </div>
      </div>
    </div>
  </div>

</div><!-- /main-content -->
👤 Cadastrar Novo Aluno
<div class="wizard-steps" id="alunoWizard">
  <div class="wizard-step active" onclick="goAlunoStep(0)"><div class="wstep-num">1</div>Básico</div>
  <div class="wizard-step" onclick="goAlunoStep(1)"><div class="wstep-num">2</div>Saúde</div>
  <div class="wizard-step" onclick="goAlunoStep(2)"><div class="wstep-num">3</div>Bioimpedância</div>
</div>

<!-- STEP 0 -->
<div id="alunoStep0">
  <div class="g2">
    <div class="fg"><label class="fl">Nome Completo *</label><input class="fi" id="aNome" placeholder="Nome do aluno"/></div>
    <div class="fg"><label class="fl">Idade</label><input class="fi" id="aIdade" type="number" placeholder="Anos"/></div>
    <div class="fg"><label class="fl">Sexo Biológico</label><select class="fs" id="aSexo"><option value="F">Feminino</option><option value="M">Masculino</option></select></div>
    <div class="fg"><label class="fl">Profissão</label><input class="fi" id="aProfissao" placeholder="ex: Professora"/></div>
    <div class="fg"><label class="fl">Peso (kg)</label><input class="fi" id="aPeso" type="number" step="0.1"/></div>
    <div class="fg"><label class="fl">Altura (cm)</label><input class="fi" id="aAltura" type="number"/></div>
    <div class="fg"><label class="fl">Objetivo</label>
      <select class="fs" id="aObjetivo">
        <option>Emagrecimento</option><option>Hipertrofia</option>
        <option>Reabilitação</option><option>Performance</option><option>Condicionamento</option>
      </select>
    </div>
    <div class="fg"><label class="fl">Nível de Atividade</label>
      <select class="fs" id="aAtividade">
        <option>Sedentário</option><option>Leve</option>
        <option selected>Moderado</option><option>Intenso</option><option>Atleta</option>
      </select>
    </div>
    <div class="fg"><label class="fl">Histórico de Treino</label>
      <select class="fs" id="aHistTreino">
        <option>Iniciante (&lt;1 ano)</option><option selected>Intermediário (1–3 anos)</option><option>Avançado (3+ anos)</option>
      </select>
    </div>
    <div class="fg"><label class="fl">Sono Médio (horas)</label><input class="fi" id="aSono" type="number" step="0.5" placeholder="ex: 7"/></div>
    <div class="fg"><label class="fl">Nível de Estresse (1–10)</label><input class="fi" id="aEstresse" type="number" min="1" max="10" placeholder="ex: 6"/></div>
    <div class="fg"><label class="fl">Telefone</label><input class="fi" id="aTelefone" placeholder="(85) 99999-9999"/></div>
  </div>
  <div style="display:flex;justify-content:flex-end;margin-top:8px">
    <button class="btn btn-primary" onclick="goAlunoStep(1)">Próximo →</button>
  </div>
</div>

<!-- STEP 1 -->
<div id="alunoStep1" style="display:none">
  <div class="g2">
    <div class="fg">
      <label class="fl">Condições de Saúde</label>
      <div style="display:flex;flex-direction:column;gap:5px;background:var(--bg3);border-radius:var(--rad);padding:10px">
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cHiper" style="accent-color:var(--brand)"> Hipertensão Arterial</label>
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cDiab"> Diabetes</label>
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cCard"> Problema Cardíaco</label>
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cColuna"> Problema de Coluna</label>
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cJoelho"> Problema de Joelho</label>
        <label style="display:flex;align-items:center;gap:6px;font-size:12px;cursor:pointer"><input type="checkbox" id="cOmbro"> Problema de Ombro</label>
      </div>
    </div>
    <div>
      <div class="fg"><label class="fl">Lesões Anteriores</label><textarea class="fta" id="aLesoes" rows="3" placeholder="Descreva lesões, cirurgias..."></textarea></div>
      <div class="fg"><label class="fl">Limitações Articulares</label><textarea class="fta" id="aLimitacoes" rows="2" placeholder="Limitações de mobilidade..."></textarea></div>
      <div class="fg"><label class="fl">Medicamentos em Uso</label><textarea class="fta" id="aMedicamentos" rows="2" placeholder="Nome e dosagem..."></textarea></div>
    </div>
  </div>
  <div style="display:flex;justify-content:space-between;margin-top:8px">
    <button class="btn btn-ghost" onclick="goAlunoStep(0)">← Anterior</button>
    <button class="btn btn-primary" onclick="goAlunoStep(2)">Próximo →</button>
  </div>
</div>

<!-- STEP 2 -->
<div id="alunoStep2" style="display:none">
  <div class="alert ai" style="margin-bottom:14px"><span>ℹ</span><div>Preencha os dados de bioimpedância inicial se disponíveis. Pode ser deixado em branco e preenchido na primeira avaliação.</div></div>
  <div class="g2">
    <div class="fg"><label class="fl">% Gordura Corporal</label><input class="fi" id="aBioGord" type="number" step="0.1" placeholder="ex: 25.0"/></div>
    <div class="fg"><label class="fl">Massa Muscular (kg)</label><input class="fi" id="aBioMusc" type="number" step="0.1" placeholder="ex: 28.0"/></div>
    <div class="fg"><label class="fl">Massa Magra (kg)</label><input class="fi" id="aBioMagra" type="number" step="0.1" placeholder="ex: 54.0"/></div>
    <div class="fg"><label class="fl">Água Corporal (%)</label><input class="fi" id="aBioAgua" type="number" step="0.1" placeholder="ex: 55.0"/></div>
    <div class="fg"><label class="fl">TMB (kcal/dia)</label><input class="fi" id="aBioTMB" type="number" placeholder="ex: 1400"/></div>
    <div class="fg"><label class="fl">Gordura Visceral</label><input class="fi" id="aBioVisc" type="number" placeholder="ex: 6"/></div>
  </div>
  <div style="display:flex;justify-content:space-between;margin-top:8px">
    <button class="btn btn-ghost" onclick="goAlunoStep(1)">← Anterior</button>
    <button class="btn btn-primary" onclick="salvarAluno()">✓ Salvar Aluno</button>
  </div>
</div>
🏋 Editor de Treino
<div class="g2" style="margin-bottom:14px">
  <div class="fg"><label class="fl">Nome do Treino</label><input class="fi" id="trNome" placeholder="ex: Treino A — Inferior"/></div>
  <div class="fg"><label class="fl">Grupo Muscular</label><input class="fi" id="trGrupo" placeholder="ex: Quadríceps, Glúteos..."/></div>
</div>

<div style="margin-bottom:10px;display:flex;align-items:center;justify-content:space-between">
  <div class="card-title" style="margin-bottom:0">Exercícios</div>
  <button class="btn btn-ghost btn-sm" onclick="addExercicio()">+ Adicionar Exercício</button>
</div>

<div style="background:var(--bg3);border-radius:var(--rad);padding:10px;margin-bottom:6px;display:grid;grid-template-columns:24px 1fr 70px 60px 60px 70px 30px;gap:6px;font-size:9px;font-weight:700;color:var(--text3);letter-spacing:0.8px;text-transform:uppercase">
  <div></div><div>Exercício</div><div>Séries</div><div>Reps</div><div>Carga</div><div>Intervalo</div><div></div>
</div>
<div id="exerciciosList"></div>

<div class="fg" style="margin-top:14px"><label class="fl">Observações do Treino</label><textarea class="fta" id="trObs" rows="2" placeholder="Orientações, adaptações..."></textarea></div>

<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:14px">
  <button class="btn btn-ghost" onclick="closeModal('modalTreino')">Cancelar</button>
  <button class="btn btn-primary" onclick="salvarTreino()">✓ Salvar Treino</button>
</div>
<script> /* ══════════════════════════════════════ ESTADO GLOBAL ══════════════════════════════════════ */ const STATE = { loggedIn: false, alunos: [], // [{id, nome, idade, sexo, ...}] avaliacoes: [], // [{id, alunoId, data, peso, ...}] treinos: [], // [{id, alunoId, nome, exercicios:[]}] currentAluno: null, editingAlunoId: null, editingTreinoId: null, currentStep: 0, currentAlunoStep: 0, bodyPains: {}, // {bpId: {regiao, intensidade}} }; /* ══ HELPERS ══ */ function uid(){ return Date.now().toString(36)+Math.random().toString(36).slice(2,7) } function today(){ return new Date().toISOString().split('T')[0] } function fmt(d){ return d ? new Date(d+'T00:00:00').toLocaleDateString('pt-BR') : '—' } function avatarColor(nome){ const c=['#00D4AA','#7C3AED','#F59E0B','#EF4444','#10B981','#3B82F6','#EC4899']; return c[(nome||'A').charCodeAt(0)%c.length]; } function initials(nome){ return (nome||'?').split(' ').map(w=>w[0]).slice(0,2).join('').toUpperCase() } function showToast(msg, type='success'){ const t=document.getElementById('toast'); const icons={success:'✓',error:'✕',info:'ℹ',warn:'⚠'}; const colors={success:STATE_COLOR_SUCCESS,error:STATE_COLOR_DANGER,info:STATE_COLOR_BRAND,warn:STATE_COLOR_ACCENT}; document.getElementById('toastIcon').textContent=icons[type]||'✓'; document.getElementById('toastMsg').textContent=msg; t.style.display='block'; t.querySelector('div').style.borderColor=colors[type]||colors.success; clearTimeout(t._tid); t._tid=setTimeout(()=>t.style.display='none',3000); } const STATE_COLOR_BRAND='rgba(0,212,170,0.5)'; const STATE_COLOR_ACCENT='rgba(245,158,11,0.5)'; const STATE_COLOR_DANGER='rgba(239,68,68,0.5)'; const STATE_COLOR_SUCCESS='rgba(16,185,129,0.5)'; /* ══ MODAL ══ */ function openModal(id){document.getElementById(id).classList.add('open')} function closeModal(id){document.getElementById(id).classList.remove('open')} /* ══════════════════════════════════════ LOGIN ══════════════════════════════════════ */ function doLogin(){ const u=document.getElementById('loginUser').value.trim(); const p=document.getElementById('loginPass').value.trim(); if(u==='Teste'&&p==='123'){ STATE.loggedIn=true; document.getElementById('loginScreen').style.display='none'; document.getElementById('app').style.display='flex'; initApp(); } else { document.getElementById('loginError').style.display='block'; } } function doLogout(){ STATE.loggedIn=false; document.getElementById('app').style.display='none'; document.getElementById('loginScreen').style.display='flex'; document.getElementById('loginUser').value=''; document.getElementById('loginPass').value=''; document.getElementById('loginError').style.display='none'; } /* ══════════════════════════════════════ INIT ══════════════════════════════════════ */ function initApp(){ document.getElementById('dash-date').textContent=new Date().toLocaleDateString('pt-BR',{weekday:'long',year:'numeric',month:'long',day:'numeric'}); document.getElementById('avalData').value=today(); preencherSelects(); renderDashboard(); renderAlunosList(); renderSidebarAlunos(); loadSampleData(); } function loadSampleData(){ if(STATE.alunos.length>0) return; // Sample aluno const id=uid(); STATE.alunos.push({ id,nome:'Ana Martins',idade:31,sexo:'F',profissao:'Advogada', peso:67.4,altura:170,objetivo:'Emagrecimento',atividade:'Moderado', histTreino:'Intermediário (1–3 anos)',sono:6.5,estresse:7, telefone:'(85) 99999-1234', lesoes:'Entorse no tornozelo direito (2023)', limitacoes:'Leve limitação na flexão do joelho direito', medicamentos:'Losartana 50mg', condicoes:['Hipertensão Arterial','Problema de Joelho'], bio:{gord:22.1,musc:30.2,magra:52.5,agua:58.2,tmb:1380,visceral:5}, createdAt:today() }); // Avaliações const datas=['2025-12-05','2026-01-10','2026-02-03','2026-03-18']; const pesos=[72.0,70.1,68.6,67.4]; const gords=[26.0,24.2,22.9,22.1]; const magras=[53.3,53.1,52.8,52.5]; datas.forEach((d,i)=>{ STATE.avaliacoes.push({ id:uid(),alunoId:id,data:d, peso:pesos[i],altura:170, medidas:{cintura:[82,80,78,76][i],quadril:[102,100,99,98][i],bracoD:32,coxaD:58}, bio:{gord:gords[i],musc:30.2,magra:magras[i],agua:58.2,tmb:1380,visceral:5}, dor:3,pa:'130/85',fc:72, posturaDesvios:i>0?['Hiperlordose Lombar','Anteroversão de Pelve']:[], funcional:{fmsAga:'2',prancha:45,flexTronco:'+4',vo2:32}, obs:'Avaliação regular. Evolução positiva.', pains:{} }); }); // Treino STATE.treinos.push({ id:uid(),alunoId:id,nome:'Treino A — Inferior',grupo:'Quadríceps, Glúteos, Posterior', exercicios:[ {nome:'Agachamento Livre',series:'4',reps:'12',carga:'60kg',intervalo:'90s'}, {nome:'Leg Press 45°',series:'3',reps:'15',carga:'120kg',intervalo:'75s'}, {nome:'Glúteo na Máquina',series:'4',reps:'20',carga:'30kg',intervalo:'60s'}, {nome:'Flexão de Joelho',series:'3',reps:'12',carga:'20kg',intervalo:'60s'}, {nome:'Mob. Quadril + Alongamento',series:'3',reps:'30s',carga:'—',intervalo:'30s'}, ], obs:'Evitar hiperflexão de joelho. Foco em ativação glútea.', geradoPorIA:false,createdAt:today() }); after(100,()=>{ renderDashboard();renderAlunosList();renderSidebarAlunos();preencherSelects(); }); } function after(ms,fn){setTimeout(fn,ms)} /* ══════════════════════════════════════ NAVEGAÇÃO ══════════════════════════════════════ */ function navTo(id){ document.querySelectorAll('.page').forEach(p=>p.classList.remove('active')); document.getElementById('page-'+id).classList.add('active'); document.querySelectorAll('.tnav,[data-slink]').forEach(t=>{ t.classList.toggle('active',t.dataset.nav===id||t.dataset.slink===id); }); if(id==='alunos') renderAlunosList(); if(id==='historico'||id==='treinos'||id==='ia') preencherSelects(); if(id==='dashboard') renderDashboard(); } /* ══════════════════════════════════════ SELECTS ══════════════════════════════════════ */ function preencherSelects(){ ['avalAlunoSelect','treinoAlunoSelect','histAlunoSelect','iaAlunoSelect'].forEach(sid=>{ const el=document.getElementById(sid); if(!el) return; const cur=el.value; el.innerHTML='— Selecione —'+ STATE.alunos.map(a=>`${a.nome}`).join(''); if(cur) el.value=cur; }); } /* ══════════════════════════════════════ DASHBOARD ══════════════════════════════════════ */ function renderDashboard(){ document.getElementById('statTotal').textContent=STATE.alunos.length; const hoje=today(); const avHoje=STATE.avaliacoes.filter(a=>a.data===hoje).length; document.getElementById('statHoje').textContent=avHoje; // Alertas let alertas=0; const alertasHtml=STATE.alunos.map(a=>{ const avs=STATE.avaliacoes.filter(x=>x.alunoId===a.id).sort((x,y)=>y.data.localeCompare(x.data)); const ultima=avs[0]; if(!ultima){ alertas++; return `
${a.nome} não possui avaliações. Agendar primeira avaliação.
`; } const dias=Math.floor((new Date()-new Date(ultima.data+' 00:00:00'))/(86400000)); if(dias>30){ alertas++; return `
${a.nome} — Última avaliação há ${dias} dias. Reavaliar.
`; } return ''; }).filter(Boolean).join('')||'
Todos os alunos com avaliações em dia!
'; document.getElementById('statAlertas').textContent=alertas; document.getElementById('statTreinos').textContent=STATE.treinos.length; document.getElementById('dashAlertas').innerHTML=alertasHtml; // Lista alunos if(STATE.alunos.length===0){ document.getElementById('dashAlunosList').innerHTML='
Nenhum aluno cadastrado.
Clique em + Novo Aluno para começar.
'; } else { document.getElementById('dashAlunosList').innerHTML=STATE.alunos.slice(0,6).map(a=>{ const avs=STATE.avaliacoes.filter(x=>x.alunoId===a.id).sort((x,y)=>y.data.localeCompare(x.data)); const ul=avs[0]; const dias=ul?Math.floor((new Date()-new Date(ul.data+' 00:00:00'))/(86400000)):null; const tag=dias===null?'Sem avaliação':dias<=7?'Recente':dias<=30?'Ok':'Reavaliar'; return `
${initials(a.nome)}
${a.nome}
${a.objetivo} • ${ul?'Última: '+fmt(ul.data):'Sem avaliação'}
${tag}
`; }).join(''); } // Atividade const ativs=STATE.avaliacoes.sort((a,b)=>b.data.localeCompare(a.data)).slice(0,4); document.getElementById('dashAtividade').innerHTML=ativs.length?ativs.map(av=>{ const al=STATE.alunos.find(a=>a.id===av.alunoId); return `
${al?.nome||'?'}${fmt(av.data)} — ${av.peso}kg
`; }).join(''):'
Nenhuma atividade.
'; buildGeralChart(); } function buildGeralChart(){ const ctx=document.getElementById('chartGeral'); if(!ctx) return; if(ctx._ch){ ctx._ch.destroy(); } const meses=['Dez','Jan','Fev','Mar','Abr','Mai']; ctx._ch=new Chart(ctx,{ type:'line', data:{labels:meses, datasets:[ {label:'Alunos Ativos',data:[1,1,1,1,1,1],borderColor:'#00D4AA',backgroundColor:'rgba(0,212,170,0.08)',tension:0.4,fill:true}, {label:'Avaliações',data:[0,1,2,3,4,4],borderColor:'#7C3AED',tension:0.4} ]}, options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}, scales:{x:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}},y:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}}}} }); } /* ══════════════════════════════════════ ALUNOS LIST ══════════════════════════════════════ */ function renderAlunosList(){ const q=(document.getElementById('searchAluno')?.value||'').toLowerCase(); const filtered=STATE.alunos.filter(a=>a.nome.toLowerCase().includes(q)); document.getElementById('alunosCount').textContent=`${filtered.length} aluno${filtered.length!==1?'s':''} cadastrado${filtered.length!==1?'s':''}`; if(filtered.length===0){ document.getElementById('alunosGrid').innerHTML=`
${STATE.alunos.length===0?'Nenhum aluno cadastrado. Clique em + Novo Aluno.':'Nenhum aluno encontrado.'}
`; return; } document.getElementById('alunosGrid').innerHTML=filtered.map(a=>{ const avs=STATE.avaliacoes.filter(x=>x.alunoId===a.id).sort((x,y)=>y.data.localeCompare(x.data)); const ul=avs[0]; const dias=ul?Math.floor((new Date()-new Date(ul.data+' 00:00:00'))/(86400000)):null; const tagCls=dias===null?'bd':dias<=7?'bg-s':dias<=30?'bb':'ba'; const tagTxt=dias===null?'Sem avaliação':dias<=7?'Recente':dias<=30?'Em dia':'Reavaliar'; const imc=a.peso&&a.altura?(a.peso/(a.altura/100)**2).toFixed(1):'—'; return `
${initials(a.nome)}
${a.nome}
${a.idade||'—'} anos • ${a.sexo==='F'?'♀':'♂'} • IMC ${imc} • ${a.objetivo}
${ul?`Última avaliação: ${fmt(ul.data)}`:'Sem avaliações'}
${tagTxt} ✏️ ✕
`; }).join(''); } function renderSidebarAlunos(){ document.getElementById('sidebarAlunos').innerHTML=STATE.alunos.slice(0,5).map(a=>{ return ` ${initials(a.nome)} ${a.nome.split(' ')[0]} `; }).join(''); } /* ══════════════════════════════════════ DETALHE ALUNO ══════════════════════════════════════ */ function abrirAluno(id){ const a=STATE.alunos.find(x=>x.id===id); if(!a) return; STATE.currentAluno=id; navTo('alunos'); document.getElementById('alunosGrid').style.display='none'; document.querySelector('.sh').style.display='none'; document.getElementById('searchAluno').parentElement.style.display='none'; document.getElementById('alunoDetail').style.display='block'; const cor=avatarColor(a.nome); document.getElementById('detAv').style.background=cor; document.getElementById('detAv').textContent=initials(a.nome); document.getElementById('detNome').textContent=a.nome; document.getElementById('detMeta').textContent=`${a.idade||'—'} anos • ${a.sexo==='F'?'Feminino':'Masculino'} • ${a.objetivo}`; // Métricas rápidas const avs=STATE.avaliacoes.filter(x=>x.alunoId===id).sort((x,y)=>y.data.localeCompare(x.data)); const ul=avs[0]; const imc=a.peso&&a.altura?(a.peso/(a.altura/100)**2).toFixed(1):'—'; const imcClass=imc==='—'?'—':imc<18.5?'Abaixo':imc<25?'Normal':imc<30?'Sobrepeso':'Obesidade'; document.getElementById('detMetrics').innerHTML=`
Peso
${a.peso||'—'} kg
atual
IMC
${imc}
${imcClass}
Avaliações
${avs.length}
registradas
`; // Tabela dados document.getElementById('detTabela').innerHTML=` CampoValor Profissão${a.profissao||'—'} Altura${a.altura||'—'} cm Atividade${a.atividade||'—'} Treino${a.histTreino||'—'} Sono${a.sono||'—'} h Estresse${a.estresse||'—'}/10 Telefone${a.telefone||'—'} Lesões${a.lesoes||'Nenhuma'} Medicamentos${a.medicamentos||'Nenhum'} Condições${(a.condicoes||[]).join(', ')||'Nenhuma'} `; // Bio const bio=ul?.bio||a.bio||{}; document.getElementById('detBio').innerHTML=bio.gord!=null?`
% Gordura
${bio.gord}%
Massa Muscular
${bio.musc}kg
Massa Magra
${bio.magra}kg
Água Corporal
${bio.agua}%
TMB
${bio.tmb}kcal
Gordura Visceral
${bio.visceral}
`:'
Dados de bioimpedância não registrados.
'; // Avaliações document.getElementById('detAvaliacoes').innerHTML=avs.length?` ${avs.map(av=>``).join('')}
DataPeso% GorduraCinturaDorScoreAções
${fmt(av.data)} ${av.peso||'—'} kg ${av.bio?.gord||'—'}% ${av.medidas?.cintura||'—'} cm ${av.dor||0}/10 ${calcScore(av)}
`:'
Nenhuma avaliação registrada. Clique em + Nova Avaliação.
'; buildDetChart(id,avs); } function calcScore(av){ let s=50; if(av.peso&&av.peso<100) s+=10; if(av.bio?.gord&&av.bio.gord<25) s+=10; if(av.dor<=3) s+=10; if(av.funcional?.prancha>60) s+=10; if(av.bio?.visceral&&av.bio.visceral<10) s+=10; return Math.min(100,s); } function buildDetChart(id,avs){ const ctx=document.getElementById('chartDetAluno'); if(!ctx) return; if(ctx._ch) ctx._ch.destroy(); const sorted=avs.slice().sort((a,b)=>a.data.localeCompare(b.data)); ctx._ch=new Chart(ctx,{ type:'line', data:{ labels:sorted.map(a=>fmt(a.data)), datasets:[ {label:'Peso (kg)',data:sorted.map(a=>a.peso||null),borderColor:'#00D4AA',tension:0.4,yAxisID:'y'}, {label:'% Gordura',data:sorted.map(a=>a.bio?.gord||null),borderColor:'#F59E0B',tension:0.4,yAxisID:'y2'}, ] }, options:{responsive:true,maintainAspectRatio:false, plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}, scales:{ x:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}}, y:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}}, y2:{position:'right',ticks:{color:'#F59E0B',font:{size:10}},grid:{display:false}} }} }); } function fecharDetalhe(){ document.getElementById('alunoDetail').style.display='none'; document.getElementById('alunosGrid').style.display='block'; document.querySelector('#page-alunos .sh').style.display='flex'; document.getElementById('searchAluno').parentElement.style.display='block'; STATE.currentAluno=null; renderAlunosList(); } function novaAvaliacaoParaAluno(){ navTo('avaliacao'); after(100,()=>{ const sel=document.getElementById('avalAlunoSelect'); sel.value=STATE.currentAluno; selecionarAlunoAval(); }); } function verHistoricoAluno(){ navTo('historico'); after(100,()=>{ document.getElementById('histAlunoSelect').value=STATE.currentAluno; carregarHistoricoAluno(); }); } /* ══════════════════════════════════════ CADASTRO ALUNO ══════════════════════════════════════ */ function goAlunoStep(n){ STATE.currentAlunoStep=n; [0,1,2].forEach(i=>{ document.getElementById('alunoStep'+i).style.display=i===n?'block':'none'; const ws=document.querySelectorAll('#alunoWizard .wizard-step'); ws[i].className='wizard-step'+(i===n?' active':ia.id===STATE.editingAlunoId); if(idx>=0){ STATE.alunos[idx]={...STATE.alunos[idx], nome,idade:parseInt(document.getElementById('aIdade').value)||null, sexo:document.getElementById('aSexo').value, profissao:document.getElementById('aProfissao').value, peso:parseFloat(document.getElementById('aPeso').value)||null, altura:parseInt(document.getElementById('aAltura').value)||null, objetivo:document.getElementById('aObjetivo').value, atividade:document.getElementById('aAtividade').value, histTreino:document.getElementById('aHistTreino').value, sono:parseFloat(document.getElementById('aSono').value)||null, estresse:parseInt(document.getElementById('aEstresse').value)||null, telefone:document.getElementById('aTelefone').value, lesoes:document.getElementById('aLesoes').value, limitacoes:document.getElementById('aLimitacoes').value, medicamentos:document.getElementById('aMedicamentos').value, condicoes,bio }; showToast('Aluno atualizado com sucesso!'); } STATE.editingAlunoId=null; } else { STATE.alunos.push({ id:uid(),nome,idade:parseInt(document.getElementById('aIdade').value)||null, sexo:document.getElementById('aSexo').value, profissao:document.getElementById('aProfissao').value, peso:parseFloat(document.getElementById('aPeso').value)||null, altura:parseInt(document.getElementById('aAltura').value)||null, objetivo:document.getElementById('aObjetivo').value, atividade:document.getElementById('aAtividade').value, histTreino:document.getElementById('aHistTreino').value, sono:parseFloat(document.getElementById('aSono').value)||null, estresse:parseInt(document.getElementById('aEstresse').value)||null, telefone:document.getElementById('aTelefone').value, lesoes:document.getElementById('aLesoes').value, limitacoes:document.getElementById('aLimitacoes').value, medicamentos:document.getElementById('aMedicamentos').value, condicoes,bio,createdAt:today() }); showToast('Aluno cadastrado com sucesso!'); } limparFormAluno(); closeModal('modalNovoAluno'); renderDashboard(); renderAlunosList(); renderSidebarAlunos(); preencherSelects(); } function limparFormAluno(){ ['aNome','aIdade','aProfissao','aPeso','aAltura','aSono','aEstresse','aTelefone','aLesoes','aLimitacoes','aMedicamentos','aBioGord','aBioMusc','aBioMagra','aBioAgua','aBioTMB','aBioVisc'].forEach(id=>{ const el=document.getElementById(id); if(el) el.value=''; }); ['cHiper','cDiab','cCard','cColuna','cJoelho','cOmbro'].forEach(id=>{ const el=document.getElementById(id); if(el) el.checked=false; }); document.getElementById('aSexo').value='F'; document.getElementById('modalAlunoTitle').textContent='Cadastrar Novo Aluno'; goAlunoStep(0); STATE.editingAlunoId=null; } function editarAluno(){ if(STATE.currentAluno) editarAlunoById(STATE.currentAluno); } function editarAlunoById(id){ const a=STATE.alunos.find(x=>x.id===id); if(!a) return; STATE.editingAlunoId=id; document.getElementById('modalAlunoTitle').textContent='Editar Aluno — '+a.nome; document.getElementById('aNome').value=a.nome||''; document.getElementById('aIdade').value=a.idade||''; document.getElementById('aSexo').value=a.sexo||'F'; document.getElementById('aProfissao').value=a.profissao||''; document.getElementById('aPeso').value=a.peso||''; document.getElementById('aAltura').value=a.altura||''; document.getElementById('aObjetivo').value=a.objetivo||'Emagrecimento'; document.getElementById('aAtividade').value=a.atividade||'Moderado'; document.getElementById('aHistTreino').value=a.histTreino||''; document.getElementById('aSono').value=a.sono||''; document.getElementById('aEstresse').value=a.estresse||''; document.getElementById('aTelefone').value=a.telefone||''; document.getElementById('aLesoes').value=a.lesoes||''; document.getElementById('aLimitacoes').value=a.limitacoes||''; document.getElementById('aMedicamentos').value=a.medicamentos||''; const cs=a.condicoes||[]; document.getElementById('cHiper').checked=cs.includes('Hipertensão Arterial'); document.getElementById('cDiab').checked=cs.includes('Diabetes'); document.getElementById('cCard').checked=cs.includes('Problema Cardíaco'); document.getElementById('cColuna').checked=cs.includes('Problema de Coluna'); document.getElementById('cJoelho').checked=cs.includes('Problema de Joelho'); document.getElementById('cOmbro').checked=cs.includes('Problema de Ombro'); const b=a.bio||{}; document.getElementById('aBioGord').value=b.gord||''; document.getElementById('aBioMusc').value=b.musc||''; document.getElementById('aBioMagra').value=b.magra||''; document.getElementById('aBioAgua').value=b.agua||''; document.getElementById('aBioTMB').value=b.tmb||''; document.getElementById('aBioVisc').value=b.visceral||''; openModal('modalNovoAluno'); goAlunoStep(0); } function excluirAluno(){ if(STATE.currentAluno) excluirAlunoById(STATE.currentAluno); } function excluirAlunoById(id){ const a=STATE.alunos.find(x=>x.id===id); if(!a) return; if(!confirm(`Excluir ${a.nome} e todas as avaliações/treinos? Esta ação não pode ser desfeita.`)) return; STATE.alunos=STATE.alunos.filter(x=>x.id!==id); STATE.avaliacoes=STATE.avaliacoes.filter(x=>x.alunoId!==id); STATE.treinos=STATE.treinos.filter(x=>x.alunoId!==id); if(STATE.currentAluno===id){ fecharDetalhe(); STATE.currentAluno=null; } showToast('Aluno excluído.'); renderDashboard();renderAlunosList();renderSidebarAlunos();preencherSelects(); } /* ══════════════════════════════════════ AVALIAÇÃO — WIZARD ══════════════════════════════════════ */ function goStep(n){ STATE.currentStep=n; for(let i=0;i<5;i++){ const el=document.getElementById('avalStep'+i); if(el) el.style.display=i===n?'block':'none'; } const ws=document.querySelectorAll('#avalWizard .wizard-step'); ws.forEach((s,i)=>{ s.className='wizard-step'+(i===n?' active':ix.id===id); document.getElementById('avalAluno').textContent=a?a.nome:'Selecione um aluno'; if(a&&a.altura) document.getElementById('avalAltura').value=a.altura; } function updateDorLabel(){ const v=document.getElementById('avalDor').value; const el=document.getElementById('avalDorVal'); el.textContent=v; el.style.color=v<=3?'var(--success)':v<=6?'var(--accent)':'var(--danger)'; } function selectBP(regiao,bpId){ document.querySelectorAll('.bp').forEach(e=>e.classList.remove('selected-part')); const el=document.getElementById(bpId); if(el) el.classList.add('selected-part'); document.getElementById('bpInfo').innerHTML=`
📍 ${regiao}
Intensidade da Dor (0–10)
0
Tipo de dor PontadaQueimaçãoPressãoFormigamentoPeso Registrar `; } function adicionarDor(regiao,bpId){ const int=parseInt(document.getElementById('bpSlider')?.value||0); const tipo=document.getElementById('bpTipo')?.value||''; STATE.bodyPains[bpId]={regiao,intensidade:int,tipo}; const el=document.getElementById(bpId); if(el){ el.classList.add('pain'); el.classList.remove('selected-part'); } renderPainEntries(); document.getElementById('bpInfo').innerHTML='
✓ Dor registrada em '+regiao+'
'; } function renderPainEntries(){ document.getElementById('painEntries').innerHTML=Object.entries(STATE.bodyPains).map(([bpId,p])=>`
${p.regiao}
${p.tipo} — ${p.intensidade}/10
${p.intensidade}/10
`).join(''); } function removerDor(bpId){ delete STATE.bodyPains[bpId]; const el=document.getElementById(bpId); if(el) el.classList.remove('pain'); renderPainEntries(); } function buildAvalSummary(){ const alunoId=document.getElementById('avalAlunoSelect').value; const a=STATE.alunos.find(x=>x.id===alunoId); const peso=document.getElementById('avalPeso').value; const altura=document.getElementById('avalAltura').value; const imc=peso&&altura?(parseFloat(peso)/(parseFloat(altura)/100)**2).toFixed(1):'—'; const gord=document.getElementById('bioGord').value; const dor=document.getElementById('avalDor').value; const desvios=[]; ['lordose','cifose','escoliose','antero','valgo','cabeca','ombros'].forEach(d=>{ const el=document.getElementById('dev-'+d); if(el?.checked) desvios.push({'lordose':'Hiperlordose','cifose':'Cifose','escoliose':'Escoliose','antero':'Anteroversão','valgo':'Joelho Valgo','cabeca':'Cabeça ant.','ombros':'Protrusão ombros'}[d]); }); document.getElementById('avalSummary').innerHTML=`
Aluno
${a?.nome||'—'}
IMC
${imc}
Peso
${peso||'—'} kg
% Gordura
${gord||'—'}%
🩺
Nível de dor geral: ${dor}/10
${desvios.length?`
📐
Desvios: ${desvios.join(', ')}
`:''} ${Object.keys(STATE.bodyPains).length?`
📍
${Object.values(STATE.bodyPains).length} região(ões) com dor mapeada(s)
`:''}
Pronto para salvar. Clique em Salvar Avaliação.
`; } function salvarAvaliacao(){ const alunoId=document.getElementById('avalAlunoSelect').value; if(!alunoId){ showToast('Selecione um aluno','error'); return; } const peso=parseFloat(document.getElementById('avalPeso').value); if(!peso){ showToast('Informe o peso','error'); return; } const desvios=[]; ['lordose','cifose','escoliose','antero','valgo','cabeca','ombros'].forEach(d=>{ const el=document.getElementById('dev-'+d); const nomes={lordose:'Hiperlordose Lombar',cifose:'Cifose Torácica',escoliose:'Escoliose',antero:'Anteroversão de Pelve',valgo:'Joelho Valgo',cabeca:'Cabeça Anteriorizada',ombros:'Protrusão de Ombros'}; if(el?.checked) desvios.push(nomes[d]); }); const av={ id:uid(), alunoId, data:document.getElementById('avalData').value||today(), peso, altura:parseInt(document.getElementById('avalAltura').value)||null, pa:document.getElementById('avalPA').value, fc:parseInt(document.getElementById('avalFC').value)||null, obs:document.getElementById('avalObs').value, dor:parseInt(document.getElementById('avalDor').value)||0, medidas:{ cintura:parseInt(document.getElementById('mCintura').value)||null, quadril:parseInt(document.getElementById('mQuadril').value)||null, bracoD:parseInt(document.getElementById('mBracoD').value)||null, bracoE:parseInt(document.getElementById('mBracoE').value)||null, coxaD:parseInt(document.getElementById('mCoxaD').value)||null, coxaE:parseInt(document.getElementById('mCoxaE').value)||null, pantD:parseInt(document.getElementById('mPantD').value)||null, pescoco:parseInt(document.getElementById('mPescoco').value)||null, }, dobras:{ triceps:parseFloat(document.getElementById('dTriceps').value)||null, subesc:parseFloat(document.getElementById('dSubesc').value)||null, peitoral:parseFloat(document.getElementById('dPeitoral').value)||null, axilar:parseFloat(document.getElementById('dAxilar').value)||null, suprail:parseFloat(document.getElementById('dSuprail').value)||null, abdom:parseFloat(document.getElementById('dAbdom').value)||null, coxa:parseFloat(document.getElementById('dCoxa').value)||null, }, bio:{ gord:parseFloat(document.getElementById('bioGord').value)||null, musc:parseFloat(document.getElementById('bioMusc').value)||null, magra:parseFloat(document.getElementById('bioMagra').value)||null, agua:parseFloat(document.getElementById('bioAgua').value)||null, tmb:parseInt(document.getElementById('bioTMB').value)||null, visceral:parseFloat(document.getElementById('bioVisceral').value)||null, }, posturaDesvios:desvios, posturaObs:document.getElementById('postureObs').value, funcional:{ fmsAga:document.getElementById('fmsAga').value, prancha:parseInt(document.getElementById('funcPrancha').value)||null, flexTronco:document.getElementById('funcFlex').value, vo2:parseInt(document.getElementById('funcVO2').value)||null, obs:document.getElementById('funcObs').value, }, pains:{...STATE.bodyPains}, }; STATE.avaliacoes.push(av); // Atualizar peso atual do aluno const idx=STATE.alunos.findIndex(x=>x.id===alunoId); if(idx>=0){ STATE.alunos[idx].peso=peso; if(av.bio.gord) STATE.alunos[idx].bio=av.bio; } // Reset form STATE.bodyPains={}; document.querySelectorAll('.bp').forEach(e=>e.classList.remove('pain','selected-part')); document.getElementById('bpInfo').innerHTML='Clique em uma região do corpo para registrar dor.'; document.getElementById('painEntries').innerHTML=''; document.querySelectorAll('#page-avaliacao .fi, #page-avaliacao .fta').forEach(e=>{ if(e.type!=='date') e.value=''; }); document.querySelectorAll('#page-avaliacao input[type=checkbox]').forEach(e=>e.checked=false); document.getElementById('avalDor').value=0; updateDorLabel(); document.getElementById('avalData').value=today(); goStep(0); showToast('Avaliação salva com sucesso!'); renderDashboard(); // Redirecionar para histórico do aluno after(1500,()=>{ STATE.currentAluno=alunoId; navTo('historico'); document.getElementById('histAlunoSelect').value=alunoId; carregarHistoricoAluno(); }); } function excluirAvaliacao(avId,alunoId){ if(!confirm('Excluir esta avaliação?')) return; STATE.avaliacoes=STATE.avaliacoes.filter(a=>a.id!==avId); showToast('Avaliação excluída.'); abrirAluno(alunoId); } /* ══════════════════════════════════════ HISTÓRICO ══════════════════════════════════════ */ function carregarHistoricoAluno(){ const id=document.getElementById('histAlunoSelect').value; const a=STATE.alunos.find(x=>x.id===id); if(!a){ document.getElementById('histContainer').innerHTML='
Selecione um aluno.
'; return; } const avs=STATE.avaliacoes.filter(x=>x.alunoId===id).sort((a,b)=>a.data.localeCompare(b.data)); if(avs.length===0){ document.getElementById('histContainer').innerHTML='
Nenhuma avaliação registrada para este aluno.
'; return; } const first=avs[0], last=avs[avs.length-1]; const deltaP=first!==last&&first.peso&&last.peso?(last.peso-first.peso).toFixed(1):null; const deltaG=first!==last&&first.bio?.gord&&last.bio?.gord?(last.bio.gord-first.bio.gord).toFixed(1):null; document.getElementById('histContainer').innerHTML=`
Avaliações
${avs.length}
Peso Inicial → Atual
${first.peso||'—'} → ${last.peso||'—'} kg
${deltaP?`${deltaP>0?'+':''}${deltaP} kg`:''}
Gordura Inicial → Atual
${first.bio?.gord||'—'} → ${last.bio?.gord||'—'}%
${deltaG?`${deltaG>0?'+':''}${deltaG}%`:''}
Período
${Math.round((new Date(last.data)-new Date(first.data))/86400000)} dias
Evolução — Peso & Gordura
Bioimpedância
Circunferências (cm)
Timeline de Avaliações
Tabela Comparativa Completa
`; // Charts after(50,()=>{ buildHistChart1(avs); buildHistChart2(avs); buildHistChart3(avs); buildHistTimeline(avs); buildHistTabela(avs); }); } function buildHistChart1(avs){ const ctx=document.getElementById('chartHist1'); if(!ctx) return; new Chart(ctx,{type:'line', data:{labels:avs.map(a=>fmt(a.data)), datasets:[ {label:'Peso (kg)',data:avs.map(a=>a.peso||null),borderColor:'#00D4AA',tension:0.4,fill:false,yAxisID:'y'}, {label:'% Gordura',data:avs.map(a=>a.bio?.gord||null),borderColor:'#F59E0B',tension:0.4,fill:false,yAxisID:'y2'}, ]}, options:{responsive:true,maintainAspectRatio:false, plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}, scales:{ x:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:9}}}, y:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}}, y2:{position:'right',ticks:{color:'#F59E0B',font:{size:10}},grid:{display:false}} }}}); } function buildHistChart2(avs){ const ctx=document.getElementById('chartHist2'); if(!ctx) return; new Chart(ctx,{type:'line', data:{labels:avs.map(a=>fmt(a.data)), datasets:[ {label:'Massa Magra (kg)',data:avs.map(a=>a.bio?.magra||null),borderColor:'#10B981',tension:0.4}, {label:'Água (%)',data:avs.map(a=>a.bio?.agua||null),borderColor:'#3B82F6',tension:0.4,yAxisID:'y2'}, ]}, options:{responsive:true,maintainAspectRatio:false, plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}, scales:{ x:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:9}}}, y:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}}, y2:{position:'right',ticks:{color:'#3B82F6',font:{size:10}},grid:{display:false}} }}}); } function buildHistChart3(avs){ const ctx=document.getElementById('chartHist3'); if(!ctx) return; new Chart(ctx,{type:'bar', data:{labels:avs.map(a=>fmt(a.data)), datasets:[ {label:'Cintura',data:avs.map(a=>a.medidas?.cintura||null),backgroundColor:'rgba(0,212,170,0.7)'}, {label:'Quadril',data:avs.map(a=>a.medidas?.quadril||null),backgroundColor:'rgba(124,58,237,0.7)'}, {label:'Coxa D',data:avs.map(a=>a.medidas?.coxaD||null),backgroundColor:'rgba(245,158,11,0.7)'}, ]}, options:{responsive:true,maintainAspectRatio:false, plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}, scales:{ x:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:9}}}, y:{grid:{color:'#ffffff08'},ticks:{color:'#64748B',font:{size:10}}} }}}); } function buildHistTimeline(avs){ const sorted=[...avs].reverse(); document.getElementById('histTimeline').innerHTML=sorted.map((av,i)=>`
${fmt(av.data)}
Avaliação ${i===0?'(mais recente)':''}
Peso: ${av.peso||'—'}kg • Gordura: ${av.bio?.gord||'—'}% • Dor: ${av.dor}/10
${av.posturaDesvios?.length?`
Desvios: ${av.posturaDesvios.join(', ')}
`:''}
`).join(''); } function buildHistTabela(avs){ document.getElementById('histTabela').innerHTML=` DataPesoIMCGorduraM.MagraÁguaTMBCinturaDorScore ${avs.map(av=>{ const imc=av.peso&&av.altura?(av.peso/(av.altura/100)**2).toFixed(1):'—'; return ` ${fmt(av.data)} ${av.peso||'—'} kg ${imc} ${av.bio?.gord||'—'}% ${av.bio?.magra||'—'} kg ${av.bio?.agua||'—'}% ${av.bio?.tmb||'—'} kcal ${av.medidas?.cintura||'—'} cm ${av.dor}/10 ${calcScore(av)} `; }).join('')} `; } function exportarHistorico(){ showToast('Relatório exportado! (simulado)','info'); } /* ══════════════════════════════════════ TREINOS ══════════════════════════════════════ */ function carregarTreinosAluno(){ const id=document.getElementById('treinoAlunoSelect').value; const a=STATE.alunos.find(x=>x.id===id); if(!a){ document.getElementById('treinosContainer').innerHTML='
Selecione um aluno.
'; return; } const ts=STATE.treinos.filter(t=>t.alunoId===id); document.getElementById('treinosContainer').innerHTML=`
${ts.map(t=>`
${t.nome}
${t.grupo||'—'} ${t.geradoPorIA?'IA':''}
✏️ Editar ✕
${t.exercicios.map(e=>``).join('')}
ExercícioSériesRepsCargaIntervalo
${e.nome}${e.series}${e.reps}${e.carga||'—'}${e.intervalo||'—'}
${t.obs?`
${t.obs}
`:''}
`).join('')} ${ts.length===0?'
Nenhum treino criado para este aluno.
Use os botões acima para criar.
':''}
`; } function abrirEditorTreino(treinoId){ const t=STATE.treinos.find(x=>x.id===treinoId); STATE.editingTreinoId=treinoId; document.getElementById('modalTreinoTitle').textContent='Editar Treino'; document.getElementById('trNome').value=t.nome||''; document.getElementById('trGrupo').value=t.grupo||''; document.getElementById('trObs').value=t.obs||''; document.getElementById('exerciciosList').innerHTML=''; t.exercicios.forEach(e=>addExercicio(e)); openModal('modalTreino'); } function novoTreinoManual(){ const id=document.getElementById('treinoAlunoSelect').value; if(!id){ showToast('Selecione um aluno primeiro','warn'); return; } STATE.editingTreinoId=null; document.getElementById('modalTreinoTitle').textContent='Novo Treino Manual'; document.getElementById('trNome').value=''; document.getElementById('trGrupo').value=''; document.getElementById('trObs').value=''; document.getElementById('exerciciosList').innerHTML=''; addExercicio();addExercicio();addExercicio(); openModal('modalTreino'); } function addExercicio(ex={}){ const row=document.createElement('div'); row.className='ex-row'; row.innerHTML=` ✕ `; document.getElementById('exerciciosList').appendChild(row); } function salvarTreino(){ const alunoId=document.getElementById('treinoAlunoSelect').value; if(!alunoId){ showToast('Selecione um aluno','error'); return; } const nome=document.getElementById('trNome').value.trim()||'Treino sem nome'; const rows=document.querySelectorAll('#exerciciosList .ex-row'); const exercicios=[...rows].map(r=>{ const inputs=r.querySelectorAll('input'); return {nome:inputs[0].value,series:inputs[1].value,reps:inputs[2].value,carga:inputs[3].value,intervalo:inputs[4].value}; }).filter(e=>e.nome.trim()); if(STATE.editingTreinoId){ const idx=STATE.treinos.findIndex(t=>t.id===STATE.editingTreinoId); if(idx>=0){ STATE.treinos[idx]={...STATE.treinos[idx],nome,grupo:document.getElementById('trGrupo').value,exercicios,obs:document.getElementById('trObs').value}; showToast('Treino atualizado!'); } } else { STATE.treinos.push({id:uid(),alunoId,nome,grupo:document.getElementById('trGrupo').value,exercicios,obs:document.getElementById('trObs').value,geradoPorIA:false,createdAt:today()}); showToast('Treino criado!'); } closeModal('modalTreino'); STATE.editingTreinoId=null; carregarTreinosAluno(); renderDashboard(); } function excluirTreino(id){ if(!confirm('Excluir este treino?')) return; STATE.treinos=STATE.treinos.filter(t=>t.id!==id); showToast('Treino excluído.'); carregarTreinosAluno(); renderDashboard(); } function gerarTreinoIA(){ const id=document.getElementById('treinoAlunoSelect').value; if(!id){ showToast('Selecione um aluno primeiro','warn'); return; } const a=STATE.alunos.find(x=>x.id===id); const avs=STATE.avaliacoes.filter(x=>x.alunoId===id).sort((a,b)=>b.data.localeCompare(a.data)); const ul=avs[0]; showToast('IA gerando treino personalizado...','info'); after(1800,()=>{ const temJoelho=a.condicoes?.includes('Problema de Joelho'); const temHiper=ul?.posturaDesvios?.includes('Hiperlordose Lombar'); const objetivo=a.objetivo||''; let exs=[]; if(objetivo.includes('Emag')||objetivo.includes('Cond')){ exs=[ {nome:'Agachamento Goblet',series:'4',reps:'15',carga:'20kg',intervalo:'60s'}, {nome:temJoelho?'Glúteo na máquina':'Leg Press 45°',series:'3',reps:'15',carga:temJoelho?'30kg':'100kg',intervalo:'75s'}, {nome:'Hip Thrust',series:'4',reps:'20',carga:'40kg',intervalo:'60s'}, {nome:'Remada Curvada',series:'3',reps:'12',carga:'30kg',intervalo:'75s'}, {nome:temHiper?'Prancha (core anti-lordose)':'Prancha Lateral',series:'3',reps:'30s',carga:'—',intervalo:'30s'}, {nome:'HIIT Bicicleta',series:'1',reps:'20min',carga:'—',intervalo:'—'}, ]; } else { exs=[ {nome:'Agachamento Livre',series:'5',reps:'5',carga:'70%1RM',intervalo:'180s'}, {nome:temJoelho?'Extensora de Joelho (arco seguro)':'Leg Press 45°',series:'4',reps:'10',carga:temJoelho?'25kg':'140kg',intervalo:'90s'}, {nome:'Supino Reto',series:'4',reps:'8',carga:'70%1RM',intervalo:'120s'}, {nome:'Remada Serrote',series:'4',reps:'10',carga:'25kg',intervalo:'90s'}, {nome:'Desenvolvimento Militar',series:'3',reps:'10',carga:'60%1RM',intervalo:'90s'}, ]; } const obs=`Treino gerado pela IA. Aluno: ${a.nome}. Objetivo: ${objetivo}. ${temJoelho?'⚠ Adaptado para joelho.':''} ${temHiper?'⚠ Incluiu exercícios posturais.':''}`; STATE.treinos.push({id:uid(),alunoId:id,nome:`Treino IA — ${objetivo}`,grupo:'Gerado automaticamente',exercicios:exs,obs,geradoPorIA:true,createdAt:today()}); showToast('Treino gerado pela IA com sucesso!'); carregarTreinosAluno(); renderDashboard(); }); } /* ══════════════════════════════════════ IA CHAT ══════════════════════════════════════ */ const iaResp=[ 'Com base nos dados registrados, identifico padrões de risco que requerem atenção. Posso analisar um aluno específico se você me informar o nome.', 'A progressão de carga deve ser gradual — aumento de 5–10% por semana é o ideal para evitar lesões. Monitorar a recuperação entre sessões é essencial.', 'Para redução de gordura corporal eficiente, o déficit calórico de 300–500kcal combinado com treino de força preserva massa muscular melhor que cardio isolado.', 'Biomarcadores como gordura visceral acima de 10 indicam risco metabólico aumentado. Recomendo monitorar junto com pressão arterial e glicemia.', 'O padrão de hiperlordose + anteroversão de pelve está frequentemente associado a encurtamento de iliopsoas e fraqueza de glúteo médio. Protocolo de correção deve incluir ativação glútea pré-treino.', 'Estagnação de peso por mais de 4 semanas com o mesmo treino indica necessidade de variação de estímulo (carga, volume ou exercícios).', ]; let iaRespIdx=0; function enviarIA(){ const input=document.getElementById('iaInput'); const chat=document.getElementById('iaChat'); const txt=input.value.trim(); if(!txt) return; chat.innerHTML+=`
${txt}
`; input.value=''; const typing=document.createElement('div'); typing.className='msg ia typing'; typing.innerHTML='
⚡ APEX IA
'; chat.appendChild(typing); chat.scrollTop=chat.scrollHeight; after(1500,()=>{ typing.remove(); let resp=iaResp[iaRespIdx%iaResp.length]; iaRespIdx++; // Contextual responses const tl=txt.toLowerCase(); if(tl.includes('joelho')) resp='Com base nos dados, dor no joelho pode estar relacionada a: (1) fraqueza de VMO, (2) encurtamento de quadríceps, (3) valgo dinâmico por glúteos fracos. Recomendo FMS screen e avaliação de pisada.'; else if(tl.includes('gordura')||tl.includes('composição')) resp='Para redução de gordura com preservação de massa magra: déficit calórico moderado (300–500kcal/dia), treino de força 3–4x/semana, consumo proteico de 1.8–2.2g/kg/dia. Monitorar bioimpedância a cada 30 dias.'; else if(tl.includes('treino')) resp='Posso gerar treinos personalizados baseados na avaliação de cada aluno. Acesse a aba Treinos, selecione o aluno e clique em "Gerar com IA".'; else if(tl.includes('risco')||tl.includes('lesão')) resp='Fatores de risco identificáveis: (1) progressão de carga excessiva, (2) desvios posturais não corrigidos, (3) mobilidade reduzida, (4) fadiga acumulada. Posso analisar qualquer aluno específico.'; chat.innerHTML+=`
⚡ APEX IA
${resp}
`; chat.scrollTop=chat.scrollHeight; }); } function analisarAluno(){ const id=document.getElementById('iaAlunoSelect').value; const a=STATE.alunos.find(x=>x.id===id); if(!a){ document.getElementById('iaAnalise').innerHTML='
Selecione um aluno.
'; return; } const avs=STATE.avaliacoes.filter(x=>x.alunoId===id).sort((a,b)=>b.data.localeCompare(a.data)); const ul=avs[0]; const prev=avs[1]; let insights=[]; let riscos=[]; if(!ul){ insights.push({type:'warn',msg:`${a.nome} não possui avaliações. Agende uma avaliação inicial.`}); } else { const dias=Math.floor((new Date()-new Date(ul.data+' 00:00:00'))/86400000); if(dias>30) insights.push({type:'warn',msg:`Última avaliação há ${dias} dias. Reavaliar em breve.`}); if(ul.bio?.gord&&ul.bio.gord>25) riscos.push({nivel:'alto',msg:`% Gordura elevada (${ul.bio.gord}%) — Risco metabólico.`}); if(ul.bio?.visceral&&ul.bio.visceral>=10) riscos.push({nivel:'alto',msg:`Gordura visceral ${ul.bio.visceral} — Acima do limite saudável.`}); if(ul.dor&&ul.dor>5) riscos.push({nivel:'alto',msg:`Dor intensa (${ul.dor}/10) — Investigar causa antes de progredir.`}); if(ul.posturaDesvios?.includes('Hiperlordose Lombar')) riscos.push({nivel:'medio',msg:'Hiperlordose — Priorizar core e mobilidade de quadril.'}); if(a.condicoes?.includes('Hipertensão Arterial')) riscos.push({nivel:'medio',msg:'Hipertensão — Evitar Valsalva e cargas máximas.'}); if(prev&&ul.peso&&prev.peso){ const dP=(ul.peso-prev.peso).toFixed(1); if(Math.abs(dP)>1) insights.push({type:dP<0?'success':'warn',msg:`Variação de peso: ${dP>0?'+':''}${dP}kg entre avaliações.`}); } if(ul.funcional?.prancha&&ul.funcional.prancha<30) insights.push({type:'warn',msg:`Core fraco (prancha ${ul.funcional.prancha}s). Priorizar estabilização.`}); if(!riscos.length) insights.push({type:'success',msg:'Nenhum risco crítico identificado. Manter progressão.'}); } document.getElementById('iaAnalise').innerHTML=insights.map(i=>`
${i.type==='success'?'✓':'⚠'}
${i.msg}
`).join(''); document.getElementById('iaRiscos').innerHTML=riscos.length?riscos.map(r=>`
${r.nivel==='alto'?'🔴':'🟡'}
${r.msg}
${r.nivel==='alto'?'Alto':'Médio'}
`).join(''):'
Nenhum risco detectado.
'; } /* ══════════════════════════════════════ CÁLCULO IMC (TEMPO REAL) ══════════════════════════════════════ */ ['avalPeso','avalAltura'].forEach(id=>{ const el=document.getElementById(id); if(el) el.addEventListener('input',calcAvalIMC); }); function calcAvalIMC(){ const p=parseFloat(document.getElementById('avalPeso').value); const h=parseFloat(document.getElementById('avalAltura').value)/100; if(!p||!h||h<=0){ document.getElementById('avalCalcs').innerHTML='
Preencha peso e altura.
'; return; } const imc=(p/h**2).toFixed(1); const cls=imc<18.5?{t:'Abaixo do Peso',c:'var(--info)'}:imc<25?{t:'Peso Normal',c:'var(--success)'}:imc<30?{t:'Sobrepeso',c:'var(--accent)'}:imc<35?{t:'Obesidade Grau I',c:'var(--danger)'}:{t:'Obesidade Grau II+',c:'var(--danger)'}; const rpc=h*100>=60?((p/h**2)*h-10*h).toFixed(1):null; document.getElementById('avalCalcs').innerHTML=`
IMC Calculado
${imc}
${cls.t}
Peso
${p} kg
Altura
${h*100} cm
`; } /* ══ INIT ══ */ document.getElementById('loginPass').addEventListener('keydown',e=>{ if(e.key==='Enter') doLogin(); }); </script>

Releases

No releases published

Packages

 
 
 

Contributors

Languages