<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Insumos — ARKHON</title>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
<style>
:root{
  --bg:#f7f8fc;--surface:#fff;--border:#eaecf4;
  --text:#111827;--text-2:#4b5563;--text-3:#9ca3af;
  --orange:#f97316;--orange-lt:rgba(249,115,22,.10);
  --red:#ef4444;--red-lt:rgba(239,68,68,.10);
  --green:#10b981;--green-lt:rgba(16,185,129,.10);
  --blue:#2563eb;--blue-lt:rgba(37,99,235,.10);
  --yellow:#f59e0b;--yellow-lt:rgba(245,158,11,.10);
  --shadow-sm:0 1px 3px rgba(17,24,39,.06);--r:10px;
}
*{margin:0;padding:0;box-sizing:border-box;}
html,body{font-family:'Plus Jakarta Sans',sans-serif;background:var(--bg);color:var(--text);min-height:100vh;font-size:13px;-webkit-font-smoothing:antialiased;}
button,input,select,textarea{font-family:'Plus Jakarta Sans',sans-serif;}
::-webkit-scrollbar{width:4px;}::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:8px;}
@keyframes spin{to{transform:rotate(360deg);}}
@keyframes fadeUp{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:translateY(0);}}
@keyframes fadeIn{from{opacity:0;}to{opacity:1;}}

/* TOPBAR */
.topbar{background:var(--surface);border-bottom:1px solid var(--border);height:52px;padding:0 18px;display:flex;align-items:center;gap:10px;position:sticky;top:0;z-index:20;box-shadow:var(--shadow-sm);}
.topbar-icon{width:32px;height:32px;border-radius:9px;background:var(--orange);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.topbar-icon svg{width:15px;height:15px;stroke:#fff;stroke-width:2.2;fill:none;}
.topbar h1{font-size:14px;font-weight:800;letter-spacing:-.3px;flex:1;}
/* Alias para el topbar existente */
.topbar-logo{width:32px;height:32px;border-radius:9px;background:var(--orange);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.topbar-logo svg{width:15px;height:15px;stroke:#fff;stroke-width:2.2;fill:none;}
.topbar-title{font-size:14px;font-weight:800;letter-spacing:-.3px;}
.topbar-sub{font-size:11px;color:var(--text-3);font-weight:600;}

/* TABS */
.tabs-bar,.tabs{background:var(--surface);border-bottom:1px solid var(--border);padding:0 18px;display:flex;gap:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;}
.tabs::-webkit-scrollbar,.tabs-bar::-webkit-scrollbar{display:none;}
.tab-btn,.tab{padding:10px 16px;border:none;border-bottom:2px solid transparent;background:transparent;font-size:12px;font-weight:700;color:var(--text-3);cursor:pointer;transition:.15s;display:flex;align-items:center;gap:6px;white-space:nowrap;}
.tab-btn svg,.tab svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none;}
.tab-btn.active,.tab.active{color:var(--orange);border-bottom-color:var(--orange);}
.tab-btn:hover:not(.active),.tab:hover:not(.active){color:var(--text);}

/* LAYOUT */
.content,.container{padding:16px 18px;max-width:1200px;}
.section{display:none;animation:fadeUp .2s ease;}
.section.active{display:block;}

/* CARDS */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow-sm);overflow:hidden;margin-bottom:14px;}
.card-head{padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;}
.card-title{font-size:13px;font-weight:800;flex:1;}
.card-body{padding:16px;}

/* TOOLBAR */
.toolbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:14px;}
.toolbar-right{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap;}

/* BOTONES */
.btn{display:inline-flex;align-items:center;gap:5px;padding:7px 14px;border-radius:8px;font-size:11px;font-weight:700;cursor:pointer;transition:.15s;border:none;white-space:nowrap;}
.btn svg{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none;flex-shrink:0;}
.btn-orange,.btn-primary{background:var(--orange);color:#fff;box-shadow:0 2px 8px rgba(249,115,22,.25);}
.btn-orange:hover,.btn-primary:hover{opacity:.9;transform:translateY(-1px);}
.btn-ghost,.btn-outline{background:transparent;border:1px solid var(--border);color:var(--text-2);}
.btn-ghost:hover,.btn-outline:hover{background:var(--bg);}
.btn-red{background:var(--red-lt);color:var(--red);border:1px solid rgba(239,68,68,.2);}
.btn-red:hover{background:var(--red);color:#fff;}
.btn-green{background:var(--green-lt);color:var(--green);border:1px solid rgba(16,185,129,.2);}
.btn-green:hover{background:var(--green);color:#fff;}
.btn-sm{padding:4px 10px;font-size:10px;}
.btn:disabled{opacity:.5;cursor:not-allowed;transform:none!important;}

/* SEARCH */
.search-wrap{position:relative;flex:1;max-width:280px;}
.search-wrap svg{position:absolute;left:9px;top:50%;transform:translateY(-50%);width:13px;height:13px;stroke:var(--text-3);stroke-width:2;fill:none;pointer-events:none;}
.search-input{width:100%;padding:7px 10px 7px 30px;border:1px solid var(--border);border-radius:8px;font-size:12px;color:var(--text);background:var(--surface);outline:none;transition:.15s;}
.search-input:focus{border-color:var(--orange);}

/* FORMULARIO */
.form-grid,.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
.form-grid-3,.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;}
.form-group,.fg{display:flex;flex-direction:column;gap:4px;margin-bottom:14px;}
.form-group label,.fg label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);}
input,select,textarea{width:100%;padding:8px 10px;border:1px solid var(--border);border-radius:8px;font-size:12px;color:var(--text);background:var(--surface);transition:.15s;outline:none;}
input:focus,select:focus,textarea:focus{border-color:var(--orange);box-shadow:0 0 0 3px var(--orange-lt);}
input[readonly]{background:var(--bg);color:var(--text-3);}
input:disabled{background:var(--bg);color:var(--text-3);}
.hint{font-size:10px;color:var(--text-3);}

/* TABLA */
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
table{width:100%;border-collapse:collapse;}
th{padding:9px 12px;text-align:left;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);background:var(--bg);border-bottom:1px solid var(--border);white-space:nowrap;}
td{padding:9px 12px;border-bottom:1px solid var(--border);font-size:12px;color:var(--text-2);vertical-align:middle;}
tr:last-child td{border-bottom:none;}
tr:hover td{background:var(--bg);}
td.r{text-align:right;font-weight:700;color:var(--text);}
td.bold{font-weight:700;color:var(--text);}

/* BADGES */
.badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:20px;font-size:10px;font-weight:700;}
.badge-green{background:var(--green-lt);color:var(--green);}
.badge-red{background:var(--red-lt);color:var(--red);}
.badge-gray{background:var(--bg);color:var(--text-3);border:1px solid var(--border);}
.badge-orange{background:var(--orange-lt);color:var(--orange);}

/* TOGGLES */
.toggle-row{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--border);}
.toggle-row:last-child{border:none;}
.toggle-label{font-size:12px;color:var(--text-2);}
.toggle{position:relative;width:36px;height:20px;flex-shrink:0;}
.toggle input{opacity:0;width:0;height:0;position:absolute;}
.toggle-slider{position:absolute;inset:0;background:var(--bg);border-radius:20px;cursor:pointer;transition:.2s;border:1px solid var(--border);}
.toggle-slider:before{content:'';position:absolute;width:14px;height:14px;left:2px;top:2px;background:var(--text-3);border-radius:50%;transition:.2s;}
.toggle input:checked+.toggle-slider{background:var(--orange);border-color:var(--orange);}
.toggle input:checked+.toggle-slider:before{transform:translateX(16px);background:#fff;}

/* MODAL */
.modal-overlay,.modal-bg{display:none;position:fixed;inset:0;background:rgba(17,24,39,.5);z-index:100;align-items:center;justify-content:center;padding:16px;animation:fadeIn .15s;}
.modal-overlay.open,.modal-bg.open{display:flex;}
.modal{background:var(--surface);border-radius:14px;width:100%;max-width:520px;max-height:90vh;overflow-y:auto;box-shadow:0 20px 60px rgba(17,24,39,.18);animation:fadeUp .2s ease;}
.modal h3,.modal-title{font-size:14px;font-weight:800;padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;margin:0;}
.modal-title svg{width:15px;height:15px;stroke:var(--orange);stroke-width:2.2;fill:none;}
.modal-body{padding:20px;}
.modal-footer,.modal h3+div>div:last-child{display:flex;gap:8px;justify-content:flex-end;padding:14px 20px;border-top:1px solid var(--border);}

/* RECETAS */
.fc-bar{height:6px;border-radius:3px;background:var(--bg);overflow:hidden;margin-top:4px;border:1px solid var(--border);}
.fc-fill{height:100%;border-radius:3px;transition:.3s;}
.cost-badge{font-size:11px;font-weight:700;}
.linea-row{display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--border);}
.linea-row:last-child{border:none;}
.linea-insumo{flex:1;min-width:0;}
.linea-cant{width:80px;}
.linea-cant input{padding:5px 8px;font-size:11px;text-align:right;}
.linea-costo{width:90px;text-align:right;font-size:11px;color:var(--text-3);font-weight:600;}

/* SELECT de filtro */
#ins-filter-grp{
  background:var(--surface);border:1px solid var(--border);border-radius:8px;
  padding:7px 10px;color:var(--text);font-size:12px;outline:none;
  min-width:160px;max-width:220px;
}
#ins-filter-grp:focus{border-color:var(--orange);}

/* IMPORT DROP */
.import-drop{border:2px dashed var(--border);border-radius:var(--r);padding:32px;text-align:center;cursor:pointer;transition:.2s;background:var(--bg);}
.import-drop:hover,.import-drop.over{border-color:var(--orange);background:var(--orange-lt);}
.import-drop svg{width:32px;height:32px;stroke:var(--text-3);stroke-width:1.5;fill:none;margin-bottom:8px;}

/* EMPTY / SPINNER */
.empty{text-align:center;padding:40px;color:var(--text-3);font-size:12px;font-weight:600;}
.spinner{width:22px;height:22px;border:2.5px solid var(--border);border-top-color:var(--orange);border-radius:50%;animation:spin .7s linear infinite;margin:28px auto;display:block;}

/* ═══════════════════════════════════════════════════════
   RESPONSIVE — móvil primero
═══════════════════════════════════════════════════════ */
@media(max-width:600px){
  .container,.content{padding:10px 10px 60px;}
  .topbar{padding:0 10px;gap:6px;}

  .tabs,.tabs-bar{padding:0 10px;}
  .tab,.tab-btn{padding:8px 11px;font-size:11px;flex-shrink:0;}

  .toolbar{flex-direction:column;align-items:stretch;gap:6px;}
  .toolbar-right{margin-left:0;width:100%;}
  .search-wrap{max-width:100%;}
  #ins-filter-grp{width:100%;max-width:100%;}

  .form-grid,.grid2,.grid3,.form-grid-3{grid-template-columns:1fr!important;}
  .card-head{flex-wrap:wrap;gap:6px;}
  .card-body{padding:12px;}

  .tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
  table{min-width:560px;}
  th,td{padding:7px 8px;font-size:11px;}

  .modal{max-width:100%;border-radius:10px;}
  .modal-body{padding:14px;}

  .btn{padding:6px 10px;font-size:11px;}
  .btn-sm{padding:4px 8px;font-size:10px;}

  .linea-row{flex-wrap:wrap;gap:4px;}
  .linea-cant{width:70px;}
}
@media(max-width:400px){
  .topbar-title{font-size:13px;}
}
</style>
<link rel="stylesheet" href="/css/responsive.css?v=406r"/>
</head>
<body>

<!-- Topbar -->
<div class="topbar">
  <div class="topbar-logo">
    <svg viewBox="0 0 24 24"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg>
  </div>
  <span class="topbar-title">Insumos</span>
  <span class="topbar-sub">· ARKHON</span>
</div>

<!-- Tabs -->
<div class="tabs">
  <button class="tab active" id="t-grupos"  onclick="showTab('grupos',this)">
    <svg viewBox="0 0 24 24"><rect x="2" y="3" width="6" height="18" rx="1"/><rect x="9" y="3" width="6" height="10" rx="1"/><rect x="16" y="3" width="6" height="14" rx="1"/></svg>Grupos
  </button>
  <button class="tab" id="t-insumos" onclick="showTab('insumos',this)">
    <svg viewBox="0 0 24 24"><path d="M20 7H4a2 2 0 00-2 2v6a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2z"/><path d="M16 21V5a2 2 0 00-2-2h-4a2 2 0 00-2 2v16"/></svg>Insumos
  </button>
  <button class="tab" id="t-presentaciones" onclick="showTab('presentaciones',this)">
    <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/></svg>Presentaciones
  </button>
  <button class="tab" id="t-recetas" onclick="showTab('recetas',this)">
    <svg viewBox="0 0 24 24"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/><path d="M9 12h6M9 16h4"/></svg>Recetas
  </button>
  <button class="tab" id="t-elaborados" onclick="showTab('elaborados',this)">
    <svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>Elaborados
  </button>
  <button class="tab" id="t-productos" onclick="showTab('productos',this)">
    <svg viewBox="0 0 24 24"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>Productos
  </button>
</div>

<div class="container">

<!-- ═══ GRUPOS ═══ -->
<div class="section active" id="sec-grupos">
  <div class="toolbar">
    <div class="search-wrap">
      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      <input type="text" class="search-input" id="grp-search" placeholder="Buscar grupo..." oninput="filtrarTabla('grp-tbody','grp-search')"/>
    </div>
    <div class="toolbar-right">
      <button class="btn btn-orange" onclick="abrirModalGrupo()">
        <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Nuevo grupo
      </button>
    </div>
  </div>
  <div class="card">
    <div class="card-head">
      <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><rect x="2" y="3" width="6" height="18" rx="1"/><rect x="9" y="3" width="6" height="10" rx="1"/></svg>
      <span class="card-title">Grupos de insumos</span>
      <span id="grp-count" style="margin-left:auto;font-size:10px;color:var(--text-3);font-weight:700;"></span>
    </div>
    <div class="tbl-wrap">
      <div id="grp-spinner" class="spinner" style="display:none"></div>
      <div id="grp-empty" class="empty" style="display:none">Sin grupos registrados</div>
      <table id="grp-table" style="display:none">
        <thead><tr><th>Clave</th><th>Descripción</th><th>Prioridad</th><th></th></tr></thead>
        <tbody id="grp-tbody"></tbody>
      </table>
    </div>
  </div>
</div>

<!-- ═══ INSUMOS ═══ -->
<div class="section" id="sec-insumos">
  <div class="toolbar">
    <div class="search-wrap">
      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      <input type="text" class="search-input" id="ins-search" placeholder="Buscar insumo..." oninput="filtrarInsumos()"/>
    </div>
    <select id="ins-filter-grp" onchange="filtrarInsumos()">
      <option value="">Todos los grupos</option>
    </select>
    <div class="toolbar-right">
      <button class="btn btn-ghost" onclick="abrirImport('insumos')">
        <svg viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>Importar Excel
      </button>
      <button class="btn btn-orange" onclick="abrirModalInsumo()">
        <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Nuevo insumo
      </button>
    </div>
  </div>
  <div class="card">
    <div class="card-head">
      <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><path d="M20 7H4a2 2 0 00-2 2v6a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2z"/></svg>
      <span class="card-title">Catálogo de insumos</span>
      <span id="ins-count" style="margin-left:auto;font-size:10px;color:var(--text-3);font-weight:700;"></span>
    </div>
    <div class="tbl-wrap">
      <div id="ins-spinner" class="spinner" style="display:none"></div>
      <div id="ins-empty" class="empty" style="display:none">Sin insumos registrados</div>
      <table id="ins-table" style="display:none">
        <thead><tr><th>Clave</th><th>Descripción</th><th>Grupo</th><th>Unidad</th><th>Costo</th><th>IVA%</th><th>Merma%</th><th>Inv.</th><th>Estado</th><th></th></tr></thead>
        <tbody id="ins-tbody"></tbody>
      </table>
    </div>
  </div>
</div>

<!-- ═══ PRESENTACIONES ═══ -->
<div class="section" id="sec-presentaciones">
  <div class="toolbar">
    <div class="search-wrap">
      <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      <input type="text" class="search-input" id="pres-search" placeholder="Buscar presentación..." oninput="filtrarTabla('pres-tbody','pres-search')"/>
    </div>
    <div class="toolbar-right">
      <button class="btn btn-orange" onclick="abrirModalPres()">
        <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Nueva presentación
      </button>
    </div>
  </div>
  <div class="card">
    <div class="card-head">
      <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/></svg>
      <span class="card-title">Presentaciones de insumos</span>
      <span id="pres-count" style="margin-left:auto;font-size:10px;color:var(--text-3);font-weight:700;"></span>
    </div>
    <div class="tbl-wrap">
      <div id="pres-spinner" class="spinner" style="display:none"></div>
      <div id="pres-empty" class="empty" style="display:none">Sin presentaciones registradas</div>
      <table id="pres-table" style="display:none">
        <thead><tr><th>Clave</th><th>Descripción</th><th>Insumo</th><th>Unidad</th><th>Rendimiento</th><th>Costo</th><th>IVA%</th><th></th></tr></thead>
        <tbody id="pres-tbody"></tbody>
      </table>
    </div>
  </div>
</div>

<!-- ═══ RECETAS ═══ -->
<div class="section" id="sec-recetas">
  <div id="rec-lista">
    <div id="rec-productos-warn" style="display:none;padding:10px 14px;background:rgba(245,158,11,.12);border:1px solid rgba(245,158,11,.3);border-radius:8px;color:#b45309;font-size:12px;font-weight:600;margin-bottom:10px;"></div>
    <div class="toolbar">
      <div class="search-wrap">
        <svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
        <input type="text" class="search-input" id="rec-search" placeholder="Buscar producto..." oninput="filtrarTabla('rec-tbody','rec-search')"/>
      </div>
      <div class="toolbar-right">
        <button class="btn btn-ghost btn-sm" onclick="refrescarCatalogo()" title="Recargar catálogo de productos">
          <svg viewBox="0 0 24 24"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>Actualizar catálogo
        </button>
        <button class="btn btn-orange" onclick="abrirNuevaReceta()">
          <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Nueva receta
        </button>
      </div>
    </div>
    <div class="card">
      <div class="card-head">
        <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/></svg>
        <span class="card-title">Recetas por producto</span>
      </div>
      <div class="tbl-wrap">
        <div id="rec-spinner" class="spinner" style="display:none"></div>
        <div id="rec-empty" class="empty" style="display:none">Sin recetas configuradas</div>
        <table id="rec-table" style="display:none">
          <thead><tr><th>Producto</th><th>Ingredientes</th><th>Costo receta</th><th>Precio venta</th><th>Food Cost %</th><th></th></tr></thead>
          <tbody id="rec-tbody"></tbody>
        </table>
      </div>
    </div>
  </div>
  <!-- Editor de receta -->
  <div id="rec-editor" style="display:none">
    <div class="toolbar">
      <button class="btn btn-ghost" onclick="cerrarEditor()">
        <svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>Volver
      </button>
      <span style="font-weight:700;font-size:14px;" id="rec-editor-title">Receta</span>
      <div class="toolbar-right">
        <button class="btn btn-orange" onclick="guardarReceta()">
          <svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>Guardar receta
        </button>
      </div>
    </div>
    <div style="display:grid;grid-template-columns:1fr 300px;gap:16px;">
      <div class="card">
        <div class="card-head">
          <span class="card-title">Ingredientes</span>
          <button class="btn btn-ghost btn-sm" style="margin-left:auto" onclick="agregarLinea()">
            <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Agregar
          </button>
        </div>
        <div class="card-body">
          <div style="display:grid;grid-template-columns:1fr 80px 90px 30px;gap:8px;margin-bottom:8px;">
            <span style="font-size:10px;font-weight:700;text-transform:uppercase;color:var(--text-3);">Insumo</span>
            <span style="font-size:10px;font-weight:700;text-transform:uppercase;color:var(--text-3);text-align:right;">Cantidad</span>
            <span style="font-size:10px;font-weight:700;text-transform:uppercase;color:var(--text-3);text-align:right;">Costo</span>
            <span></span>
          </div>
          <div id="rec-lineas"></div>
          <div style="margin-top:12px;display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:8px;align-items:center;">
            <select id="rec-grupo" onchange="recetaGrupoSel=this.value;renderSelectoresReceta()"></select>
            <select id="rec-insumo"></select>
            <button class="btn btn-ghost btn-sm" onclick="agregarLinea()" style="justify-content:center;">
              <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Agregar ingrediente
            </button>
          </div>
        </div>
      </div>
      <div>
        <div class="card">
          <div class="card-head"><span class="card-title">Resumen de costos</span></div>
          <div class="card-body">
            <div style="margin-bottom:12px;">
              <div style="font-size:10px;color:var(--text-3);font-weight:700;text-transform:uppercase;margin-bottom:4px;">Costo total de receta</div>
              <div style="font-size:28px;font-weight:900;color:var(--orange);" id="rec-costo-total">$0.00</div>
            </div>
            <div style="margin-bottom:12px;">
              <div style="font-size:10px;color:var(--text-3);font-weight:700;text-transform:uppercase;margin-bottom:4px;">Precio de venta</div>
              <div style="font-size:18px;font-weight:700;" id="rec-precio-venta">$0.00</div>
            </div>
            <div>
              <div style="display:flex;justify-content:space-between;margin-bottom:4px;">
                <span style="font-size:10px;color:var(--text-3);font-weight:700;text-transform:uppercase;">Food cost %</span>
                <span style="font-size:13px;font-weight:800;" id="rec-fc-pct">0%</span>
              </div>
              <div class="fc-bar"><div class="fc-fill" id="rec-fc-bar"></div></div>
              <div style="font-size:10px;color:var(--text-3);margin-top:4px;" id="rec-fc-label">Óptimo: 25-35%</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- ═══ ELABORADOS ═══ -->
<div class="section" id="sec-elaborados">
  <div class="card">
    <div class="card-head">
      <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
      <span class="card-title">Insumos elaborados</span>
    </div>
    <div class="card-body">
      <div class="empty" style="display:block;padding:20px 0;">
        Los insumos elaborados son insumos marcados como <strong style="color:var(--orange)">elaborado=1</strong> en el catálogo. Para configurar su receta de producción, edita el insumo desde la pestaña <strong>Insumos</strong> y activa la opción "Elaborado", luego configura su receta en <strong>Recetas</strong>.
      </div>
      <div id="elab-spinner" class="spinner" style="display:none"></div>
      <div id="elab-empty" class="empty" style="display:none">Sin insumos elaborados</div>
      <table id="elab-table" style="display:none">
        <thead><tr><th>Clave</th><th>Descripción</th><th>Unidad</th><th>Grupo</th><th>Costo</th></tr></thead>
        <tbody id="elab-tbody"></tbody>
      </table>
    </div>
  </div>
</div>

</div><!-- /container -->

<!-- ═══ PRODUCTOS ═══ -->
<div class="section" id="sec-productos">
  <div class="card">
    <div class="card-head">
      <svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:var(--orange);stroke-width:2.2;fill:none;"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
      <span class="card-title">Catálogo de productos</span>
      <span id="prod-count" class="card-badge"></span>
    </div>
    <div class="card-body" style="padding:10px 14px;">
      <div style="display:flex;gap:8px;margin-bottom:10px;flex-wrap:wrap;">
        <input type="text" class="search-input" id="prod-search" placeholder="Buscar producto..."
          oninput="filtrarProductosCat()" style="flex:1;min-width:160px;"/>
        <select id="prod-filter-grp" onchange="filtrarProductosCat()"
          style="padding:7px 10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-2);color:var(--text);font-size:12px;">
          <option value="">Todos los grupos</option>
        </select>
      </div>
      <div id="prod-spinner" class="spinner" style="display:none"></div>
      <div id="prod-empty" class="empty" style="display:none">Sin productos encontrados.</div>
      <table id="prod-table" style="display:none">
        <thead>
          <tr>
            <th>Clave</th>
            <th>Descripción</th>
            <th>Grupo</th>
            <th style="text-align:right">Precio 1</th>
            <th style="text-align:right">Precio 2</th>
            <th style="text-align:right">Costo receta</th>
            <th style="text-align:right">Modif.</th>
          </tr>
        </thead>
        <tbody id="prod-tbody"></tbody>
      </table>
    </div>
  </div>
</div>

<!-- ── MODAL GRUPO ── -->
<div class="modal-bg" id="modal-prod-mods">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><path d="M4 6h16M7 12h10M10 18h4"/></svg>
      <span id="mpm-title">Modificadores</span>
    </div>
    <div class="modal-body">
      <div id="mpm-body" class="empty">Cargando...</div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-prod-mods')">Cerrar</button>
    </div>
  </div>
</div>

<div class="modal-bg" id="modal-elaborado">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
      <span id="melab-title">Receta de elaborado</span>
    </div>
    <div class="modal-body">
      <div id="melab-lineas"></div>
      <div style="margin-top:12px;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;align-items:center;">
        <select id="melab-grupo" onchange="elaboradoGrupoSel=this.value;renderSelectoresElaborado()"></select>
        <select id="melab-insumo"></select>
        <button class="btn btn-ghost btn-sm" onclick="agregarLineaElaborado()" style="justify-content:center;">Agregar ingrediente</button>
      </div>
      <div style="margin-top:12px;text-align:right;font-weight:800;">Costo receta: <span id="melab-costo">$0.00</span></div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-elaborado')">Cancelar</button>
      <button class="btn btn-orange" onclick="guardarElaborado()">Guardar receta</button>
    </div>
  </div>
</div>

<div class="modal-bg" id="modal-grupo">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><rect x="2" y="3" width="6" height="18" rx="1"/></svg>
      <span id="mgrp-title">Nuevo grupo</span>
    </div>
    <div class="modal-body">
      <div class="grid2">
        <div class="fg"><label>Clave *</label><input id="mgrp-id" placeholder="Ej: 001" maxlength="10"/></div>
        <div class="fg"><label>Descripción *</label><input id="mgrp-desc" placeholder="Ej: CARNES"/></div>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-grupo')">Cancelar</button>
      <button class="btn btn-orange" onclick="guardarGrupo()">Guardar</button>
    </div>
  </div>
</div>

<!-- ── MODAL INSUMO ── -->
<div class="modal-bg" id="modal-insumo">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><path d="M20 7H4a2 2 0 00-2 2v6a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2z"/></svg>
      <span id="mins-title">Nuevo insumo</span>
    </div>
    <div class="modal-body">
      <div class="grid2">
        <div class="fg"><label>Clave *</label><input id="mins-id" placeholder="Ej: 001001" maxlength="20"/></div>
        <div class="fg"><label>Descripción *</label><input id="mins-desc" placeholder="Ej: ACEITE DE OLIVA"/></div>
      </div>
      <div class="grid3">
        <div class="fg">
          <label>Grupo</label>
          <select id="mins-grupo"><option value="">Sin grupo</option></select>
        </div>
        <div class="fg"><label>Unidad</label><input id="mins-unidad" value="KGS" maxlength="10"/></div>
        <div class="fg"><label>Costo unitario</label><input id="mins-costo" type="number" step="0.01" min="0" value="0"/></div>
      </div>
      <div class="grid3">
        <div class="fg"><label>IVA %</label>
          <select id="mins-iva"><option value="16">16%</option><option value="0">0%</option></select>
        </div>
        <div class="fg"><label>Merma %</label><input id="mins-merma" type="number" step="0.01" min="0" value="0"/></div>
        <div class="fg"><label>Costo c/ impuestos</label><input id="mins-costo-imp" type="number" step="0.01" min="0" value="0"/></div>
      </div>
      <div class="grid3">
        <div class="fg"><label>Último costo c/ merma</label><input id="mins-costo-merma" type="number" step="0.01" min="0" value="0"/></div>
        <div class="fg"><label>Costo estándar</label><input id="mins-costoestandar" type="number" step="0.01" min="0" value="0"/></div>
        <div class="fg"><label>Proveedor</label><input id="mins-proveedor" maxlength="15" placeholder="Clave proveedor"/></div>
      </div>
      <div class="grid3">
        <div class="fg"><label>Stock mínimo</label><input id="mins-stock-min" type="number" step="0.0001" min="0" value="0"/></div>
        <div class="fg"><label>Stock ideal</label><input id="mins-stock-ideal" type="number" step="0.0001" min="0" value="0"/></div>
        <div class="fg"><label>Stock máximo</label><input id="mins-stock-max" type="number" step="0.0001" min="0" value="0"/></div>
      </div>
      <div class="grid3">
        <div class="fg"><label>Ubicación</label><input id="mins-ubicacion" maxlength="150"/></div>
        <div class="fg"><label>Área</label><input id="mins-idarea" maxlength="4"/></div>
        <div class="fg" style="justify-content:flex-end;">
          <label style="margin-bottom:8px;">Opciones</label>
          <div class="toggle-row" style="border:none;padding:0;gap:8px;">
            <span class="toggle-label">Elaborado</span>
            <label class="toggle"><input type="checkbox" id="mins-elaborado"/><span class="toggle-slider"></span></label>
          </div>
        </div>
      </div>
      <div style="border-top:1px solid var(--border);padding-top:12px;margin-top:4px;">
        <div class="toggle-row">
          <span class="toggle-label">Inventariable</span>
          <label class="toggle"><input type="checkbox" id="mins-inventariable" checked/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Activar alerta de existencias</span>
          <label class="toggle"><input type="checkbox" id="mins-alerta"/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Usar báscula en inventarios</span>
          <label class="toggle"><input type="checkbox" id="mins-bascula"/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Descargar de inventario</span>
          <label class="toggle"><input type="checkbox" id="mins-descargar" checked/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Activo</span>
          <label class="toggle"><input type="checkbox" id="mins-estatus" checked/><span class="toggle-slider"></span></label>
        </div>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-insumo')">Cancelar</button>
      <button class="btn btn-orange" id="mins-btn" onclick="guardarInsumo()">Guardar</button>
    </div>
  </div>
</div>

<!-- ── MODAL PRESENTACIÓN ── -->
<div class="modal-bg" id="modal-pres">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/></svg>
      <span id="mpres-title">Nueva presentación</span>
    </div>
    <div class="modal-body">
      <div class="grid2">
        <div class="fg"><label>Clave *</label><input id="mpres-id" placeholder="Ej: 001001" maxlength="20"/></div>
        <div class="fg"><label>Descripción *</label><input id="mpres-desc" placeholder="Ej: GALON"/></div>
      </div>
      <div class="fg">
        <label>Insumo *</label>
        <select id="mpres-insumo"><option value="">Selecciona insumo...</option></select>
      </div>
      <div class="grid3">
        <div class="fg"><label>Unidad</label><input id="mpres-unidad" value="KGS" maxlength="10"/></div>
        <div class="fg"><label>Rendimiento</label><input id="mpres-rend" type="number" step="0.0001" min="0.0001" value="1"/></div>
        <div class="fg"><label>Costo</label><input id="mpres-costo" type="number" step="0.01" min="0" value="0"/></div>
      </div>
      <div class="fg">
        <label>IVA %</label>
        <select id="mpres-iva"><option value="16">16%</option><option value="0">0%</option></select>
      </div>
      <div class="grid3">
        <div class="fg"><label>Proveedor</label><input id="mpres-proveedor" maxlength="15" placeholder="Clave proveedor"/></div>
        <div class="fg"><label>Stock mínimo</label><input id="mpres-stock-min" type="number" step="0.0001" min="0" value="0"/></div>
        <div class="fg"><label>Stock máximo</label><input id="mpres-stock-max" type="number" step="0.0001" min="0" value="0"/></div>
      </div>
      <div class="grid3">
        <div class="fg"><label>Stock ideal</label><input id="mpres-stock-ideal" type="number" step="0.0001" min="0" value="0"/></div>
        <div class="fg"><label>Costo estándar</label><input id="mpres-costoestandar" type="number" step="0.01" min="0" value="0"/></div>
        <div class="fg"><label>Ubicación</label><input id="mpres-ubicacion" maxlength="150"/></div>
      </div>
      <div style="border-top:1px solid var(--border);padding-top:12px;margin-top:4px;">
        <div class="toggle-row">
          <span class="toggle-label">Descargar de inventario</span>
          <label class="toggle"><input type="checkbox" id="mpres-descargar" checked/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Usar báscula en inventarios</span>
          <label class="toggle"><input type="checkbox" id="mpres-bascula"/><span class="toggle-slider"></span></label>
        </div>
        <div class="toggle-row">
          <span class="toggle-label">Activo</span>
          <label class="toggle"><input type="checkbox" id="mpres-estatus" checked/><span class="toggle-slider"></span></label>
        </div>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-pres')">Cancelar</button>
      <button class="btn btn-orange" id="mpres-btn" onclick="guardarPresentacion()">Guardar</button>
    </div>
  </div>
</div>

<!-- ── MODAL NUEVA RECETA ── -->
<div class="modal-bg" id="modal-nueva-receta">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"/><rect x="9" y="3" width="6" height="4" rx="1"/></svg>
      Selecciona un producto
    </div>
    <div class="modal-body">
      <div class="fg">
        <label>Producto</label>
        <select id="mnr-producto"><option value="">Cargando...</option></select>
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-nueva-receta')">Cancelar</button>
      <button class="btn btn-orange" onclick="irAReceta()">Editar receta</button>
    </div>
  </div>
</div>

<!-- ── MODAL IMPORT ── -->
<div class="modal-bg" id="modal-import">
  <div class="modal" onclick="event.stopPropagation()">
    <div class="modal-title">
      <svg viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
      Importar desde Excel
    </div>
    <div class="modal-body">
      <div class="import-drop" id="import-drop" onclick="document.getElementById('import-file').click()" ondragover="event.preventDefault();this.classList.add('over')" ondragleave="this.classList.remove('over')" ondrop="handleDrop(event)">
        <svg viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
        <div style="color:var(--text-2);font-weight:700;margin-bottom:4px;">Arrastra un archivo .xlsx o haz clic</div>
        <div style="color:var(--text-3);font-size:11px;">Formato: CSV con columnas clave, descripcion, unidad, costo</div>
      </div>
      <input type="file" id="import-file" accept=".csv,.txt" style="display:none" onchange="procesarImport(this)"/>
      <div id="import-preview" style="display:none;margin-top:12px;"></div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-ghost" onclick="cerrarModal('modal-import')">Cancelar</button>
      <button class="btn btn-orange" id="import-btn" onclick="ejecutarImport()" style="display:none">Importar</button>
    </div>
  </div>
</div>

<script src="/js/arkhon-utils.js"></script>
<script>
'use strict';
// ─── Auth ─────────────────────────────────────────────────────────────────────
var LOCAL_API_KEY = '';
const pct  = v => Number(v||0).toFixed(1)+'%';
const numVal = id => parseFloat(document.getElementById(id)?.value || 0) || 0;
function calcCostosInsumo() {
  const costo = numVal('mins-costo');
  const iva = numVal('mins-iva');
  const merma = numVal('mins-merma');
  const costoImp = Math.round((costo * (1 + iva / 100)) * 100) / 100;
  const costoMerma = merma > 0 && merma < 100 ? Math.round((costoImp / (1 - merma / 100)) * 100) / 100 : costoImp;
  const impEl = document.getElementById('mins-costo-imp');
  const mermaEl = document.getElementById('mins-costo-merma');
  const stdEl = document.getElementById('mins-costoestandar');
  if (impEl && (!impEl.dataset.manual || Number(impEl.value || 0) === 0)) impEl.value = costoImp.toFixed(2);
  if (mermaEl && (!mermaEl.dataset.manual || Number(mermaEl.value || 0) === 0)) mermaEl.value = costoMerma.toFixed(2);
  if (stdEl && (!stdEl.dataset.manual || Number(stdEl.value || 0) === 0)) stdEl.value = costo.toFixed(2);
}

// ─── Datos globales ───────────────────────────────────────────────────────────
let DATA = { grupos:[], insumos:[], presentaciones:[], recetas:[], productos:[], productosCat:[], _productosCatEn:0 };
let editandoInsumo    = null;
let editandoGrupo     = null;
let editandoPres      = null;
let recetaActual      = null; // { idproducto, precio_venta }
let lineasReceta      = [];
let elaboradoActual   = null;
let lineasElaborado   = [];
let recetaGrupoSel    = '';
let elaboradoGrupoSel = '';
let importTarget      = '';
let importRows        = [];

// ─── Tabs ─────────────────────────────────────────────────────────────────────
function showTab(name, btn) {
  document.querySelectorAll('.section').forEach(s=>s.classList.remove('active'));
  document.querySelectorAll('.tab').forEach(b=>b.classList.remove('active'));
  document.getElementById('sec-'+name).classList.add('active');
  if(btn) btn.classList.add('active');
  if(name==='grupos'         && !DATA.grupos.length)        cargarGrupos();
  if(name==='insumos'        && !DATA.insumos.length)       cargarInsumos();
  if(name==='presentaciones' && !DATA.presentaciones.length)cargarPresentaciones();
  if(name==='recetas'        && !DATA.recetas.length)       cargarRecetas();
  // Recargar catálogo si está vacío O si tiene más de 5 minutos (evita datos stale)
  const catalogoVencido = !DATA._productosCargadoEn || (Date.now() - DATA._productosCargadoEn) > 5 * 60 * 1000;
  if(name==='recetas' && (!DATA.productos.length || catalogoVencido)) cargarProductosCatalogo();
  if(name==='elaborados')    cargarElaborados();
  if(name==='productos')     cargarProductosCat();
}

// ─── GRUPOS ───────────────────────────────────────────────────────────────────
async function cargarGrupos() {
  show('grp-spinner'); hide('grp-table'); hide('grp-empty');
  try {
    DATA.grupos = await apiFetch('/api/insumos/grupos');
    renderGrupos(DATA.grupos);
    poblarSelectGrupos();
  } catch(e) { showEmpty('grp-empty', e.message); }
  hide('grp-spinner');
}
function renderGrupos(data) {
  const tbody = document.getElementById('grp-tbody');
  if(!data.length) { showEmpty('grp-empty','Sin grupos registrados'); return; }
  show('grp-table');
  document.getElementById('grp-count').textContent = data.length+' grupos';
  tbody.innerHTML = data.map(g=>`
    <tr>
      <td><span class="badge badge-orange">${escHtml(g.idgruposi)}</span></td>
      <td style="font-weight:600">${escHtml(g.descripcion)}</td>
      <td>${g.prioridad||'—'}</td>
      <td style="text-align:right;white-space:nowrap">
        <button class="btn btn-ghost btn-sm" onclick="abrirModalGrupo('${escHtml(g.idgruposi)}')">Editar</button>
        <button class="btn btn-red btn-sm" onclick="eliminarGrupo('${escHtml(g.idgruposi)}','${escHtml(g.descripcion)}')">Eliminar</button>
      </td>
    </tr>`).join('');
}
function abrirModalGrupo(id=null) {
  editandoGrupo = id;
  document.getElementById('mgrp-title').textContent = id ? 'Editar grupo' : 'Nuevo grupo';
  const g = id ? DATA.grupos.find(x=>x.idgruposi===id) : null;
  document.getElementById('mgrp-id').value   = g?.idgruposi||'';
  document.getElementById('mgrp-id').disabled = !!id;
  document.getElementById('mgrp-desc').value = g?.descripcion||'';
  abrirModal('modal-grupo');
}
async function guardarGrupo() {
  const id   = document.getElementById('mgrp-id').value.trim();
  const desc = document.getElementById('mgrp-desc').value.trim();
  if(!desc) return alert('La descripción es requerida');
  try {
    if(editandoGrupo) await apiFetch(`/api/insumos/grupos/${editandoGrupo}`,{method:'PUT',body:JSON.stringify({descripcion:desc})});
    else              await apiFetch('/api/insumos/grupos',{method:'POST',body:JSON.stringify({idgruposi:id,descripcion:desc})});
    cerrarModal('modal-grupo');
    DATA.grupos=[];
    await cargarGrupos();
  } catch(e) { alert('Error: '+e.message); }
}
async function eliminarGrupo(id, desc) {
  if(!confirm(`¿Eliminar grupo "${desc}"?\nSolo se puede eliminar si no tiene insumos asignados.`)) return;
  try { await apiFetch(`/api/insumos/grupos/${id}`,{method:'DELETE'}); DATA.grupos=[]; cargarGrupos(); }
  catch(e) { alert('Error: '+e.message); }
}

// ─── INSUMOS ──────────────────────────────────────────────────────────────────
async function cargarInsumos() {
  show('ins-spinner'); hide('ins-table'); hide('ins-empty');
  try {
    DATA.insumos = await apiFetch('/api/insumos/lista');
    renderInsumos(DATA.insumos);
    if(!DATA.grupos.length) await cargarGrupos();
    poblarSelectGrupos();
  } catch(e) { showEmpty('ins-empty', e.message); }
  hide('ins-spinner');
}
function renderInsumos(data) {
  const tbody = document.getElementById('ins-tbody');
  document.getElementById('ins-count').textContent = data.length+' insumos';
  if(!data.length) { showEmpty('ins-empty','Sin insumos'); return; }
  show('ins-table');
  tbody.innerHTML = data.map(i=>`
    <tr data-grp="${escHtml(i.idgruposi)}">
      <td><code style="font-size:11px;color:var(--orange)">${escHtml(i.idinsumo)}</code></td>
      <td style="font-weight:600">${escHtml(i.descripcion)}</td>
      <td>${escHtml(i.grupo)}</td>
      <td>${escHtml(i.unidad)}</td>
      <td style="font-weight:700">${fmt(i.costo)}</td>
      <td>${i.impuesto1||0}%</td>
      <td>${i.merma||0}%</td>
      <td>${i.inventariable?'<span class="badge badge-green">Sí</span>':'<span class="badge badge-gray">No</span>'}</td>
      <td>${i.estatus?'<span class="badge badge-green">Activo</span>':'<span class="badge badge-red">Inactivo</span>'}</td>
      <td style="text-align:right;white-space:nowrap">
        <button class="btn btn-ghost btn-sm" onclick="abrirModalInsumo('${escHtml(i.idinsumo)}')">Editar</button>
        <button class="btn btn-red btn-sm" onclick="eliminarInsumo('${escHtml(i.idinsumo)}','${escHtml(i.descripcion)}')">Eliminar</button>
      </td>
    </tr>`).join('');
}
function filtrarInsumos() {
  const grpFil = document.getElementById('ins-filter-grp').value;
  const txt    = document.getElementById('ins-search').value.toLowerCase();
  const rows   = document.querySelectorAll('#ins-tbody tr');
  rows.forEach(r => {
    const grpOk = !grpFil || r.dataset.grp===grpFil;
    const txtOk = !txt || r.textContent.toLowerCase().includes(txt);
    r.style.display = grpOk&&txtOk ? '' : 'none';
  });
}
function abrirModalInsumo(id=null) {
  editandoInsumo = id;
  document.getElementById('mins-title').textContent = id ? 'Editar insumo' : 'Nuevo insumo';
  document.getElementById('mins-btn').textContent   = id ? 'Guardar cambios' : 'Guardar';
  const ins = id ? DATA.insumos.find(x=>x.idinsumo===id) : null;
  document.getElementById('mins-id').value          = ins?.idinsumo||'';
  document.getElementById('mins-id').disabled       = !!id;
  document.getElementById('mins-desc').value        = ins?.descripcion||'';
  document.getElementById('mins-unidad').value      = ins?.unidad||'KGS';
  document.getElementById('mins-costo').value       = ins?.costo||0;
  document.getElementById('mins-iva').value         = ins?.impuesto1||16;
  document.getElementById('mins-merma').value       = ins?.merma||0;
  document.getElementById('mins-costo-imp').value   = ins?.costoconimpuestos||0;
  document.getElementById('mins-costo-merma').value = ins?.ultimocostoconmerma||ins?.costo_con_merma||0;
  document.getElementById('mins-costoestandar').value = ins?.costoestandar||ins?.costo||0;
  document.getElementById('mins-proveedor').value   = ins?.idproveedor||'';
  document.getElementById('mins-stock-min').value   = ins?.stockminimo||0;
  document.getElementById('mins-stock-ideal').value = ins?.stockideal||0;
  document.getElementById('mins-stock-max').value   = ins?.stockmaximo||0;
  document.getElementById('mins-ubicacion').value   = ins?.ubicacion||'';
  document.getElementById('mins-idarea').value      = ins?.idarea||'';
  document.getElementById('mins-grupo').value       = ins?.idgruposi||'';
  document.getElementById('mins-elaborado').checked = !!ins?.elaborado;
  document.getElementById('mins-inventariable').checked = ins ? !!ins.inventariable : true;
  document.getElementById('mins-alerta').checked    = !!ins?.alertaexistencias;
  document.getElementById('mins-bascula').checked   = !!ins?.usarbascula;
  document.getElementById('mins-descargar').checked = ins ? !!ins.descargar : true;
  document.getElementById('mins-estatus').checked   = ins ? !!ins.estatus : true;
  calcCostosInsumo();
  abrirModal('modal-insumo');
}
async function guardarInsumo() {
  const id   = document.getElementById('mins-id').value.trim();
  const desc = document.getElementById('mins-desc').value.trim();
  if(!desc) return alert('La descripción es requerida');
  const payload = {
    idinsumo:      id,
    descripcion:   desc,
    unidad:        document.getElementById('mins-unidad').value.trim()||'KGS',
    idgruposi:     document.getElementById('mins-grupo').value||null,
    costo:         parseFloat(document.getElementById('mins-costo').value)||0,
    impuesto1:     parseInt(document.getElementById('mins-iva').value)||16,
    merma:         parseFloat(document.getElementById('mins-merma').value)||0,
    costoconimpuestos: parseFloat(document.getElementById('mins-costo-imp').value)||0,
    ultimocostoconmerma: parseFloat(document.getElementById('mins-costo-merma').value)||0,
    costoestandar: parseFloat(document.getElementById('mins-costoestandar').value)||0,
    idproveedor:   document.getElementById('mins-proveedor').value.trim()||undefined,
    stockminimo:   parseFloat(document.getElementById('mins-stock-min').value)||0,
    stockideal:    parseFloat(document.getElementById('mins-stock-ideal').value)||0,
    stockmaximo:   parseFloat(document.getElementById('mins-stock-max').value)||0,
    ubicacion:     document.getElementById('mins-ubicacion').value.trim(),
    idarea:        document.getElementById('mins-idarea').value.trim(),
    elaborado:     document.getElementById('mins-elaborado').checked?1:0,
    inventariable: document.getElementById('mins-inventariable').checked?1:0,
    alertaexistencias: document.getElementById('mins-alerta').checked?1:0,
    usarbascula:   document.getElementById('mins-bascula').checked?1:0,
    descargar:     document.getElementById('mins-descargar').checked?1:0,
    estatus:       document.getElementById('mins-estatus').checked?1:0,
  };
  try {
    if(editandoInsumo) await apiFetch(`/api/insumos/lista/${editandoInsumo}`,{method:'PUT',body:JSON.stringify(payload)});
    else               await apiFetch('/api/insumos/lista',{method:'POST',body:JSON.stringify(payload)});
    cerrarModal('modal-insumo');
    DATA.insumos=[];
    await cargarInsumos();
  } catch(e) { alert('Error: '+e.message); }
}
async function eliminarInsumo(id, desc) {
  if(!confirm(`¿Eliminar insumo "${desc}" (${id})?\nEsta acción eliminará también su presentación y costos asociados.`)) return;
  try { await apiFetch(`/api/insumos/lista/${id}`,{method:'DELETE'}); DATA.insumos=[]; cargarInsumos(); }
  catch(e) { alert('Error: '+e.message); }
}

// ─── PRESENTACIONES ───────────────────────────────────────────────────────────
async function cargarPresentaciones() {
  show('pres-spinner'); hide('pres-table'); hide('pres-empty');
  try {
    DATA.presentaciones = await apiFetch('/api/insumos/presentaciones');
    renderPresentaciones(DATA.presentaciones);
    if(!DATA.insumos.length) await cargarInsumos();
    poblarSelectInsumos('mpres-insumo');
  } catch(e) { showEmpty('pres-empty', e.message); }
  hide('pres-spinner');
}
function renderPresentaciones(data) {
  const tbody = document.getElementById('pres-tbody');
  document.getElementById('pres-count').textContent = data.length+' presentaciones';
  if(!data.length) { showEmpty('pres-empty','Sin presentaciones'); return; }
  show('pres-table');
  tbody.innerHTML = data.map(p=>`
    <tr>
      <td><code style="font-size:11px;color:var(--orange)">${escHtml(p.idinsumospresentaciones)}</code></td>
      <td style="font-weight:600">${escHtml(p.descripcion)}</td>
      <td>${escHtml(p.insumo)}</td>
      <td>${escHtml(p.unidad)}</td>
      <td>${Number(p.rendimiento||1).toFixed(4)}</td>
      <td style="font-weight:700">${fmt(p.costo)}</td>
      <td>${p.impuesto1||0}%</td>
      <td style="text-align:right;white-space:nowrap">
        <button class="btn btn-ghost btn-sm" onclick="abrirModalPres('${escHtml(p.idinsumospresentaciones)}')">Editar</button>
        <button class="btn btn-red btn-sm" onclick="eliminarPres('${escHtml(p.idinsumospresentaciones)}','${escHtml(p.descripcion)}')">Eliminar</button>
      </td>
    </tr>`).join('');
}
function abrirModalPres(id=null) {
  editandoPres = id;
  document.getElementById('mpres-title').textContent = id ? 'Editar presentación' : 'Nueva presentación';
  document.getElementById('mpres-btn').textContent   = id ? 'Guardar cambios' : 'Guardar';
  const p = id ? DATA.presentaciones.find(x=>x.idinsumospresentaciones===id) : null;
  document.getElementById('mpres-id').value      = p?.idinsumospresentaciones||'';
  document.getElementById('mpres-id').disabled   = !!id;
  document.getElementById('mpres-desc').value    = p?.descripcion||'';
  document.getElementById('mpres-insumo').value  = p?.idinsumo||'';
  document.getElementById('mpres-unidad').value  = p?.unidad||'KGS';
  document.getElementById('mpres-rend').value    = p?.rendimiento||1;
  document.getElementById('mpres-costo').value   = p?.costo||0;
  document.getElementById('mpres-iva').value     = p?.impuesto1||16;
  document.getElementById('mpres-proveedor').value = p?.idproveedor||'';
  document.getElementById('mpres-stock-min').value = p?.stockminimogeneral||p?.stockminimo||0;
  document.getElementById('mpres-stock-max').value = p?.stockmaximogeneral||p?.stockmaximo||0;
  document.getElementById('mpres-stock-ideal').value = p?.stockideal||0;
  document.getElementById('mpres-costoestandar').value = p?.costoestandar||p?.costo||0;
  document.getElementById('mpres-ubicacion').value = p?.ubicacion||'';
  document.getElementById('mpres-descargar').checked = p ? !!p.descargar : true;
  document.getElementById('mpres-bascula').checked = !!p?.usarbascula;
  document.getElementById('mpres-estatus').checked = p ? !!p.estatus : true;
  if(!DATA.insumos.length) cargarInsumos().then(()=>poblarSelectInsumos('mpres-insumo'));
  abrirModal('modal-pres');
}
async function guardarPresentacion() {
  const id   = document.getElementById('mpres-id').value.trim();
  const desc = document.getElementById('mpres-desc').value.trim();
  const ins  = document.getElementById('mpres-insumo').value;
  if(!desc||!ins) return alert('Descripción e insumo son requeridos');
  const payload = {
    idinsumospresentaciones: id,
    descripcion: desc,
    idinsumo:    ins,
    unidad:      document.getElementById('mpres-unidad').value.trim()||'KGS',
    rendimiento: parseFloat(document.getElementById('mpres-rend').value)||1,
    costo:       parseFloat(document.getElementById('mpres-costo').value)||0,
    impuesto1:   parseInt(document.getElementById('mpres-iva').value)||16,
    idproveedor: document.getElementById('mpres-proveedor').value.trim()||undefined,
    stockminimogeneral: parseFloat(document.getElementById('mpres-stock-min').value)||0,
    stockmaximogeneral: parseFloat(document.getElementById('mpres-stock-max').value)||0,
    stockideal: parseFloat(document.getElementById('mpres-stock-ideal').value)||0,
    costoestandar: parseFloat(document.getElementById('mpres-costoestandar').value)||0,
    ubicacion: document.getElementById('mpres-ubicacion').value.trim(),
    descargar: document.getElementById('mpres-descargar').checked?1:0,
    usarbascula: document.getElementById('mpres-bascula').checked?1:0,
    estatus: document.getElementById('mpres-estatus').checked?1:0,
  };
  try {
    if(editandoPres) await apiFetch(`/api/insumos/presentaciones/${editandoPres}`,{method:'PUT',body:JSON.stringify(payload)});
    else             await apiFetch('/api/insumos/presentaciones',{method:'POST',body:JSON.stringify(payload)});
    cerrarModal('modal-pres');
    DATA.presentaciones=[];
    await cargarPresentaciones();
  } catch(e) { alert('Error: '+e.message); }
}
async function eliminarPres(id, desc) {
  if(!confirm(`¿Eliminar presentación "${desc}"?`)) return;
  try { await apiFetch(`/api/insumos/presentaciones/${id}`,{method:'DELETE'}); DATA.presentaciones=[]; cargarPresentaciones(); }
  catch(e) { alert('Error: '+e.message); }
}

// ─── RECETAS ──────────────────────────────────────────────────────────────────
async function cargarProductosCatalogo() {
  try {
    DATA.productos = await apiFetch('/api/insumos/productos');
    DATA._productosCargadoEn = Date.now();  // TTL: guardar momento de carga
    const warn = document.getElementById('rec-productos-warn');
    if(warn) warn.style.display = 'none';
  } catch(e) {
    console.warn('[cargarProductosCatalogo]', e.message);
    const warn = document.getElementById('rec-productos-warn');
    if(warn) { warn.textContent = '⚠️ No se pudo cargar el catálogo de productos: ' + e.message; warn.style.display = 'block'; }
  }
}

// Forzar recarga del catálogo (botón "Actualizar catálogo")
async function refrescarCatalogo() {
  DATA.productos = [];
  DATA._productosCargadoEn = 0;
  await cargarProductosCatalogo();
}

async function cargarRecetas() {
  show('rec-spinner'); hide('rec-table'); hide('rec-empty');
  try {
    DATA.recetas = await apiFetch('/api/insumos/recetas');
    renderRecetas(DATA.recetas);
  } catch(e) { showEmpty('rec-empty', e.message); }
  hide('rec-spinner');
}
function renderRecetas(data) {
  const tbody = document.getElementById('rec-tbody');
  if(!data.length) { showEmpty('rec-empty','Sin recetas configuradas'); return; }
  show('rec-table');
  tbody.innerHTML = data.map(r=>{
    const fc = r.precio_venta>0 ? Math.round(r.costo_total/r.precio_venta*100) : 0;
    const fcColor = fc<=25?'#10b981':fc<=35?'#f97316':fc<=50?'#f59e0b':'#ef4444';
    return `<tr>
      <td style="font-weight:600">${escHtml(r.producto)}</td>
      <td><span class="badge badge-gray">${r.num_ingredientes}</span></td>
      <td style="font-weight:700">${fmt(r.costo_total)}</td>
      <td>${fmt(r.precio_venta)}</td>
      <td>
        <span class="cost-badge" style="color:${fcColor}">${fc}%</span>
        <div class="fc-bar" style="width:80px;display:inline-block;vertical-align:middle;margin-left:6px">
          <div class="fc-fill" style="width:${Math.min(fc,100)}%;background:${fcColor}"></div>
        </div>
      </td>
      <td style="text-align:right">
        <button class="btn btn-orange btn-sm" onclick="editarReceta('${escHtml(r.idproducto)}','${escHtml(r.producto)}',${r.precio_venta})">Editar</button>
      </td>
    </tr>`;
  }).join('');
}

async function verModificadoresProducto(idproducto, descripcion) {
  document.getElementById('mpm-title').textContent = `Modificadores / ${descripcion || idproducto}`;
  const body = document.getElementById('mpm-body');
  body.className = 'empty';
  body.textContent = 'Cargando...';
  abrirModal('modal-prod-mods');
  try {
    const data = await apiFetch(`/api/productos/${encodeURIComponent(idproducto)}/modificadores`);
    if (!data.supported) {
      body.textContent = 'SoftRestaurant no expone tablas de modificadores en esta base.';
      return;
    }
    if (!data.groups || !data.groups.length) {
      body.textContent = 'Sin grupos de modificadores asignados.';
      return;
    }
    body.className = '';
    body.innerHTML = data.groups.map(g => `
      <div class="card" style="box-shadow:none;margin-bottom:10px;">
        <div class="card-head">
          <span class="card-title">${escHtml(g.descripcion || g.idgrupo_modificador)}</span>
          <span class="badge">${escHtml(g.idgrupo_modificador || '')}</span>
        </div>
        <div class="card-body" style="padding:10px 14px;">
          <div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;font-size:11px;color:var(--text-3);margin-bottom:10px;">
            <div><b>Sec.</b> ${escHtml(g.secuencia ?? '0')}</div>
            <div><b>Incl.</b> ${escHtml(g.incluidos ?? '0')}</div>
            <div><b>Max.</b> ${escHtml(g.maximomodificadores ?? '0')}</div>
            <div><b>Forzar</b> ${g.forzarcaptura ? 'Si' : 'No'}</div>
          </div>
          <table>
            <thead><tr><th>Clave</th><th>Modificador</th><th style="text-align:right">Precio</th></tr></thead>
            <tbody>${(g.modifiers || []).map(m => `
              <tr>
                <td><code style="font-size:11px;color:var(--orange)">${escHtml(m.idproducto)}</code></td>
                <td>${escHtml(m.descripcion || '')}</td>
                <td style="text-align:right">${fmt(m.precio || 0)}</td>
              </tr>
            `).join('') || '<tr><td colspan="3" class="empty">Sin modificadores.</td></tr>'}</tbody>
          </table>
        </div>
      </div>
    `).join('');
  } catch(e) {
    body.textContent = 'Error al cargar modificadores: ' + e.message;
  }
}

async function abrirNuevaReceta() {
  if(!DATA.productos.length) {
    await cargarProductosCatalogo();
  }
  if(!DATA.productos.length) {
    alert('No se encontraron productos en el catálogo. Verifica la conexión o que existan productos configurados en el sistema.');
    return;
  }
  const sel = document.getElementById('mnr-producto');
  sel.innerHTML = DATA.productos.map(p=>`<option value="${escHtml(p.idproducto)}">${escHtml(p.descripcion)} — ${fmt(p.precio1)}</option>`).join('');
  abrirModal('modal-nueva-receta');
}

function irAReceta() {
  const sel = document.getElementById('mnr-producto');
  const id  = sel.value;
  const txt = sel.options[sel.selectedIndex]?.text||id;
  const precio = DATA.productos.find(p=>p.idproducto===id)?.precio1||0;
  cerrarModal('modal-nueva-receta');
  editarReceta(id, txt, precio);
}

async function editarReceta(idproducto, nombre, precioVenta) {
  recetaActual = { idproducto, precioVenta };
  document.getElementById('rec-editor-title').textContent = nombre;
  document.getElementById('rec-precio-venta').textContent = fmt(precioVenta);
  show('rec-editor'); hide('rec-lista');

  // Cargar insumos si no están
  if(!DATA.insumos.length) await cargarInsumos();

  lineasReceta = [];
  try {
    const detalle = await apiFetch(`/api/insumos/recetas/${idproducto}`);
    detalle.forEach(d => lineasReceta.push({
      idinsumo:     d.idinsumo,
      descripcion:  d.insumo,
      unidad:       d.unidad,
      cantidad:     d.cantidad,
      costoUnitario:d.costo_unitario,
    }));
  } catch(e) {}
  renderLineas();
  renderSelectoresReceta();
}

function cerrarEditor() {
  hide('rec-editor'); show('rec-lista');
  recetaActual=null; lineasReceta=[];
}

function renderLineas() {
  const cont = document.getElementById('rec-lineas');
  if(!lineasReceta.length) {
    cont.innerHTML = '<div class="empty" style="padding:20px 0">Sin ingredientes — usa Agregar para comenzar</div>';
    calcFC(0);
    return;
  }
  let costoTotal = 0;
  cont.innerHTML = lineasReceta.map((l,i)=>{
    const cLinea = (l.cantidad||0)*(l.costoUnitario||0);
    costoTotal += cLinea;
    return `<div class="linea-row">
      <div class="linea-insumo">
        <div style="font-weight:600;font-size:12px">${escHtml(l.descripcion)}</div>
        <div style="font-size:10px;color:var(--text-3)">${escHtml(l.unidad)} · ${fmt(l.costoUnitario)}/u</div>
      </div>
      <div class="linea-cant">
        <input type="number" step="0.001" min="0" value="${l.cantidad||0}"
          oninput="lineasReceta[${i}].cantidad=parseFloat(this.value)||0;recalcLineas()"/>
      </div>
      <div class="linea-costo">${fmt(cLinea)}</div>
      <button class="btn btn-red btn-sm" style="padding:4px 6px;flex-shrink:0" onclick="eliminarLinea(${i})">
        <svg viewBox="0 0 24 24" style="width:11px;height:11px"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
      </button>
    </div>`;
  }).join('');
  calcFC(costoTotal);
}

function recalcLineas() {
  let costoTotal=0;
  lineasReceta.forEach((l,i)=>{
    const cLinea=(l.cantidad||0)*(l.costoUnitario||0);
    costoTotal+=cLinea;
    const celdas=document.querySelectorAll('#rec-lineas .linea-costo');
    if(celdas[i]) celdas[i].textContent=fmt(cLinea);
  });
  calcFC(costoTotal);
}

function calcFC(costoTotal) {
  document.getElementById('rec-costo-total').textContent=fmt(costoTotal);
  const precio=recetaActual?.precioVenta||0;
  const fc = precio>0 ? costoTotal/precio*100 : 0;
  document.getElementById('rec-fc-pct').textContent=fc.toFixed(1)+'%';
  const bar=document.getElementById('rec-fc-bar');
  const color=fc<=25?'#10b981':fc<=35?'#f97316':fc<=50?'#f59e0b':'#ef4444';
  bar.style.width=Math.min(fc,100)+'%';
  bar.style.background=color;
  document.getElementById('rec-fc-pct').style.color=color;
  const lbl=document.getElementById('rec-fc-label');
  lbl.textContent=fc<=25?'Excelente — food cost bajo':fc<=35?'Óptimo — rango ideal':fc<=50?'Alto — revisar costos':'Crítico — pérdida probable';
  lbl.style.color=color;
}

function gruposParaSelector() {
  const map = new Map();
  DATA.insumos.forEach(i => {
    const id = i.idgruposi || i.idgrupo || '';
    const nombre = i.grupo || (id ? id : 'Sin grupo');
    if(!map.has(id)) map.set(id, nombre);
  });
  return [...map.entries()].sort((a,b)=>String(a[1]).localeCompare(String(b[1])));
}

function costoInsumo(i) {
  return Number(i.costo ?? i.ultimocosto ?? i.ultimo_costo ?? i.costopromedio ?? i.costo_promedio ?? 0);
}

function renderInsumoSelector(prefix, selectedGroup, excludeId='') {
  const grupoEl = document.getElementById(`${prefix}-grupo`);
  const insEl = document.getElementById(`${prefix}-insumo`);
  if(!grupoEl || !insEl) return selectedGroup || '';
  const grupos = gruposParaSelector();
  if(!grupos.length) {
    grupoEl.innerHTML = '<option value="">Sin grupos</option>';
    insEl.innerHTML = '<option value="">Sin insumos</option>';
    return '';
  }
  let groupValue = selectedGroup;
  if(!groupValue || !grupos.some(([id]) => String(id) === String(groupValue))) groupValue = grupos[0][0];
  grupoEl.innerHTML = grupos.map(([id,nombre]) => `<option value="${escHtml(id)}" ${String(id)===String(groupValue)?'selected':''}>${escHtml(nombre)}</option>`).join('');
  const items = DATA.insumos
    .filter(i => String(i.idgruposi || i.idgrupo || '') === String(groupValue))
    .filter(i => !excludeId || i.idinsumo !== excludeId);
  insEl.innerHTML = items.length
    ? items.map(i => `<option value="${escHtml(i.idinsumo)}">${escHtml(i.descripcion)} (${escHtml(i.unidad||'')}) - ${fmt(costoInsumo(i))}</option>`).join('')
    : '<option value="">Sin insumos en este grupo</option>';
  return groupValue;
}

function renderSelectoresReceta() {
  recetaGrupoSel = renderInsumoSelector('rec', recetaGrupoSel);
}

function renderSelectoresElaborado() {
  elaboradoGrupoSel = renderInsumoSelector('melab', elaboradoGrupoSel, elaboradoActual?.idinsumo || '');
}

function agregarLinea() {
  const idinsumo = document.getElementById('rec-insumo')?.value;
  if(!idinsumo) return alert('Selecciona un ingrediente');
  const ins = DATA.insumos.find(i=>i.idinsumo===idinsumo);
  if(!ins) return alert(`Insumo '${idinsumo}' no encontrado`);
  lineasReceta.push({ idinsumo:ins.idinsumo, descripcion:ins.descripcion, unidad:ins.unidad, cantidad:1, costoUnitario:costoInsumo(ins) });
  renderLineas();
}

function eliminarLinea(i) {
  lineasReceta.splice(i,1);
  renderLineas();
}

async function guardarReceta() {
  if(!recetaActual) return;
  if(!lineasReceta.length) return alert('Agrega al menos un ingrediente');
  try {
    await apiFetch(`/api/insumos/recetas/${recetaActual.idproducto}`,{
      method:'POST',
      body: JSON.stringify({ lineas: lineasReceta.map(l=>({idinsumo:l.idinsumo,cantidad:l.cantidad,unidad:l.unidad})) })
    });
    alert('Receta guardada correctamente');
    DATA.recetas=[];
    cerrarEditor();
    await cargarRecetas();
  } catch(e) { alert('Error: '+e.message); }
}

// ─── ELABORADOS ───────────────────────────────────────────────────────────────
async function cargarElaborados() {
  document.querySelector('#sec-elaborados .card-body > .empty[style*="display:block"]')?.remove();
  show('elab-spinner'); hide('elab-table'); hide('elab-empty');
  if(!DATA.insumos.length) await cargarInsumos();
  let elab = [];
  try {
    elab = await apiFetch('/api/insumos/elaborados');
  } catch(e) {
    showEmpty('elab-empty', e.message);
    hide('elab-spinner');
    return;
  }
  const tbody = document.getElementById('elab-tbody');
  if(!elab.length) {
    hide('elab-table');
    showEmpty('elab-empty','Sin insumos elaborados');
    hide('elab-spinner');
    return;
  }
  hide('elab-empty');
  show('elab-table');
  tbody.innerHTML = elab.map(i=>`
    <tr>
      <td><code style="font-size:11px;color:var(--orange)">${escHtml(i.idinsumo)}</code></td>
      <td style="font-weight:600">${escHtml(i.descripcion)}</td>
      <td>${escHtml(i.unidad)}</td>
      <td>${escHtml(i.grupo)}</td>
      <td><span class="badge badge-gray">${i.num_ingredientes||0}</span></td>
      <td style="font-weight:700">${fmt(i.costo_receta||i.costo||0)}</td>
      <td style="text-align:right"><button class="btn btn-orange btn-sm" onclick="editarElaborado('${escHtml(i.idinsumo)}','${escHtml(i.descripcion)}')">Editar receta</button></td>
    </tr>`).join('');
  hide('elab-spinner');
}

// ─── PRODUCTOS (catálogo de SR) ──────────────────────────────────────────────
async function editarElaborado(idinsumo, descripcion) {
  elaboradoActual = { idinsumo, descripcion };
  lineasElaborado = [];
  document.getElementById('melab-title').textContent = `Receta de elaborado / ${descripcion || idinsumo}`;
  if(!DATA.insumos.length) await cargarInsumos();
  try {
    const detalle = await apiFetch(`/api/insumos/elaborados/${encodeURIComponent(idinsumo)}`);
    lineasElaborado = detalle.map(d => ({
      idinsumo: d.idinsumo,
      descripcion: d.insumo,
      unidad: d.unidad,
      cantidad: d.cantidad,
      costoUnitario: d.costo_unitario,
    }));
  } catch(_) {}
  renderLineasElaborado();
  renderSelectoresElaborado();
  abrirModal('modal-elaborado');
}

function renderLineasElaborado() {
  const cont = document.getElementById('melab-lineas');
  if(!lineasElaborado.length) {
    cont.innerHTML = '<div class="empty" style="padding:18px 0">Sin ingredientes</div>';
    document.getElementById('melab-costo').textContent = fmt(0);
    return;
  }
  let total = 0;
  cont.innerHTML = lineasElaborado.map((l,i) => {
    const linea = (l.cantidad || 0) * (l.costoUnitario || 0);
    total += linea;
    return `<div class="linea-row">
      <div class="linea-insumo">
        <div style="font-weight:600;font-size:12px">${escHtml(l.descripcion)}</div>
        <div style="font-size:10px;color:var(--text-3)">${escHtml(l.idinsumo)} · ${escHtml(l.unidad)} · ${fmt(l.costoUnitario)}/u</div>
      </div>
      <div class="linea-cant">
        <input type="number" step="0.001" min="0" value="${l.cantidad||0}"
          oninput="lineasElaborado[${i}].cantidad=parseFloat(this.value)||0;renderLineasElaborado()"/>
      </div>
      <div class="linea-costo">${fmt(linea)}</div>
      <button class="btn btn-red btn-sm" style="padding:4px 6px;flex-shrink:0" onclick="lineasElaborado.splice(${i},1);renderLineasElaborado()">Eliminar</button>
    </div>`;
  }).join('');
  document.getElementById('melab-costo').textContent = fmt(total);
}

function agregarLineaElaborado() {
  const idinsumo = document.getElementById('melab-insumo')?.value;
  if(!idinsumo) return alert('Selecciona un ingrediente');
  const ins = DATA.insumos.find(i => i.idinsumo !== elaboradoActual?.idinsumo && i.idinsumo === idinsumo);
  if(!ins) return alert(`Insumo '${idinsumo}' no encontrado`);
  lineasElaborado.push({ idinsumo: ins.idinsumo, descripcion: ins.descripcion, unidad: ins.unidad, cantidad: 1, costoUnitario: costoInsumo(ins) });
  renderLineasElaborado();
}

async function guardarElaborado() {
  if(!elaboradoActual) return;
  if(!lineasElaborado.length) return alert('Agrega al menos un ingrediente');
  try {
    await apiFetch(`/api/insumos/elaborados/${encodeURIComponent(elaboradoActual.idinsumo)}`, {
      method: 'POST',
      body: JSON.stringify({ lineas: lineasElaborado.map(l => ({ idinsumo: l.idinsumo, cantidad: l.cantidad })) })
    });
    cerrarModal('modal-elaborado');
    DATA.insumos = [];
    await cargarElaborados();
  } catch(e) { alert('Error: ' + e.message); }
}

let _prodCatAll = [];

async function cargarProductosCat() {
  const vencido = !DATA._productosCatEn || (Date.now() - DATA._productosCatEn) > 3 * 60 * 1000;
  if (DATA.productosCat.length && !vencido) {
    renderProductosCat(DATA.productosCat);
    return;
  }
  show('prod-spinner'); hide('prod-table'); hide('prod-empty');
  try {
    // Usar el endpoint extendido para obtener precio2 y costo receta
    const raw = await apiFetch('/api/insumos/productos-cat');
    DATA.productosCat = raw || [];
    DATA._productosCatEn = Date.now();
    _prodCatAll = DATA.productosCat;
    poblarFiltroGruposProd();
    renderProductosCat(DATA.productosCat);
  } catch(e) {
    hide('prod-spinner');
    show('prod-empty');
    document.getElementById('prod-empty').textContent = 'Error al cargar productos: ' + e.message;
  }
  hide('prod-spinner');
}

function poblarFiltroGruposProd() {
  const sel = document.getElementById('prod-filter-grp');
  if (!sel) return;
  const grupos = [...new Set(_prodCatAll.map(p => p.grupo || 'Sin grupo'))].sort();
  sel.innerHTML = '<option value="">Todos los grupos</option>' +
    grupos.map(g => `<option value="${escHtml(g)}">${escHtml(g)}</option>`).join('');
}

function filtrarProductosCat() {
  const txt = (document.getElementById('prod-search')?.value || '').toLowerCase();
  const grp = document.getElementById('prod-filter-grp')?.value || '';
  const filtrado = _prodCatAll.filter(p => {
    const matchTxt = !txt ||
      p.descripcion?.toLowerCase().includes(txt) ||
      p.idproducto?.toLowerCase().includes(txt);
    const matchGrp = !grp || (p.grupo || 'Sin grupo') === grp;
    return matchTxt && matchGrp;
  });
  renderProductosCat(filtrado);
}

function renderProductosCat(data) {
  const tbody = document.getElementById('prod-tbody');
  const table = document.getElementById('prod-table');
  const empty = document.getElementById('prod-empty');
  const badge = document.getElementById('prod-count');
  if (!tbody) return;
  if (!data.length) {
    if (table) table.style.display = 'none';
    if (empty) { empty.textContent = 'Sin productos encontrados.'; empty.style.display = 'block'; }
    if (badge) badge.textContent = '0';
    return;
  }
  if (empty) empty.style.display = 'none';
  if (table) table.style.display = '';
  if (badge) badge.textContent = data.length + ' producto' + (data.length !== 1 ? 's' : '');
  tbody.innerHTML = data.map(p => {
    const margen = p.precio1 > 0 && p.costo_receta > 0
      ? Math.round((1 - p.costo_receta / p.precio1) * 100)
      : null;
    const margenColor = margen === null ? 'var(--text-3)' :
      margen >= 60 ? 'var(--green,#22c55e)' :
      margen >= 40 ? 'var(--orange)' : '#ef4444';
    return `<tr>
      <td><code style="font-size:11px;color:var(--orange)">${escHtml(p.idproducto)}</code></td>
      <td style="font-weight:600">${escHtml(p.descripcion)}</td>
      <td style="color:var(--text-3);font-size:12px">${escHtml(p.grupo || '—')}</td>
      <td style="text-align:right">${fmt(p.precio1)}</td>
      <td style="text-align:right;color:var(--text-3)">${p.precio2 > 0 ? fmt(p.precio2) : '—'}</td>
      <td style="text-align:right;color:${margenColor};font-weight:700">
        ${p.costo_receta > 0 ? fmt(p.costo_receta) + (margen !== null ? ` <span style="font-size:10px">(${margen}% mg)</span>` : '') : '—'}
      </td>
    </tr>`;
  }).join('');
}

// ─── IMPORT EXCEL ─────────────────────────────────────────────────────────────
function abrirImport(target) {
  importTarget=target; importRows=[];
  document.getElementById('import-preview').style.display='none';
  document.getElementById('import-btn').style.display='none';
  document.getElementById('import-file').value='';
  abrirModal('modal-import');
}

function handleDrop(e) {
  e.preventDefault();
  document.getElementById('import-drop').classList.remove('over');
  const file=e.dataTransfer.files[0];
  if(file) procesarImportFile(file);
}

function procesarImport(input) {
  const file=input.files[0]; if(!file) return;
  procesarImportFile(file);
}

function procesarImportFile(file) {
  // Solo CSV soportado — XLSX es formato binario que requiere librería externa
  if(file.name.match(/\.xlsx?$/i)) {
    alert('Por favor exporta tu archivo como CSV (.csv) desde Excel primero.\nArchivo > Guardar como > CSV UTF-8');
    return;
  }
  const reader=new FileReader();
  reader.onload=function(e) {
    const data=new Uint8Array(e.target.result);
    const text=new TextDecoder().decode(data);
    const lines=text.split('\n').map(l=>l.trim()).filter(Boolean);
    if(!lines.length) return alert('Archivo vacío');
    const headers=lines[0].split(/[,;\t]/).map(h=>h.toLowerCase().trim().replace(/"/g,''));
    importRows=lines.slice(1).map(l=>{
      const vals=l.split(/[,;\t]/).map(v=>v.trim().replace(/"/g,''));
      const obj={};
      headers.forEach((h,i)=>obj[h]=vals[i]||'');
      return obj;
    }).filter(r=>r.clave||r.idinsumo||r.descripcion);

    const prev=document.getElementById('import-preview');
    prev.style.display='block';
    prev.innerHTML=`<div style="color:var(--text-2);font-size:12px;margin-bottom:8px;font-weight:700">${importRows.length} registros detectados</div>
    <div class="tbl-wrap" style="max-height:200px;overflow-y:auto">
    <table><thead><tr>${headers.map(h=>`<th>${escHtml(h)}</th>`).join('')}</tr></thead>
    <tbody>${importRows.slice(0,10).map(r=>`<tr>${headers.map(h=>`<td>${escHtml(r[h]||'')}</td>`).join('')}</tr>`).join('')}</tbody>
    </table></div>`;
    document.getElementById('import-btn').style.display='inline-flex';
  };
  reader.readAsArrayBuffer(file);
}

async function ejecutarImport() {
  if(!importRows.length) return;
  let ok=0,err=0;
  for(const row of importRows) {
    const payload={
      idinsumo:    (row.clave||row.idinsumo||'').trim(),
      descripcion: (row.descripcion||row.nombre||'').trim(),
      unidad:      (row.unidad||'KGS').trim(),
      costo:       parseFloat(row.costo||row.precio||0)||0,
      impuesto1:   parseFloat(row.iva||row.impuesto1||16)||16,
      merma:       parseFloat(row.merma||0)||0,
      costoconimpuestos: parseFloat(row.costoconimpuestos||row.costo_con_impuestos||0)||0,
      ultimocostoconmerma: parseFloat(row.ultimocostoconmerma||row.costo_con_merma||0)||0,
      costoestandar: parseFloat(row.costoestandar||row.costo_estandar||row.costo||0)||0,
      idproveedor: (row.idproveedor||row.proveedor||'').trim()||undefined,
      stockminimo: parseFloat(row.stockminimo||row.stock_minimo||0)||0,
      stockideal: parseFloat(row.stockideal||row.stock_ideal||0)||0,
      stockmaximo: parseFloat(row.stockmaximo||row.stock_maximo||0)||0,
      ubicacion: (row.ubicacion||'').trim(),
      idarea: (row.idarea||row.area||'').trim(),
      inventariable: row.inventariable === '0' ? 0 : 1,
      alertaexistencias: row.alertaexistencias === '1' || row.alerta === '1' ? 1 : 0,
      usarbascula: row.usarbascula === '1' || row.usarbasculainv === '1' ? 1 : 0,
      descargar: row.descargar === '0' ? 0 : 1,
      estatus: row.estatus === '0' ? 0 : 1,
    };
    if(!payload.idinsumo||!payload.descripcion) { err++; continue; }
    try { await apiFetch('/api/insumos/lista',{method:'POST',body:JSON.stringify(payload)}); ok++; }
    catch(_) { err++; }
  }
  cerrarModal('modal-import');
  alert(`Importación completada:\n${ok} insumos creados\n${err} errores/duplicados`);
  DATA.insumos=[];
  await cargarInsumos();
}

// ─── Helpers ──────────────────────────────────────────────────────────────────
function poblarSelectGrupos() {
  const sels = ['mins-grupo','ins-filter-grp'];
  sels.forEach(sid=>{
    const sel=document.getElementById(sid);
    if(!sel) return;
    const first=sid==='ins-filter-grp'?'<option value="">Todos los grupos</option>':'<option value="">Sin grupo</option>';
    sel.innerHTML=first+DATA.grupos.map(g=>`<option value="${escHtml(g.idgruposi)}">${escHtml(g.descripcion)}</option>`).join('');
  });
}
function poblarSelectInsumos(selId) {
  const sel=document.getElementById(selId); if(!sel) return;
  sel.innerHTML='<option value="">Selecciona insumo...</option>'+
    DATA.insumos.map(i=>`<option value="${escHtml(i.idinsumo)}">${escHtml(i.descripcion)} (${escHtml(i.idinsumo)})</option>`).join('');
}
function filtrarTabla(tbodyId, inputId) {
  const txt=document.getElementById(inputId).value.toLowerCase();
  document.querySelectorAll('#'+tbodyId+' tr').forEach(r=>{
    r.style.display=!txt||r.textContent.toLowerCase().includes(txt)?'':'none';
  });
}
function escHtml(s){return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
function show(id){const e=document.getElementById(id);if(e)e.style.display='';}
function hide(id){const e=document.getElementById(id);if(e)e.style.display='none';}
function showEmpty(id,msg){const e=document.getElementById(id);if(e){e.textContent=msg||'Sin datos';e.style.display='block';}}
function abrirModal(id){document.getElementById(id).classList.add('open');}
function cerrarModal(id){document.getElementById(id).classList.remove('open');}

// ─── Init ─────────────────────────────────────────────────────────────────────
(async()=>{
  try {
    await _initAuth();
    ['mins-costo','mins-iva','mins-merma'].forEach(id => {
      const el = document.getElementById(id);
      if (el) el.addEventListener('input', calcCostosInsumo);
    });
    ['mins-costo-imp','mins-costo-merma','mins-costoestandar'].forEach(id => {
      const el = document.getElementById(id);
      if (el) el.addEventListener('input', () => { el.dataset.manual = '1'; });
    });
    if (window.self !== window.top) {
      const tb = document.querySelector('.topbar');
      if (tb) tb.style.display = 'none';
    }
    await Promise.all([cargarGrupos(), cargarInsumos()]);
  } catch(e) {
    // Mostrar error visible al usuario si la autenticación o carga inicial fallan
    document.body.insertAdjacentHTML('afterbegin',
      `<div style="position:fixed;top:0;left:0;right:0;background:#ef4444;color:#fff;
        text-align:center;padding:10px 16px;font-size:13px;font-weight:700;z-index:9999;">
        ⚠️ ${e.message || 'Error al cargar el módulo'} — 
        <a href="javascript:location.reload()" style="color:#fff;text-decoration:underline;">Reintentar</a>
      </div>`
    );
  }
})();
</script>
</body>
</html>
