<!DOCTYPE html>
<html lang="es">
<head>
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64, ">
  <link rel="icon" type="image/png" sizes="16x16" href="data:image/png;base64, ">
  <link rel="apple-touch-icon" href="data:image/png;base64, ">
  <meta name="application-name" content="PodoCLINIC v4.0">
  <meta name="msapplication-TileImage" content="data:image/png;base64, ">
  <meta name="msapplication-TileColor" content="#0f1e2e">
  <meta name="theme-color" content="#4a9d8f">
  <meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="PodoCLINIC">
<title>PodoCLINIC — Sistema de Gestión v4.0.10</title>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=Lora:ital,wght@0,500;0,600;1,400;1,500&display=swap" rel="stylesheet"/>
<script src="assets/react.min.js"></script>
<script src="assets/react-dom.min.js"></script>
<script src="assets/babel.min.js"></script>
<script src="assets/xlsx.min.js"></script>
<script>
// ─── GLOBAL ERROR CATCHER ─────────────────────────────────────────────────────
window.onerror=function(msg,src,line,col,err){
  var d=document.getElementById('pre-error');
  if(d){d.style.display='flex';d.querySelector('#pre-error-msg').textContent=(err?err.toString():msg)+' ('+src+':'+line+')';}
  return false;
};
window.onunhandledrejection=function(e){
  var reason=e&&e.reason?e.reason.toString():'';
  if(/sesión inválida|sesion invalida|expirada|no autenticado/i.test(reason)){if(e&&e.preventDefault)e.preventDefault();return true;}
  var d=document.getElementById('pre-error');
  if(d){d.style.display='flex';d.querySelector('#pre-error-msg').textContent='Promise error: '+(e.reason?e.reason.toString():'unknown');}
};
// Check if critical libraries loaded
window.addEventListener('DOMContentLoaded',function(){
  if(typeof React==='undefined'||typeof ReactDOM==='undefined'||typeof Babel==='undefined'){
    var d=document.getElementById('pre-error');
    if(d){d.style.display='flex';d.querySelector('#pre-error-msg').textContent='Error: No se cargaron las librerías (React/Babel). Verifique su instalación.';}
  }
});
</script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Outfit',sans-serif;background:#eef2f7;color:#1a2332}
::-webkit-scrollbar{width:5px;height:5px}
::-webkit-scrollbar-track{background:#e4eaf0}
::-webkit-scrollbar-thumb{background:#4a9d8f;border-radius:3px}
input,select,textarea,button{font-family:'Outfit',sans-serif}
.fade-in{animation:fadeIn .25s ease}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.slide-in{animation:slideIn .3s ease}
@keyframes slideIn{from{opacity:0;transform:translateX(-12px)}to{opacity:1;transform:translateX(0)}}
.pop-in{animation:popIn .2s cubic-bezier(.175,.885,.32,1.275)}
@keyframes popIn{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:scale(1)}}
#root{min-height:100vh}
.bar-fill{transition:width .8s cubic-bezier(.22,1,.36,1)}
.pulse{animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
</style>
</head>
<body>
<!-- PRE-REACT LOADING INDICATOR (hidden once React mounts) -->
<div id="pre-loader" style="position:fixed;inset:0;background:linear-gradient(135deg,#0f3a2a,#081828);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:16px;z-index:99999;font-family:Arial,sans-serif;">
  <svg width="64" height="64" viewBox="0 0 64 64" fill="none"><circle cx="32" cy="32" r="28" stroke="#4a9d8f" stroke-width="4" stroke-dasharray="44 132" style="transform-origin:center;animation:spin 1s linear infinite"/><style>@keyframes spin{to{transform:rotate(360deg)}}</style></svg>
  <div style="color:#5dd4c6;font-size:18px;font-weight:700;">PodoCLINIC</div>
  <div style="color:rgba(255,255,255,0.45);font-size:13px;">Iniciando sistema...</div>
</div>
<!-- PRE-REACT ERROR PANEL (shown on global JS errors) -->
<div id="pre-error" style="display:none;position:fixed;inset:0;background:linear-gradient(135deg,#0f3a2a,#081828);align-items:center;justify-content:center;z-index:99999;font-family:Arial,sans-serif;">
  <div style="background:#fff;border-radius:16px;padding:36px 44px;max-width:500px;width:90%;text-align:center;box-shadow:0 24px 64px rgba(0,0,0,0.4);">
    <div style="font-size:52px;margin-bottom:12px;">⚠️</div>
    <div style="font-size:18px;font-weight:700;color:#1a2332;margin-bottom:8px;">Error al Iniciar</div>
    <div style="font-size:12.5px;color:#8a9aaa;margin-bottom:16px;">Se produjo un error al cargar la aplicación.</div>
    <div id="pre-error-msg" style="background:#fff3cd;border:1px solid #ffc107;border-radius:8px;padding:10px 14px;margin-bottom:20px;font-size:11.5px;color:#856404;text-align:left;font-family:monospace;word-break:break-all;max-height:100px;overflow-y:auto;"></div>
    <button onclick="window.location.reload()" style="padding:10px 32px;background:linear-gradient(135deg,#4a9d8f,#3a8d80);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:700;cursor:pointer;">🔄 Recargar</button>
  </div>
</div>
<div id="root"></div>
<script>
// Hide pre-loader once React mounts (root div gets content)
var _obs=new MutationObserver(function(){
  var r=document.getElementById('root');
  if(r&&r.children.length>0){
    var l=document.getElementById('pre-loader');
    if(l)l.style.display='none';
    _obs.disconnect();
  }
});
_obs.observe(document.getElementById('root'),{childList:true,subtree:false});
// Dynamic loading messages while Babel compiles
var _msgs=['Iniciando sistema...','Compilando interfaz...','Cargando módulos...','Conectando con el servidor...','Preparando datos...','Casi listo...'];
var _mi=0;
var _loaderText=document.querySelector('#pre-loader div:last-of-type');
var _msgInterval=setInterval(function(){
  _mi=(_mi+1)%_msgs.length;
  if(_loaderText)_loaderText.textContent=_msgs[_mi];
},4000);
// Safety timeout: hide loader after 60s regardless
setTimeout(function(){
  clearInterval(_msgInterval);
  var l=document.getElementById('pre-loader');
  if(l&&l.style.display!=='none'){
    l.style.display='none';
    var e=document.getElementById('pre-error');
    var m=document.getElementById('pre-error-msg');
    if(e&&m){e.style.display='flex';m.textContent='Timeout: La aplicación tardó demasiado en cargar. Verifique que el servidor backend esté corriendo en el puerto 3737.';}
  }
},60000);
</script>
<script type="text/babel">
const {useState,useEffect,useRef,useCallback,useMemo}=React;

// ─── PHP API CLIENT ────────────────────────────────────────────────────────────
// Auto-detecta el subdirectorio donde está instalado (raíz / ó subdirectorio /podoclinic/)
const API_BASE=(()=>{const p=window.location.pathname;const base=p.endsWith('/')?p:p.substring(0,p.lastIndexOf('/')+1);return window.location.origin+base+'api';})();
const _cache={};
const _pendingGets={};
let _authToken=localStorage.getItem('podo_token')||'';
const apiEndpoint=(endpoint)=>endpoint.replace(/^\/(auth|crud|special)(?=\?|$)/,'/$1.php');
const isAuthExpiredMessage=msg=>/sesión inválida|sesion invalida|expirada|no autenticado/i.test(String(msg||""));
const makeApiError=(msg,status=0)=>{
  const err=new Error(msg||`HTTP ${status}`);
  err.status=status;
  err.authExpired=status===401&&isAuthExpiredMessage(msg);
  return err;
};
const clearExpiredSession=()=>{
  _authToken="";
  localStorage.removeItem('podo_token');
  Object.keys(_cache).filter(k=>k!=='pmb_module_perms'&&k!=='pmb_module_locked_off').forEach(k=>delete _cache[k]);
  window.dispatchEvent(new CustomEvent('podo-auth-expired'));
};
const safeJson=(raw,fallback=[])=>{
  if(raw===undefined||raw===null||raw==='')return fallback;
  if(Array.isArray(raw)||typeof raw==='object')return raw;
  try{return JSON.parse(raw);}catch{return fallback;}
};
const runWhenIdle=(cb)=>{
  if(typeof window!=="undefined"&&window.requestIdleCallback)return window.requestIdleCallback(cb,{timeout:1800});
  return setTimeout(cb,0);
};
const appointmentStatusOf=(appt,attendances=[])=>{
  const st=String(appt?.status||"pending").trim().toLowerCase();
  if(["done","attended","atendida","atendido"].includes(st))return "done";
  if(["cancelled","cancelado","cancelada"].includes(st))return "cancelled";
  const paid=attendances.some(a=>{
    const sameAppointment=appt?.id&&String(a.appointmentId||a.appointment_id||"")===String(appt.id);
    const samePatientDate=String(a.patientId||a.patient_id||"")===String(appt?.patientId||appt?.patient_id||"")&&String(a.date||"").slice(0,10)===String(appt?.date||"").slice(0,10);
    const sameService=!appt?.service||!a.service||String(a.service).trim().toLowerCase()===String(appt.service).trim().toLowerCase();
    return (sameAppointment||(samePatientDate&&sameService))&&(a.closed||a.payStatus==="pagado"||a.pay_status==="pagado");
  });
  if(paid)return "done";
  if(["confirmed","confirmado","confirmada"].includes(st))return "confirmed";
  return "pending";
};
const appointmentStatusLabel={pending:"Pendiente",confirmed:"Confirmada",done:"Atendida",cancelled:"Cancelada"};
const appointmentStatusColor={pending:"blue",confirmed:"purple",done:"green",cancelled:"gray"};
const appointmentPodologa=(appt,attendances=[])=>{
  if(appt?.podologa)return appt.podologa;
  if(appt?.attendedBy)return appt.attendedBy;
  if(appt?.attended_by)return appt.attended_by;
  const att=attendances.find(a=>{
    const sameAppointment=appt?.id&&String(a.appointmentId||a.appointment_id||"")===String(appt.id);
    const samePatientDate=String(a.patientId||a.patient_id||"")===String(appt?.patientId||appt?.patient_id||"")&&String(a.date||"").slice(0,10)===String(appt?.date||"").slice(0,10);
    return sameAppointment||samePatientDate;
  });
  return att?.attendedBy||att?.attended_by||"";
};
const patientHasClinicalHistory=(p)=>{
  if(!p)return false;
  return !!(
    (Array.isArray(p.pathologies)&&p.pathologies.length>0)||
    (Array.isArray(p.pathAnt)&&p.pathAnt.length>0)||
    (Array.isArray(p.path_ant)&&p.path_ant.length>0)||
    String(p.location||p.triggers||p.notes||p.background||p.antecedentes||"").trim()
  );
};

// ── REACTIVE STORE ──────────────────────────────────────────────────────────
// Notifica a los componentes cuando _cache se actualiza
// Elimina la necesidad de refrescar manualmente la página
const _subscribers={};
const _notifyKey=(key)=>{
  if(typeof key!=="string"||!key)return;
  const mk=key.replace(/^pmb_/,'');
  const cbs=[...(_subscribers[key]||[]),...(_subscribers[mk]||[])];
  cbs.forEach(cb=>{try{cb(_cache[key]??_cache[mk]);}catch{}});
};
const _subscribe=(key,cb)=>{
  if(typeof key!=="string"||!key)return()=>{};
  const mk=key.replace(/^pmb_/,'');
  [key,mk].forEach(k=>{
    if(!_subscribers[k])_subscribers[k]=new Set();
    _subscribers[k].add(cb);
  });
  return ()=>[key,mk].forEach(k=>_subscribers[k]&&_subscribers[k].delete(cb));
};

// Hook: useStore(SK.patients) → retorna datos vivos del cache, se actualiza automáticamente
const useStore=(skKey,defaultVal=[])=>{
  const [val,setVal]=useState(()=>{
    if(typeof skKey!=="string"||!skKey)return defaultVal;
    const mk=skKey.replace(/^pmb_/,'');
    return _cache[skKey]??_cache[mk]??defaultVal;
  });
  useEffect(()=>{
    if(typeof skKey!=="string"||!skKey){setVal(defaultVal);return()=>{};}
    // Actualizar inmediatamente si ya hay datos en cache
    const mk=skKey.replace(/^pmb_/,'');
    const current=_cache[skKey]??_cache[mk];
    if(current!==undefined&&current!==null)setVal(current);
    // Suscribirse a futuras actualizaciones
    const unsub=_subscribe(skKey,(newVal)=>{
      if(newVal!==undefined&&newVal!==null)setVal(newVal);
    });
    return unsub;
  },[skKey]);
  return val;
};

const wait=ms=>new Promise(resolve=>setTimeout(resolve,ms));
const parseApiJsonText=(txt,endpoint='API')=>{
  if(!txt)return {};
  try{return JSON.parse(txt);}
  catch(err){}

  const cleaned=String(txt).trim().replace(/^[^\[{]+/,'');
  const extractFirstJson=(raw)=>{
    if(!raw)return '';
    const stack=[];
    let inString=false,escaped=false,started=false,start=0;
    for(let i=0;i<raw.length;i++){
      const ch=raw[i];
      if(!started){
        if(ch==='{'||ch==='['){started=true;start=i;stack.push(ch==='{'?'}':']');}
        continue;
      }
      if(inString){
        if(escaped)escaped=false;
        else if(ch==='\\')escaped=true;
        else if(ch==='"')inString=false;
        continue;
      }
      if(ch==='"')inString=true;
      else if(ch==='{'||ch==='[')stack.push(ch==='{'?'}':']');
      else if(ch==='}'||ch===']'){
        if(!stack.length||stack[stack.length-1]!==ch)break;
        stack.pop();
        if(!stack.length)return raw.slice(start,i+1);
      }
    }
    return started?raw.slice(start):raw;
  };

  const candidate=extractFirstJson(cleaned);
  if(candidate){
    try{return JSON.parse(candidate);}
    catch(parseErr){}
  }
  throw new Error(`Respuesta no valida del servidor en ${endpoint}: ${String(txt).slice(0,180)}`);
};
const apiFetch=async(endpoint,opts={})=>{
  const {timeoutMs=20000,retries,...fetchOpts}=opts;
  const headers={'Content-Type':'application/json','Cache-Control':'no-cache','Pragma':'no-cache',...(fetchOpts.headers||{})};
  if(_authToken) headers['X-Auth-Token']=_authToken;
  // Agregar timestamp para romper cache del navegador en GETs
  const resolvedEndpoint=apiEndpoint(endpoint);
  const sep=resolvedEndpoint.includes('?')?'&':'?';
  const method=(fetchOpts.method||'GET').toUpperCase();
  const url=API_BASE+resolvedEndpoint+(method!=='GET'?'':sep+'_t='+Date.now());
  const attempts=(retries!==undefined?retries:(method==='GET'?1:0))+1;
  let lastError=null;
  for(let attempt=0;attempt<attempts;attempt++){
    const ctrl=new AbortController();
    const id=setTimeout(()=>ctrl.abort(),timeoutMs);
    try{
      const r=await fetch(url,{...fetchOpts,headers,signal:fetchOpts.signal||ctrl.signal});
      const parseResponse=async()=>{
        const txt=await r.text();
        return parseApiJsonText(txt,resolvedEndpoint);
      };
      if(!r.ok){
        const e=await parseResponse().catch(()=>({error:`HTTP ${r.status}`}));
        const apiErr=makeApiError(e.error||`HTTP ${r.status}`,r.status);
        if(apiErr.authExpired)clearExpiredSession();
        throw apiErr;
      }
      return parseResponse();
    }catch(e){
      lastError=e?.name==='AbortError'
        ?new Error(`Tiempo de espera agotado al consultar ${resolvedEndpoint}`)
        :e;
      if(attempt<attempts-1&&method==='GET'){
        await wait(350*(attempt+1));
        continue;
      }
      throw lastError;
    }finally{
      clearTimeout(id);
    }
  }
  throw lastError||new Error(`No se pudo consultar ${resolvedEndpoint}`);
};

// SK = Storage Keys (mantenidos para compatibilidad con todos los módulos)
const SK={patients:"pmb_patients",appointments:"pmb_appointments",users:"pmb_users",
  services:"pmb_services",attendances:"pmb_attendances",payments:"pmb_payments",
  cashbox:"pmb_cashbox",inventory:"pmb_inventory",commissions:"pmb_commissions",
  suppliers:"pmb_suppliers",salesProducts:"pmb_sales_products",salesServices:"pmb_sales_services",
  company:"pmb_company",categories:"pmb_categories",memberships:"pmb_memberships",
  photos:"pmb_photos",laboratory:"pmb_laboratory",documents:"pmb_documents",
  salesOrders:"pmb_sales_orders",modulePerms:"pmb_module_perms",
  partialCuts:"pmb_partial_cuts",kpiSettings:"pmb_kpi_settings"};

// Mapa SK → entidad PHP
const SK_API={
  pmb_patients:'patients', pmb_appointments:'appointments', pmb_users:'users',
  pmb_services:'services', pmb_attendances:'attendances', pmb_payments:'payments',
  pmb_inventory:'inventory', pmb_suppliers:'suppliers',
  pmb_sales_products:'sales_products', pmb_sales_services:'sales_services',
  pmb_company:'company_obj', pmb_categories:'categories',
  pmb_laboratory:'laboratory', pmb_photos:'photos', pmb_documents:null,
  pmb_commission_scheme:'commission_scheme_obj', pmb_memberships:'memberships',
  pmb_sales_orders:'sales_orders', pmb_module_perms:'module_perms_obj',
  pmb_partial_cuts:'cashbox_cuts',
};

const api={
  async get(entityOrSkKey,options={}){
    const apiKey=SK_API['pmb_'+entityOrSkKey]||SK_API[entityOrSkKey]||entityOrSkKey;
    const pendingKey=String(apiKey||entityOrSkKey);
    if(!options.force&&_pendingGets[pendingKey])return _pendingGets[pendingKey];
    const cached=_cache[entityOrSkKey]??_cache[apiKey];
    if(!options.refresh&&cached!==undefined&&cached!==null)return cached;
    if(!apiKey||apiKey.endsWith('_obj')){
      // Objetos singleton (company, commission_scheme, module_perms)
      const base=apiKey?apiKey.replace('_obj',''):'company';
      _pendingGets[pendingKey]=(async()=>{
      try{
        const d=await apiFetch('/special?action='+base);
        _cache[entityOrSkKey]=d;
        _cache[base]=d;
        _notifyKey(entityOrSkKey);
        _notifyKey(base);
        return d;
      }catch{return _cache[entityOrSkKey]||null;}
      })().finally(()=>{delete _pendingGets[pendingKey];});
      return _pendingGets[pendingKey];
    }
    // Listas
    _pendingGets[pendingKey]=(async()=>{
    try{
      const pageSize=options.pageSize||1000;
      let offset=0;
      let total=null;
      let rows=[];
      do{
        const d=await apiFetch('/crud?entity='+apiKey+'&limit='+pageSize+'&offset='+offset);
        const page=Array.isArray(d)?d:(d.data||[]);
        if(!Array.isArray(page))throw new Error(`Formato inesperado al cargar ${apiKey}`);
        rows=rows.concat(page);
        total=Array.isArray(d)?rows.length:Number(d.total||0);
        offset+=page.length;
        if(page.length===0)break;
      }while(offset<total);
      // Normalizar snake_case → camelCase para entidades clave del servidor
      if(apiKey==='appointments'||entityOrSkKey==='appointments'){
        rows=rows.map(a=>({...a,
          patientId: a.patientId||a.patient_id||null,
          patient_id: a.patient_id||a.patientId||null,
        }));
      }
      if(apiKey==='attendances'||entityOrSkKey==='attendances'){
        rows=rows.map(a=>({...a,
          patientId:    a.patientId||a.patient_id||null,
          patient_id:    a.patient_id||a.patientId||null,
          patientDni:   String(a.patientDni||a.patient_dni||''),
          patient_dni:  String(a.patient_dni||a.patientDni||''),
          patientName:  a.patientName||a.patient_name||`${a.first_name||''} ${a.last_name||''}`.trim()||'',
          patient_name: a.patient_name||a.patientName||`${a.first_name||''} ${a.last_name||''}`.trim()||'',
          attendedBy:   a.attendedBy||a.attended_by||'',
          attended_by:  a.attended_by||a.attendedBy||'',
          payMethod:    a.payMethod||a.pay_method||a.paidMethod||a.paid_method||'Efectivo',
          pay_method:   a.pay_method||a.payMethod||a.paid_method||a.paidMethod||'Efectivo',
          payStatus:    String(a.payStatus||a.pay_status||'pendiente').trim().toLowerCase(),
          pay_status:   String(a.pay_status||a.payStatus||'pendiente').trim().toLowerCase(),
          closed:       a.closed===true||a.closed===1||["1","true","si","sí","cerrado"].includes(String(a.closed||"").trim().toLowerCase()),
        }));
      }
      if(apiKey==='sales_orders'||entityOrSkKey==='sales_orders'){
        rows=rows.map(o=>({...o,
          dniRuc:      o.dniRuc||o.dni_ruc||'',
          razonSocial: o.razonSocial||o.razon_social||'',
          assignedTo:  o.assignedTo||o.assigned_to||'',
          payMethod:   o.payMethod||o.pay_method||o.paid_method||'Efectivo',
          paidAt:      o.paidAt||o.paid_at||'',
          createdBy:   o.createdBy||o.created_by||'',
        }));
      }
      if(apiKey==='inventory'||entityOrSkKey==='inventory'){
        rows=rows.map(p=>({...p,
          code:      p.code||'',
          code_type: p.code_type||'',
          price:     parseFloat(p.price||p.price_sell||0),
          cost:      parseFloat(p.cost||p.price_buy||0),
          stock:     parseInt(p.stock||0),
          minStock:  parseInt(p.minStock||p.min_stock||0),
          unit:      p.unit||'unidad',
        }));
      }
      if(apiKey==='patients'||entityOrSkKey==='patients'||entityOrSkKey==='pmb_patients'){
        rows=rows.map(p=>({
          ...p,
          // Asegurar ambos formatos para compatibilidad total
          firstName:  p.firstName||p.first_name||'',
          lastName:   p.lastName||p.last_name||'',
          first_name: p.first_name||p.firstName||'',
          last_name:  p.last_name||p.lastName||'',
          dob:        p.dob||null,
          sex:        p.sex||null,
          phone:      p.phone||'',
          dni:        String(p.dni??''),
          registrationDate: p.registrationDate||p.created_at||'',
          pathologies: Array.isArray(p.pathologies)?p.pathologies:safeJson(p.pathologies,[]),
          pathAnt:     Array.isArray(p.pathAnt)?p.pathAnt:(Array.isArray(p.path_ant)?p.path_ant:safeJson(p.path_ant,[])),
          zoneLeft:   Array.isArray(p.zoneLeft)?p.zoneLeft:(Array.isArray(p.zone_left)?p.zone_left:[]),
          zoneRight:  Array.isArray(p.zoneRight)?p.zoneRight:(Array.isArray(p.zone_right)?p.zone_right:[]),
          attendedBy: p.attendedBy||p.attended_by||'',
          shoeSize:   p.shoeSize||p.shoe_size||'',
          shoeType:   p.shoeType||p.shoe_type||'',
          physicalActivity: p.physicalActivity||p.physical_activity||'',
          emergencyContact: p.emergencyContact||p.emergency_contact||'',
          emergencyPhone:   p.emergencyPhone||p.emergency_phone||'',
          nailColor: p.nailColor||(p.nail_color?[p.nail_color]:[]),
          nailThickness: p.nailThickness||(p.nail_thick?[p.nail_thick]:[]),
          nailShape: p.nailShape||(p.nail_shape?[p.nail_shape]:[]),
          status: p.status||'active',
        }));
      }
      _cache[entityOrSkKey]=rows;
      _cache[apiKey]=rows;
      // Notificar a componentes suscritos → re-render automático sin refrescar
      _notifyKey(entityOrSkKey);
      _notifyKey(apiKey);
      _notifyKey('pmb_'+entityOrSkKey);
      return rows;
    }catch(e){
      console.warn('api.get',entityOrSkKey,e.message);
      if(options.strict)throw e;
      return Array.isArray(_cache[entityOrSkKey])?_cache[entityOrSkKey]:(_cache[entityOrSkKey]||[]);
    }
    })().finally(()=>{delete _pendingGets[pendingKey];});
    return _pendingGets[pendingKey];
  },
  async set(key,val){
    _cache[key]=val;
    _cache[key.replace('pmb_','')]=val;
    // Sync to server handled by individual modules via POST/PUT
  },
  async post(entityOrSkKey,item){
    const apiKey=SK_API['pmb_'+entityOrSkKey]||SK_API[entityOrSkKey]||entityOrSkKey;
    return apiFetch('/crud?entity='+apiKey,{method:'POST',body:JSON.stringify(item)});
  }
};

// db: interfaz sincrónica usando caché (igual que antes — mantiene compatibilidad total)
const warmupKeys=(keys)=>runWhenIdle(()=>{
  keys.forEach((key,idx)=>setTimeout(()=>api.get(key).catch(()=>{}),idx*45));
});

const db={
  get:(k)=>{
    const mk=k.replace(/^pmb_/,'').replace('_sales_products','sales_products').replace('_sales_services','sales_services');
    const v=_cache[k]??_cache[mk];
    if(v===undefined||v===null){
      const ARR=['patients','appointments','attendances','users','services','inventory',
        'suppliers','sales_products','sales_services','categories','payments',
        'laboratory','photos','sales_orders','memberships','cashbox_cuts'];
      if(ARR.some(a=>mk.includes(a)||k.includes(a)))return[];
      return null;
    }
    return v;
  },
  set:(k,v)=>{
    const mk=k.replace(/^pmb_/,'').replace('_sales_products','sales_products').replace('_sales_services','sales_services');
    _cache[k]=v; _cache[mk]=v;
    _notifyKey(k);
    _notifyKey(mk);
  }
};

// Función helper para operaciones CRUD desde módulos
const crudApi={
  async list(entity,params={}){
    const qs=new URLSearchParams({entity,...params,limit:5000}).toString();
    const d=await apiFetch('/crud?'+qs);
    return Array.isArray(d)?d:(d.data||[]);
  },
  async create(entity,data){return apiFetch('/crud?entity='+entity,{method:'POST',body:JSON.stringify(data)});},
  async update(entity,id,data){return apiFetch('/crud?entity='+entity+'&id='+id,{method:'PUT',body:JSON.stringify(data)});},
  async remove(entity,id){return apiFetch('/crud?entity='+entity+'&id='+id,{method:'DELETE'});},
  async special(action,data={},method='GET'){
    if(method==='GET'){
      const qs=new URLSearchParams({action,...data}).toString();
      return apiFetch('/special?'+qs);
    }
    return apiFetch('/special?action='+action,{method:'POST',body:JSON.stringify(data)});
  }
};

const serverPayload=(entity,row={})=>{
  const p={...row};
  const map={
    patientId:'patient_id',patientName:'patient_name',patientDni:'patient_dni',
    firstName:'first_name',lastName:'last_name',pathAnt:'path_ant',
    zoneLeft:'zone_left',zoneRight:'zone_right',shoeSize:'shoe_size',
    shoeType:'shoe_type',physicalActivity:'physical_activity',
    emergencyContact:'emergency_contact',emergencyPhone:'emergency_phone',
    customPathologies:'custom_pathologies',customAntecedents:'custom_antecedents',
    customTags:'custom_tags',attendedBy:'attended_by',payMethod:'pay_method',
    payStatus:'pay_status',registeredAt:'registered_at',appointmentId:'appointment_id',
    orderItems:'order_items',minStock:'min_stock',validityDays:'validity_days',
    monthlyFee:'monthly_fee',annualFee:'annual_fee',discountPct:'discount_pct',
    currencyCode:'currency_code',aiApiKey:'ai_api_key',assignedTo:'assigned_to',
    dniRuc:'dni_ruc',razonSocial:'razon_social',createdBy:'created_by',
    paidAt:'paid_at',paidMethod:'paid_method',byMethod:'by_method',byVendor:'by_vendor'
  };
  Object.entries(map).forEach(([from,to])=>{if(p[from]!==undefined&&p[to]===undefined)p[to]=p[from];});
  if(entity==='memberships'){
    if(p.price===undefined)p.price=parseFloat(p.monthlyFee||p.monthly_fee||0)||0;
    if(p.description===undefined)p.description=p.benefits||'';
  }
  if(entity==='inventory'||entity==='sales_products'){
    if(p.min_stock===undefined)p.min_stock=parseInt(p.minStock||0)||0;
    if(p.cost===undefined&&p.price_buy!==undefined)p.cost=p.price_buy;
  }
  if(entity==='services'||entity==='sales_services'||entity==='sales_products'||entity==='inventory'){
    if(p.active!==undefined)p.active=p.active?1:0;
  }
  return p;
};

const saveCrudAndSync=async(entity,row,sk,setter,tempId)=>{
  const payload=serverPayload(entity,row);
  const saved=row.id&&String(row.id)!==String(tempId)
    ?await crudApi.update(entity,row.id,payload)
    :await crudApi.create(entity,payload);
  if(sk){
    const current=db.get(sk)||[];
    const matchId=String(tempId||row.id||saved?.id);
    let replaced=false;
    const next=current.map(x=>{
      if(String(x.id)===matchId||String(x.id)===String(saved?.id)){replaced=true;return{...x,...row,...saved,id:saved?.id||x.id};}
      return x;
    });
    if(!replaced)next.push({...row,...saved,id:saved?.id||row.id});
    db.set(sk,next);
    if(setter)setter(next);
  }
  return saved;
};

const removeCrudAndSync=async(entity,id,sk,setter)=>{
  await crudApi.remove(entity,id);
  if(sk){
    const next=(db.get(sk)||[]).filter(x=>String(x.id)!==String(id));
    db.set(sk,next);
    if(setter)setter(next);
  }
  return true;
};

// ─── ROLES & PERMISSIONS ──────────────────────────────────────────────────────
const ALL_PERMS=["dashboard","patients","appointments","reports","config","admin","payments","cashbox","inventory","commissions","corte","reminders","portal","laboratory","photos","documents","library","ventas","suppliers"];
const ROLES={
  "Super Admin":{label:"Super Admin",color:"purple",perms:ALL_PERMS},
  Administrador:{label:"Administrador",color:"red",perms:["dashboard","patients","appointments","reports","config","admin","payments","cashbox","inventory","commissions","corte","reminders","portal","laboratory","photos","documents","library","ventas","suppliers"]},
  Podólogo:{label:"Podólogo",color:"blue",perms:["dashboard","patients","appointments","reports","payments","laboratory","photos"]},
  Recepcionista:{label:"Recepcionista",color:"green",perms:["dashboard","patients","appointments","cashbox","reminders","portal"]},
};
const PODO_FUNCTIONS=["Atención Clínica","Venta de Productos","Recepción","Laboratorio","Control de Fotos","Documentos","Inventarios","Comisiones"];

// Lista de todas las herramientas/licencias del sistema
const SYSTEM_TOOLS=[
  {id:"patients",label:"Gestión de Pacientes",icon:"👥",category:"Clínica"},
  {id:"appointments",label:"Agenda / Citas",icon:"📅",category:"Clínica"},
  {id:"laboratory",label:"Laboratorio",icon:"🔬",category:"Clínica"},
  {id:"photos",label:"Control de Fotos",icon:"📷",category:"Clínica"},
  {id:"documents",label:"Documentos Clínicos",icon:"📄",category:"Clínica"},
  {id:"ventas",label:"Punto de Venta",icon:"🛒",category:"Comercial"},
  {id:"inventory",label:"Inventario",icon:"📦",category:"Comercial"},
  {id:"suppliers",label:"Proveedores",icon:"🚚",category:"Comercial"},
  {id:"cashbox",label:"Caja",icon:"💰",category:"Finanzas"},
  {id:"payments",label:"Cobros / Pagos",icon:"💳",category:"Finanzas"},
  {id:"commissions",label:"Comisiones",icon:"💹",category:"Finanzas"},
  {id:"corte",label:"Corte de Caja",icon:"✂️",category:"Finanzas"},
  {id:"reports",label:"Reportes y Analytics",icon:"📊",category:"Gestión"},
  {id:"reminders",label:"Recordatorios",icon:"🔔",category:"Gestión"},
  {id:"portal",label:"Portal Web",icon:"🌐",category:"Gestión"},
  {id:"library",label:"Biblioteca Médica",icon:"📚",category:"Gestión"},
];

// KPIs disponibles del dashboard
const SYSTEM_KPIS=[
  {id:"atencionesHoy",label:"Atenciones de Hoy",icon:"🩺",desc:"Cantidad de pacientes atendidos hoy"},
  {id:"porCobrar",label:"Por Cobrar",icon:"💳",desc:"Monto pendiente de cobro"},
  {id:"ingresosHoy",label:"Ingresos del Día",icon:"💵",desc:"Total cobrado hoy"},
  {id:"citasPendientes",label:"Citas Pendientes",icon:"📅",desc:"Citas sin confirmar o próximas"},
  {id:"pacientesNuevos",label:"Pacientes Nuevos",icon:"🆕",desc:"Altas del mes actual"},
  {id:"ticketPromedio",label:"Ticket Promedio",icon:"📈",desc:"Valor promedio por atención"},
];

// Helper: leer datos de permiso con fallback seguro
const _getModuleData=(key,defaultVal)=>{
  // Busca en: cache → db → localStorage → default
  // Usa función auxiliar para evitar el bug de {} truthy que rompe ||
  const fromCache=_cache[key];
  if(fromCache!==undefined&&fromCache!==null)return fromCache;
  const fromDb=typeof db!=="undefined"?db.get(key):null;
  if(fromDb!==undefined&&fromDb!==null)return fromDb;
  try{
    const raw=typeof localStorage!=="undefined"?localStorage.getItem(key):null;
    if(raw)return JSON.parse(raw);
  }catch{}
  return defaultVal;
};

const isAdminPrincipalUser=user=>(
  String(user?.username||'').trim().toLowerCase()==='admin'||
  String(user?.name||'').trim().toLowerCase()==='admin principal'
);

const can=(user,perm)=>{
  if(!user)return false;
  if(user.role==="Super Admin")return true;

  const isAdminPrincipal=isAdminPrincipalUser(user);
  if(isAdminPrincipal&&perm==='corte')return true;

  // 1. lockedOff: módulos que SA desactivó — tienen prioridad absoluta
  const lockedOff=_getModuleData('pmb_module_locked_off',{});
  if((lockedOff[user.role]||[]).includes(perm))return false;

  // 2. Permisos dinámicos del servidor (guardados al init o al guardar en PermsTab)
  const dynPerms=_getModuleData('pmb_module_perms',null)
    ||_getModuleData(SK.modulePerms,null);
  if(dynPerms&&dynPerms[user.role]&&Array.isArray(dynPerms[user.role])){
    return dynPerms[user.role].includes(perm);
  }

  // 3. Fallback: permisos estáticos por rol (cuando BD no ha devuelto datos aún)
  return(ROLES[user.role]?.perms||[]).includes(perm);
};
const isSA=(user)=>user?.role==="Super Admin";

// ─── DEFAULTS ─────────────────────────────────────────────────────────────────
const DEF_USERS=[
  {id:0,username:"superadmin",password:"super123",role:"Super Admin",name:"Super Administrador",active:true,podoFunctions:PODO_FUNCTIONS},
  {id:1,username:"admin",password:"admin123",role:"Administrador",name:"Admin Principal",active:true,podoFunctions:PODO_FUNCTIONS},
  {id:2,username:"podologa",password:"podo123",role:"Podólogo",name:"Dra. Bela Ramos",active:true,podoFunctions:["Atención Clínica","Laboratorio","Control de Fotos"]},
  {id:3,username:"recep",password:"recep123",role:"Recepcionista",name:"Lucía Torres",active:true,podoFunctions:["Recepción","Venta de Productos"]},
];
const DEF_SERVICES=[
  {id:1,name:"Consulta General",price:50,duration:30,category:"Consulta",active:true},
  {id:2,name:"Tratamiento de Uñas",price:80,duration:45,category:"Tratamiento",active:true},
  {id:3,name:"Podología Quirúrgica",price:150,duration:60,category:"Quirúrgico",active:true},
  {id:4,name:"Plantillas Ortopédicas",price:200,duration:60,category:"Ortopedia",active:true},
  {id:5,name:"Reflexología",price:120,duration:60,category:"Terapia",active:true},
  {id:6,name:"Onicomicosis",price:90,duration:45,category:"Tratamiento",active:true},
];
const DEF_CATEGORIES=[
  {id:1,name:"Biomecánica",color:"#2563eb",type:"service"},
  {id:2,name:"Masajes y Terapias",color:"#2ea87e",type:"service"},
  {id:3,name:"Medicina Alternativa",color:"#7c3aed",type:"service"},
  {id:4,name:"Ortesis y Plantillas",color:"#f59223",type:"service"},
  {id:5,name:"Servicios Podológicos",color:"#4a9d8f",type:"service"},
  {id:6,name:"Tratamientos para la piel",color:"#e05050",type:"product"},
  {id:7,name:"Consulta",color:"#0891b2",type:"service"},
  {id:8,name:"Quirúrgico",color:"#dc2626",type:"service"},
];
const PATHOLOGIES=["Onicomicosis","Uña Encarnada","Hallux Valgus","Pie Plano","Pie Cavo","Metatarsalgia","Fascitis Plantar","Verruga Plantar","Heloma","Callosidad","Fisura Plantar","Bromhidrosis","Hiperhidrosis","Espolón Calcáneo","Artritis","Neuropatía Diabética"];
const PATHO_ANT=["Hipertensión","Diabetes","Artrosis","Artritis","Varices","Parkinson","Hepatitis A","Hepatitis B","Hepatitis C"];
const SHOE_TYPES=["Zapatilla deportiva","Zapato formal","Bota","Sandalia","Chancleta","Mocasín","Zapato ortopédico","Calzado de seguridad"];
const ZONES_L=["Anhidrosis","Bromhidrosis","Espolón Calcáneo","Fascitis Plantar","Heloma Plantar","Hiperhidrosis","Metatarsalgia","Verruga Plantar","Micosis Plantar"];
const ZONES_R=[...ZONES_L];
const NAIL_COLORS=["Amarillo","Negro","Verde","Blanco","Marrón"];
const NAIL_THICK=["Engrosada","Muy gruesa","Delgada","Normal"];
const NAIL_SHAPE=["Teja","Grapa","Cucharilla","Normal"];
const PAY_METHODS=["Efectivo","Yape","Plin","Tarjeta Débito","Tarjeta Crédito","Transferencia"];

// ─── HELPERS ──────────────────────────────────────────────────────────────────
const calcAge=dob=>{if(!dob)return"";const t=new Date(),b=new Date(dob);let a=t.getFullYear()-b.getFullYear();if(t.getMonth()<b.getMonth()||(t.getMonth()===b.getMonth()&&t.getDate()<b.getDate()))a--;return a};
const todayStr=()=>new Date().toLocaleDateString("en-CA",{timeZone:"America/Lima"});
const fmt=d=>{if(!d)return"—";const[y,m,dd]=d.split("-");return`${dd}/${m}/${y}`};
const genId=list=>list.length===0?1:Math.max(...list.map(x=>x.id))+1;
const padId=id=>String(id).padStart(6,"0");
const getCurrency=()=>{try{return(db.get(SK.company)||{currency:"S/"}).currency||"S/"}catch{return"S/"}};
const currency=n=>n!=null?`${getCurrency()} ${parseFloat(n).toFixed(2)}`:"—";
const monthName=m=>["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"][m];

// ─── LOGO IMAGEN REAL ─────────────────────────────────────────────────────────
const LOGO_SRC="data:image/png;base64, ";
const Logo=({size=52,style={}})=>(
  <img src={LOGO_SRC} alt="Podología Más Bela" style={{width:size,height:size,objectFit:"contain",borderRadius:"50%",...style}}/>
);

// ─── ICONS ────────────────────────────────────────────────────────────────────
const Icon=({name,size=18})=>{
  const ic={
    users:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>,
    calendar:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>,
    file:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>,
    book:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>,
    flask:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 3h6l3 9H6L9 3z"/><path d="M6 12l-2 6a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1l-2-6"/></svg>,
    camera:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>,
    box:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>,
    percent:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="19" y1="5" x2="5" y2="19"/><circle cx="6.5" cy="6.5" r="2.5"/><circle cx="17.5" cy="17.5" r="2.5"/></svg>,
    scissors:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><line x1="20" y1="4" x2="8.12" y2="15.88"/><line x1="14.47" y1="14.48" x2="20" y2="20"/><line x1="8.12" y1="8.12" x2="12" y2="12"/></svg>,
    bell:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>,
    globe:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>,
    cake:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 21v-8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8"/><path d="M4 16s.5-1 2-1 2.5 2 4 2 2.5-2 4-2 2.5 2 4 2 2-1 2-1"/><path d="M2 21h20"/><path d="M7 8v2"/><path d="M12 8v2"/><path d="M17 8v2"/><path d="M7 4h.01"/><path d="M12 4h.01"/><path d="M17 4h.01"/></svg>,
    settings:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>,
    chart:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>,
    plus:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>,
    search:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>,
    edit:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>,
    trash:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>,
    close:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>,
    check:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><polyline points="20 6 9 17 4 12"/></svg>,
    photo:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>,
    logout:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>,
    eye:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>,
    lock:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>,
    map:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>,
    dollar:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>,
    ai:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7h1V5.73c-.6-.34-1-.99-1-1.73a2 2 0 0 1 2-2z"/><circle cx="9" cy="14" r="1" fill="currentColor"/><circle cx="15" cy="14" r="1" fill="currentColor"/></svg>,
    cash:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/></svg>,
    shield:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>,
    trend:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/></svg>,
    info:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>,
    arrow:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>,
    receipt:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 2v20l3-2 3 2 3-2 3 2 3-2V2z"/><line x1="9" y1="9" x2="15" y2="9"/><line x1="9" y1="13" x2="15" y2="13"/></svg>,
    star:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>,
    truck:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="1" y="3" width="15" height="13"/><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg>,
    tag:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>,
    shop:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>,
    image:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>,
    palette:<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>,
  };
  return ic[name]||null;
};

// ─── UI BASE ──────────────────────────────────────────────────────────────────
const Field=({label,children,required,col,hint})=>(
  <div style={{marginBottom:14,gridColumn:col}}>
    <label style={{display:"block",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",marginBottom:5}}>
      {label}{required&&<span style={{color:"#e05050",marginLeft:2}}>*</span>}
    </label>
    {children}
    {hint&&<div style={{fontSize:10.5,color:"#9aacb8",marginTop:3}}>{hint}</div>}
  </div>
);
const inp={width:"100%",padding:"9px 12px",border:"1.5px solid #d4dde5",borderRadius:8,fontSize:13.5,background:"#fff",outline:"none",transition:"border-color .15s,box-shadow .15s",color:"#1a2332"};
const Inp=({style,...p})=><input {...p} style={{...inp,...style}} onFocus={e=>{e.target.style.borderColor="#4a9d8f";e.target.style.boxShadow="0 0 0 3px #4a9d8f18"}} onBlur={e=>{e.target.style.borderColor="#d4dde5";e.target.style.boxShadow="none"}}/>;
const Sel=({children,style,...p})=><select {...p} style={{...inp,cursor:"pointer",...style}} onFocus={e=>{e.target.style.borderColor="#4a9d8f";e.target.style.boxShadow="0 0 0 3px #4a9d8f18"}} onBlur={e=>{e.target.style.borderColor="#d4dde5";e.target.style.boxShadow="none"}}>{children}</select>;
const TA=({style,...p})=><textarea {...p} style={{...inp,resize:"vertical",minHeight:70,...style}} onFocus={e=>{e.target.style.borderColor="#4a9d8f";e.target.style.boxShadow="0 0 0 3px #4a9d8f18"}} onBlur={e=>{e.target.style.borderColor="#d4dde5";e.target.style.boxShadow="none"}}/>;

const Btn=({children,variant="primary",size="md",onClick,disabled,style={}})=>{
  const base={display:"inline-flex",alignItems:"center",gap:6,fontFamily:"'Outfit',sans-serif",fontWeight:600,borderRadius:9,cursor:disabled?"not-allowed":"pointer",border:"none",transition:"all .15s",opacity:disabled?.5:1,...style};
  const sz={xs:{padding:"4px 10px",fontSize:11.5},sm:{padding:"5px 12px",fontSize:12},md:{padding:"8px 18px",fontSize:13.5},lg:{padding:"12px 26px",fontSize:15}}[size];
  const vs={
    primary:{background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",boxShadow:"0 2px 8px #4a9d8f44"},
    secondary:{background:"#e8edf2",color:"#3a5a6a"},
    danger:{background:"linear-gradient(135deg,#e05050,#c83030)",color:"#fff"},
    ghost:{background:"transparent",color:"#4a9d8f",border:"1.5px solid #4a9d8f"},
    success:{background:"linear-gradient(135deg,#2ea87e,#1a9060)",color:"#fff"},
    warning:{background:"linear-gradient(135deg,#f59223,#e07d10)",color:"#fff"},
    dark:{background:"linear-gradient(135deg,#1a2332,#0f1828)",color:"#fff"},
    purple:{background:"linear-gradient(135deg,#7c3aed,#5b21b6)",color:"#fff"},
  };
  return <button onClick={disabled?undefined:onClick} style={{...base,...sz,...vs[variant]}}>{children}</button>;
};

const Badge=({children,color="teal"})=>{
  const cs={teal:"#4a9d8f22|#2a7d70",blue:"#2563eb22|#1a50c0",green:"#2ea87e22|#1a8060",orange:"#f5922322|#c06a10",gray:"#8a9aaa22|#5a7a8a",red:"#e0505022|#c03030",purple:"#7c3aed22|#5b21b6",yellow:"#eab30822|#92700a"};
  const[bg,text]=(cs[color]||cs.teal).split("|");
  return <span style={{display:"inline-flex",alignItems:"center",padding:"2px 9px",borderRadius:20,fontSize:11,fontWeight:700,background:bg,color:text,whiteSpace:"nowrap"}}>{children}</span>;
};

const Card=({children,style={},className=""})=>(
  <div className={className} style={{background:"#fff",borderRadius:14,padding:20,boxShadow:"0 1px 4px rgba(0,0,0,0.06),0 4px 16px rgba(0,0,0,0.04)",...style}}>{children}</div>
);

const Modal=({title,children,onClose,width=680})=>(
  <div onClick={e=>{if(e.target===e.currentTarget)onClose()}} style={{position:"fixed",inset:0,background:"rgba(10,20,35,0.65)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:1000,padding:16,overflowY:"auto"}}>
    <div className="pop-in" style={{background:"#fff",borderRadius:18,width:"100%",maxWidth:width,maxHeight:"93vh",overflow:"auto",boxShadow:"0 24px 80px rgba(0,0,0,0.3)",margin:"auto"}}>
      <div style={{padding:"16px 24px",borderBottom:"1px solid #eef2f7",display:"flex",alignItems:"center",justifyContent:"space-between",position:"sticky",top:0,background:"#fff",zIndex:2,borderRadius:"18px 18px 0 0"}}>
        <h3 style={{fontSize:15.5,fontWeight:700,color:"#1a2332"}}>{title}</h3>
        <button onClick={onClose} style={{background:"#f0f4f8",border:"none",cursor:"pointer",color:"#5a7a8a",padding:6,borderRadius:8,display:"flex",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="#e0e8f0"} onMouseOut={e=>e.currentTarget.style.background="#f0f4f8"}><Icon name="close" size={16}/></button>
      </div>
      <div style={{padding:24}}>{children}</div>
    </div>
  </div>
);

const Tabs=({tabs,active,onChange})=>(
  <div style={{display:"flex",gap:2,borderBottom:"2px solid #eef2f7",marginBottom:20,flexWrap:"wrap"}}>
    {tabs.map(t=>(
      <button key={t.id} onClick={()=>onChange(t.id)} style={{padding:"8px 16px",fontSize:12.5,fontWeight:600,border:"none",background:"none",cursor:"pointer",color:active===t.id?"#4a9d8f":"#8a9aaa",borderBottom:active===t.id?"2.5px solid #4a9d8f":"2.5px solid transparent",marginBottom:-2,transition:"all .15s",borderRadius:"6px 6px 0 0",whiteSpace:"nowrap"}}>{t.label}</button>
    ))}
  </div>
);

const CBox=({label,checked,onChange})=>(
  <label style={{display:"flex",alignItems:"center",gap:7,cursor:"pointer",fontSize:12.5,color:"#3a5a6a",marginBottom:5,userSelect:"none"}}>
    <div onClick={onChange} style={{width:16,height:16,borderRadius:4,border:`2px solid ${checked?"#4a9d8f":"#c0d0dc"}`,background:checked?"#4a9d8f":"#fff",display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",flexShrink:0,transition:"all .15s"}}>
      {checked&&<Icon name="check" size={9}/>}
    </div>
    {label}
  </label>
);

const Stat=({emoji,label,value,sub,color="#4a9d8f",onClick,tooltip})=>{
  const[showTip,setShowTip]=useState(false);
  return(
    <div style={{position:"relative"}}>
      <Card style={{background:`linear-gradient(135deg,${color}12,${color}04)`,border:`1px solid ${color}20`,cursor:onClick||tooltip?"pointer":"default",transition:"transform .15s,box-shadow .15s"}}
        onMouseOver={e=>{e.currentTarget.style.transform="translateY(-2px)";e.currentTarget.style.boxShadow=`0 8px 24px ${color}22`}}
        onMouseOut={e=>{e.currentTarget.style.transform="none";e.currentTarget.style.boxShadow=""}}>
        <div onClick={()=>{if(onClick)onClick();if(tooltip)setShowTip(true)}} style={{userSelect:"none"}}>
          <div style={{fontSize:28,marginBottom:6}}>{emoji}</div>
          <div style={{fontSize:30,fontWeight:800,color,lineHeight:1,letterSpacing:"-0.02em"}}>{value}</div>
          <div style={{fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",marginTop:6}}>{label}</div>
          {sub&&<div style={{fontSize:10,color:"#9aacb8",marginTop:2}}>{sub}</div>}
          {tooltip&&<div style={{fontSize:9.5,color,marginTop:4,fontWeight:600}}>🔍 Ver detalle</div>}
        </div>
      </Card>
      {showTip&&tooltip&&(
        <div id="kpi-detail-print" style={{position:"fixed",top:"50%",left:"50%",transform:"translate(-50%,-50%)",background:"#fff",borderRadius:16,padding:"24px 28px",boxShadow:"0 24px 64px rgba(0,0,0,0.25)",zIndex:9999,minWidth:420,maxWidth:620,maxHeight:"82vh",overflowY:"auto"}}>
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:16}}>
            <div style={{fontSize:15,fontWeight:800,color:"#1a2332"}}>{emoji} {label}</div>
            <div style={{display:"flex",gap:8,alignItems:"center"}}>
              <button onClick={()=>{
                const el=document.getElementById("kpi-detail-print");
                const win=window.open("","_blank","width=700,height=600");
                win.document.write(`<html><head><title>${label}</title><style>body{font-family:Arial,sans-serif;font-size:13px;padding:24px}table{width:100%;border-collapse:collapse}th,td{padding:7px 10px;text-align:left;border-bottom:1px solid #e0e0e0}th{background:#f4f8fa;font-size:11px;text-transform:uppercase;letter-spacing:.05em}h2{color:#1a2332}@media print{button{display:none}}</style></head><body>`);
                win.document.write(`<h2>${emoji} ${label}</h2>`);
                win.document.write(el.querySelector(".kpi-print-body").innerHTML);
                win.document.write("</body></html>");
                win.document.close();win.focus();win.print();
              }} style={{padding:"5px 12px",borderRadius:8,border:"1.5px solid #4a9d8f",background:"#4a9d8f",color:"#fff",fontWeight:700,fontSize:12,cursor:"pointer",display:"flex",alignItems:"center",gap:5}}>🖨️ Imprimir</button>
              <button onClick={()=>setShowTip(false)} style={{background:"none",border:"none",cursor:"pointer",fontSize:20,color:"#8a9aaa",lineHeight:1,padding:"0 4px"}}>✕</button>
            </div>
          </div>
          <div className="kpi-print-body">{tooltip}</div>
        </div>
      )}
      {showTip&&<div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.3)",zIndex:9998}} onClick={()=>setShowTip(false)}/>}
    </div>
  );
};

// ─── DYNAMIC LIST FIELD ──────────────────────────────────────────────────────
const DynamicListField=({label,items,selected,onToggle,onAdd})=>{
  const[search,setSearch]=useState("");
  const[showAdd,setShowAdd]=useState(false);
  const[newVal,setNewVal]=useState("");
  const filtered=items.filter(i=>!search||i.toLowerCase().includes(search.toLowerCase()));
  const handleAdd=()=>{
    const v=newVal.trim();
    if(!v)return;
    onAdd(v);
    if(!selected.includes(v))onToggle(v);
    setNewVal("");setShowAdd(false);
  };
  return(
    <div>
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:8}}>
        <span style={{fontSize:12,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em"}}>{label}</span>
        <div style={{display:"flex",gap:6}}>
          <button onClick={()=>setSearch(s=>s===" "?"":s===""?" ":"")} title="Buscar" style={{background:"#f0f4f8",border:"1px solid #d4dde5",borderRadius:6,padding:"3px 8px",cursor:"pointer",display:"flex",alignItems:"center",gap:4,fontSize:11,color:"#4a9d8f",fontWeight:700}}>
            <Icon name="search" size={12}/>Buscar
          </button>
          <button onClick={()=>{setShowAdd(true);setSearch("")}} title="Agregar nuevo" style={{background:"#4a9d8f",border:"none",borderRadius:6,padding:"3px 8px",cursor:"pointer",display:"flex",alignItems:"center",gap:4,fontSize:11,color:"#fff",fontWeight:700}}>
            <Icon name="plus" size={12}/>Nuevo
          </button>
        </div>
      </div>
      {(search!==""||search===" ")&&(
        <div style={{marginBottom:8}}>
          <input value={search===" "?"":search} onChange={e=>setSearch(e.target.value||" ")} placeholder="Buscar en la lista..." autoFocus style={{width:"100%",padding:"6px 10px",border:"1.5px solid #4a9d8f",borderRadius:8,fontSize:13,outline:"none"}}/>
        </div>
      )}
      {showAdd&&(
        <div style={{display:"flex",gap:6,marginBottom:8}}>
          <input value={newVal} onChange={e=>setNewVal(e.target.value)} onKeyDown={e=>e.key==="Enter"&&handleAdd()} placeholder="Escribir nuevo elemento..." autoFocus style={{flex:1,padding:"6px 10px",border:"1.5px solid #4a9d8f",borderRadius:8,fontSize:13,outline:"none"}}/>
          <button onClick={handleAdd} style={{background:"#4a9d8f",color:"#fff",border:"none",borderRadius:8,padding:"6px 12px",cursor:"pointer",fontSize:12,fontWeight:700}}>Agregar</button>
          <button onClick={()=>{setShowAdd(false);setNewVal("")}} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1px solid #d4dde5",borderRadius:8,padding:"6px 10px",cursor:"pointer",fontSize:12}}>✕</button>
        </div>
      )}
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:2,maxHeight:200,overflowY:"auto",paddingRight:4}}>
        {filtered.map(p=><CBox key={p} label={p} checked={selected.includes(p)} onChange={()=>onToggle(p)}/>)}
        {filtered.length===0&&<div style={{gridColumn:"1/-1",color:"#8a9aaa",fontSize:12,padding:"8px 0"}}>Sin resultados</div>}
      </div>
    </div>
  );
};

// ─── MINI SPARKLINE ───────────────────────────────────────────────────────────
const Sparkline=({data,color="#4a9d8f",height=40,width=120})=>{
  if(!data||data.length<2)return null;
  const max=Math.max(...data),min=Math.min(...data),range=max-min||1;
  const pts=data.map((v,i)=>`${(i/(data.length-1))*width},${height-((v-min)/range)*height}`).join(" ");
  return(
    <svg width={width} height={height} style={{overflow:"visible"}}>
      <defs><linearGradient id={`sg${color.replace("#","")}`} x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor={color} stopOpacity="0.3"/><stop offset="100%" stopColor={color} stopOpacity="0"/></linearGradient></defs>
      <polygon points={`0,${height} ${pts} ${width},${height}`} fill={`url(#sg${color.replace("#","")})`}/>
      <polyline points={pts} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
};

// ─── BAR CHART ────────────────────────────────────────────────────────────────
const BarChart=({data,color="#4a9d8f",label="",valueFormatter=v=>v})=>{
  const max=Math.max(...data.map(d=>d.value),1);
  return(
    <div>
      {label&&<div style={{fontSize:13,fontWeight:700,color:"#1a2332",marginBottom:12}}>{label}</div>}
      <div style={{display:"flex",gap:6,alignItems:"flex-end",height:90}}>
        {data.map((d,i)=>(
          <div key={i} style={{flex:1,display:"flex",flexDirection:"column",alignItems:"center",gap:4}}>
            <div style={{fontSize:9,fontWeight:700,color:color}}>{d.value>0?valueFormatter(d.value):""}</div>
            <div style={{width:"100%",borderRadius:"4px 4px 0 0",background:`linear-gradient(180deg,${color},${color}88)`,height:`${(d.value/max)*70+4}px`,minHeight:4,transition:"height .5s ease"}}/>
            <div style={{fontSize:9,color:"#8a9aaa",textAlign:"center",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",maxWidth:36}}>{d.label}</div>
          </div>
        ))}
      </div>
    </div>
  );
};

// ─── PIE ANATÓMICO ────────────────────────────────────────────────────────────
const FootSVG=({side,selected,onToggle})=>{
  const zones=side==="left"?ZONES_L:ZONES_R;
  const isLeft=side==="left";
  return(
    <div style={{textAlign:"center"}}>
      <div style={{fontSize:11.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:6}}>Pie {isLeft?"Izquierdo":"Derecho"}</div>
      <div style={{display:"inline-block",background:"#fdf8f4",border:"2px solid #e8ddd4",borderRadius:12,padding:10,marginBottom:8}}>
        <svg viewBox="0 0 120 270" width={90} height={202} style={{display:"block"}}>
          <ellipse cx="60" cy="238" rx="34" ry="28" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/>
          <path d={isLeft?"M26 210 Q22 175 30 155 Q38 135 50 125 L70 125 Q78 135 82 155 Q88 175 90 210 Z":"M30 210 Q28 175 32 155 Q40 135 50 125 L70 125 Q82 135 90 155 Q98 175 94 210 Z"} fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/>
          <ellipse cx="60" cy="118" rx="28" ry="20" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/>
          <ellipse cx="60" cy="92" rx="30" ry="25" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/>
          {isLeft?<><ellipse cx="24" cy="55" rx="9" ry="18" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="37" cy="45" rx="8" ry="19" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="51" cy="42" rx="8" ry="20" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="65" cy="46" rx="7.5" ry="18" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="78" cy="55" rx="6.5" ry="15" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/></>:<><ellipse cx="96" cy="55" rx="9" ry="18" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="83" cy="45" rx="8" ry="19" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="69" cy="42" rx="8" ry="20" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="55" cy="46" rx="7.5" ry="18" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/><ellipse cx="42" cy="55" rx="6.5" ry="15" fill="#f5d5be" stroke="#c8906a" strokeWidth="1.5"/></>}
          {isLeft?<><ellipse cx="24" cy="42" rx="6" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="37" cy="31" rx="5.5" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="51" cy="28" rx="5.5" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="65" cy="33" rx="5" ry="4.5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="78" cy="44" rx="4.5" ry="4" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/></>:<><ellipse cx="96" cy="42" rx="6" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="83" cy="31" rx="5.5" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="69" cy="28" rx="5.5" ry="5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="55" cy="33" rx="5" ry="4.5" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/><ellipse cx="42" cy="44" rx="4.5" ry="4" fill="#e8c4aa" stroke="#b8806a" strokeWidth="1"/></>}
          {isLeft?<path d="M26 210 Q15 185 20 160 Q24 148 30 155" fill="none" stroke="#c8906a" strokeWidth="1" strokeDasharray="3 2"/>:<path d="M94 210 Q105 185 100 160 Q96 148 90 155" fill="none" stroke="#c8906a" strokeWidth="1" strokeDasharray="3 2"/>}
          <line x1="60" y1="75" x2="60" y2="215" stroke="#c8906a" strokeWidth="0.5" strokeDasharray="4 3" opacity="0.4"/>
        </svg>
      </div>
      <div style={{textAlign:"left"}}>
        {zones.map(z=><CBox key={z} label={z} checked={selected.includes(z)} onChange={()=>onToggle(z)}/>)}
      </div>
    </div>
  );
};

// ─── MAPA REFLEXOLOGÍA ────────────────────────────────────────────────────────
const ReflexologyMap=({onClose})=>(
  <Modal title="🗺️ Mapa de Reflexología Podal — Zonas Reflejas" onClose={onClose} width={900}>
    <div style={{textAlign:"center",marginBottom:12,fontSize:13,color:"#5a7a8a"}}>
      Zonas Reflejas del Pie — Cara Plantar. Fuente de referencia para sesiones de reflexología podal.
    </div>
    <div style={{textAlign:"center",background:"#f8fafc",borderRadius:14,padding:16,marginBottom:16}}>
      <img src="data:image/jpeg;base64, " alt="Mapa de Reflexología Podal — Zonas Reflejas" style={{maxWidth:"100%",maxHeight:"65vh",objectFit:"contain",borderRadius:10,boxShadow:"0 4px 24px rgba(0,0,0,0.12)"}}/>
    </div>
    <div style={{marginBottom:12,background:"#f4f8fa",borderRadius:10,padding:14}}>
      <div style={{fontWeight:700,fontSize:11,color:"#5a7a8a",marginBottom:8,textTransform:"uppercase",letterSpacing:"0.06em"}}>Sistemas Reflejos Principales</div>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:6}}>
        {[["Sistema Nervioso","#ffaaaa"],["Sistema Digestivo","#99cc99"],["Sistema Cardiovascular","#ff6666"],["Sistema Endocrino","#99ffcc"],["Sistema Urinario","#ffb366"],["Sistema Respiratorio","#99ccff"],["Sistema Reproductor","#ff9999"],["Sistema Músculo-Esq.","#cc99cc"],["Plexos Nerviosos","#cc99ff"],["Glándulas Suprarrenales","#9999ff"]].map(([lbl,col])=>(
          <div key={lbl} style={{display:"flex",alignItems:"center",gap:6,fontSize:11}}>
            <div style={{width:14,height:10,borderRadius:3,background:col,flexShrink:0}}/>
            <span style={{color:"#3a5a6a"}}>{lbl}</span>
          </div>
        ))}
      </div>
    </div>
    <div style={{display:"flex",justifyContent:"flex-end"}}>
      <Btn variant="secondary" onClick={onClose}>Cerrar</Btn>
    </div>
  </Modal>
);
// ─── HISTORY MODAL ────────────────────────────────────────────────────────────
// ─── PHOTO LIGHTBOX ──────────────────────────────────────────────────────────
const PhotoLightbox=({src,alt,onClose})=>{
  const[zoom,setZoom]=React.useState(1);
  const[pos,setPos]=React.useState({x:0,y:0});
  const[drag,setDrag]=React.useState(null);
  const imgRef=React.useRef();
  React.useEffect(()=>{const h=e=>{if(e.key==="Escape")onClose();};document.addEventListener("keydown",h);return()=>document.removeEventListener("keydown",h);},[]);
  const onWheel=e=>{e.preventDefault();const delta=e.deltaY>0?-0.15:0.15;setZoom(z=>Math.min(5,Math.max(0.5,z+delta)));};
  const onMouseDown=e=>{if(zoom>1){setDrag({sx:e.clientX-pos.x,sy:e.clientY-pos.y});}};
  const onMouseMove=e=>{if(drag){setPos({x:e.clientX-drag.sx,y:e.clientY-drag.sy});}};
  const onMouseUp=()=>setDrag(null);
  const reset=()=>{setZoom(1);setPos({x:0,y:0});};
  return(
    <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.92)",zIndex:9999,display:"flex",alignItems:"center",justifyContent:"center"}}
      onClick={e=>{if(e.target===e.currentTarget)onClose();}}
      onMouseMove={onMouseMove} onMouseUp={onMouseUp} onMouseLeave={onMouseUp}>
      <div style={{position:"absolute",top:16,right:16,display:"flex",gap:8,zIndex:10001}}>
        <button onClick={()=>setZoom(z=>Math.min(5,z+0.3))} title="Acercar" style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:8,width:38,height:38,cursor:"pointer",fontSize:18,fontWeight:700,display:"flex",alignItems:"center",justifyContent:"center"}}>+</button>
        <button onClick={()=>setZoom(z=>Math.max(0.5,z-0.3))} title="Alejar" style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:8,width:38,height:38,cursor:"pointer",fontSize:18,fontWeight:700,display:"flex",alignItems:"center",justifyContent:"center"}}>−</button>
        <button onClick={reset} title="Restablecer" style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:8,width:38,height:38,cursor:"pointer",fontSize:13,fontWeight:700,display:"flex",alignItems:"center",justifyContent:"center"}}>1:1</button>
        <button onClick={onClose} title="Cerrar" style={{background:"rgba(224,80,80,0.4)",color:"#fff",border:"1px solid rgba(224,80,80,0.5)",borderRadius:8,width:38,height:38,cursor:"pointer",fontSize:18,fontWeight:700,display:"flex",alignItems:"center",justifyContent:"center"}}>✕</button>
      </div>
      <div style={{position:"absolute",bottom:16,left:"50%",transform:"translateX(-50%)",background:"rgba(0,0,0,0.6)",color:"#fff",fontSize:12,padding:"4px 14px",borderRadius:20,pointerEvents:"none"}}>
        {Math.round(zoom*100)}% — Rueda del ratón para zoom · Click y arrastra para mover
      </div>
      <div style={{overflow:"hidden",width:"100vw",height:"100vh",display:"flex",alignItems:"center",justifyContent:"center",cursor:zoom>1?"grab":"zoom-in"}} onWheel={onWheel}>
        <img ref={imgRef} src={src} alt={alt||""} onMouseDown={onMouseDown}
          style={{maxWidth:"90vw",maxHeight:"90vh",objectFit:"contain",borderRadius:8,
            transform:`scale(${zoom}) translate(${pos.x/zoom}px,${pos.y/zoom}px)`,
            transition:drag?"none":"transform 0.15s ease",
            cursor:drag?"grabbing":zoom>1?"grab":"zoom-in",
            userSelect:"none",pointerEvents:"auto"}}
          draggable={false}/>
      </div>
    </div>
  );
};

// ─── QR HISTORIA CLÍNICA MODAL ────────────────────────────────────────────────
const attendanceBelongsToPatient=(a,p)=>{
  const pid=String(a?.patientId||a?.patient_id||"").trim();
  const pdni=String(a?.patientDni||a?.patient_dni||"").trim();
  const id=String(p?.id||"").trim();
  const dni=String(p?.dni||"").trim();
  return (id&&(pid===id||String(a?.patient_id||"").trim()===id))||(dni&&(pid===dni||pdni===dni));
};

const QRHistoriaModal=({patient,onClose})=>{
  const p=patient;
  const attendances=(db.get(SK.attendances)||[]).filter(a=>attendanceBelongsToPatient(a,p));
  const sorted=[...attendances].filter(a=>a.closed||a.payStatus==="pagado").sort((a,b)=>a.date>b.date?1:-1);
  // Generate QR URL — points to a public patient evolution page
  const baseUrl=window.location.origin+window.location.pathname;
  const qrUrl=`${baseUrl}?portal=evolucion&pid=${p.id}&dni=${p.dni||''}`;
  const qrApiUrl=`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(qrUrl)}`;

  const openEvolucion=()=>{
    var win=window.open('','_blank');
    var company=db.get('pmb_company')||{name:"Podología Más Bela"};
    var rows=sorted.map(function(a,i){
      var meds=(a.orderItems||[]).filter(function(it){return it._type==="product"||it._type==="inventory";}).map(function(it){return it.name;}).join(", ")||"—";
      var photos=(a.photos||[]).map(function(ph){return '<img src="'+ph.data+'" style="width:100px;height:100px;object-fit:cover;border-radius:6px;border:2px solid #e8edf2;" />';}).join(" ");
      var notesHtml=a.notes?'<div style="background:#fff;border:1px solid #d4dde5;border-radius:6px;padding:8px;font-size:12px;margin-bottom:8px;"><strong>Indicaciones:</strong><br/>'+a.notes+'</div>':''
      var photosHtml=photos?'<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:6px;">'+photos+'</div>':''
      return '<div style="margin-bottom:24px;padding:16px;background:#f8fafc;border-radius:10px;border-left:4px solid #4a9d8f;">'+
        '<div style="font-weight:700;color:#4a9d8f;margin-bottom:6px;">Atención #'+(i+1)+' — '+(a.date||"—")+' '+(a.time||"")+'</div>'+
        '<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;font-size:12px;margin-bottom:8px;">'+
          '<div><strong>Servicio:</strong> '+(a.service||"—")+'</div>'+
          '<div><strong>Atendido por:</strong> '+(a.attendedBy||"—")+'</div>'+
          '<div><strong>Medicamentos:</strong> '+meds+'</div>'+
          '<div><strong>Estado:</strong> '+(a.payStatus==="pagado"?"✅ Pagado":"⏳ Pendiente")+'</div>'+
        '</div>'+notesHtml+photosHtml+'</div>';
    }).join("");
    var html='<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">'+
      '<title>Evolución - '+p.firstName+' '+p.lastName+'</title>'+
      '<style>body{font-family:Arial,sans-serif;margin:0;padding:0;background:#eef2f7;color:#1a2332;}'+
      '.hdr{background:linear-gradient(135deg,#0f3a2a,#1a4a5a);color:#fff;padding:20px 24px;}'+
      '.bdy{padding:20px 16px;max-width:700px;margin:0 auto;}'+
      '</style></head><body>'+
      '<div class="hdr">'+
        '<div style="font-size:18px;font-weight:800;margin-bottom:4px;">📋 Evolución del Tratamiento</div>'+
        '<div style="font-size:14px;font-weight:700;">'+p.firstName+' '+p.lastName+'</div>'+
        '<div style="font-size:12px;opacity:0.7;">DNI: '+(p.dni||"—")+' · '+company.name+'</div>'+
      '</div>'+
      '<div class="bdy">'+
        '<div style="background:#fff;border-radius:10px;padding:14px;margin-bottom:16px;display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;font-size:12px;">'+
          '<div><strong>Paciente</strong><br/>'+p.firstName+' '+p.lastName+'</div>'+
          '<div><strong>DNI</strong><br/>'+(p.dni||"—")+'</div>'+
          '<div><strong>Total atenciones</strong><br/>'+sorted.length+'</div>'+
        '</div>'+
        (rows||'<div style="text-align:center;color:#8a9aaa;padding:24px;">Sin atenciones registradas</div>')+
        '<div style="text-align:center;font-size:11px;color:#8a9aaa;margin-top:24px;">'+company.name+' · Generado el '+new Date().toLocaleDateString('es-PE')+'</div>'+
      '</div></body></html>';
    win.document.write(html);
    win.document.close();
  };

  return(
    <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.65)",zIndex:2000,display:"flex",alignItems:"center",justifyContent:"center",padding:20}}>
      <div style={{background:"#fff",borderRadius:20,padding:"28px 32px",maxWidth:420,width:"100%",textAlign:"center",boxShadow:"0 24px 64px rgba(0,0,0,0.3)"}}>
        <div style={{fontWeight:800,fontSize:18,color:"#1a2332",marginBottom:4}}>📲 QR Evolución del Tratamiento</div>
        <div style={{fontSize:12,color:"#5a7a8a",marginBottom:20}}>El paciente puede escanear este código para ver su evolución de forma secuencial: fotos, indicaciones, fechas, medicamentos y podóloga que lo atendió.</div>
        <div style={{background:"#f4f8fa",borderRadius:12,padding:"16px",marginBottom:16,display:"inline-block"}}>
          <img src={qrApiUrl} alt="QR Evolución" style={{width:200,height:200,borderRadius:8}}/>
        </div>
        <div style={{background:"#f0f9f7",border:"1px solid #4a9d8f44",borderRadius:8,padding:"8px 12px",fontSize:11,color:"#2a7a6a",fontFamily:"monospace",wordBreak:"break-all",marginBottom:16}}>
          {qrUrl}
        </div>
        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10,marginBottom:8}}>
          <button onClick={openEvolucion} style={{padding:"9px",borderRadius:10,background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",color:"#fff",border:"none",fontWeight:700,fontSize:12,cursor:"pointer"}}>
            👁️ Ver Evolución
          </button>
          <button onClick={()=>{const a=document.createElement('a');a.href=qrApiUrl;a.download='QR_'+p.firstName+'_'+p.lastName+'.png';a.click();}} style={{padding:"9px",borderRadius:10,background:"linear-gradient(135deg,#6366f1,#4f46e5)",color:"#fff",border:"none",fontWeight:700,fontSize:12,cursor:"pointer"}}>
            ⬇️ Descargar QR
          </button>
        </div>
        <button onClick={onClose} style={{width:"100%",padding:"9px",borderRadius:10,background:"#f0f4f8",color:"#5a7a8a",border:"none",fontWeight:600,fontSize:13,cursor:"pointer"}}>Cerrar</button>
      </div>
    </div>
  );
};

const HistoryModal=({patient,onClose})=>{
  const p=patient;
  const[showQRHistory,setShowQRHistory]=useState(false);
  const attendances=(db.get(SK.attendances)||[]).filter(a=>attendanceBelongsToPatient(a,p));
  const appointments=(db.get(SK.appointments)||[]).filter(a=>
    String(a.patientId)===String(p.id)).sort((a,b)=>b.date?.localeCompare(a.date)||0);
  const company=db.get(SK.company)||{name:"Podología Más Bela"};
  const cur=getCurrency();
  const[lightboxSrc,setLightboxSrc]=React.useState(null);
  const generateAttReport=(a)=>{
    const win=window.open("","_blank");
    const fecha=a.date?a.date.split("-").reverse().join("/"):"—";
    const hora=a.time?a.time+"h":"—";
    win.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Informe de Atención</title><style>body{font-family:'Segoe UI',Arial,sans-serif;margin:0;padding:0;color:#1a2332;background:#fff}@media print{.no-print{display:none}}.header{background:linear-gradient(135deg,#0f3a2a,#1a4a5a);color:#fff;padding:24px 32px}.header h1{margin:0;font-size:20px;font-weight:800}.header p{margin:4px 0 0;font-size:12px;color:rgba(255,255,255,0.6)}.body{padding:32px}.section{margin-bottom:24px}.section-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:#5a7a8a;border-bottom:2px solid #e8edf2;padding-bottom:6px;margin-bottom:12px}.grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}.field{background:#f8fafc;border-radius:8px;padding:10px 14px}.field .lbl{font-size:10px;font-weight:700;text-transform:uppercase;color:#8a9aaa;margin-bottom:3px}.field .val{font-size:14px;font-weight:600;color:#1a2332}.badge{display:inline-block;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700}.badge-green{background:#dcfce7;color:#16a34a}.badge-orange{background:#fef3c7;color:#b45309}.notes-box{background:#f0f9f7;border:1px solid #4a9d8f33;border-radius:8px;padding:14px;font-size:13px;color:#1a4a3a;line-height:1.7;white-space:pre-wrap}.photo-grid{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}.photo-grid img{width:120px;height:120px;object-fit:cover;border-radius:8px;border:2px solid #e8edf2}.footer{margin-top:32px;padding-top:16px;border-top:1px solid #e8edf2;font-size:11px;color:#8a9aaa;text-align:center}.print-btn{margin:20px 32px 0;padding:9px 22px;background:#0f3a2a;color:#fff;border:none;border-radius:8px;font-size:13px;font-weight:700;cursor:pointer}</style></head><body><div class="header"><h1>📋 Informe de Atención Podológica</h1><p>${company.name} · Generado el ${new Date().toLocaleDateString("es-PE")}</p></div><button class="print-btn no-print" onclick="window.print()">🖨️ Imprimir / Guardar PDF</button><div class="body"><div class="section"><div class="section-title">Datos del Paciente</div><div class="grid"><div class="field"><div class="lbl">Nombre</div><div class="val">${p.firstName} ${p.lastName}</div></div><div class="field"><div class="lbl">DNI</div><div class="val">${p.dni||"—"}</div></div><div class="field"><div class="lbl">Teléfono</div><div class="val">${p.phone||"—"}</div></div></div></div><div class="section"><div class="section-title">Datos de la Atención</div><div class="grid"><div class="field"><div class="lbl">Fecha</div><div class="val">${fecha}</div></div><div class="field"><div class="lbl">Hora</div><div class="val">${hora}</div></div><div class="field"><div class="lbl">Servicio</div><div class="val">${a.service||"—"}</div></div><div class="field"><div class="lbl">Monto</div><div class="val">${cur} ${parseFloat(a.price||0).toFixed(2)}</div></div><div class="field"><div class="lbl">Método de Pago</div><div class="val">${a.payMethod||"—"}</div></div><div class="field"><div class="lbl">Atendido por</div><div class="val">${a.attendedBy||"—"}</div></div><div class="field"><div class="lbl">Estado</div><div class="val"><span class="badge ${a.payStatus==="pagado"?"badge-green":"badge-orange"}">${a.payStatus==="pagado"?"✓ Pagado":"⏳ Pendiente"}</span></div></div></div></div>${p.pathologies?.length>0?`<div class="section"><div class="section-title">Patologías Registradas</div><div style="display:flex;flex-wrap:wrap;gap:6px">${p.pathologies.map(x=>`<span class="badge" style="background:#4a9d8f18;color:#4a9d8f">${x}</span>`).join("")}</div></div>`:""}<div class="section"><div class="section-title">Notas / Diagnóstico de la Atención</div><div class="notes-box">${a.notes||"Sin notas registradas para esta atención."}</div></div>${a.photos?.length>0?`<div class="section"><div class="section-title">Fotos de Evidencia (${a.photos.length})</div><div class="photo-grid">${a.photos.map(ph=>`<img src="${ph.data}" alt="foto"/>`).join("")}</div></div>`:""}</div><div class="footer">${company.name} · Historia Clínica de ${p.firstName} ${p.lastName} · DNI: ${p.dni||"—"}<br/>Atención del ${fecha} · Atendido por ${a.attendedBy||"—"}</div></body></html>`);
    win.document.close();
    setTimeout(()=>win.print(),600);
  };

  const printPDF=()=>{
    const win=window.open("","_blank");
    win.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8">
    <title>Historia Clínica — ${p.firstName} ${p.lastName}</title>
    <style>
      body{font-family:Arial,sans-serif;font-size:12px;color:#1a2332;margin:20px}
      h1{font-size:18px;color:#0f3a2a;border-bottom:2px solid #4a9d8f;padding-bottom:8px}
      h2{font-size:14px;color:#1a4a5a;margin-top:16px;margin-bottom:6px}
      .grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
      .field{margin-bottom:6px}.lbl{font-weight:700;color:#5a7a8a;font-size:10px;text-transform:uppercase}
      .val{font-size:12px;color:#1a2332}
      .att{border:1px solid #e8edf2;border-radius:6px;padding:10px;margin-bottom:8px}
      .tag{display:inline-block;padding:2px 8px;border-radius:12px;background:#4a9d8f22;color:#4a9d8f;font-size:10px;margin:2px}
      @media print{body{margin:10px}}
    </style></head><body>
    <div style="display:flex;align-items:center;gap:12px;border-bottom:2px solid #4a9d8f;padding-bottom:10px;margin-bottom:10px"><img src="data:image/png;base64, " style="width:54px;height:54px;border-radius:50%;object-fit:contain"/><div><h1 style="margin:0;font-size:18px;color:#0f3a2a">Historia Clínica Podológica</h1><div style="font-size:10px;color:#8a9aaa">${company.name} · Generado ${new Date().toLocaleString('es-PE')}</div></div></div>
    <div class="grid">
      <div class="field"><div class="lbl">Paciente</div><div class="val" style="font-size:16px;font-weight:700">${p.firstName} ${p.lastName}</div></div>
      <div class="field"><div class="lbl">DNI</div><div class="val">${p.dni||"—"}</div></div>
      <div class="field"><div class="lbl">Fecha Nacimiento</div><div class="val">${p.dob?p.dob.split("-").reverse().join("/"):"—"}</div></div>
      <div class="field"><div class="lbl">Teléfono</div><div class="val">${p.phone||"—"}</div></div>
      <div class="field"><div class="lbl">Dirección</div><div class="val">${p.address||"—"}</div></div>
      <div class="field"><div class="lbl">Tipo Paciente</div><div class="val">${p.patientType||"Público"}</div></div>
    </div>
    <h2>Patologías</h2>
    <div>${(p.pathologies||[]).map(x=>`<span class="tag">${x}</span>`).join("")||"—"}</div>
    <h2>Antecedentes</h2>
    <div>${(p.pathAnt||[]).map(x=>`<span class="tag">${x}</span>`).join("")||"—"}</div>
    <h2>Atenciones (${attendances.length})</h2>
    ${attendances.slice(0,20).map(a=>`<div class="att">
      <b>${a.date?a.date.split("-").reverse().join("/"):"—"}${a.time?` ${a.time}h`:""}</b> — ${a.service||"Sin servicio"}
      <div style="color:#4a9d8f;font-weight:700">${cur} ${parseFloat(a.price||0).toFixed(2)} · ${a.payMethod||"—"}</div>
      ${a.notes?`<div style="color:#5a7a8a;font-size:11px">${a.notes}</div>`:""}
    </div>`).join("")}
    </body></html>`);
    win.document.close();
    setTimeout(()=>{win.print();win.close()},400);
  };

  const sendWhatsApp=()=>{
    const phone=p.phone?.replace(/\D/g,"");
    if(!phone){alert("El paciente no tiene teléfono registrado");return}
    const msg=`Hola ${p.firstName}, le enviamos su resumen de historia clínica de ${company.name}. Atenciones registradas: ${attendances.length}. Para más información contáctenos.`;
    window.open(`https://wa.me/51${phone}?text=${encodeURIComponent(msg)}`,"_blank");
  };

  const sendEmail=()=>{
    if(!p.email){alert("El paciente no tiene correo registrado");return}
    const sub=encodeURIComponent(`Historia Clínica — ${p.firstName} ${p.lastName}`);
    const body=encodeURIComponent(`Estimado/a ${p.firstName},\n\nAdjunto encontrará su resumen de historia clínica.\n\nAtenciones registradas: ${attendances.length}\nÚltima atención: ${attendances[attendances.length-1]?.date||"—"}\n\nSaludos,\n${company.name}`);
    window.location.href=`mailto:${p.email}?subject=${sub}&body=${body}`;
  };

  return(<>
    <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",zIndex:1000,display:"flex",alignItems:"center",justifyContent:"center",padding:20}} onClick={e=>e.target===e.currentTarget&&onClose()}>
      <div style={{background:"#fff",borderRadius:18,width:"100%",maxWidth:760,maxHeight:"90vh",display:"flex",flexDirection:"column",boxShadow:"0 24px 64px rgba(0,0,0,0.25)"}}>
        <div style={{background:"linear-gradient(135deg,#0f3a2a,#1a4a5a)",borderRadius:"18px 18px 0 0",padding:"18px 24px",display:"flex",alignItems:"center",justifyContent:"space-between"}}>
          <div>
            <div style={{fontSize:12,color:"rgba(255,255,255,0.5)",letterSpacing:"0.08em",textTransform:"uppercase"}}>Historia Clínica</div>
            <div style={{fontSize:19,fontWeight:800,color:"#fff",marginTop:2}}>{p.firstName} {p.lastName}</div>
            <div style={{fontSize:12,color:"#5dd4c6",marginTop:1}}>DNI: {p.dni} · {attendances.length} atención{attendances.length!==1?"es":""} · {appointments.length} cita{appointments.length!==1?"s":""}</div>
          </div>
          <div style={{display:"flex",gap:8,flexWrap:"wrap",justifyContent:"flex-end"}}>
            <button onClick={printPDF} style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>🖨️ Imprimir PDF</button>
            <button onClick={sendWhatsApp} style={{background:"#25D366",color:"#fff",border:"none",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>📱 WhatsApp</button>
            <button onClick={sendEmail} style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>✉️ Email</button>
            <button onClick={()=>setShowQRHistory(true)} style={{background:"rgba(99,102,241,0.3)",color:"#fff",border:"1px solid rgba(99,102,241,0.5)",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>📲 QR Evolución</button>
            <button onClick={onClose} style={{background:"rgba(224,80,80,0.25)",color:"#fff",border:"1px solid rgba(224,80,80,0.4)",borderRadius:9,padding:"7px 12px",cursor:"pointer",fontSize:14,fontWeight:700}}>✕</button>
          </div>
        </div>
        <div style={{overflowY:"auto",padding:"20px 24px",flex:1}}>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(180px,1fr))",gap:10,marginBottom:20}}>
            {[["DNI",p.dni],["Teléfono",p.phone],["Email",p.email],["Dirección",p.address],["Sexo",p.sex==="F"?"Femenino":p.sex==="M"?"Masculino":"—"],["Tipo",p.patientType||"Público"]].map(([l,v])=>(
              <div key={l} style={{background:"#f8fafc",borderRadius:8,padding:"10px 12px"}}>
                <div style={{fontSize:9.5,color:"#8a9aaa",textTransform:"uppercase",fontWeight:700,letterSpacing:"0.06em",marginBottom:3}}>{l}</div>
                <div style={{fontSize:13,fontWeight:600,color:"#1a2332"}}>{v||"—"}</div>
              </div>
            ))}
          </div>
          {p.pathologies?.length>0&&(
            <div style={{marginBottom:16}}>
              <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8}}>Patologías</div>
              <div style={{display:"flex",flexWrap:"wrap",gap:5}}>{p.pathologies.map(x=><span key={x} style={{padding:"3px 10px",borderRadius:20,background:"#4a9d8f18",color:"#4a9d8f",fontSize:12,fontWeight:600}}>{x}</span>)}</div>
            </div>
          )}
          {p.pathAnt?.length>0&&(
            <div style={{marginBottom:16}}>
              <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8}}>Antecedentes</div>
              <div style={{display:"flex",flexWrap:"wrap",gap:5}}>{p.pathAnt.map(x=><span key={x} style={{padding:"3px 10px",borderRadius:20,background:"#2563eb18",color:"#2563eb",fontSize:12,fontWeight:600}}>{x}</span>)}</div>
            </div>
          )}
          {appointments.length>0&&(<div style={{marginBottom:18}}>
            <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8}}>📅 Citas Agendadas ({appointments.length})</div>
            {appointments.slice(0,10).map(a=>(<div key={a.id} style={{border:"1px solid #e8edf2",borderRadius:8,padding:"10px 14px",marginBottom:6,display:"flex",justifyContent:"space-between",alignItems:"center",background:"#fafcfd"}}>
              <div>
                <div style={{fontWeight:700,fontSize:12.5,color:"#1a2332"}}>{a.date?a.date.split("-").reverse().join("/"):"—"} {a.time?`${a.time}h`:""}</div>
                <div style={{fontSize:11.5,color:"#4a9d8f"}}>{a.service||"Sin servicio especificado"}</div>
                {a.notes&&<div style={{fontSize:11,color:"#8a9aaa",marginTop:2}}>{a.notes}</div>}
              </div>
              <Badge color={a.status==="confirmada"?"green":a.status==="cancelada"?"red":"teal"}>{a.status||"pendiente"}</Badge>
            </div>))}
          </div>)}
          <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:10}}>Historial de Atenciones</div>
          {attendances.length===0?<div style={{textAlign:"center",padding:"20px 0",color:"#8a9aaa",fontSize:13}}>Sin atenciones registradas</div>:
            attendances.slice().reverse().map(a=>(
              <div key={a.id} style={{border:"1px solid #e8edf2",borderRadius:10,padding:"12px 16px",marginBottom:10}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:6}}>
                  <div>
                    <div style={{fontWeight:700,fontSize:13,color:"#1a2332"}}>{a.date?a.date.split("-").reverse().join("/"):"—"}{a.time?` ${a.time}h`:""} — {a.service||"Sin servicio"}</div>
                    <div style={{fontSize:11,color:"#8a9aaa",marginTop:2}}>Por: <b style={{color:"#4a9d8f"}}>{a.attendedBy||"—"}</b> · Método: {a.payMethod||"—"}</div>
                  </div>
                  <div style={{textAlign:"right",display:"flex",flexDirection:"column",alignItems:"flex-end",gap:4}}>
                    <div style={{fontWeight:800,fontSize:15,color:"#059669"}}>{getCurrency()} {parseFloat(a.price||0).toFixed(2)}</div>
                    <Badge color={a.payStatus==="pagado"?"green":"orange"}>{a.payStatus==="pagado"?"Pagado":"Pendiente"}</Badge>
                    <button onClick={()=>generateAttReport(a)} style={{background:"linear-gradient(135deg,#0f3a2a,#1a4a5a)",color:"#fff",border:"none",borderRadius:7,padding:"4px 10px",cursor:"pointer",fontSize:11,fontWeight:700,display:"flex",alignItems:"center",gap:4,marginTop:2}}>📄 Informe</button>
                  </div>
                </div>
                {a.notes&&<div style={{fontSize:12,color:"#3a5a6a",lineHeight:1.5,background:"#f8fafc",borderRadius:6,padding:"6px 10px"}}>{a.notes}</div>}
                {a.photos?.length>0&&<div style={{display:"flex",gap:5,flexWrap:"wrap",marginTop:8}}>{a.photos.map((ph,i)=><img key={i} src={ph.data} alt="" onClick={()=>setLightboxSrc(ph.data)} style={{width:58,height:58,objectFit:"cover",borderRadius:7,border:"2px solid #d0dce5",cursor:"zoom-in"}}/>)}</div>}
              </div>
            ))
          }
        </div>
      </div>
    </div>
    {lightboxSrc&&<PhotoLightbox src={lightboxSrc} onClose={()=>setLightboxSrc(null)}/>}
  {showQRHistory&&<QRHistoriaModal patient={p} onClose={()=>setShowQRHistory(false)}/>}
  </>);
};

// ─── FORMULARIO PACIENTE ──────────────────────────────────────────────────────
const emptyPt=()=>({
  id:null,registrationDate:todayStr(),firstName:"",lastName:"",dob:"",dni:"",address:"",
  phone:"",email:"",sex:"",occupation:"",weight:"",height:"",shoeSize:"",shoeType:"",
  pathologies:[],location:"",triggers:"",pathAnt:[],smoke:"",alcohol:"",meds:"",
  sharesShoes:"",physicalActivity:"",activityDetail:"",
  zoneLeft:[],zoneRight:[],nailColor:[],nailThickness:[],nailShape:[],
  notes:"",status:"active",emergencyContact:"",emergencyPhone:"",insurance:"",referredBy:"",
  patientType:"publico",membershipId:null,convenioName:"",convenioPrice:null,
  customPathologies:[],customAntecedents:[],customTags:[]
});

const PatientForm=({initial,onSave,onCancel,patients,currentUser})=>{
  const[f,setF]=useState(initial||emptyPt());
  const[tab,setTab]=useState("basic");
  const[aiLoading,setAiLoading]=useState(false);
  const[saving,setSaving]=useState(false);
  const[formError,setFormError]=useState("");
  const[aiSuggestion,setAiSuggestion]=useState("");
  const[showHistory,setShowHistory]=useState(false);
  const s=(k,v)=>setF(p=>({...p,[k]:v}));
  const tog=(k,v)=>setF(p=>({...p,[k]:p[k].includes(v)?p[k].filter(x=>x!==v):[...p[k],v]}));

  const validate=()=>{
    if(!f.firstName.trim())return"Ingrese el nombre";
    if(!f.lastName.trim())return"Ingrese el apellido";
    const dni=String(f.dni||"").trim();
    if(!dni)return"Ingrese DNI";
    if(!/^[0-9A-Za-z]{8}$/.test(dni))return"El DNI debe tener exactamente 8 dígitos";
    if(!f.dob)return"Ingrese fecha de nacimiento";
    if(!f.sex)return"Seleccione sexo";
    if(!f.id&&patients.find(p=>String(p.dni||"")===dni))return"Ya existe un paciente con ese DNI";
    return null;
  };
  const go=async()=>{
    const e=validate();if(e){setFormError(e);return}
    setFormError("");
    setSaving(true);
    try{
      await onSave({...f,attendedBy:currentUser?.name});
    }catch(e){
      setFormError(e?.userMessage||e?.message||"No se pudo guardar la historia clínica. Revise los datos e intente nuevamente.");
      console.warn('No se guardó la historia clínica',e);
    }finally{
      setSaving(false);
    }
  };

  const generateAISuggestion=async()=>{
    if(!f.pathologies.length&&!f.pathAnt.length){alert("Ingrese al menos una patología o antecedente para generar sugerencias.");return}
    setAiLoading(true);setAiSuggestion("");
    try{
      const prompt=`Eres un podólogo experto. Un paciente tiene estos datos:
- Sexo: ${f.sex==="F"?"Femenino":"Masculino"}, Edad: ${calcAge(f.dob)} años
- Patologías: ${f.pathologies.join(", ")||"ninguna"}
- Antecedentes patológicos: ${f.pathAnt.join(", ")||"ninguno"}
- Fuma: ${f.smoke||"No especificado"}, Alcohol: ${f.alcohol||"No especificado"}
- Actividad física: ${f.physicalActivity||"No especificada"}
- Tipo calzado: ${f.shoeType||"No especificado"}
- Zonas afectadas pie izq: ${f.zoneLeft.join(", ")||"ninguna"}
- Zonas afectadas pie der: ${f.zoneRight.join(", ")||"ninguna"}

Proporciona en español:
1. IMPRESIÓN CLÍNICA: resumen del cuadro podológico (2-3 oraciones)
2. RECOMENDACIONES: 3-4 puntos de tratamiento y cuidados
3. ALERTAS: factores de riesgo a monitorear
Sé conciso y clínico. Máximo 200 palabras.`;
      const res=await fetch(API_BASE+'/special.php?action=ai_suggest',{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({prompt,apiKey:db.get("pmb_company")?.aiApiKey||""})});
      const data=await res.json();
      const txt=data.content?.find(c=>c.type==="text")?.text||data.error||"No se pudo generar sugerencia. Configure la clave API de Claude en Configuración.";
      setAiSuggestion(txt);
    }catch{setAiSuggestion("Error al conectar con el asistente IA. Verifique su conexión.")}
    setAiLoading(false);
  };

  const tabs=[{id:"basic",label:"📋 Datos Básicos"},{id:"clinical",label:"🏥 Clínico"},{id:"antecedents",label:"📜 Antecedentes"},{id:"diagnosis",label:"🦶 Diagnóstico"},{id:"ai",label:"🤖 Asistente IA"}];
  const G={display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 16px"};

  return(
    <div>
      <div style={{background:"linear-gradient(135deg,#0f2a3a,#1a4a5a)",borderRadius:12,padding:"14px 20px",marginBottom:20,display:"flex",alignItems:"center",justifyContent:"space-between"}}>
        <div>
          <div style={{fontSize:10,color:"rgba(255,255,255,0.45)",textTransform:"uppercase",letterSpacing:"0.1em"}}>Ficha de Historia Clínica</div>
          <div style={{fontSize:17,fontWeight:700,color:"#fff",marginTop:2}}>{f.id?`#${padId(f.id)} — ${f.firstName||f.first_name||'Paciente'} ${f.lastName||f.last_name||''}`:"Nueva Historia Clínica"}</div>
        </div>
        <div style={{textAlign:"right"}}>
          <div style={{fontSize:10,color:"rgba(255,255,255,0.45)"}}>Fecha Alta</div>
          <div style={{fontSize:13,fontWeight:600,color:"#5dd4c6"}}>{fmt(f.registrationDate)}</div>
        </div>
      </div>
      <Tabs tabs={tabs} active={tab} onChange={setTab}/>

      {tab==="basic"&&(
        <div className="fade-in" style={G}>
          <Field label="Fecha de Alta" required><Inp type="date" value={f.registrationDate} onChange={e=>s("registrationDate",e.target.value)}/></Field>
          <Field label="Edad (auto)"><Inp value={f.dob?`${calcAge(f.dob)} años`:"—"} readOnly style={{background:"#f0f4f8",color:"#4a9d8f",fontWeight:700}}/></Field>
          <Field label="Nombres" required><Inp value={f.firstName} onChange={e=>s("firstName",e.target.value)} placeholder="Nombres completos"/></Field>
          <Field label="Apellidos" required><Inp value={f.lastName} onChange={e=>s("lastName",e.target.value)} placeholder="Apellidos completos"/></Field>
          <Field label="Fecha de Nacimiento" required><Inp type="date" value={f.dob} onChange={e=>s("dob",e.target.value)}/></Field>
          <Field label="DNI / Carnet" required><Inp value={f.dni} onChange={e=>s("dni",e.target.value.replace(/[^0-9A-Za-z]/g,"").slice(0,8))} placeholder="12345678" maxLength={8}/></Field>
          <Field label="Dirección" col="1/-1"><Inp value={f.address} onChange={e=>s("address",e.target.value)} placeholder="Dirección completa"/></Field>
          <Field label="Celular"><Inp value={f.phone} onChange={e=>s("phone",e.target.value)} placeholder="+51 999 999 999"/></Field>
          <Field label="Correo Electrónico"><Inp value={f.email||""} onChange={e=>s("email",e.target.value)} placeholder="paciente@email.com"/></Field>
          <Field label="Tipo de Paciente" required col="1/-1">
            <div style={{display:"flex",gap:8,flexWrap:"wrap",paddingTop:4}}>
              {[["publico","🌍 Público","#4a9d8f"],["convenio","🤝 Convenio","#2563eb"],["afiliado","⭐ Afiliado","#7c3aed"]].map(([v,l,c])=>(
                <button key={v} onClick={()=>s("patientType",v)} style={{padding:"7px 16px",borderRadius:9,border:`2px solid ${f.patientType===v?c:"#d4dde5"}`,background:f.patientType===v?c+"18":"#fff",color:f.patientType===v?c:"#5a7a8a",fontWeight:700,fontSize:12.5,cursor:"pointer",display:"flex",alignItems:"center",gap:5}}>{l}</button>
              ))}
            </div>
            {f.patientType==="convenio"&&(
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px",marginTop:10}}>
                <Field label="Nombre del Convenio"><Inp value={f.convenioName||""} onChange={e=>s("convenioName",e.target.value)} placeholder="EsSalud, MINSA, Empresa..."/></Field>
                <Field label="Precio Convenio (opcional)"><Inp type="number" value={f.convenioPrice||""} onChange={e=>s("convenioPrice",e.target.value)} placeholder="0.00"/></Field>
              </div>
            )}
            {f.patientType==="afiliado"&&(
              <div style={{marginTop:10}}>
                <Field label="Membresía">
                  <Sel value={f.membershipId||""} onChange={e=>s("membershipId",e.target.value)}>
                    <option value="">Sin membresía...</option>
                    {(db.get(SK.memberships)||[]).map(m=><option key={m.id} value={m.id}>{m.name} — {getCurrency()} {parseFloat(m.monthlyFee||0).toFixed(2)}/mes</option>)}
                  </Sel>
                </Field>
              </div>
            )}
          </Field>
          <Field label="Sexo" required>
            <div style={{display:"flex",gap:20,paddingTop:8}}>{[["F","Femenino"],["M","Masculino"]].map(([v,l])=>(
              <label key={v} style={{display:"flex",alignItems:"center",gap:6,cursor:"pointer",fontSize:13.5}}>
                <input type="radio" checked={f.sex===v} onChange={()=>s("sex",v)} style={{accentColor:"#4a9d8f",width:15,height:15}}/><span style={{fontWeight:600}}>{l}</span>
              </label>
            ))}</div>
          </Field>
          <Field label="Ocupación"><Inp value={f.occupation} onChange={e=>s("occupation",e.target.value)}/></Field>
          <Field label="Peso (kg)"><Inp type="number" value={f.weight} onChange={e=>s("weight",e.target.value)} placeholder="70"/></Field>
          <Field label="Talla (cm)"><Inp type="number" value={f.height} onChange={e=>s("height",e.target.value)} placeholder="170"/></Field>
          <Field label="N° Calzado"><Inp type="number" value={f.shoeSize} onChange={e=>s("shoeSize",e.target.value)} placeholder="42"/></Field>
          <Field label="Tipo Calzado"><Sel value={f.shoeType} onChange={e=>s("shoeType",e.target.value)}><option value="">Seleccionar...</option>{SHOE_TYPES.map(x=><option key={x}>{x}</option>)}</Sel></Field>
          <Field label="Contacto de Emergencia"><Inp value={f.emergencyContact} onChange={e=>s("emergencyContact",e.target.value)} placeholder="Nombre y parentesco"/></Field>
          <Field label="Tel. Emergencia"><Inp value={f.emergencyPhone} onChange={e=>s("emergencyPhone",e.target.value)} placeholder="+51 999 000 000"/></Field>
          <Field label="Seguro Médico"><Inp value={f.insurance} onChange={e=>s("insurance",e.target.value)} placeholder="EsSalud, SIS, particular..."/></Field>
          <Field label="Referido por"><Inp value={f.referredBy} onChange={e=>s("referredBy",e.target.value)} placeholder="Médico, amigo, etc."/></Field>
        </div>
      )}

      {tab==="clinical"&&(
        <div className="fade-in">
          <DynamicListField
            label="Tipos de Patología"
            items={[...PATHOLOGIES,...(f.customPathologies||[])]}
            selected={f.pathologies}
            onToggle={v=>tog("pathologies",v)}
            onAdd={v=>{if(!PATHOLOGIES.includes(v)&&!(f.customPathologies||[]).includes(v))s("customPathologies",[...(f.customPathologies||[]),v])}}
          />
          <Field label="Localización — Descripción gráfica"><TA value={f.location} onChange={e=>s("location",e.target.value)} placeholder="Describe localización..."/></Field>
          <Field label="Circunstancias Desencadenantes"><TA value={f.triggers} onChange={e=>s("triggers",e.target.value)} placeholder="Describe circunstancias..."/></Field>
        </div>
      )}

      {tab==="antecedents"&&(
        <div className="fade-in">
          <DynamicListField
            label="Antecedentes Patológicos"
            items={[...PATHO_ANT,...(f.customAntecedents||[])]}
            selected={f.pathAnt}
            onToggle={v=>tog("pathAnt",v)}
            onAdd={v=>{if(!PATHO_ANT.includes(v)&&!(f.customAntecedents||[]).includes(v))s("customAntecedents",[...(f.customAntecedents||[]),v])}}
          />
          <div style={{height:14}}/>
          <div style={{fontWeight:700,fontSize:11,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",marginBottom:12}}>Antecedentes No Patológicos</div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 20px"}}>
            {[["smoke","Fuma"],["alcohol","Hábito Alcohólico"],["meds","Toma Medicamentos"],["sharesShoes","Comparte Calzados"]].map(([k,l])=>(
              <div key={k} style={{marginBottom:14}}>
                <div style={{fontSize:12.5,fontWeight:600,color:"#3a5a6a",marginBottom:6}}>{l}:</div>
                <div style={{display:"flex",gap:20}}>{["Si","No"].map(v=><label key={v} style={{display:"flex",alignItems:"center",gap:6,cursor:"pointer",fontSize:13}}><input type="radio" checked={f[k]===v} onChange={()=>s(k,v)} style={{accentColor:"#4a9d8f",width:14,height:14}}/>{v}</label>)}</div>
              </div>
            ))}
          </div>
          <div style={{marginTop:6}}>
            <div style={{fontSize:12.5,fontWeight:600,color:"#3a5a6a",marginBottom:6}}>Realiza Actividad Física:</div>
            <div style={{display:"flex",gap:20,marginBottom:10}}>{["Si","No"].map(v=><label key={v} style={{display:"flex",alignItems:"center",gap:6,cursor:"pointer",fontSize:13}}><input type="radio" checked={f.physicalActivity===v} onChange={()=>s("physicalActivity",v)} style={{accentColor:"#4a9d8f",width:14,height:14}}/>{v}</label>)}</div>
            {f.physicalActivity==="Si"&&<Field label="¿Cuál y con qué frecuencia?"><Inp value={f.activityDetail} onChange={e=>s("activityDetail",e.target.value)} placeholder="Ej: Natación 3 veces por semana"/></Field>}
          </div>
        </div>
      )}

      {tab==="diagnosis"&&(
        <div className="fade-in">
          <div style={{marginBottom:22}}>
            <div style={{fontSize:12.5,fontWeight:700,color:"#1a3a4a",marginBottom:14,paddingBottom:8,borderBottom:"2px solid #4a9d8f25"}}>📍 TÍTULO ZONAL PLANTAR</div>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:20}}>
              <FootSVG side="left" selected={f.zoneLeft} onToggle={v=>tog("zoneLeft",v)}/>
              <FootSVG side="right" selected={f.zoneRight} onToggle={v=>tog("zoneRight",v)}/>
            </div>
          </div>
          <div>
            <div style={{fontSize:12.5,fontWeight:700,color:"#1a3a4a",marginBottom:14,paddingBottom:8,borderBottom:"2px solid #4a9d8f25"}}>💅 CARACTERÍSTICAS DE LA LÁMINA UNGUEAL</div>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:16}}>
              {[["Color",NAIL_COLORS,"nailColor"],["Grosor",NAIL_THICK,"nailThickness"],["Forma",NAIL_SHAPE,"nailShape"]].map(([t,opts,key])=>(
                <div key={key} style={{background:"#f8fafc",borderRadius:8,padding:"12px 14px"}}>
                  <div style={{fontSize:10,fontWeight:700,color:"#4a9d8f",textTransform:"uppercase",marginBottom:8,letterSpacing:"0.06em"}}>{t}</div>
                  {opts.map(o=><CBox key={o} label={o} checked={f[key].includes(o)} onChange={()=>tog(key,o)}/>)}
                </div>
              ))}
            </div>
          </div>
          <div style={{marginTop:16}}><Field label="Notas adicionales del diagnóstico"><TA value={f.notes} onChange={e=>s("notes",e.target.value)} style={{minHeight:70}}/></Field></div>
        </div>
      )}

      {tab==="ai"&&(
        <div className="fade-in">
          <div style={{background:"linear-gradient(135deg,#0f2a3a,#1a3a6a)",borderRadius:12,padding:20,marginBottom:20,color:"#fff"}}>
            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:10}}>
              <div style={{fontSize:28}}>🤖</div>
              <div>
                <div style={{fontSize:15,fontWeight:700}}>Asistente Clínico IA</div>
                <div style={{fontSize:11,color:"rgba(255,255,255,0.55)"}}>Powered by Claude · Análisis podológico automatizado</div>
              </div>
            </div>
            <p style={{fontSize:12.5,color:"rgba(255,255,255,0.7)",lineHeight:1.6}}>Genera una impresión clínica, recomendaciones de tratamiento y alertas de riesgo basadas en los datos del paciente ingresados en las demás pestañas.</p>
            <Btn variant="success" onClick={generateAISuggestion} disabled={aiLoading} style={{marginTop:14}}>
              {aiLoading?<span className="pulse">⏳ Analizando...</span>:<><Icon name="ai" size={14}/>Generar Análisis IA</>}
            </Btn>
          </div>
          {aiSuggestion&&(
            <div style={{background:"#f4f9f7",border:"1.5px solid #4a9d8f44",borderRadius:12,padding:20}}>
              <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:14}}>
                <div style={{width:32,height:32,borderRadius:"50%",background:"#4a9d8f",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:16}}>🤖</div>
                <div style={{fontSize:13,fontWeight:700,color:"#1a3a4a"}}>Análisis Generado</div>
              </div>
              <div style={{fontSize:13,color:"#2a4a5a",lineHeight:1.75,whiteSpace:"pre-wrap"}}>{aiSuggestion}</div>
              <div style={{fontSize:10.5,color:"#9aacb8",marginTop:14,padding:"8px 12px",background:"#fff",borderRadius:8}}>⚠️ Este análisis es orientativo. El diagnóstico final debe ser emitido por el profesional de salud.</div>
            </div>
          )}
          {!aiSuggestion&&!aiLoading&&(
            <div style={{textAlign:"center",padding:"30px 0",color:"#8a9aaa",fontSize:13}}>
              <div style={{fontSize:40,marginBottom:10}}>🦶</div>
              Complete los datos clínicos y antecedentes del paciente en las pestañas anteriores, luego presione "Generar Análisis IA".
            </div>
          )}
        </div>
      )}

      {f.id&&(()=>{
        const patAtts=(db.get(SK.attendances)||[]).filter(a=>attendanceBelongsToPatient(a,f)).slice().reverse();
        return patAtts.length>0?(
          <div style={{marginTop:18,borderTop:"1px solid #eef2f7",paddingTop:16}}>
            <div style={{fontSize:12,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:10,display:"flex",alignItems:"center",justifyContent:"space-between"}}>
              <span>📋 Historial de Atenciones</span>
              <Badge color="teal">{patAtts.length} atención{patAtts.length!==1?"es":""}</Badge>
            </div>
            <div style={{maxHeight:220,overflowY:"auto",display:"flex",flexDirection:"column",gap:8}}>
              {patAtts.map(a=>(
                <div key={a.id} style={{background:"#f4f8fa",borderRadius:9,padding:"10px 14px",border:"1px solid #e8edf2"}}>
                  <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",flexWrap:"wrap",gap:4}}>
                    <div>
                      <div style={{fontWeight:700,fontSize:12.5,color:"#1a2332"}}>{a.date?a.date.split("-").reverse().join("/"):"—"}{a.time?" — "+a.time+"h":""} · {a.service||"Sin servicio"}</div>
                      <div style={{fontSize:11,color:"#8a9aaa",marginTop:1}}>Por: <b style={{color:"#4a9d8f"}}>{a.attendedBy||"—"}</b></div>
                    </div>
                    <div style={{display:"flex",gap:5,alignItems:"center"}}>
                      <span style={{fontWeight:700,fontSize:13,color:"#059669"}}>{getCurrency()} {parseFloat(a.price||0).toFixed(2)}</span>
                      <Badge color={a.payStatus==="pagado"?"green":"orange"}>{a.payStatus==="pagado"?"Pagado":"Pendiente"}</Badge>
                    </div>
                  </div>
                  {a.notes&&<div style={{fontSize:11.5,color:"#3a5a6a",marginTop:5,lineHeight:1.5}}>{a.notes}</div>}
                </div>
              ))}
            </div>
          </div>
        ):null;
      })()}
      {formError&&(
        <div style={{marginTop:16,background:"#fff5f5",border:"1.5px solid #fecaca",borderRadius:10,padding:"12px 14px",color:"#991b1b",fontSize:13,lineHeight:1.45,display:"flex",gap:10,alignItems:"flex-start"}}>
          <span style={{fontSize:18,lineHeight:1,fontWeight:900}}>!</span>
          <div>
            <div style={{fontWeight:800,marginBottom:2}}>No se pudo guardar en la base de datos</div>
            <div>{formError}</div>
          </div>
        </div>
      )}
      <div style={{display:"flex",gap:10,justifyContent:"space-between",marginTop:22,paddingTop:16,borderTop:"1px solid #eef2f7",flexWrap:"wrap"}}>
        <div style={{display:"flex",gap:8}}>
          {f.id&&<Btn variant="ghost" onClick={()=>setShowHistory(true)}><Icon name="eye" size={14}/>Ver Historia Clínica</Btn>}
        </div>
        <div style={{display:"flex",gap:8}}>
          <Btn variant="secondary" onClick={onCancel} disabled={saving}>Cancelar</Btn>
          <Btn onClick={go} disabled={saving}><Icon name="check" size={14}/>{saving?"Guardando en BD...":"Guardar Historia Clínica"}</Btn>
        </div>
      </div>
      {showHistory&&<HistoryModal patient={f} onClose={()=>setShowHistory(false)}/>}
    </div>
  );
};

// ─── MODAL ATENCIÓN ───────────────────────────────────────────────────────────
const AttModal=({patient,onClose,onSave,currentUser})=>{
  const[lightboxSrc,setLightboxSrc]=React.useState(null);
  const[note,setNote]=useState("");const[photos,setPhotos]=useState([]);
  const[service,setService]=useState("");const[price,setPrice]=useState("");
  const[payMethod,setPayMethod]=useState("Efectivo");const[payStatus,setPayStatus]=useState("pendiente");
  const[closedNow,setClosedNow]=useState(false);
  const isAdminUser=String(currentUser?.role||"").toLowerCase().includes("admin")||String(currentUser?.name||"").trim().toLowerCase()==="admin principal";
  const[attendedBy,setAttendedBy]=useState(isAdminUser?"":(currentUser?.name||""));
  const[attType,setAttType]=useState("clinical");
  const services=db.get(SK.services)||DEF_SERVICES;
  const salesProds=db.get(SK.salesProducts)||[];
  const salesSvcsAtt=db.get(SK.salesServices)||[];
  const fileRef=useRef();
  const allAttItems=[
    ...services.filter(s=>s.active).map(s=>({...s,_cat:"Servicios Clínicos"})),
    ...salesProds.filter(s=>s.active!==false).map(s=>({...s,_cat:"Productos Venta"})),
    ...salesSvcsAtt.filter(s=>s.active!==false).map(s=>({...s,_cat:"Servicios Venta"})),
  ];
  const pickService=e=>{
    const val=e.target.value;
    setService(val);
    const sv=allAttItems.find(x=>x.name===val);
    if(sv)setPrice(String(sv.price||0));
  };
  const handleFiles=e=>{
    const files=Array.from(e.target.files);
    Promise.all(files.map(f=>new Promise(r=>{const rd=new FileReader();rd.onload=()=>r({name:f.name,data:rd.result});rd.readAsDataURL(f)}))).then(imgs=>setPhotos(p=>[...p,...imgs]));
  };
  const patientId=patient?.id||patient?.patientId||patient?.patient_id||null;
  const patientDni=String(patient?.dni||"").trim();
  const patientFirstName=String(patient?.firstName||patient?.first_name||"").trim();
  const patientLastName=String(patient?.lastName||patient?.last_name||"").trim();
  const patientName=`${patientFirstName} ${patientLastName}`.trim();
  const go=async()=>{
    const missing=[];
    if(!patientId)missing.push("ID interno del paciente");
    if(!patientFirstName)missing.push("Nombres");
    if(!patientLastName)missing.push("Apellidos");
    if(!patientDni)missing.push("DNI");
    if(missing.length){
      alert("No se puede registrar la atención porque faltan datos del paciente: "+missing.join(", ")+". Complete la Historia Clínica y vuelva a intentarlo.");
      return;
    }
    if(!service){alert("Seleccione el servicio o producto de la atención.");return;}
    if((parseFloat(price)||0)<=0){alert("Ingrese un monto válido para la atención.");return;}
    if(!attendedBy){alert("Seleccione quién hizo la atención.");return;}
    const attId=genId(db.get(SK.attendances)||[]);
    const nowTime=new Date().toLocaleTimeString("es-PE",{hour:"2-digit",minute:"2-digit",hour12:false});
    const responsible=attendedBy;
    const att={id:attId,patientId,patient_id:patientId,patientName,patient_name:patientName,patientDni,patient_dni:patientDni,date:todayStr(),time:nowTime,registeredAt:new Date().toISOString(),registered_at:new Date().toISOString(),notes:note,photos,service,price:parseFloat(price)||0,attendedBy:responsible,attended_by:responsible,closed:closedNow,payMethod,pay_method:payMethod,payStatus:payStatus,pay_status:payStatus,itemType:attType==="product"?"product":"service",item_type:attType==="product"?"product":"service"};
    // ── FIX 1 & 2: Si es venta de producto (bien), reducir su stock ──
    if(attType==="product"&&service){
      // Buscar en catálogo Ventas→Productos
      const salProds=db.get(SK.salesProducts)||[];
      const foundInCat=salProds.find(p=>p.name===service);
      if(foundInCat){
        const upd=salProds.map(p=>p.id===foundInCat.id?{...p,stock:Math.max(0,(parseInt(p.stock)||0)-1)}:p);
        db.set(SK.salesProducts,upd);
        const changed=upd.find(p=>p.id===foundInCat.id);
        if(changed)crudApi.update('sales_products',changed.id,serverPayload('sales_products',changed)).catch(()=>{});
      } else {
        // Buscar en Inventario
        const inv=db.get(SK.inventory)||[];
        const foundInInv=inv.find(p=>p.name===service);
        if(foundInInv){
          const upd=inv.map(p=>p.id===foundInInv.id?{...p,stock:Math.max(0,(parseInt(p.stock)||0)-1),
            moves:[...(p.moves||[]),{type:"salida",qty:1,note:"Venta desde atención",date:todayStr()}]}:p);
          db.set(SK.inventory,upd);
          const changed=upd.find(p=>p.id===foundInInv.id);
          if(changed)crudApi.update('inventory',changed.id,serverPayload('inventory',changed)).catch(()=>{});
        }
      }
    }
    try{
      await onSave(att);
      alert("✅ Atención guardada en la base de datos");
      onClose();
    }catch(e){alert("No se guardó la atención en la base de datos: "+e.message);}
  };
  return(<>
    <Modal title={`Registrar Atención — ${patientName||"Paciente sin nombre"}`} onClose={onClose} width={560}>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
        <Field label="Tipo de Atención" col="1/-1">
          <div style={{display:"flex",gap:8,marginBottom:4}}>
            {[["clinical","🏥 Servicio Clínico"],["product","🛒 Producto / Servicio Venta"]].map(([v,label])=>(
              <button key={v} onClick={()=>{setAttType(v);setService("");setPrice("");}} style={{flex:1,padding:"7px 10px",borderRadius:8,border:`2px solid ${attType===v?"#4a9d8f":"#d4dde5"}`,background:attType===v?"#f0f9f7":"#fff",color:attType===v?"#1a4a3a":"#5a7a8a",fontWeight:attType===v?700:400,fontSize:12.5,cursor:"pointer",transition:"all .15s"}}>{label}</button>
            ))}
          </div>
        </Field>
        <Field label="Servicio / Producto" col="1/-1">
          <Sel value={service} onChange={pickService}>
            <option value="">Seleccionar...</option>
            {attType==="clinical"&&<optgroup label="── Servicios Clínicos ──">{services.filter(s=>s.active).map(s=><option key={s.id} value={s.name}>{s.name} — S/ {s.price}</option>)}</optgroup>}
            {attType==="product"&&<optgroup label="── Productos ──">{salesProds.filter(s=>s.active!==false).map(s=><option key={`p-${s.id}`} value={s.name}>{s.name} — S/ {s.price||0}</option>)}</optgroup>}
            {attType==="product"&&<optgroup label="── Servicios de Venta ──">{salesSvcsAtt.filter(s=>s.active!==false).map(s=><option key={`sv-${s.id}`} value={s.name}>{s.name} — S/ {s.price||0}</option>)}</optgroup>}
          </Sel>
        </Field>
        <Field label="Monto (S/)"><Inp type="number" value={price} onChange={e=>setPrice(e.target.value)} placeholder="0.00"/></Field>
        <Field label="Método de Pago">
          <Sel value={payMethod} onChange={e=>setPayMethod(e.target.value)}>{PAY_METHODS.map(m=><option key={m}>{m}</option>)}</Sel>
        </Field>
        <Field label="Estado de Pago">
          <Sel value={payStatus} onChange={e=>setPayStatus(e.target.value)}>
            <option value="pendiente">Pendiente</option>
            <option value="pagado">Pagado</option>
          </Sel>
        </Field>
        <Field label="Atendido por">
          <Sel value={attendedBy} onChange={e=>setAttendedBy(e.target.value)}>
            {(db.get(SK.users)||[]).filter(u=>u.active!==false).map(u=><option key={u.id} value={u.name}>{u.name} — {u.role}</option>)}
          </Sel>
        </Field>
      </div>
      <Field label="Notas de la Atención">
        <TA value={note} onChange={e=>setNote(e.target.value)} placeholder="Descripción del tratamiento, observaciones..." style={{minHeight:90}}/>
      </Field>
      <Field label="Fotos de Evidencia">
        <input ref={fileRef} type="file" accept="image/*" multiple onChange={handleFiles} style={{display:"none"}}/>
        <Btn variant="ghost" size="sm" onClick={()=>fileRef.current.click()}><Icon name="photo" size={13}/>Agregar Fotos</Btn>
        {photos.length>0&&(
          <div style={{display:"flex",gap:6,flexWrap:"wrap",marginTop:8}}>
            {photos.map((ph,i)=>(
              <div key={i} style={{position:"relative"}}>
                <img src={ph.data} alt="" onClick={()=>setLightboxSrc(ph.data)} style={{width:72,height:72,objectFit:"cover",borderRadius:7,border:"2px solid #d0dce5",cursor:"zoom-in"}}/>
                <button onClick={()=>setPhotos(p=>p.filter((_,j)=>j!==i))} style={{position:"absolute",top:-5,right:-5,background:"#e05050",border:"none",borderRadius:"50%",width:17,height:17,cursor:"pointer",color:"#fff",fontSize:11,display:"flex",alignItems:"center",justifyContent:"center"}}>×</button>
              </div>
            ))}
          </div>
        )}
      </Field>
      <div style={{display:"flex",alignItems:"center",gap:8,marginTop:14,padding:"10px 14px",background:"#f0f9f7",borderRadius:8,border:"1.5px solid #4a9d8f33"}}>
        <input type="checkbox" id="closeAtt" checked={closedNow} onChange={e=>setClosedNow(e.target.checked)} style={{accentColor:"#4a9d8f",width:16,height:16}}/>
        <label htmlFor="closeAtt" style={{fontSize:13,fontWeight:700,color:"#1a4a3a",cursor:"pointer"}}>✅ Cerrar atención al guardar (marcar como cobrado)</label>
      </div>
      <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:16}}>
        <Btn variant="secondary" onClick={onClose}>Cancelar</Btn>
        <Btn onClick={go}><Icon name="check" size={14}/>Registrar Atención</Btn>
      </div>
    </Modal>
    {lightboxSrc&&<PhotoLightbox src={lightboxSrc} onClose={()=>setLightboxSrc(null)}/>}
  </>);
};

// ─── MÓDULO PACIENTES ─────────────────────────────────────────────────────────
const PatientsModule=({patients,setPatients,currentUser})=>{
  const[lightboxPhoto,setLightboxPhoto]=React.useState(null);
  const safePatients=Array.isArray(patients)?patients:[];
  const[modal,setModal]=useState(null);
  const[prefillPatient,setPrefillPatient]=useState(null);
  const[linkAtt,setLinkAtt]=useState(null);
  const[sel,setSel]=useState(null);
  const[search,setSearch]=useState("");
  const[attModal,setAttModal]=useState(null);
  const[historyWarn,setHistoryWarn]=useState(null);
  const[reflexMap,setReflexMap]=useState(false);
  const[filterStatus,setFilterStatus]=useState("all");
  const[importPatModal,setImportPatModal]=useState(false);
  const[importPatResult,setImportPatResult]=useState(null);
  const[saveNotice,setSaveNotice]=useState("");
  // Auto-abrir desde tarjeta de visita de cliente (sessionStorage)
  useEffect(()=>{
    const openId=sessionStorage.getItem('podo_open_patient_id');
    const openNew=sessionStorage.getItem('podo_open_new_patient');
    const prefill=sessionStorage.getItem('podo_new_patient_prefill');
    const pendingLink=sessionStorage.getItem('podo_link_attendance');
    if(pendingLink){
      try{
        const parsed=JSON.parse(pendingLink);
        setLinkAtt(parsed);
        const q=parsed.patientDni||parsed.patient_dni||parsed.patientName||parsed.patient_name||parsed.service||"";
        if(q)setSearch(String(q));
      }catch{}
    }
    if(openId){
      sessionStorage.removeItem('podo_open_patient_id');
      const all=(_cache['patients']||[]).concat(safePatients);
      const found=all.find(p=>String(p.id)===openId||String(p.id)===String(openId));
      if(found){setSel(found);}
    } else if(openNew){
      sessionStorage.removeItem('podo_open_new_patient');
      if(prefill){
        try{
          const pre=JSON.parse(prefill);
          sessionStorage.removeItem('podo_new_patient_prefill');
          setPrefillPatient({...emptyPt(),...pre});
          setModal('new_prefill');
          sessionStorage.setItem('podo_patient_prefill_data',JSON.stringify(pre));
        }catch{}
      } else {
        setModal('new');
      }
    }
  },[]);
  const[importPatProgress,setImportPatProgress]=useState("");
  const importPatRef=useRef();

  const filtered=patients.filter(p=>{
    const pFN=p.firstName||p.first_name||'';const pLN=p.lastName||p.last_name||'';const matchSearch=!search||(pFN+' '+pLN+' '+(p.dni||'')+' '+(p.id||'')).toLowerCase().includes(search.toLowerCase());
    const matchStatus=filterStatus==="all"||(filterStatus==="active"?p.status==="active":p.status!=="active");
    return matchSearch&&matchStatus;
  });

  const save=async f=>{
    const saved=f.id?{...f,dni:String(f.dni??"").trim()}:{...f,dni:String(f.dni??"").trim()};
    const patientPayload=p=>({
      ...p,
      dni:String(p.dni??"").trim(),
      registration_date:p.registrationDate||p.registration_date||null,
      first_name:p.firstName||p.first_name||"",
      last_name:p.lastName||p.last_name||"",
      path_ant:p.pathAnt||p.path_ant||[],
      zone_left:p.zoneLeft||p.zone_left||[],
      zone_right:p.zoneRight||p.zone_right||[],
      nail_color:p.nailColor||p.nail_color||[],
      nail_thick:p.nailThickness||p.nail_thick||[],
      nail_shape:p.nailShape||p.nail_shape||[],
      shoe_size:p.shoeSize||p.shoe_size||"",
      shoe_type:p.shoeType||p.shoe_type||"",
      patient_type:p.patientType||p.patient_type||"publico",
      membership_id:p.membershipId||p.membership_id||null,
      convenio_name:p.convenioName||p.convenio_name||"",
      convenio_price:p.convenioPrice||p.convenio_price||null,
      physical_activity:p.physicalActivity||p.physical_activity||"",
      activity_detail:p.activityDetail||p.activity_detail||"",
      shares_shoes:p.sharesShoes||p.shares_shoes||"",
      emergency_contact:p.emergencyContact||p.emergency_contact||"",
      emergency_phone:p.emergencyPhone||p.emergency_phone||"",
      referred_by:p.referredBy||p.referred_by||"",
      custom_pathologies:p.customPathologies||p.custom_pathologies||[],
      custom_antecedents:p.customAntecedents||p.custom_antecedents||[],
      custom_tags:p.customTags||p.custom_tags||[]
    });
    const normalizePatient=p=>({
      ...p,
      dni:String(p?.dni??"").trim(),
      firstName:p?.firstName||p?.first_name||"",
      lastName:p?.lastName||p?.last_name||"",
      first_name:p?.first_name||p?.firstName||"",
      last_name:p?.last_name||p?.lastName||"",
      status:p?.status||"active",
      pathologies:Array.isArray(p?.pathologies)?p.pathologies:safeJson(p?.pathologies,[]),
      pathAnt:Array.isArray(p?.pathAnt)?p.pathAnt:(Array.isArray(p?.path_ant)?p.path_ant:safeJson(p?.path_ant,[])),
      zoneLeft:Array.isArray(p?.zoneLeft)?p.zoneLeft:(Array.isArray(p?.zone_left)?p.zone_left:safeJson(p?.zone_left,[])),
      zoneRight:Array.isArray(p?.zoneRight)?p.zoneRight:(Array.isArray(p?.zone_right)?p.zone_right:safeJson(p?.zone_right,[])),
    });
    const replacePatientInCache=(tempId,patientRecord)=>{
      const normalized=normalizePatient(patientRecord);
      const current=db.get(SK.patients)||[];
      let replaced=false;
      const next=current.map(p=>{
        const sameTemp=String(p.id)===String(tempId);
        const sameReal=normalized.id&&String(p.id)===String(normalized.id);
        const sameDni=normalized.dni&&String(p.dni||"").trim()===normalized.dni;
        if(sameTemp||sameReal||sameDni){replaced=true;return{...p,...normalized};}
        return p;
      });
      if(!replaced)next.push(normalized);
      setPatients(next);
      return normalized;
    };
    const resolveCreatedPatient=async(created,savedPatient)=>{
      if(created&&created.id)return created;
      const dni=String(savedPatient?.dni||"").trim();
      if(dni){
        const matches=await crudApi.list('patients',{dni,limit:1});
        const found=matches.find(p=>String(p?.dni||"").trim()===dni);
        if(found?.id)return found;
      }
      throw new Error("El servidor no devolvió el ID del paciente guardado");
    };
    const applyPendingLink=patientRecord=>{
      if(!linkAtt||!patientRecord?.id)return false;
      const realPatient=normalizePatient(patientRecord);
      const patientName=`${realPatient.firstName||realPatient.first_name||''} ${realPatient.lastName||realPatient.last_name||''}`.trim();
      const patientDni=String(realPatient.dni||"").trim();
      const linked=(db.get(SK.attendances)||[]).map(a=>String(a.id)===String(linkAtt.id)?{
        ...a,
        patientId:realPatient.id,
        patient_id:realPatient.id,
        patientName,
        patient_name:patientName,
        patientDni,
        patient_dni:patientDni
      }:a);
      db.set(SK.attendances,linked);
      crudApi.update('attendances',linkAtt.id,{patient_id:realPatient.id,patient_name:patientName,patient_dni:patientDni}).catch(()=>{});
      sessionStorage.removeItem('podo_link_attendance');
      setLinkAtt(null);
      return true;
    };
    try{
      if(f.id){
        const updated=await crudApi.update('patients',f.id,patientPayload(saved));
        if(!updated||!updated.id)throw new Error("El servidor no devolvió el paciente actualizado");
        const syncedPatient=replacePatientInCache(f.id,{...saved,...updated});
        applyPendingLink(syncedPatient);
      }else{
        const created=await crudApi.create('patients',patientPayload(saved));
        const realPatient=await resolveCreatedPatient(created,saved);
        const syncedPatient=replacePatientInCache(realPatient.id,{...saved,...realPatient,id:realPatient.id});
        applyPendingLink(syncedPatient);
      }
      setModal(null);
      setSaveNotice(f.id?"Historia clínica actualizada exitosamente en la base de datos.":"Paciente guardado exitosamente en la base de datos.");
      setTimeout(()=>setSaveNotice(""),3500);
    }catch(e){
      e.userMessage=e?.authExpired
        ?"La sesión expiró. Inicie sesión nuevamente y vuelva a registrar al paciente."
        :"Revise conexión, permisos y DNI duplicado. Detalle: "+(e?.message||e);
      throw e;
    }
  };
  const openAttention=p=>{
    if(!patientHasClinicalHistory(p)){setHistoryWarn(p);return;}
    setAttModal(p);
  };
  const linkPatientToAttention=p=>{
    if(!linkAtt||!p?.id)return;
    const patientName=`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`.trim();
    const patientDni=String(p.dni||"").trim();
    const linked=(db.get(SK.attendances)||[]).map(a=>String(a.id)===String(linkAtt.id)?{
      ...a,
      patientId:p.id,
      patient_id:p.id,
      patientName,
      patient_name:patientName,
      patientDni,
      patient_dni:patientDni
    }:a);
    db.set(SK.attendances,linked);
    crudApi.update('attendances',linkAtt.id,{patient_id:p.id,patient_name:patientName,patient_dni:patientDni}).catch(()=>{});
    sessionStorage.removeItem('podo_link_attendance');
    setLinkAtt(null);
    alert("Paciente vinculado correctamente a la atención.");
  };
  const del=async id=>{
    if(window.confirm("¿Eliminar este paciente?")){
      try{
        await crudApi.remove('patients',id);
        const next=safePatients.filter(p=>String(p.id)!==String(id));
        setPatients(next);
      }catch(e){alert("No se eliminó el paciente en la base de datos: "+e.message);}
    }
  };
  const saveAtt=async att=>{
    const created=await crudApi.create('attendances',att);
    const saved={...att,...created,id:created?.id||att.id};
    const all=db.get(SK.attendances)||[];
    db.set(SK.attendances,[...all,saved]);
    if(saved.closed||saved.payStatus==="pagado"){
      const appts=db.get(SK.appointments)||[];
      db.set(SK.appointments,appts.map(ap=>{
        const same=String(ap.patientId||ap.patient_id||"")===String(saved.patientId||saved.patient_id||"")&&String(ap.date||"").slice(0,10)===String(saved.date||"").slice(0,10)&&(!ap.service||!saved.service||String(ap.service).trim().toLowerCase()===String(saved.service).trim().toLowerCase());
        return same?{...ap,status:"done"}:ap;
      }));
    }
    return saved;
  };
  const patAtt=sel?(db.get(SK.attendances)||[]).filter(a=>a.patientId===sel.id):[];
  const closeAtt=async attId=>{
    try{
      const saved=await crudApi.update('attendances',attId,{closed:1,pay_status:"pagado"});
      const all=(db.get(SK.attendances)||[]).map(a=>a.id===attId?{...a,...saved,closed:true,payStatus:"pagado"}:a);
      db.set(SK.attendances,all);setSel(s=>s?{...s}:s);
      alert("✅ Cierre de atención guardado en la base de datos");
    }catch(e){alert("No se guardó el cierre de atención en la base de datos: "+e.message);}
  };

  // ─── IMPORT PATIENTS FROM PDF/EXCEL/CSV ──────────────────────────────────
  const handleImportPatients=async(e)=>{
    const file=e.target.files[0];
    if(!file)return;
    importPatRef.current.value="";
    const ext=file.name.split(".").pop().toLowerCase();
    setImportPatResult(null);
    setImportPatProgress("Procesando archivo...");

    const existing=db.get(SK.patients)||[];
    const maxId=existing.length?Math.max(...existing.map(p=>p.id||0)):0;

    // ── Helper: split full name intelligently ─────────────────────────────
    const splitName=(fullName)=>{
      const clean=(fullName||"").trim().replace(/\s+/g," ");
      const words=clean.split(" ").filter(Boolean);
      if(words.length===0)return{firstName:"",lastName:""};
      if(words.length===1)return{firstName:words[0],lastName:""};
      if(words.length===2)return{firstName:words[0],lastName:words[1]};
      if(words.length===3)return{firstName:words[0],lastName:words[1]+" "+words[2]};
      // 4+ words: first 2 = nombres, rest = apellidos (common in Peru/LATAM)
      return{firstName:words[0]+" "+words[1],lastName:words.slice(2).join(" ")};
    };

    // ── Helper: clean NULL/-/empty values ────────────────────────────────
    const clean=(v)=>{
      const s=String(v||"").trim();
      return(s==="NULL"||s==="-"||s==="null"||s==="undefined")?"":s;
    };

    // ── Helper: capitalize properly ──────────────────────────────────────
    const toTitleCase=(s)=>clean(s).replace(/\w\S*/g,t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase());
    const persistImportedPatients=async(list)=>{
      let savedCount=0,failedCount=0;
      for(const p0 of list){
        const p={...p0,firstName:p0.firstName||"-",lastName:p0.lastName||"-",dni:String(p0.dni||`SIN-${String(p0.id||Date.now()).padStart(5,"0")}`).trim()};
        try{
          const created=await crudApi.create('patients',serverPayload('patients',p));
          savedCount++;
          if(created?.id){
            const current=db.get(SK.patients)||[];
            const next=current.map(x=>String(x.id)===String(p0.id)?{...x,...created,id:created.id}:x);
            db.set(SK.patients,next);setPatients(next);
          }
        }catch(e){failedCount++;console.warn('import patient',e.message);}
      }
      return{savedCount,failedCount};
    };

    // ── PDF import via Anthropic IA ──────────────────────────────────────
    if(ext==="pdf"){
      setImportPatProgress("Leyendo PDF con IA...");
      try{
        const b64=await new Promise((resolve,reject)=>{
          const reader=new FileReader();
          reader.onload=()=>resolve(reader.result.split(",")[1]);
          reader.onerror=()=>reject(new Error("No se pudo leer el PDF"));
          reader.readAsDataURL(file);
        });
        const res=await fetch(API_BASE+'/special.php?action=ai_import_pdf',{
          method:"POST",
          headers:{"Content-Type":"application/json"},
          body:JSON.stringify({
            b64,
            apiKey:db.get(SK.company)?.aiApiKey||"",
            messages:[{role:"user",content:[
              {type:"document",source:{type:"base64",media_type:"application/pdf",data:b64}},
              {type:"text",text:`Extrae los datos de paciente(s) de este documento de historia clínica podológica.
Devuelve SOLO un array JSON con objetos. Campos posibles:
firstName (Nombres), lastName (Apellidos), dni (DNI/Carnet), dob (fecha nacimiento YYYY-MM-DD),
sex (M/F), phone (Celular/Teléfono), email, address (Dirección),
occupation (Ocupación/Profesión), weight (Peso kg), height (Talla cm),
shoeSize (Talla calzado), shoeType (Tipo calzado),
pathologies (array de patologías), pathAnt (array antecedentes),
smoke (Fuma: Si/No), alcohol (Alcohol: Si/No), meds (Medicamentos),
emergencyContact (Contacto emergencia), emergencyPhone (Tel emergencia),
notes (Observaciones/Notas).
Si no encuentras un campo déjalo vacío. Responde SOLO el JSON array sin explicación ni markdown.`}
            ]}]
          })
        });
        const data=await res.json();
        if(data.error){throw new Error(data.error.message||"Error de API");}
        const txt=data.content?.find(c=>c.type==="text")?.text||"[]";
        const clean2=txt.replace(/```json|```/g,"").trim();
        let parsed;
        try{parsed=JSON.parse(clean2);}catch{throw new Error("La IA no devolvió JSON válido. Intente con un PDF más simple.");}
        const arr=Array.isArray(parsed)?parsed:[parsed];
        const newPats=arr.filter(r=>r.firstName||r.dni).map((r,i)=>({
          ...emptyPt(),id:maxId+i+1,
          firstName:toTitleCase(r.firstName),lastName:toTitleCase(r.lastName),
          dni:clean(r.dni),dob:clean(r.dob),sex:clean(r.sex).toUpperCase(),
          phone:clean(r.phone),email:clean(r.email),address:clean(r.address),
          occupation:toTitleCase(r.occupation),weight:clean(r.weight),height:clean(r.height),
          shoeSize:clean(r.shoeSize),shoeType:clean(r.shoeType),
          pathologies:Array.isArray(r.pathologies)?r.pathologies:[],
          pathAnt:Array.isArray(r.pathAnt)?r.pathAnt:[],
          smoke:clean(r.smoke),alcohol:clean(r.alcohol),meds:clean(r.meds),
          emergencyContact:clean(r.emergencyContact),emergencyPhone:clean(r.emergencyPhone),
          notes:clean(r.notes),registrationDate:todayStr(),status:"active"
        }));
        if(!newPats.length){setImportPatResult({ok:false,msg:"No se pudieron extraer datos del PDF. Verifique que el PDF contiene una historia clínica."});setImportPatProgress("");return;}
        const merged=[...existing,...newPats];
        db.set(SK.patients,merged);setPatients(merged);
        const persisted=await persistImportedPatients(newPats);
        setImportPatResult({ok:persisted.failedCount===0,msg:`✅ PDF importado con IA: ${newPats.length} paciente(s) extraído(s). Guardados en base: ${persisted.savedCount}. ${persisted.failedCount?`No guardados: ${persisted.failedCount}.`:''}`});
      }catch(err){
        setImportPatResult({ok:false,msg:"Error al procesar PDF: "+err.message});
      }
      setImportPatProgress("");
      return;
    }

    // ── Excel (.xlsx/.xls) via SheetJS ───────────────────────────────────
    if(ext==="xlsx"||ext==="xls"){
      setImportPatProgress("Leyendo Excel...");
      try{
        const XLSX=window.XLSX;
        if(!XLSX)throw new Error("Biblioteca Excel no disponible. Reintente en unos segundos.");
        const ab=await file.arrayBuffer();
        const wb=XLSX.read(ab,{type:"array"});
        const ws=wb.Sheets[wb.SheetNames[0]];
        const rows=XLSX.utils.sheet_to_json(ws,{defval:""});
        // Field mapping: supports Spanish and English column names
        const FM={
          "Nombres":"fn","Nombre":"fn","firstName":"fn","nombres":"fn","NOMBRES":"fn",
          "Apellidos":"ln","Apellido":"ln","lastName":"ln","apellidos":"ln","APELLIDOS":"ln",
          "Nombre Completo":"full","NombreCompleto":"full",
          "DNI":"dni","Carnet":"dni","Documento":"dni","dni":"dni","RUC":"dni",
          "Celular":"ph","Teléfono":"ph","Telefono":"ph","phone":"ph","Tel":"ph","CELULAR":"ph",
          "Fecha Nacimiento":"dob","FechaNac":"dob","F.Nacimiento":"dob","dob":"dob","Fecha_Nac":"dob",
          "Sexo":"sx","Género":"sx","Genero":"sx","sex":"sx","SEXO":"sx",
          "Dirección":"ad","Direccion":"ad","address":"ad","Direc":"ad","DIRECCIÓN":"ad",
          "Correo":"em","Email":"em","email":"em","Correo Electrónico":"em",
          "Ocupación":"oc","Ocupacion":"oc","Profesión":"oc","Profesion":"oc","occupation":"oc","OCUPACIÓN":"oc",
          "Actividad":"ac","Activ":"ac",
          "Peso":"wt","weight":"wt","Edad":"ag",
          "Talla":"ht","height":"ht","N° Calzado":"ss","Calzado":"ss","shoeSize":"ss",
          "Observaciones":"nt","Notas":"nt","notes":"nt","OBSERVACIONES":"nt",
        };
        const newPats=rows.map((r,i)=>{
          const p={...emptyPt(),id:maxId+i+1,registrationDate:todayStr(),status:"active"};
          let fullName="";
          Object.entries(r).forEach(([k,v])=>{
            const f=FM[k];
            const val=clean(String(v));
            if(!f||!val)return;
            if(f==="fn")p.firstName=toTitleCase(val);
            else if(f==="ln")p.lastName=toTitleCase(val);
            else if(f==="full")fullName=val;
            else if(f==="dni")p.dni=val;
            else if(f==="ph")p.phone=val.replace(/\D/g,"").slice(0,15);
            else if(f==="dob")p.dob=val;
            else if(f==="sx")p.sex=val.charAt(0).toUpperCase();
            else if(f==="ad")p.address=val;
            else if(f==="em")p.email=val;
            else if(f==="oc")p.occupation=toTitleCase(val);
            else if(f==="wt")p.weight=val;
            else if(f==="ht")p.height=val;
            else if(f==="ss")p.shoeSize=val;
            else if(f==="nt")p.notes=val;
          });
          if(fullName&&!p.firstName){const n=splitName(fullName);p.firstName=toTitleCase(n.firstName);p.lastName=toTitleCase(n.lastName);}
          return p;
        }).filter(p=>p.firstName||p.dni);
        if(!newPats.length){setImportPatResult({ok:false,msg:"No se encontraron datos en el Excel. Descargue la plantilla para ver el formato esperado."});setImportPatProgress("");return;}
        const merged=[...existing,...newPats];
        db.set(SK.patients,merged);setPatients(merged);
        const persisted=await persistImportedPatients(newPats);
        setImportPatResult({ok:persisted.failedCount===0,msg:`✅ Excel importado: ${newPats.length} paciente(s) agregado(s) de ${rows.length} filas. Guardados en base: ${persisted.savedCount}. ${persisted.failedCount?`No guardados: ${persisted.failedCount}.`:''}`});
      }catch(err){
        setImportPatResult({ok:false,msg:"Error al leer Excel: "+err.message});
      }
      setImportPatProgress("");
      return;
    }

    // ── CSV — soporta formato estándar Y formato especial podología ──────
    if(ext==="csv"){
      setImportPatProgress("Leyendo CSV...");
      try{
        const text=await file.text();
        // Remove BOM if present
        const cleaned=text.replace(/^\uFEFF/,"");
        const lines=cleaned.split("\n").filter(l=>l.trim());
        if(lines.length<2){setImportPatResult({ok:false,msg:"CSV vacío o sin datos"});setImportPatProgress("");return;}

        let newPats=[];

        // ── Detect format: special podology CSV vs standard CSV ──────────
        const firstLine=lines[0];
        const isSpecialFormat=firstLine.includes("\"\"\"") || 
          (firstLine.startsWith('"') && lines[1] && lines[1].startsWith('"Historial'));

        if(isSpecialFormat){
          // ── SPECIAL FORMAT: "#,""Nombres"",""Dirección""..." ─────────
          // Format: "Historial,""Name"",""Dir"",""Tel"",""Age"",""Activity"",""Occupation"",""""" 
          setImportPatProgress(`Procesando formato podología (${lines.length-1} registros)...`);
          newPats=lines.slice(1).map((line,i)=>{
            line=line.trim();
            if(!line)return null;
            // Remove outer wrapping quotes
            if(line.startsWith('"')&&line.endsWith('"'))line=line.slice(1,-1);
            // Split by "," - each field is wrapped in ""
            const parts=line.split('","');
            if(parts.length<2)return null;
            // First part: "Historial,"Name" — extract name after first comma
            const firstPart=parts[0];
            const commaIdx=firstPart.indexOf(",");
            const nombreCompleto=commaIdx>=0?firstPart.slice(commaIdx+1).replace(/"/g,"").trim():firstPart.replace(/"/g,"").trim();
            if(!nombreCompleto)return null;
            const {firstName,lastName}=splitName(nombreCompleto);
            const telefono=clean(parts[2]?.replace(/"/g,"")||"");
            const edad=clean(parts[3]?.replace(/"/g,"")||"");
            const ocupacion=toTitleCase(clean(parts[5]?.replace(/"/g,"")||""));
            const direccion=clean(parts[1]?.replace(/"/g,"")||"");
            return{
              ...emptyPt(),
              id:maxId+i+1,
              firstName:toTitleCase(firstName),
              lastName:toTitleCase(lastName),
              phone:telefono==="NULL"||telefono==="-"?"":telefono.replace(/\D/g,"").slice(0,15),
              address:direccion,
              occupation:ocupacion,
              notes:edad&&edad!=="NULL"?`Edad referencial: ${edad} años`:"",
              registrationDate:todayStr(),
              status:"active"
            };
          }).filter(Boolean).filter(p=>p.firstName||p.lastName);

        } else {
          // ── STANDARD CSV FORMAT ────────────────────────────────────────
          const quote=/"/g;
          const headers=lines[0].split(",").map(h=>h.trim().replace(quote,""));
          const FM2={
            "firstName":"fn","Nombres":"fn","Nombre":"fn","nombre":"fn",
            "lastName":"ln","Apellidos":"ln","Apellido":"ln","apellido":"ln",
            "dni":"dni","DNI":"dni","Carnet":"dni",
            "phone":"ph","Celular":"ph","celular":"ph","Teléfono":"ph","telefono":"ph",
            "dob":"dob","fecha_nacimiento":"dob","Fecha Nacimiento":"dob",
            "sex":"sx","Sexo":"sx","sexo":"sx",
            "address":"ad","Dirección":"ad","Direccion":"ad","direccion":"ad",
            "email":"em","Email":"em","correo":"em",
            "occupation":"oc","Ocupación":"oc","Ocupacion":"oc","ocupacion":"oc",
            "weight":"wt","Peso":"wt","height":"ht","Talla":"ht",
            "shoeSize":"ss","N° Calzado":"ss",
            "notes":"nt","Observaciones":"nt","observaciones":"nt",
          };
          // ── Proper RFC 4180 CSV parser ──────────────────────────────────
          const parseCSVLine=(line)=>{
            const result=[];let cur="";let inQ=false;
            for(let ci=0;ci<line.length;ci++){
              const ch=line[ci];
              if(ch==='"'){
                if(inQ&&line[ci+1]==='"'){cur+='"';ci++;}
                else{inQ=!inQ;}
              } else if(ch===','&&!inQ){result.push(cur.trim());cur="";}
              else{cur+=ch;}
            }
            result.push(cur.trim());return result;
          };
          newPats=lines.slice(1).map((line,i)=>{
            const vals=parseCSVLine(line);
            const r={};headers.forEach((h,j)=>{r[h]=(vals[j]||"").replace(quote,"");});
            const p={...emptyPt(),id:maxId+i+1,registrationDate:todayStr(),status:"active"};
            let fullName="";
            headers.forEach(h=>{
              const f=FM2[h];const val=clean(r[h]);
              if(!f||!val)return;
              if(f==="fn")p.firstName=toTitleCase(val);
              else if(f==="ln")p.lastName=toTitleCase(val);
              else if(f==="dni")p.dni=val;
              else if(f==="ph")p.phone=val.replace(/\D/g,"").slice(0,15);
              else if(f==="dob")p.dob=val;
              else if(f==="sx")p.sex=val.charAt(0).toUpperCase();
              else if(f==="ad")p.address=val;
              else if(f==="em")p.email=val;
              else if(f==="oc")p.occupation=toTitleCase(val);
              else if(f==="wt")p.weight=val;
              else if(f==="ht")p.height=val;
              else if(f==="ss")p.shoeSize=val;
              else if(f==="nt")p.notes=val;
            });
            if(fullName&&!p.firstName){const n=splitName(fullName);p.firstName=toTitleCase(n.firstName);p.lastName=toTitleCase(n.lastName);}
            return p;
          }).filter(p=>p.firstName||p.dni);
        }

        if(!newPats.length){setImportPatResult({ok:false,msg:"No se encontraron registros válidos en el CSV."});setImportPatProgress("");return;}
        const merged=[...existing,...newPats];
        db.set(SK.patients,merged);setPatients(merged);
        const persisted=await persistImportedPatients(newPats);
        setImportPatResult({ok:persisted.failedCount===0,msg:`✅ CSV importado: ${newPats.length} paciente(s) agregado(s). Guardados en base: ${persisted.savedCount}. ${persisted.failedCount?`No guardados: ${persisted.failedCount}.`:''}`});
      }catch(err){
        setImportPatResult({ok:false,msg:"Error al leer CSV: "+err.message});
      }
      setImportPatProgress("");
      return;
    }

    setImportPatResult({ok:false,msg:"Formato no soportado. Use PDF, Excel (.xlsx) o CSV."});
    setImportPatProgress("");
  };

    const downloadPatientsTemplate=()=>{
    const headers="firstName,lastName,dni,dob,sex,phone,email,address,occupation,weight,height,shoeSize,shoeType,notes";
    const example="Juan,Perez,12345678,1985-03-15,M,999888777,juan@email.com,Av. Lima 123,Contador,70,170,42,Zapatilla deportiva,Paciente referido";
    const csv=headers+"\n"+example;
    const blob=new Blob([csv],{type:"text/csv;charset=utf-8"});
    const url=URL.createObjectURL(blob);
    const a=document.createElement("a");
    a.href=url;a.download="plantilla_pacientes_podoclinic.csv";
    a.click();URL.revokeObjectURL(url);
  };

  return(
    <div className="slide-in">
      {saveNotice&&(
        <div style={{background:"#ecfdf5",border:"1.5px solid #86efac",borderRadius:10,padding:"10px 14px",marginBottom:14,color:"#166534",fontSize:13,fontWeight:700}}>
          {saveNotice}
        </div>
      )}
      {linkAtt&&(
        <div style={{background:"#fff7ed",border:"1.5px solid #f59e0b55",borderRadius:10,padding:"10px 14px",marginBottom:14,display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"}}>
          <div style={{fontSize:13,color:"#8a4b08",fontWeight:700,flex:1}}>
            Atención pendiente por vincular: {linkAtt.time||"—"} · {linkAtt.service||"Sin servicio"} · {currency(linkAtt.price||0)}
          </div>
          <Btn size="sm" variant="ghost" onClick={()=>{sessionStorage.removeItem('podo_link_attendance');setLinkAtt(null);}}>Cancelar vínculo</Btn>
        </div>
      )}
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Pacientes</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>{patients.length} pacientes registrados · {patients.filter(p=>p.status==="active").length} activos</div>
        </div>
        <div style={{display:"flex",gap:8,flexWrap:"wrap"}}>
          <Btn variant="ghost" onClick={()=>setReflexMap(true)}><Icon name="map" size={14}/>Reflexología</Btn>
          <Btn variant="ghost" onClick={()=>{setImportPatResult(null);setImportPatModal(true)}} style={{background:"#f0f9f7",color:"#2ea87e",border:"1.5px solid #2ea87e44"}}><Icon name="arrow" size={14}/>📥 Importar PDF/Excel</Btn>
          <Btn onClick={()=>{setSel(null);setModal("new")}}><Icon name="plus" size={14}/>Nuevo Paciente</Btn>
        </div>
      </div>

      <Card style={{marginBottom:14,padding:"12px 16px"}}>
        <div style={{display:"flex",gap:10,alignItems:"center",flexWrap:"wrap"}}>
          <div style={{position:"relative",flex:1,minWidth:200}}>
            <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
            <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar por nombre, DNI o ID..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
          </div>
          <div style={{display:"flex",gap:4}}>
            {[["all","Todos"],["active","Activos"],["closed","Cerrados"]].map(([v,l])=>(
              <button key={v} onClick={()=>setFilterStatus(v)} style={{padding:"7px 13px",borderRadius:8,border:`1.5px solid ${filterStatus===v?"#4a9d8f":"#d4dde5"}`,background:filterStatus===v?"#4a9d8f":"#fff",color:filterStatus===v?"#fff":"#5a7a8a",fontWeight:600,fontSize:12,cursor:"pointer"}}>{l}</button>
            ))}
          </div>
        </div>
      </Card>

      <Card style={{padding:0,overflow:"hidden"}}>
        <div style={{overflowX:"auto"}}>
          <table style={{width:"100%",borderCollapse:"collapse",minWidth:720}}>
            <thead>
              <tr style={{background:"linear-gradient(90deg,#f4f8fa,#eef3f7)"}}>
                {["ID","Paciente","DNI","Edad","Celular","Patologías","Estado","Acciones"].map(h=>(
                  <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",whiteSpace:"nowrap"}}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {filtered.length===0&&<tr><td colSpan={8} style={{textAlign:"center",padding:40,color:"#8a9aaa",fontSize:13}}>No se encontraron pacientes</td></tr>}
              {filtered.map((p,i)=>(
                <tr key={p.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff",transition:"background .1s"}} onMouseOver={e=>e.currentTarget.style.background="#f0f8f6"} onMouseOut={e=>e.currentTarget.style.background=i%2?"#fafcfd":"#fff"}>
                  <td style={{padding:"10px 14px",fontSize:12,fontWeight:700,color:"#4a9d8f",whiteSpace:"nowrap"}}>#{padId(p.id)}</td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{p.firstName||p.first_name||''} {p.lastName||p.last_name||''}</div>
                    <div style={{fontSize:10.5,color:"#8a9aaa"}}>{fmt(p.registrationDate||p.created_at||'')} · {p.sex==="F"?"♀":"♂"}</div>
                  </td>
                  <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a",whiteSpace:"nowrap"}}>{p.dni}</td>
                  <td style={{padding:"10px 14px",fontSize:13,whiteSpace:"nowrap",fontWeight:600}}>{calcAge(p.dob)} años</td>
                  <td style={{padding:"10px 14px",fontSize:13}}>{p.phone||"—"}</td>
                  <td style={{padding:"10px 14px",maxWidth:180}}>
                    <div style={{display:"flex",gap:3,flexWrap:"wrap"}}>
                      {(p.pathologies||[]).slice(0,2).map(pt=><Badge key={pt} color="teal">{pt}</Badge>)}
                      {(p.pathologies||[]).length>2&&<Badge color="gray">+{p.pathologies.length-2}</Badge>}
                      {!(p.pathologies||[]).length&&<span style={{fontSize:11,color:"#b0bcc8"}}>—</span>}
                    </div>
                  </td>
                  <td style={{padding:"10px 14px"}}><Badge color={p.status==="active"?"green":"gray"}>{p.status==="active"?"Activo":"Cerrado"}</Badge></td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{display:"flex",gap:4}}>
                      {linkAtt&&<button onClick={()=>linkPatientToAttention(p)} title="Vincular esta atención a este paciente" style={{background:"#f59e0b18",border:"1px solid #f59e0b55",borderRadius:6,padding:"5px 8px",cursor:"pointer",color:"#8a4b08",fontSize:11,fontWeight:700}}>Vincular</button>}
                      <button onClick={()=>{setSel(p);setModal("view")}} title="Ver" style={{background:"#4a9d8f14",border:"none",borderRadius:6,padding:6,cursor:"pointer",color:"#4a9d8f"}}><Icon name="eye" size={13}/></button>
                      <button onClick={()=>{setSel(p);setModal("edit")}} title="Editar" style={{background:"#2563eb14",border:"none",borderRadius:6,padding:6,cursor:"pointer",color:"#2563eb"}}><Icon name="edit" size={13}/></button>
                      <button onClick={()=>openAttention(p)} title="Nueva Atención" style={{background:"#2ea87e14",border:"none",borderRadius:6,padding:6,cursor:"pointer",color:"#2ea87e"}}><Icon name="plus" size={13}/></button>
                      {can(currentUser,"admin")&&<button onClick={()=>del(p.id)} title="Eliminar" style={{background:"#e0505014",border:"none",borderRadius:6,padding:6,cursor:"pointer",color:"#e05050"}}><Icon name="trash" size={13}/></button>}
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>

      {(modal==="new"||modal==="edit"||modal==="new_prefill")&&(
        <Modal title={modal==="edit"?"Editar Historia Clínica":"Nueva Historia Clínica"} onClose={()=>setModal(null)} width={800}>
          <PatientForm initial={modal==="edit"?sel:(modal==="new_prefill"?prefillPatient:null)} onSave={save} onCancel={()=>setModal(null)} patients={patients} currentUser={currentUser}/>
        </Modal>
      )}

      {modal==="view"&&sel&&(
        <Modal title={`Historia Clínica #${padId(sel.id)} — ${sel.firstName||sel.first_name||''} ${sel.lastName||sel.last_name||''}`} onClose={()=>setModal(null)} width={780}>
          <div className="fade-in">
            <div style={{background:"linear-gradient(135deg,#0f2a3a,#1a4a5a)",borderRadius:12,padding:"16px 20px",marginBottom:20,display:"flex",flexWrap:"wrap",gap:16}}>
              <div style={{flex:1,minWidth:180}}>
                <div style={{fontSize:10,color:"rgba(255,255,255,0.45)",textTransform:"uppercase"}}>Historia Clínica</div>
                <div style={{fontSize:20,fontWeight:800,color:"#fff",letterSpacing:"-0.02em"}}>#{padId(sel.id)}</div>
              </div>
              <div style={{flex:2,minWidth:200}}>
                <div style={{fontSize:16,fontWeight:700,color:"#5dd4c6"}}>{sel.firstName||sel.first_name||''} {sel.lastName||sel.last_name||''}</div>
                <div style={{fontSize:12,color:"rgba(255,255,255,0.55)"}}>DNI: {sel.dni} · {sel.sex==="F"?"Femenino":"Masculino"} · {calcAge(sel.dob)} años</div>
                {sel.insurance&&<div style={{fontSize:11,color:"rgba(255,255,255,0.45)",marginTop:2}}>Seguro: {sel.insurance}</div>}
              </div>
              <div style={{textAlign:"right"}}>
                <div style={{fontSize:10,color:"rgba(255,255,255,0.45)"}}>Fecha de Alta</div>
                <div style={{fontSize:13,fontWeight:600,color:"#fff"}}>{fmt(sel.registrationDate)}</div>
                <Badge color={sel.status==="active"?"green":"gray"} >{sel.status==="active"?"Activo":"Cerrado"}</Badge>
              </div>
            </div>
            <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:10,marginBottom:18}}>
              {[["Celular",sel.phone||"—"],["Dirección",sel.address||"—"],["Ocupación",sel.occupation||"—"],["Peso",sel.weight?`${sel.weight} kg`:"—"],["Talla",sel.height?`${sel.height} cm`:"—"],["N° Calzado",sel.shoeSize||"—"],["Tipo Calzado",sel.shoeType||"—"],["Actividad Física",sel.physicalActivity||"—"],["Referido por",sel.referredBy||"—"]].map(([l,v])=>(
                <div key={l} style={{background:"#f8fafc",borderRadius:8,padding:"8px 12px",border:"1px solid #eef2f7"}}>
                  <div style={{fontSize:9.5,fontWeight:700,color:"#8a9aaa",textTransform:"uppercase",marginBottom:2,letterSpacing:"0.06em"}}>{l}</div>
                  <div style={{fontSize:13,color:"#1a2332",fontWeight:500,wordBreak:"break-word"}}>{v}</div>
                </div>
              ))}
            </div>
            {sel.pathAnt?.length>0&&<div style={{marginBottom:12}}><div style={{fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:6,letterSpacing:"0.06em"}}>Antecedentes Patológicos</div><div style={{display:"flex",gap:5,flexWrap:"wrap"}}>{sel.pathAnt.map(p=><Badge key={p} color="orange">{p}</Badge>)}</div></div>}
            {sel.pathologies?.length>0&&<div style={{marginBottom:12}}><div style={{fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:6,letterSpacing:"0.06em"}}>Patologías</div><div style={{display:"flex",gap:5,flexWrap:"wrap"}}>{sel.pathologies.map(p=><Badge key={p} color="teal">{p}</Badge>)}</div></div>}
            {(sel.zoneLeft?.length>0||sel.zoneRight?.length>0)&&(
              <div style={{marginBottom:14,background:"#f8fafc",borderRadius:8,padding:"10px 14px"}}>
                <div style={{fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:6,letterSpacing:"0.06em"}}>Zona Plantar</div>
                {sel.zoneLeft?.length>0&&<div style={{fontSize:12.5,marginBottom:3}}><b>Pie Izq:</b> {sel.zoneLeft.join(", ")}</div>}
                {sel.zoneRight?.length>0&&<div style={{fontSize:12.5}}><b>Pie Der:</b> {sel.zoneRight.join(", ")}</div>}
              </div>
            )}
            <div style={{marginBottom:16}}>
              <div style={{fontSize:14,fontWeight:700,color:"#1a3a4a",marginBottom:12,paddingBottom:8,borderBottom:"1px solid #eef2f7",display:"flex",alignItems:"center",justifyContent:"space-between"}}>
                <span>📋 Historial de Atenciones</span>
                <Badge color="blue">{patAtt.length} atenciones</Badge>
              </div>
              {patAtt.length===0?<div style={{textAlign:"center",padding:"20px 0",color:"#8a9aaa",fontSize:13}}>Sin atenciones registradas</div>:patAtt.map(a=>(
                <div key={a.id} style={{background:"#f4f8fa",borderRadius:10,padding:14,marginBottom:10,border:"1px solid #e8edf2"}}>
                  <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:8,flexWrap:"wrap",gap:6}}>
                    <div>
                      <div style={{fontWeight:700,fontSize:13,color:"#1a2332"}}>{fmt(a.date)}{a.time?` — ${a.time}h`:""} — {a.service||"Sin servicio"}</div>
                      <div style={{fontSize:11,color:"#8a9aaa",marginTop:2}}>Por: <b style={{color:"#4a9d8f"}}>{a.attendedBy||"—"}</b> · <b style={{color:"#2ea87e"}}>{currency(a.price)}</b> · {a.payMethod||"—"}</div>
                    </div>
                    <div style={{display:"flex",gap:6,alignItems:"center",flexWrap:"wrap"}}>
                      <Badge color={a.payStatus==="pagado"?"green":"orange"}>{a.payStatus==="pagado"?"Pagado":"Pendiente"}</Badge>
                      <Badge color={a.closed?"gray":"blue"}>{a.closed?"Cerrado":"Abierto"}</Badge>
                      {!a.closed&&<Btn size="sm" variant="warning" onClick={()=>closeAtt(a.id)}><Icon name="lock" size={11}/>Cerrar</Btn>}
                    </div>
                  </div>
                  {a.notes&&<div style={{fontSize:12.5,color:"#3a5a6a",marginTop:4,lineHeight:1.6}}>{a.notes}</div>}
                  {a.photos?.length>0&&(
                    <div style={{display:"flex",gap:6,marginTop:8,flexWrap:"wrap"}}>
                      {a.photos.map((ph,i)=><img key={i} src={ph.data} alt="" onClick={()=>setLightboxPhoto(ph.data)} style={{width:60,height:60,objectFit:"cover",borderRadius:7,border:"1.5px solid #d0dce5",cursor:"zoom-in"}}/>)}
                    </div>
                  )}
                </div>
              ))}
            </div>
            <div style={{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"}}>
              <Btn variant="secondary" onClick={()=>setModal(null)}>Cerrar</Btn>
              <Btn variant="ghost" onClick={()=>setReflexMap(true)}><Icon name="map" size={13}/>Reflexología</Btn>
              <Btn onClick={()=>setModal("edit")}><Icon name="edit" size={13}/>Editar</Btn>
              <Btn variant="success" onClick={()=>openAttention(sel)}><Icon name="plus" size={13}/>Nueva Atención</Btn>
            </div>
          </div>
        </Modal>
      )}
      {historyWarn&&(
        <Modal title="PACIENTE NO TIENE HISTORIA CLÍNICA" onClose={()=>setHistoryWarn(null)} width={420}>
          <div style={{fontSize:13.5,color:"#3a5a6a",lineHeight:1.6,marginBottom:16}}>
            El paciente <b>{historyWarn.firstName||historyWarn.first_name||""} {historyWarn.lastName||historyWarn.last_name||""}</b> debe tener historia clínica antes de registrar una atención.
          </div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end"}}>
            <Btn variant="secondary" onClick={()=>setHistoryWarn(null)}>Cerrar</Btn>
            <Btn onClick={()=>{setSel(historyWarn);setHistoryWarn(null);setModal("edit");}}>Crear / completar historia</Btn>
          </div>
        </Modal>
      )}
      {attModal&&<AttModal patient={attModal} onClose={()=>setAttModal(null)} onSave={saveAtt} currentUser={currentUser}/>}
      {lightboxPhoto&&<PhotoLightbox src={lightboxPhoto} onClose={()=>setLightboxPhoto(null)}/>}
      {reflexMap&&<ReflexologyMap onClose={()=>setReflexMap(false)}/>}

      {/* ── IMPORT PATIENTS MODAL ───────────────────────────────────── */}
      {importPatModal&&(
        <Modal title="📥 Importar Pacientes" onClose={()=>{setImportPatModal(false);setImportPatResult(null);setImportPatProgress("");}} width={560}>
          <div style={{background:"#f0f4f8",borderRadius:10,padding:"12px 16px",marginBottom:16,fontSize:13,color:"#3a5a6a",lineHeight:1.6}}>
            <b>Formatos soportados:</b><br/>
            📄 <b>PDF</b> — Ficha de historia clínica (extracción con IA)<br/>
            📊 <b>Excel (.xlsx)</b> — Planilla con columnas del sistema<br/>
            📋 <b>CSV estándar</b> — Columnas: firstName, lastName, dni, phone...<br/>
            📋 <b>CSV Podología</b> — Formato especial del sistema (Nombres, Dirección, Teléfono, Edad, Actividad, Ocupación)
          </div>
          
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:10,marginBottom:16}}>
            {[
              {icon:"📄",label:"PDF",desc:"Historia clínica escaneada o digital",color:"#e05050",bg:"#fff5f5",border:"#e0505033"},
              {icon:"📊",label:"Excel",desc:"Planilla .xlsx con columnas",color:"#059669",bg:"#f0f9f7",border:"#05966933"},
              {icon:"📋",label:"CSV",desc:"Estándar o formato Podología",color:"#2563eb",bg:"#f0f4ff",border:"#2563eb33"},
            ].map(t=>(
              <div key={t.label} style={{background:t.bg,border:`1.5px solid ${t.border}`,borderRadius:10,padding:"12px 10px",textAlign:"center"}}>
                <div style={{fontSize:24,marginBottom:4}}>{t.icon}</div>
                <div style={{fontWeight:700,fontSize:13,color:"#1a2332"}}>{t.label}</div>
                <div style={{fontSize:10.5,color:"#5a7a8a",marginTop:3}}>{t.desc}</div>
              </div>
            ))}
          </div>

          <div style={{background:"#fff8e1",border:"1px solid #f59223",borderRadius:8,padding:"10px 14px",marginBottom:14,fontSize:12,color:"#7a4a00"}}>
            💡 <b>PDF con IA:</b> El sistema extrae automáticamente los campos: Nombres, DNI, Fecha Nacimiento, Sexo, Teléfono, Dirección, Patologías, Antecedentes y más. Para Excel/CSV descargue la plantilla.
          </div>

          <div style={{marginBottom:14,display:"flex",justifyContent:"flex-end"}}>
            <button onClick={downloadPatientsTemplate} style={{background:"#2563eb",color:"#fff",border:"none",borderRadius:7,padding:"6px 14px",cursor:"pointer",fontSize:12,fontWeight:700}}>
              ⬇ Descargar Plantilla CSV/Excel
            </button>
          </div>

          <input ref={importPatRef} type="file" accept=".pdf,.xlsx,.xls,.csv" onChange={handleImportPatients} style={{display:"none"}}/>

          {importPatProgress&&(
            <div style={{background:"#f0f4f8",borderRadius:8,padding:"10px 14px",marginBottom:12,fontSize:13,color:"#3a5a6a",display:"flex",alignItems:"center",gap:8}}>
              <span className="pulse">⏳</span> {importPatProgress}
            </div>
          )}

          {importPatResult&&(
            <div style={{background:importPatResult.ok?"#f0f9f7":"#fff3f3",border:`1px solid ${importPatResult.ok?"#4a9d8f":"#e05050"}`,borderRadius:10,padding:"12px 16px",marginBottom:12,fontSize:13,color:importPatResult.ok?"#1a5a4a":"#c03030"}}>
              {importPatResult.msg}
              {importPatResult.ok&&<div style={{marginTop:6,fontSize:11.5,color:"#4a9d8f"}}>Los nuevos pacientes ya aparecen en la lista. Puede verificarlos ahora.</div>}
            </div>
          )}

          <div style={{display:"flex",gap:10,justifyContent:"flex-end"}}>
            <Btn variant="secondary" onClick={()=>{setImportPatModal(false);setImportPatResult(null);setImportPatProgress("");}}>Cerrar</Btn>
            <Btn onClick={()=>importPatRef.current.click()} style={{background:"#2ea87e"}}>
              <Icon name="arrow" size={13}/>Seleccionar Archivo
            </Btn>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ─── COMPONENTE BÚSQUEDA DE PACIENTE ─────────────────────────────────────────
const PatientSearchSelect=({patients,value,onChange,placeholder="Buscar por nombre, apellido o DNI..."})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const[query,setQuery]=useState("");
  const[open,setOpen]=useState(false);
  const[focused,setFocused]=useState(false);
  const containerRef=React.useRef(null);
  const selected=safePatients.find(p=>String(p.id)===String(value));

  React.useEffect(()=>{
    const handler=e=>{if(containerRef.current&&!containerRef.current.contains(e.target)){setOpen(false);setFocused(false);}};
    document.addEventListener("mousedown",handler);
    return()=>document.removeEventListener("mousedown",handler);
  },[]);

  const filtered=query.trim()===""?[]:safePatients.filter(p=>{
    const q=query.toLowerCase();
    return (`${p.firstName} ${p.lastName}`.toLowerCase().includes(q)||
      String(p.dni||"").toLowerCase().includes(q)||
      String(p.id).includes(q));
  }).slice(0,12);

  const handleSelect=p=>{
    onChange(String(p.id));
    setQuery("");
    setOpen(false);
    setFocused(false);
  };

  const handleClear=e=>{
    e.stopPropagation();
    onChange("");
    setQuery("");
    setOpen(false);
  };

  const dropStyle={position:"absolute",top:"calc(100% + 4px)",left:0,right:0,background:"#fff",border:"1.5px solid #2ea87e",borderRadius:10,boxShadow:"0 8px 28px rgba(0,0,0,0.13)",zIndex:999,maxHeight:260,overflowY:"auto"};
  const itemStyle=(hover)=>({padding:"10px 14px",cursor:"pointer",background:hover?"#f0faf7":"#fff",borderBottom:"1px solid #f0f4f8",display:"flex",justifyContent:"space-between",alignItems:"center"});

  return(
    <div ref={containerRef} style={{position:"relative"}}>
      {selected&&!focused?(
        <div onClick={()=>{setFocused(true);setOpen(true);setTimeout(()=>containerRef.current?.querySelector("input")?.focus(),50);}}
          style={{display:"flex",alignItems:"center",justifyContent:"space-between",border:"1.5px solid #2ea87e",borderRadius:9,padding:"9px 12px",background:"#f0faf7",cursor:"pointer",minHeight:40}}>
          <div>
            <span style={{fontWeight:700,color:"#1a2332",fontSize:13.5}}>{selected.firstName} {selected.lastName}</span>
            <span style={{marginLeft:8,fontSize:11.5,color:"#4a9d8f",background:"#d4f0ea",borderRadius:5,padding:"1px 7px"}}>DNI: {selected.dni||"—"}</span>
          </div>
          <button onClick={handleClear} style={{background:"none",border:"none",cursor:"pointer",color:"#8a9aaa",fontSize:16,lineHeight:1,padding:"0 2px"}}>✕</button>
        </div>
      ):(
        <div style={{position:"relative"}}>
          <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa",pointerEvents:"none"}}>
            <Icon name="search" size={14}/>
          </div>
          <input
            autoFocus={focused}
            value={query}
            onChange={e=>{setQuery(e.target.value);setOpen(true);}}
            onFocus={()=>{setFocused(true);setOpen(true);}}
            placeholder={placeholder}
            style={{width:"100%",padding:"9px 12px 9px 34px",border:"1.5px solid #2ea87e",borderRadius:9,fontSize:13.5,outline:"none",background:"#fff",boxSizing:"border-box"}}
          />
          {query&&<button onClick={()=>{setQuery("");setOpen(false);}} style={{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",background:"none",border:"none",cursor:"pointer",color:"#8a9aaa",fontSize:15}}>✕</button>}
        </div>
      )}
      {open&&filtered.length>0&&(
        <div style={dropStyle}>
          {filtered.map(p=>(
            <PatientSearchItem key={p.id} p={p} onSelect={handleSelect}/>
          ))}
        </div>
      )}
      {open&&query.trim()!=""&&filtered.length===0&&(
        <div style={{...dropStyle,padding:"14px",color:"#8a9aaa",fontSize:13,textAlign:"center"}}>
          No se encontraron pacientes
        </div>
      )}
      {open&&query.trim()===""&&!selected&&(
        <div style={{...dropStyle,padding:"12px 14px",color:"#8a9aaa",fontSize:12.5}}>
          Escriba nombre, apellido o DNI para buscar
        </div>
      )}
    </div>
  );
};
const PatientSearchItem=({p,onSelect})=>{
  const[hover,setHover]=React.useState(false);
  return(
    <div onMouseEnter={()=>setHover(true)} onMouseLeave={()=>setHover(false)} onClick={()=>onSelect(p)} style={{padding:"10px 14px",cursor:"pointer",background:hover?"#f0faf7":"#fff",borderBottom:"1px solid #f0f4f8"}}>
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}>
        <div>
          <span style={{fontWeight:700,fontSize:13.5,color:"#1a2332"}}>{p.firstName} {p.lastName}</span>
          {p.patientType&&<span style={{marginLeft:6,fontSize:11,color:"#8a9aaa"}}>· {p.patientType}</span>}
        </div>
        <span style={{fontSize:11.5,color:"#4a9d8f",background:"#e6f7f4",borderRadius:5,padding:"2px 7px",whiteSpace:"nowrap"}}>DNI: {p.dni||"—"}</span>
      </div>
      {p.phone&&<div style={{fontSize:11.5,color:"#8a9aaa",marginTop:1}}>{p.phone}</div>}
    </div>
  );
};

// ─── MÓDULO AGENDA ────────────────────────────────────────────────────────────
const AgendaModule=({patients,currentUser})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  // Resuelve paciente por id numérico O por dni string (soporta ambos formatos de datos)
  const resolvePt=(patientId)=>{
    if(!patientId)return null;
    const pid=String(patientId).trim();
    // Combinar todas las fuentes: props, cache, db
    const src1=safePatients.length>0?safePatients:[];
    const src2=_cache['patients']||[];
    const src3=db.get(SK.patients)||[];
    const combined=[...src1,...src2,...src3];
    const seen=new Set();
    const unique=combined.filter(x=>{const k=String(x.id);if(seen.has(k))return false;seen.add(k);return true;});
    return unique.find(x=>String(x.id)===pid||String(x.dni||'')===pid)||null;
  };
  const appts=useStore(SK.appointments,[]);
  const attendances=useStore(SK.attendances,[]);
  const setAppts=(rows)=>db.set(SK.appointments,Array.isArray(rows)?rows:[]);
  const[patientsLoaded,setPatientsLoaded]=useState((_cache['patients']||[]).length>0||safePatients.length>0);
  // Recargar citas y pacientes frescos del servidor al abrir Agenda
  useEffect(()=>{
    api.get('appointments').then(rows=>{if(Array.isArray(rows)&&rows.length>0)setAppts(rows);}).catch(()=>{});
    api.get('attendances').catch(()=>{});
    // Cargar pacientes si no están en caché (necesario para mostrar nombres)
    const cached=_cache['patients']||[];
    if(cached.length===0&&safePatients.length===0){
      api.get('patients').then(rows=>{
        if(Array.isArray(rows)&&rows.length>0){setPatientsLoaded(true);}
      }).catch(()=>{});
    } else {
      setPatientsLoaded(true);
    }
  },[]);
  const[modal,setModal]=useState(false);
  const[reschedModal,setReschedModal]=useState(null);
  const[form,setForm]=useState({patientId:"",date:todayStr(),time:"09:00",service:"",podologa:"",notes:""});
  const[reschedForm,setReschedForm]=useState({date:todayStr(),time:"09:00"});
  const[search,setSearch]=useState("");
  const[filterDate,setFilterDate]=useState("");
  const[filterPodo,setFilterPodo]=useState("");
  const[filterStatus,setFilterStatus]=useState("all");
  const services=db.get(SK.services)||DEF_SERVICES;
  const users=db.get(SK.users)||DEF_USERS;
  const podologas=users.filter(u=>u.active&&u.role==="Podólogo");

  const saveAppt=async()=>{
    if(!form.patientId||!form.date||!form.time){alert("Complete los campos requeridos");return}
    const tempId=genId(appts);
    const local={...form,id:tempId,status:"pending",createdBy:currentUser?.name,created_by:currentUser?.name,patient_id:form.patientId};
    try{
      await saveCrudAndSync('appointments',local,SK.appointments,setAppts,tempId);
      setModal(false);setForm({patientId:"",date:todayStr(),time:"09:00",service:"",podologa:"",notes:""});
      alert("✅ Cita guardada en la base de datos");
    }catch(e){alert("No se guardó la cita en la base de datos: "+e.message);}
  };
  const setApptStatus=async(id,status)=>{
    try{
      const saved=await crudApi.update('appointments',id,{status});
      const all=appts.map(a=>a.id===id?{...a,...saved,status}:a);
      setAppts(all);db.set(SK.appointments,all);
    }catch(e){alert("No se guardó el cambio de cita en la base de datos: "+e.message);}
  };
  const confirmAppt=id=>setApptStatus(id,"confirmed");
  const done=id=>setApptStatus(id,"done");
  const cancel=id=>{if(window.confirm("¿Cancelar esta cita?"))setApptStatus(id,"cancelled")};
  const doResched=async()=>{
    if(!reschedForm.date||!reschedForm.time){alert("Ingrese fecha y hora");return}
    try{
      const saved=await crudApi.update('appointments',reschedModal.id,{...reschedForm,status:"pending",rescheduled:1});
      const all=appts.map(a=>a.id===reschedModal.id?{...a,...reschedForm,...saved,status:"pending",rescheduled:true}:a);
      setAppts(all);db.set(SK.appointments,all);setReschedModal(null);
      alert("✅ Reprogramación guardada en la base de datos");
    }catch(e){alert("No se guardó la reprogramación en la base de datos: "+e.message);}
  };
  const chargeAppt=async id=>{
    const att=appts.find(a=>a.id===id);if(!att)return;
    const svPrice=(db.get(SK.services)||DEF_SERVICES).find(s=>s.name===att.service)?.price||0;
    const price=parseFloat(prompt("Monto a cobrar (S/):",svPrice)||0);
    if(isNaN(price)||price<0)return;
    const method=prompt("Método de pago (Efectivo/Yape/Tarjeta):",PAY_METHODS[0])||"Efectivo";
    const attId=genId(db.get(SK.attendances)||[]);
    const p=resolvePt(att.patientId);
    const patientName=p?`${p.firstName||p.first_name||""} ${p.lastName||p.last_name||""}`.trim():"—";
    const responsible=att.podologa||currentUser?.name||"—";
    const newAtt={id:attId,appointmentId:att.id,appointment_id:att.id,patientId:att.patientId,patient_id:att.patientId,patientName,patient_name:patientName,date:att.date,time:att.time||new Date().toLocaleTimeString("es-PE",{hour:"2-digit",minute:"2-digit",hour12:false}),registeredAt:new Date().toISOString(),registered_at:new Date().toISOString(),service:att.service,price,payMethod:method,pay_method:method,payStatus:"pagado",pay_status:"pagado",closed:true,attendedBy:responsible,attended_by:responsible,notes:att.notes||""};
    try{
      const created=await crudApi.create('attendances',newAtt);
      await crudApi.update('appointments',id,{status:"done",charged:1});
      const allAtt=db.get(SK.attendances)||[];db.set(SK.attendances,[...allAtt,{...newAtt,...created,id:created?.id||newAtt.id}]);
      const allAppts=appts.map(a=>a.id===id?{...a,status:"done",charged:true}:a);
      setAppts(allAppts);db.set(SK.appointments,allAppts);
      alert(`✅ Cobrado y guardado en BD ${getCurrency()} ${price.toFixed(2)} — ${method}`);
    }catch(e){alert("No se guardó el cobro en la base de datos: "+e.message);}
  };
  const exportCSV=()=>{
    const rows=[["ID","Paciente","DNI","Fecha","Hora","Servicio","Podologa","Estado","Notas"],...filtered.map(a=>{
      const p=resolvePt(a.patientId);
      const nm=p?((p.firstName||p.first_name||"")+" "+(p.lastName||p.last_name||"")).trim():"N/A";
      const dni=p?p.dni||"":a.patientId||"";
      const st=appointmentStatusOf(a,attendances);
      return[a.id,nm,dni,a.date,a.time,a.service||"",appointmentPodologa(a,attendances)||"",sL[st]||st,a.notes||""];
    })];
    const csv=rows.map(r=>r.map(x=>'"'+String(x==null?"":x).replace(/"/g,'""')+'"').join(",")).join("\n");
    const blob=new Blob(["\uFEFF"+csv],{type:"text/csv;charset=utf-8;"});
    const url=URL.createObjectURL(blob);const a=document.createElement("a");a.href=url;a.download=`agenda_${todayStr()}.csv`;a.click();URL.revokeObjectURL(url);
  };

  const filtered=appts.filter(a=>{
    const p=resolvePt(a.patientId);
    const matchSearch=!search||p&&`${p.firstName} ${p.lastName} ${p.dni}`.toLowerCase().includes(search.toLowerCase());
    const matchDate=!filterDate||a.date===filterDate;
    const matchPodo=!filterPodo||appointmentPodologa(a,attendances)===filterPodo;
    const matchStatus=filterStatus==="all"||appointmentStatusOf(a,attendances)===filterStatus;
    return matchSearch&&matchDate&&matchPodo&&matchStatus;
  }).sort((a,b)=>a.date>b.date?1:a.date<b.date?-1:a.time>b.time?1:-1);

  const stateCounts={pending:0,confirmed:0,done:0,cancelled:0};
  appts.forEach(a=>{const st=appointmentStatusOf(a,attendances);stateCounts[st]=(stateCounts[st]||0)+1;});
  const sC=appointmentStatusColor;
  const sL=appointmentStatusLabel;

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Agenda de Citas</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>{stateCounts.pending} pendientes · {stateCounts.confirmed} confirmadas · {stateCounts.done} atendidas</div>
        </div>
        <div style={{display:"flex",gap:8,flexWrap:"wrap"}}>
          <Btn variant="secondary" onClick={exportCSV}><Icon name="file" size={13}/>Exportar CSV</Btn>
          <Btn onClick={()=>setModal(true)}><Icon name="plus" size={14}/>Nueva Cita</Btn>
        </div>
      </div>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(160px,1fr))",gap:10,marginBottom:14}}>
        {[
          ["Pendiente",stateCounts.pending,"#2563eb"],
          ["Confirmada",stateCounts.confirmed,"#7c3aed"],
          ["Atendida",stateCounts.done,"#2ea87e"],
          ["Cancelada",stateCounts.cancelled,"#8a9aaa"],
        ].map(([label,value,color])=>(
          <div key={label} style={{background:"#fff",border:`1px solid ${color}30`,borderLeft:`4px solid ${color}`,borderRadius:10,padding:"10px 14px",boxShadow:"0 2px 8px rgba(0,0,0,0.04)"}}>
            <div style={{fontSize:22,fontWeight:900,color}}>{value}</div>
            <div style={{fontSize:11,fontWeight:800,color:"#5a7a8a",textTransform:"uppercase"}}>{label}</div>
          </div>
        ))}
      </div>
      <Card style={{marginBottom:14,padding:"12px 16px"}}>
        <div style={{display:"flex",gap:8,flexWrap:"wrap",alignItems:"center"}}>
          <div style={{position:"relative",flex:1,minWidth:180}}>
            <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
            <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar paciente..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
          </div>
          <Inp type="date" value={filterDate} onChange={e=>setFilterDate(e.target.value)} style={{width:"auto",minWidth:150}}/>
          {filterDate&&<Btn variant="ghost" size="sm" onClick={()=>setFilterDate("")}>✕</Btn>}
          <Sel value={filterPodo} onChange={e=>setFilterPodo(e.target.value)} style={{minWidth:150}}>
            <option value="">Todas las podólogas</option>
            {podologas.map(u=><option key={u.id} value={u.name}>{u.name}</option>)}
          </Sel>
          <div style={{display:"flex",gap:3,flexWrap:"wrap"}}>
            {[["all","Todas"],["pending","Pendiente"],["confirmed","Confirmada"],["done","Atendida"],["cancelled","Cancelada"]].map(([v,l])=>(
              <button key={v} onClick={()=>setFilterStatus(v)} style={{padding:"5px 10px",borderRadius:7,border:`1.5px solid ${filterStatus===v?"#4a9d8f":"#d4dde5"}`,background:filterStatus===v?"#4a9d8f":"#fff",color:filterStatus===v?"#fff":"#5a7a8a",fontWeight:600,fontSize:11,cursor:"pointer"}}>{l}</button>
            ))}
          </div>
        </div>
      </Card>
      <Card style={{padding:0,overflow:"hidden"}}>
        <div style={{overflowX:"auto"}}>
          <table style={{width:"100%",borderCollapse:"collapse",minWidth:780}}>
            <thead>
              <tr style={{background:"linear-gradient(90deg,#f4f8fa,#eef3f7)"}}>
                {["Fecha","Hora","Paciente","DNI","Servicio","Podóloga","Estado","Acciones"].map(h=>(
                  <th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",whiteSpace:"nowrap"}}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {!patientsLoaded&&appts.length>0&&<tr><td colSpan={8} style={{textAlign:"center",padding:16,color:"#8a9aaa",fontSize:13}}>⏳ Cargando datos de pacientes...</td></tr>}
              {filtered.length===0&&patientsLoaded&&<tr><td colSpan={8} style={{textAlign:"center",padding:36,color:"#8a9aaa",fontSize:13}}>No hay citas para mostrar</td></tr>}
              {filtered.map((a,i)=>{
                const p=resolvePt(a.patientId);
                const pName=p?((p.firstName||p.first_name||'')+' '+(p.lastName||p.last_name||'')).trim():null;
                const st=appointmentStatusOf(a,attendances);
                const podologaName=appointmentPodologa(a,attendances);
                return(
                  <tr key={a.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff",opacity:a.status==="cancelled"?.6:1}} onMouseOver={e=>e.currentTarget.style.background="#f0f8f6"} onMouseOut={e=>e.currentTarget.style.background=i%2?"#fafcfd":"#fff"}>
                    <td style={{padding:"10px 14px",whiteSpace:"nowrap"}}>
                      <div style={{fontSize:13,fontWeight:600,color:a.date===todayStr()?"#4a9d8f":"#1a2332"}}>{fmt(a.date)}</div>
                      {a.rescheduled&&<Badge color="yellow">Reagendada</Badge>}
                    </td>
                    <td style={{padding:"10px 14px"}}><div style={{background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",borderRadius:7,padding:"3px 10px",fontSize:12,fontWeight:700,display:"inline-block"}}>{a.time}</div></td>
                    <td style={{padding:"10px 14px"}}>
                      <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{pName?pName.trim():"Sin nombre"}</div>
                      {p?.phone&&<div style={{fontSize:10.5,color:"#8a9aaa"}}>{p.phone}</div>}
                    </td>
                    <td style={{padding:"10px 14px",fontSize:12,color:"#5a7a8a",fontFamily:"monospace"}}>{p?.dni||a.patientId||"—"}</td>
                    <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a"}}>{a.service||"—"}</td>
                    <td style={{padding:"10px 14px",fontSize:13,color:"#4a9d8f",fontWeight:600}}>{podologaName||"—"}</td>
                    <td style={{padding:"10px 14px"}}><Badge color={sC[st]||"gray"}>{sL[st]||st}</Badge></td>
                    <td style={{padding:"10px 14px"}}>
                      <div style={{display:"flex",gap:3,flexWrap:"wrap"}}>
                        <select value={st} onChange={e=>setApptStatus(a.id,e.target.value)} style={{border:"1px solid #d4dde5",borderRadius:6,padding:"4px 6px",fontSize:11,fontWeight:700,color:"#3a5a6a",background:"#fff"}}>
                          <option value="pending">Pendiente</option>
                          <option value="confirmed">Confirmada</option>
                          <option value="done">Atendida</option>
                          <option value="cancelled">Cancelada</option>
                        </select>
                        {a.status==="pending"&&<button onClick={()=>confirmAppt(a.id)} style={{background:"#7c3aed14",border:"none",borderRadius:5,padding:"4px 7px",cursor:"pointer",color:"#7c3aed",fontSize:11,fontWeight:600}}>✓ Confirmar</button>}
                        {(a.status==="pending"||a.status==="confirmed")&&<button onClick={()=>setReschedModal(a)} style={{background:"#f5922314",border:"none",borderRadius:5,padding:"4px 7px",cursor:"pointer",color:"#d07010",fontSize:11,fontWeight:600}}>↻ Reagendar</button>}
                        {(a.status==="pending"||a.status==="confirmed")&&<button onClick={()=>chargeAppt(a.id)} style={{background:"#2ea87e14",border:"none",borderRadius:5,padding:"4px 7px",cursor:"pointer",color:"#1a8060",fontSize:11,fontWeight:600}}>$ Cobrar</button>}
                        {(a.status==="pending"||a.status==="confirmed")&&<button onClick={()=>cancel(a.id)} style={{background:"#e0505014",border:"none",borderRadius:5,padding:"4px 7px",cursor:"pointer",color:"#c03030",fontSize:11,fontWeight:600}}>✕ Cancelar</button>}
                      </div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>
      {modal&&(
        <Modal title="Nueva Cita" onClose={()=>setModal(false)} width={520}>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
            <Field label="Paciente *" col="1/-1">
              <PatientSearchSelect
                patients={patients.filter(p=>p.status==="active")}
                value={form.patientId}
                onChange={v=>setForm(p=>({...p,patientId:v}))}
              />
            </Field>
            <Field label="Fecha *"><Inp type="date" value={form.date} onChange={e=>setForm(p=>({...p,date:e.target.value}))}/></Field>
            <Field label="Hora *"><Inp type="time" value={form.time} onChange={e=>setForm(p=>({...p,time:e.target.value}))}/></Field>
            <Field label="Servicio">
              <Sel value={form.service} onChange={e=>setForm(p=>({...p,service:e.target.value}))}>
                <option value="">Seleccionar...</option>
                {services.filter(s=>s.active).map(s=><option key={s.id}>{s.name}</option>)}
              </Sel>
            </Field>
            <Field label="Podóloga">
              <Sel value={form.podologa} onChange={e=>setForm(p=>({...p,podologa:e.target.value}))}>
                <option value="">Sin asignar</option>
                {podologas.map(u=><option key={u.id} value={u.name}>{u.name}</option>)}
              </Sel>
            </Field>
          </div>
          <Field label="Notas"><TA value={form.notes} onChange={e=>setForm(p=>({...p,notes:e.target.value}))}/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setModal(false)}>Cancelar</Btn>
            <Btn onClick={saveAppt}><Icon name="check" size={13}/>Guardar Cita</Btn>
          </div>
        </Modal>
      )}
      {reschedModal&&(
        <Modal title="Reagendar Cita" onClose={()=>setReschedModal(null)} width={400}>
          <div style={{background:"#f4f8fa",borderRadius:10,padding:"12px 16px",marginBottom:16,fontSize:13,color:"#3a5a6a"}}>
            <b>Cita original:</b> {fmt(reschedModal.date)} a las {reschedModal.time} — {reschedModal.service||"Sin servicio"}
          </div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
            <Field label="Nueva Fecha *"><Inp type="date" value={reschedForm.date} onChange={e=>setReschedForm(p=>({...p,date:e.target.value}))}/></Field>
            <Field label="Nueva Hora *"><Inp type="time" value={reschedForm.time} onChange={e=>setReschedForm(p=>({...p,time:e.target.value}))}/></Field>
          </div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setReschedModal(null)}>Cancelar</Btn>
            <Btn variant="warning" onClick={doResched}><Icon name="calendar" size={13}/>Reagendar</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO CAJA & PAGOS ──────────────────────────────────────────────────────
const CashModule=({patients,currentUser})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const[range,setRange]=useState("today");
  const adminPrincipalBlocked=isAdminPrincipalUser(currentUser);
  const[cashTab,setCashTab]=useState(()=>{
    const openOrders=sessionStorage.getItem('podo_open_cash_orders')==='1';
    if(openOrders)sessionStorage.removeItem('podo_open_cash_orders');
    return openOrders?'orders':'summary';
  });
  const[cobroModal,setCobroModal]=useState(null);
  const[cobroForm,setCobroForm]=useState({method:"Efectivo",note:""});
  const[kpiDetailModal,setKpiDetailModal]=useState(null); // {title, rows, total}
  const[anularModal,setAnularModal]=useState(null); // attendance to void
  const[anularMotivo,setAnularMotivo]=useState("");
  const[tick,setTick]=useState(0);
  const now=new Date();

  const rerender=()=>setTick(t=>t+1);

  const attendances=useStore(SK.attendances,[]);
  const salesOrders=useStore(SK.salesOrders,[]);
  useEffect(()=>{
    api.get('attendances').catch(()=>{});
    api.get('sales_orders').catch(()=>{});
  },[]);

  const inRange=d=>{
    const dt=new Date(d+"T00:00:00");
    if(range==="today")return d===todayStr();
    if(range==="week"){const w=new Date(now);w.setDate(w.getDate()-7);return dt>=w}
    if(range==="month")return dt.getMonth()===now.getMonth()&&dt.getFullYear()===now.getFullYear();
    return true;
  };
  const filtAtt=attendances.filter(a=>inRange(a.date));
  const cashStatus=a=>String(a?.payStatus||a?.pay_status||"").trim().toLowerCase();
  const isClosedCash=a=>a?.closed===true||a?.closed===1||String(a?.closed||"").trim()==="1";
  const isAnulledCash=a=>{
    const st=cashStatus(a);
    return ["anulado","anulada","cancelado","cancelada"].includes(st)||!!(a?.anuladoAt||a?.anulado_at||a?.anuladoMotivo||a?.anulado_motivo);
  };
  const isPaidCash=a=>!isAnulledCash(a)&&(cashStatus(a)==="pagado"||isClosedCash(a));
  const paidAtt=filtAtt.filter(isPaidCash);
  const pendAtt=filtAtt.filter(a=>!isPaidCash(a)&&!isAnulledCash(a));
  const anulAtt=filtAtt.filter(isAnulledCash);
  const totalPaid=paidAtt.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const totalPend=pendAtt.reduce((s,a)=>s+(parseFloat(a.price)||0),0);

  const pendOrders=salesOrders.filter(o=>o.status==="procesando"||o.status==="pendiente");

  const getPayMethod=a=>a?.payMethod||a?.pay_method||a?.paidMethod||a?.paid_method||"Efectivo";
  const openCobro=(type,data)=>{
    setCobroForm({method:getPayMethod(data),note:""});
    setCobroModal({type,data});
  };

  const byMethod={};
  paidAtt.forEach(a=>{const m=getPayMethod(a);byMethod[m]=(byMethod[m]||0)+(parseFloat(a.price)||0)});

  const rangeLabel={"today":"Hoy","week":"Semana","month":"Mes","all":"Todo"}[range]||range;
  const resolvePatient=(a)=>{
    const id=String(a?.patientId||a?.patient_id||"").trim();
    const dni=String(a?.patientDni||a?.patient_dni||"").trim();
    return safePatients.find(x=>String(x.id)===id||String(x.dni||"")===id||String(x.id)===dni||String(x.dni||"")===dni)||null;
  };
  const patientLabel=(a)=>{
    if(String(a?.patientId||a?.patient_id||"")==="0")return"Cliente gral.";
    const p=resolvePatient(a);
    const fromPatient=p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`.trim():"";
    const fromAttendance=a?.patientName||a?.patient_name||`${a?.first_name||''} ${a?.last_name||''}`.trim();
    return fromPatient||fromAttendance||"Falta vincular paciente: registre Nombres, Apellidos y DNI";
  };
  const setAllowedRange=(nextRange)=>{
    if(adminPrincipalBlocked&&["week","month","all"].includes(nextRange)){
      alert("ACCIÓN NO PERMITIDA");
      return;
    }
    setRange(nextRange);
  };

  const markPaid=(attId,method)=>{
    const original=(db.get(SK.attendances)||[]).find(a=>a.id===attId);
    const finalMethod=method||getPayMethod(original);
    const all=(db.get(SK.attendances)||[]).map(a=>a.id===attId?{...a,payStatus:"pagado",pay_status:"pagado",closed:true,payMethod:finalMethod,pay_method:finalMethod}:a);
    db.set(SK.attendances,all);
    apiFetch('/special?action=mark_paid',{
      method:'POST',
      body:JSON.stringify({id:attId,pay_method:finalMethod})
    }).then(updated=>{
      if(!updated||!updated.id)return;
      const synced=(db.get(SK.attendances)||[]).map(a=>String(a.id)===String(updated.id)?{...a,...updated}:a);
      db.set(SK.attendances,synced);
    }).catch(e=>{
      console.warn('mark_paid',e.message);
      alert("No se pudo guardar el cobro en el servidor. Revise la conexiÃ³n o permisos.");
    });
    if(original){
      const appts=db.get(SK.appointments)||[];
      const nextAppts=appts.map(ap=>{
        const sameAppointment=original.appointmentId&&String(original.appointmentId)===String(ap.id);
        const samePatientDate=String(original.patientId||original.patient_id||"")===String(ap.patientId||ap.patient_id||"")&&String(original.date||"").slice(0,10)===String(ap.date||"").slice(0,10)&&(!ap.service||!original.service||String(ap.service).trim().toLowerCase()===String(original.service).trim().toLowerCase());
        return sameAppointment||samePatientDate?{...ap,status:"done"}:ap;
      });
      db.set(SK.appointments,nextAppts);
    }
    setCobroModal(null);
    rerender();
  };

  const cobrarOrden=(order,method)=>{
    const finalMethod=method||getPayMethod(order);
    const atts=db.get(SK.attendances)||[];
    const now=new Date();
    const nowTime=now.toLocaleTimeString("es-PE",{hour:"2-digit",minute:"2-digit",hour12:false});

    // ── FIX 3: Resolver patientId real desde DNI para vincular al historial del paciente ──
    const allPtsForOrder=[...(_cache['patients']||[]),...(db.get(SK.patients)||[])];
    const orderDoc=String(order.dniRuc||order.dni_ruc||"").trim();
    const foundPtForOrder=allPtsForOrder.find(p=>String(p.dni||"").trim()===orderDoc);
    const resolvedPatientId=foundPtForOrder?foundPtForOrder.id:(orderDoc.length===8?orderDoc:"0");
    const orderPatientName=(order.razonSocial||order.razon_social||"Cliente general").trim();

    const newAtts=order.items.map((item,i)=>({
      id:genId([...atts,...order.items.map((_,j)=>({id:j}))].concat([{id:i}])),
      patientId:resolvedPatientId,
      patient_id:resolvedPatientId,
      patientName:orderPatientName,
      patient_name:orderPatientName,
      patientDni:orderDoc,
      patient_dni:orderDoc,
      date:todayStr(),
      time:nowTime,
      registeredAt:now.toISOString(),
      service:item.name,
      price:item.lineTotal!==undefined?parseFloat(item.lineTotal)||0:Math.max(0,(parseFloat(item.price)||0)*(item.qty||1)-(parseFloat(item.discount)||0)),
      grossPrice:item.grossTotal!==undefined?parseFloat(item.grossTotal)||0:(parseFloat(item.price)||0)*(item.qty||1),
      discount:parseFloat(item.discount)||0,
      payMethod:finalMethod,
      pay_method:finalMethod,
      payStatus:"pagado",
      pay_status:"pagado",
      closed:true,
      attendedBy:order.assignedTo||order.assigned_to||"Sin responsable",
      attended_by:order.assignedTo||order.assigned_to||"Sin responsable",
      orderCode:order.code,
      type:"venta",
      itemType:item._type||"service",
      orderItems:order.items
    }));
    db.set(SK.attendances,[...atts,...newAtts]);

    // ── FIX 1 & 2: Reducir stock al cobrar productos (bienes) ──
    const productItems=order.items.filter(i=>i._type==="product");
    if(productItems.length>0){
      // Reducir stock en Inventario (items de fuente inventory)
      const inv=db.get(SK.inventory)||[];
      const updInv=inv.map(prod=>{
        const ordered=productItems.find(i=>i._source==="inventory"&&(String(i._id)===String(prod.id)||i.name===prod.name));
        if(ordered){
          const qty=parseInt(ordered.qty)||1;
          return{...prod,stock:Math.max(0,(parseInt(prod.stock)||0)-qty),
            moves:[...(prod.moves||[]),{type:"salida",qty,note:`Venta ${order.code}`,date:todayStr()}]};
        }
        return prod;
      });
      db.set(SK.inventory,updInv);
      // Reducir stock en catálogo Ventas→Productos (items de fuente catalog)
      const salProds=db.get(SK.salesProducts)||[];
      const updSalProds=salProds.map(prod=>{
        const ordered=productItems.find(i=>i._source==="catalog"&&(String(i._id)===String(prod.id)||i.name===prod.name));
        if(ordered){
          const qty=parseInt(ordered.qty)||1;
          return{...prod,stock:Math.max(0,(parseInt(prod.stock)||0)-qty)};
        }
        return prod;
      });
      db.set(SK.salesProducts,updSalProds);
    }

    const orders=db.get(SK.salesOrders)||[];
    db.set(SK.salesOrders,orders.map(o=>o.id===order.id?{...o,status:"cobrado",paidAt:todayStr(),paidMethod:finalMethod,paid_method:finalMethod,payMethod:finalMethod,pay_method:finalMethod}:o));
    apiFetch('/crud?entity=sales_orders&id='+encodeURIComponent(order.id),{
      method:'PUT',
      body:JSON.stringify({status:"cobrado",paid_at:todayStr(),paid_method:finalMethod,pay_method:finalMethod})
    }).catch(e=>console.warn('sales_order paid',e.message));

    // Persistir descuento de stock en servidor al cobrar
    if(productItems.length>0){
      apiFetch('/special?action=stock_move',{
        method:'POST',
        body:JSON.stringify({
          order_code:order.code,date:todayStr(),
          items:productItems.map(i=>({id:i._id,source:i._source||'catalog',name:i.name,qty:parseInt(i.qty)||1}))
        })
      }).catch(()=>{});
    }
    // Marcar atenciones en servidor
    newAtts.forEach(att=>{
      apiFetch('/crud?entity=attendances',{method:'POST',body:JSON.stringify(att)}).then(created=>{
        if(!created||!created.id)return;
        const synced=(db.get(SK.attendances)||[]).map(a=>String(a.id)===String(att.id)?{...a,...created}:a);
        db.set(SK.attendances,synced);
      }).catch(()=>{});
    });
    setCobroModal(null);
    rerender();
  };

  const eliminarOrdenPendiente=async(order)=>{
    if(!confirm("¿Eliminar esta pre-venta sin cobrar?"))return;
    try{
      await crudApi.remove('sales_orders',order.id);
      const orders=db.get(SK.salesOrders)||[];
      db.set(SK.salesOrders,orders.filter(o=>String(o.id)!==String(order.id)));
      rerender();
      alert("✅ Pre-venta eliminada");
    }catch(e){
      alert("No se pudo eliminar la pre-venta en la base de datos: "+e.message);
    }
  };

  // ── ANULAR VENTA: marca como anulada y devuelve productos al stock ─────────
  const anularVenta=(att,motivo)=>{
    // 1. Marcar atención como anulada
    const allAtts=(db.get(SK.attendances)||[]).map(a=>
      a.id===att.id?{...a,payStatus:"anulado",pay_status:"anulado",closed:false,anuladoAt:todayStr(),anuladoMotivo:motivo||"Sin motivo",anuladoPor:currentUser?.name||"Sistema"}:a
    );
    db.set(SK.attendances,allAtts);
    apiFetch('/special?action=anular',{
      method:'POST',
      body:JSON.stringify({id:att.id,motivo:motivo||"Sin motivo"})
    }).then(updated=>{
      if(!updated||!updated.id)return;
      const synced=(db.get(SK.attendances)||[]).map(a=>String(a.id)===String(updated.id)?{...a,...updated}:a);
      db.set(SK.attendances,synced);
    }).catch(e=>{
      console.warn('anular',e.message);
      alert("No se pudo guardar la anulaciÃ³n en el servidor. Revise la conexiÃ³n o permisos.");
    });

    // 2. Si es una venta de producto (type==="venta" y tiene orderItems), devolver stock
    const itemsToReturn=att.orderItems||[];
    if(itemsToReturn.length>0){
      const inv=db.get(SK.inventory)||[];
      const updInv=inv.map(prod=>{
        const ordered=itemsToReturn.find(i=>i.name===prod.name||i.id===prod.id);
        if(ordered){
          const qty=parseInt(ordered.qty)||1;
          return{...prod,stock:(parseInt(prod.stock)||0)+qty,
            moves:[...(prod.moves||[]),{type:"entrada",qty,note:`Devolución por anulación — ${motivo||"Sin motivo"}`,date:todayStr()}]};
        }
        return prod;
      });
      db.set(SK.inventory,updInv);
      updInv.forEach(prod=>{
        const touched=itemsToReturn.some(i=>i.name===prod.name||String(i.id)===String(prod.id));
        if(touched)crudApi.update('inventory',prod.id,serverPayload('inventory',prod)).catch(()=>{});
      });
    }

    // 3. Si tiene orderCode, actualizar estado de la orden
    if(att.orderCode){
      const orders=db.get(SK.salesOrders)||[];
      db.set(SK.salesOrders,orders.map(o=>o.code===att.orderCode?{...o,status:"anulado",anuladoAt:todayStr()}:o));
      const ord=orders.find(o=>o.code===att.orderCode);
      if(ord?.id){
        apiFetch('/crud?entity=sales_orders&id='+encodeURIComponent(ord.id),{
          method:'PUT',
          body:JSON.stringify({status:"anulado",anulado_at:todayStr()})
        }).catch(e=>console.warn('sales_order anulado',e.message));
      }
    }

    setAnularModal(null);
    rerender();
  };

  // ── IMPRIMIR COBRANZA ──────────────────────────────────────────────────────
  const printCobranza=()=>{
    const company=db.get(SK.company)||{name:"Podología Más Bela",currency:"S/"};
    const cur=company.currency||"S/";
    const bySvc={};
    paidAtt.forEach(a=>{if(a.service)bySvc[a.service]=(bySvc[a.service]||0)+(parseFloat(a.price)||0)});
    const topSvc=Object.entries(bySvc).sort((a,b)=>b[1]-a[1]);

    const html=`<!DOCTYPE html><html><head><meta charset="UTF-8"/><title>Cobranza ${rangeLabel}</title>
<style>
  body{font-family:'Segoe UI',Arial,sans-serif;color:#1a2332;margin:0;padding:24px;background:#fff}
  .header{text-align:center;border-bottom:2px solid #4a9d8f;padding-bottom:16px;margin-bottom:20px}
  .header h1{font-size:22px;color:#4a9d8f;margin:0 0 4px}
  .header p{font-size:12px;color:#5a7a8a;margin:2px 0}
  .kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px}
  .kpi{background:#f4f8fa;border-radius:10px;padding:14px;text-align:center;border-top:3px solid}
  .kpi.green{border-color:#059669}.kpi.orange{border-color:#f59223}.kpi.blue{border-color:#2563eb}.kpi.purple{border-color:#7c3aed}
  .kpi-val{font-size:20px;font-weight:800;margin:6px 0}
  .kpi-label{font-size:10px;text-transform:uppercase;color:#5a7a8a;font-weight:700}
  .section{margin-bottom:20px}
  .section-title{font-size:13px;font-weight:800;color:#1a2332;border-bottom:1.5px solid #eef2f7;padding-bottom:6px;margin-bottom:12px;text-transform:uppercase;letter-spacing:.04em}
  table{width:100%;border-collapse:collapse;font-size:11.5px}
  th{background:#f4f8fa;padding:7px 10px;text-align:left;font-weight:700;color:#5a7a8a;text-transform:uppercase;font-size:10px}
  td{padding:7px 10px;border-bottom:1px solid #f0f4f8}
  .amt{text-align:right;font-weight:700;color:#059669}
  .badge-red{background:#fee2e2;color:#dc2626;padding:2px 7px;border-radius:4px;font-size:10px;font-weight:700}
  .badge-green{background:#d1fae5;color:#059669;padding:2px 7px;border-radius:4px;font-size:10px;font-weight:700}
  .total-row td{font-weight:800;font-size:13px;border-top:2px solid #4a9d8f;color:#1a2332}
  .method-bar{background:#eef2f7;border-radius:4px;height:8px;margin-top:4px}
  .method-fill{height:8px;border-radius:4px;background:linear-gradient(90deg,#4a9d8f,#5dd4c6)}
  .footer{margin-top:24px;text-align:center;font-size:10px;color:#8a9aaa;border-top:1px solid #eef2f7;padding-top:12px}
  @media print{.no-print{display:none}body{padding:12px}}
</style></head><body>
<div class="header">
  <div style="display:flex;align-items:center;gap:12px;margin-bottom:4px"><img src="data:image/png;base64, " style="width:56px;height:56px;border-radius:50%;object-fit:contain"/><div><h1 style="margin:0">${company.name||"Podología Más Bela"}</h1><p style="margin:2px 0">Reporte de Cobranza — Período: <b>${rangeLabel}</b></p><p style="margin:0;font-size:11px;color:#8a9aaa">Generado: ${new Date().toLocaleString("es-PE")}</p></div></div>
</div>
<div class="kpis">
  <div class="kpi green"><div class="kpi-label">Cobrado</div><div class="kpi-val" style="color:#059669">${cur} ${totalPaid.toFixed(2)}</div><div style="font-size:10px;color:#8a9aaa">${paidAtt.length} atenciones</div></div>
  <div class="kpi orange"><div class="kpi-label">Por Cobrar</div><div class="kpi-val" style="color:#f59223">${cur} ${totalPend.toFixed(2)}</div><div style="font-size:10px;color:#8a9aaa">${pendAtt.length} pendientes</div></div>
  <div class="kpi blue"><div class="kpi-label">Atenciones Cobradas</div><div class="kpi-val" style="color:#2563eb">${paidAtt.length}</div><div style="font-size:10px;color:#8a9aaa">pagadas</div></div>
  <div class="kpi purple"><div class="kpi-label">Ticket Promedio</div><div class="kpi-val" style="color:#7c3aed">${paidAtt.length?(cur+" "+(totalPaid/paidAtt.length).toFixed(2)):"—"}</div><div style="font-size:10px;color:#8a9aaa">por atención</div></div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:20px">
  <div class="section">
    <div class="section-title">💳 Por Método de Pago</div>
    ${Object.entries(byMethod).sort((a,b)=>b[1]-a[1]).map(([m,v])=>{const pct=totalPaid>0?Math.round((v/totalPaid)*100):0;return`<div style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;font-size:12px"><span style="font-weight:600">${m}</span><span style="font-weight:700;color:#059669">${cur} ${v.toFixed(2)}</span></div><div class="method-bar"><div class="method-fill" style="width:${pct}%"></div></div><div style="font-size:10px;color:#8a9aaa">${pct}%</div></div>`}).join("")||'<p style="color:#8a9aaa;font-size:12px">Sin datos</p>'}
  </div>
  <div class="section">
    <div class="section-title">🏆 Top Servicios</div>
    ${topSvc.slice(0,5).map(([s,v],i)=>`<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid #f0f4f8;font-size:12px"><span><b>${i+1}.</b> ${s}</span><span style="font-weight:700;color:#059669">${cur} ${v.toFixed(2)}</span></div>`).join("")||'<p style="color:#8a9aaa;font-size:12px">Sin datos</p>'}
  </div>
</div>
<div class="section">
  <div class="section-title">📋 Detalle de Cobranzas Pagadas</div>
  <table><thead><tr><th>#</th><th>Paciente / Cliente</th><th>Fecha</th><th>Hora</th><th>Servicio / Producto</th><th>Método</th><th>Atendido por</th><th style="text-align:right">Monto</th></tr></thead>
  <tbody>
  ${paidAtt.map((a,i)=>{const name=patientLabel(a);return`<tr><td style="color:#8a9aaa">${i+1}</td><td style="font-weight:600">${name}</td><td style="white-space:nowrap">${fmt(a.date)}</td><td style="white-space:nowrap;color:#5a7a8a">${a.time||"—"}</td><td>${a.service||"—"}</td><td><span class="badge-green">${a.payMethod||"—"}</span></td><td>${a.attendedBy||"—"}</td><td class="amt">${cur} ${parseFloat(a.price||0).toFixed(2)}</td></tr>`}).join("")}
  <tr class="total-row"><td colspan="7" style="text-align:right;padding-right:12px">TOTAL COBRADO:</td><td class="amt">${cur} ${totalPaid.toFixed(2)}</td></tr>
  </tbody></table>
</div>
${anulAtt.length>0?`<div class="section"><div class="section-title">🚫 Ventas Anuladas (${anulAtt.length})</div><table><thead><tr><th>Paciente</th><th>Fecha</th><th>Hora</th><th>Servicio</th><th>Motivo</th><th>Anulado por</th><th style="text-align:right">Monto</th></tr></thead><tbody>${anulAtt.map(a=>{const name=patientLabel(a);return`<tr><td>${name}</td><td>${fmt(a.date)}</td><td style="color:#5a7a8a">${a.time||"—"}</td><td>${a.service||"—"}</td><td><span class="badge-red">${a.anuladoMotivo||"Sin motivo"}</span></td><td>${a.anuladoPor||"—"}</td><td class="amt" style="color:#dc2626">-${cur} ${parseFloat(a.price||0).toFixed(2)}</td></tr>`}).join("")}</tbody></table></div>`:""}
<div class="footer">${company.name||"PodoCLINIC"} · Sistema de Gestión v4.0 · ${new Date().toLocaleDateString("es-PE")}</div>
<script>window.onload=()=>{window.print();}<\/script>
</body></html>`;
    const w=window.open("","_blank","width=900,height=700");
    if(w){w.document.write(html);w.document.close();}
    else alert("Permita las ventanas emergentes para imprimir.");
  };

  // ── KPI DETAIL CLICK ───────────────────────────────────────────────────────
  const openKpiDetail=(type)=>{
    if(type==="cobrado"){
      setKpiDetailModal({
        title:"💰 Detalle de Cobros",
        color:"#059669",
        rows:paidAtt.map(a=>({
          name:patientLabel(a),
          date:fmt(a.date),service:a.service||"—",
          method:a.payMethod||"—",by:a.attendedBy||"—",
          amount:parseFloat(a.price||0),color:"#059669",status:"pagado"
        })),
        total:totalPaid
      });
    } else if(type==="pendiente"){
      setKpiDetailModal({
        title:"⏳ Detalle Por Cobrar",
        color:"#f59223",
        rows:pendAtt.map(a=>({
          name:patientLabel(a),
          date:fmt(a.date),service:a.service||"—",
          method:"Pendiente",by:a.attendedBy||"—",
          amount:parseFloat(a.price||0),color:"#f59223",status:"pendiente"
        })),
        total:totalPend
      });
    } else if(type==="atenciones"){
      setKpiDetailModal({
        title:"🧾 Atenciones Pagadas / Cobradas",
        color:"#2563eb",
        rows:paidAtt.map(a=>({
          name:patientLabel(a),
          date:fmt(a.date),service:a.service||"—",
          method:a.payMethod||a.pay_method||"Cobrado",by:a.attendedBy||a.attended_by||"—",
          amount:parseFloat(a.price||0),color:"#059669",
          status:"pagado"
        })),
        total:paidAtt.length,
        isCount:true
      });
    } else if(type==="ticket"){
      setKpiDetailModal({
        title:"📊 Ticket Promedio — Detalle",
        color:"#7c3aed",
        rows:paidAtt.map(a=>({
          name:patientLabel(a),
          date:fmt(a.date),service:a.service||"—",
          method:a.payMethod||"—",by:a.attendedBy||"—",
          amount:parseFloat(a.price||0),color:"#7c3aed",status:"pagado"
        })).sort((a,b)=>b.amount-a.amount),
        total:paidAtt.length?totalPaid/paidAtt.length:0,
        isAvg:true
      });
    }
  };

  const StatClickable=({emoji,label,value,color,sub,kpiType})=>(
    <div onClick={()=>openKpiDetail(kpiType)} style={{background:"#fff",borderRadius:14,padding:"18px 20px",boxShadow:"0 2px 12px rgba(0,0,0,0.07)",cursor:"pointer",transition:"transform .15s,box-shadow .15s",borderLeft:`4px solid ${color}`}}
      onMouseOver={e=>{e.currentTarget.style.transform="translateY(-3px)";e.currentTarget.style.boxShadow="0 8px 24px rgba(0,0,0,0.13)"}}
      onMouseOut={e=>{e.currentTarget.style.transform="none";e.currentTarget.style.boxShadow="0 2px 12px rgba(0,0,0,0.07)"}}>
      <div style={{fontSize:26,marginBottom:6}}>{emoji}</div>
      <div style={{fontSize:22,fontWeight:800,color,letterSpacing:"-0.02em"}}>{value}</div>
      <div style={{fontSize:11,fontWeight:700,color:"#8a9aaa",textTransform:"uppercase",letterSpacing:"0.06em",marginTop:4}}>{label}</div>
      <div style={{fontSize:11,color:"#a0b0bc",marginTop:2}}>{sub}</div>
      <div style={{fontSize:10,color:color,marginTop:6,fontWeight:600,opacity:.7}}>👆 Ver detalle</div>
    </div>
  );

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Caja & Pagos</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Ingresos · Cobros · Pre-ventas</div>
        </div>
        <div style={{display:"flex",gap:6,flexWrap:"wrap",alignItems:"center"}}>
          {[["today","Hoy"],["week","Semana"],["month","Mes"],["all","Todo"]].map(([v,l])=>{
            const blocked=adminPrincipalBlocked&&["week","month","all"].includes(v);
            return(
              <button key={v} onClick={()=>setAllowedRange(v)} title={blocked?"ACCIÓN NO PERMITIDA":l} style={{padding:"6px 14px",borderRadius:8,border:`1.5px solid ${range===v?"#4a9d8f":"#d4dde5"}`,background:range===v?"#4a9d8f":blocked?"#f4f6f8":"#fff",color:range===v?"#fff":blocked?"#a0a8b0":"#3a5a6a",fontWeight:600,fontSize:12,cursor:blocked?"not-allowed":"pointer",opacity:blocked?0.72:1}}>{l}</button>
            );
          })}
          <button onClick={printCobranza} title={`Imprimir cobranza — ${rangeLabel}`} style={{padding:"6px 14px",borderRadius:8,border:"1.5px solid #2563eb",background:"#eff6ff",color:"#2563eb",fontWeight:700,fontSize:12,cursor:"pointer",display:"flex",alignItems:"center",gap:5}}>
            🖨️ Imprimir
          </button>
        </div>
      </div>

      <Tabs tabs={[
        {id:"summary",label:"📊 Resumen"},
        {id:"pending",label:`⏳ Por Cobrar (${pendAtt.length+pendOrders.length})`},
        {id:"orders",label:`🛒 Pre-ventas (${pendOrders.length})`},
        {id:"cobradas",label:`✅ Cobradas (${paidAtt.length})`},
      ]} active={cashTab} onChange={setCashTab}/>

      {cashTab==="summary"&&(
        <div className="fade-in">
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:12,marginBottom:20}}>
            <StatClickable emoji="💰" label="Cobrado" value={currency(totalPaid)} color="#059669" sub="Atenciones pagadas" kpiType="cobrado"/>
            <StatClickable emoji="⏳" label="Por Cobrar" value={currency(totalPend)} color="#f59223" sub="Pendientes" kpiType="pendiente"/>
            <StatClickable emoji="🧾" label="Atenciones" value={paidAtt.length} color="#2563eb" sub="Pagadas / cobradas" kpiType="atenciones"/>
            <StatClickable emoji="📊" label="Ticket Promedio" value={paidAtt.length?currency(totalPaid/paidAtt.length):"—"} color="#7c3aed" sub="Por atención" kpiType="ticket"/>
          </div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16}}>
            <Card>
              <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>💳 Por Método de Pago</div>
              {Object.keys(byMethod).length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>:
                Object.entries(byMethod).sort((a,b)=>b[1]-a[1]).map(([m,v])=>{
                  const pct=totalPaid>0?Math.round((v/totalPaid)*100):0;
                  return(
                    <div key={m} style={{marginBottom:12}}>
                      <div style={{display:"flex",justifyContent:"space-between",fontSize:12.5,marginBottom:4}}>
                        <span style={{fontWeight:600}}>{m}</span><span style={{fontWeight:700,color:"#059669"}}>{currency(v)}</span>
                      </div>
                      <div style={{background:"#eef2f7",borderRadius:4,height:8}}><div className="bar-fill" style={{width:`${pct}%`,height:"100%",background:"linear-gradient(90deg,#4a9d8f,#5dd4c6)",borderRadius:4}}/></div>
                      <div style={{fontSize:10,color:"#8a9aaa",marginTop:2}}>{pct}%</div>
                    </div>
                  );
                })
              }
            </Card>
            <Card>
              <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>🏆 Top Servicios</div>
              {(()=>{
                const bySvc={};paidAtt.forEach(a=>{if(a.service){bySvc[a.service]=(bySvc[a.service]||0)+(parseFloat(a.price)||0)}});
                const rows=Object.entries(bySvc).sort((a,b)=>b[1]-a[1]).slice(0,5);
                if(!rows.length)return<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>;
                return rows.map(([s,v],i)=>(
                  <div key={s} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"7px 0",borderBottom:"1px solid #f0f4f8"}}>
                    <div style={{display:"flex",alignItems:"center",gap:9}}>
                      <div style={{width:24,height:24,borderRadius:"50%",background:`hsl(${i*60+150},55%,55%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:10.5,fontWeight:700,color:"#fff"}}>{i+1}</div>
                      <span style={{fontSize:12.5,fontWeight:600}}>{s}</span>
                    </div>
                    <span style={{fontWeight:700,color:"#059669",fontSize:13}}>{currency(v)}</span>
                  </div>
                ));
              })()}
            </Card>
          </div>
          {anulAtt.length>0&&(
            <Card style={{marginTop:14,borderLeft:"4px solid #dc2626"}}>
              <div style={{fontWeight:700,fontSize:13,marginBottom:10,color:"#dc2626"}}>🚫 Ventas Anuladas ({anulAtt.length}) — {currency(anulAtt.reduce((s,a)=>s+(parseFloat(a.price)||0),0))}</div>
              <div style={{overflowX:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:12}}>
                  <thead><tr style={{background:"#fef2f2"}}>{["Paciente","Fecha","Hora","Servicio","Monto","Motivo","Por"].map(h=><th key={h} style={{padding:"6px 10px",textAlign:"left",fontSize:10,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase"}}>{h}</th>)}</tr></thead>
                  <tbody>
                    {anulAtt.map(a=>(
                      <tr key={a.id} style={{borderTop:"1px solid #fee2e2"}}>
                        <td style={{padding:"6px 10px",fontWeight:600}}>{patientLabel(a)}</td>
                        <td style={{padding:"6px 10px",whiteSpace:"nowrap"}}>{fmt(a.date)}</td>
                        <td style={{padding:"6px 10px",whiteSpace:"nowrap",color:"#5a7a8a"}}>{a.time||"—"}</td>
                        <td style={{padding:"6px 10px"}}>{a.service||"—"}</td>
                        <td style={{padding:"6px 10px",fontWeight:700,color:"#dc2626",textDecoration:"line-through"}}>{currency(a.price)}</td>
                        <td style={{padding:"6px 10px",fontSize:11,color:"#8a9aaa"}}>{a.anuladoMotivo||"—"}</td>
                        <td style={{padding:"6px 10px",fontSize:11,color:"#8a9aaa"}}>{a.anuladoPor||"—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </Card>
          )}
        </div>
      )}

      {cashTab==="pending"&&(
        <div className="fade-in">
          <Card>
            <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>⏳ Cobros Pendientes — Atenciones</div>
            {pendAtt.length===0?<div style={{textAlign:"center",padding:"16px 0",color:"#8a9aaa",fontSize:13}}>No hay cobros pendientes 🎉</div>:(
              <div style={{overflowX:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:12.5}}>
                  <thead><tr style={{background:"#f4f8fa"}}>{["Paciente","Fecha","Hora","Servicio","Monto","Acción"].map(h=><th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase"}}>{h}</th>)}</tr></thead>
                  <tbody>
                    {pendAtt.map(a=>(
                        <tr key={a.id} style={{borderTop:"1px solid #f0f4f8"}}>
                          <td style={{padding:"8px 12px",fontWeight:600}}>{patientLabel(a)}</td>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap"}}>{fmt(a.date)}</td>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap",color:"#5a7a8a"}}>{a.time||"—"}</td>
                          <td style={{padding:"8px 12px"}}>{a.service||"—"}</td>
                          <td style={{padding:"8px 12px",fontWeight:700,color:"#f59223"}}>{currency(a.price)}</td>
                          <td style={{padding:"8px 12px"}}>
                            {can(currentUser,"cashbox")&&<Btn size="sm" variant="success" onClick={()=>openCobro("attendance",a)}><Icon name="check" size={11}/>Cobrar</Btn>}
                          </td>
                        </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </Card>
        </div>
      )}

      {cashTab==="orders"&&(
        <div className="fade-in">
          {pendOrders.length===0?<Card style={{textAlign:"center",padding:40}}><div style={{fontSize:36,marginBottom:10}}>🛒</div><div style={{fontWeight:700,color:"#3a5a6a"}}>Sin pre-ventas pendientes</div></Card>:
            pendOrders.map(o=>(
              <Card key={o.id} style={{marginBottom:12}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:10}}>
                  <div>
                    <div style={{fontFamily:"monospace",fontWeight:700,color:"#4a9d8f",fontSize:13}}>{o.code}</div>
                    <div style={{fontWeight:600,fontSize:13}}>{o.razonSocial||"Cliente general"}</div>
                    {o.dniRuc&&<div style={{fontSize:11,color:"#8a9aaa"}}>DNI/RUC: {o.dniRuc}</div>}
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Personal: <b style={{color:"#4a9d8f"}}>{o.assignedTo||"—"}</b></div>
                  </div>
                  <div style={{textAlign:"right"}}>
                    <div style={{fontSize:20,fontWeight:800,color:"#059669"}}>{currency(o.total)}</div>
                    <Badge color="orange">{o.status}</Badge>
                  </div>
                </div>
                <div style={{background:"#f8fafc",borderRadius:8,padding:"8px 12px",marginBottom:10,fontSize:12,color:"#3a5a6a"}}>
                  {o.items.map(i=><span key={`${i._source}-${i._id}`} style={{marginRight:12}}>
                    {i.name} ×{i.qty} = <b style={{color:"#059669"}}>{currency(i.lineTotal!==undefined?i.lineTotal:(i.price*i.qty))}</b>
                    {(parseFloat(i.discount)||0)>0&&<small style={{color:"#dc2626",marginLeft:4}}>(-{currency(i.discount)})</small>}
                  </span>)}
                </div>
                <div style={{display:"flex",gap:8,flexWrap:"wrap"}}>
                  <Btn variant="success" onClick={()=>openCobro("order",o)}><Icon name="cash" size={13}/>Cobrar Pre-venta</Btn>
                  <Btn variant="danger" onClick={()=>eliminarOrdenPendiente(o)}>Eliminar</Btn>
                </div>
              </Card>
            ))
          }
        </div>
      )}

      {/* Tab Cobradas con botón Anular */}
      {cashTab==="cobradas"&&(
        <div className="fade-in">
          <Card>
            <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>✅ Cobros Realizados — {rangeLabel}</div>
            {paidAtt.length===0?<div style={{textAlign:"center",padding:"16px 0",color:"#8a9aaa",fontSize:13}}>Sin cobros en este período</div>:(
              <div style={{overflowX:"auto"}}>
                <table style={{width:"100%",borderCollapse:"collapse",fontSize:12.5}}>
                  <thead><tr style={{background:"#f4f8fa"}}>{["Paciente","Fecha","Hora","Servicio","Método","Monto","Acción"].map(h=><th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase"}}>{h}</th>)}</tr></thead>
                  <tbody>
                    {paidAtt.map(a=>(
                        <tr key={a.id} style={{borderTop:"1px solid #f0f4f8"}}>
                          <td style={{padding:"8px 12px",fontWeight:600}}>{patientLabel(a)}</td>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap"}}>{fmt(a.date)}</td>
                          <td style={{padding:"8px 12px",whiteSpace:"nowrap",color:"#5a7a8a"}}>{a.time||"—"}</td>
                          <td style={{padding:"8px 12px"}}>{a.service||"—"}</td>
                          <td style={{padding:"8px 12px"}}><Badge color="green">{a.payMethod||"—"}</Badge></td>
                          <td style={{padding:"8px 12px",fontWeight:700,color:"#059669"}}>{currency(a.price)}</td>
                          <td style={{padding:"8px 12px"}}>
                            {can(currentUser,"cashbox")&&<button onClick={()=>setAnularModal(a)} title="Anular venta" style={{padding:"4px 10px",borderRadius:7,border:"1.5px solid #dc2626",background:"#fef2f2",color:"#dc2626",fontWeight:700,fontSize:11,cursor:"pointer",display:"flex",alignItems:"center",gap:4}}>🚫 Anular</button>}
                          </td>
                        </tr>
                    ))}
                    <tr style={{borderTop:"2px solid #4a9d8f",background:"#f0faf8"}}>
                      <td colSpan={5} style={{padding:"8px 12px",fontWeight:800,textAlign:"right",color:"#1a2332"}}>TOTAL:</td>
                      <td style={{padding:"8px 12px",fontWeight:800,color:"#059669",fontSize:14}}>{currency(totalPaid)}</td>
                      <td/>
                    </tr>
                  </tbody>
                </table>
              </div>
            )}
          </Card>
        </div>
      )}

      {/* Cobro Modal */}
      {cobroModal&&(
        <Modal title="Registrar Cobro" onClose={()=>setCobroModal(null)} width={420}>
          <div style={{background:"#f0f9f7",borderRadius:10,padding:"14px 18px",marginBottom:16}}>
            {cobroModal.type==="attendance"?(
              <>
                <div style={{fontSize:13,fontWeight:700,color:"#1a2332"}}>{safePatients.find(p=>p.id===parseInt(cobroModal.data.patientId))?`${safePatients.find(p=>p.id===parseInt(cobroModal.data.patientId)).firstName} ${safePatients.find(p=>p.id===parseInt(cobroModal.data.patientId)).lastName}`:"Paciente"}</div>
                <div style={{fontSize:12,color:"#5a7a8a"}}>{cobroModal.data.service}</div>
              </>
            ):(
              <>
                <div style={{fontSize:13,fontWeight:700,color:"#1a2332"}}>{cobroModal.data.code} — {cobroModal.data.razonSocial||"Cliente"}</div>
                <div style={{fontSize:12,color:"#5a7a8a"}}>{cobroModal.data.items?.map(i=>i.name).join(", ")}</div>
                {cobroModal.data.discount>0&&(
                  <div style={{fontSize:12,color:"#dc2626",marginTop:4}}>🏷️ Descuento: − {currency(cobroModal.data.discount)}</div>
                )}
              </>
            )}
            <div style={{fontSize:22,fontWeight:800,color:"#059669",marginTop:8}}>
              {cobroModal.type==="attendance"?currency(cobroModal.data.price):currency(cobroModal.data.total)}
            </div>
          </div>
          <Field label="Método de Pago">
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:6}}>
              {PAY_METHODS.map(m=>(
                <button key={m} onClick={()=>setCobroForm(f=>({...f,method:m}))} style={{padding:"8px 4px",borderRadius:8,border:`2px solid ${cobroForm.method===m?"#4a9d8f":"#d4dde5"}`,background:cobroForm.method===m?"#4a9d8f18":"#fff",color:cobroForm.method===m?"#4a9d8f":"#5a7a8a",fontWeight:600,fontSize:11.5,cursor:"pointer",textAlign:"center"}}>{m}</button>
              ))}
            </div>
          </Field>
          <Field label="Nota (opcional)"><Inp value={cobroForm.note} onChange={e=>setCobroForm(f=>({...f,note:e.target.value}))} placeholder="Número de operación, comprobante..."/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setCobroModal(null)}>Cancelar</Btn>
            <Btn variant="success" onClick={()=>{
              if(cobroModal.type==="attendance")markPaid(cobroModal.data.id,cobroForm.method);
              else cobrarOrden(cobroModal.data,cobroForm.method);
            }}><Icon name="check" size={13}/>Confirmar Cobro</Btn>
          </div>
        </Modal>
      )}

      {/* Modal Anular Venta */}
      {anularModal&&(()=>{
        return(
          <Modal title="🚫 Anular Venta" onClose={()=>{setAnularModal(null);setAnularMotivo("");}} width={460}>
            <div style={{background:"#fef2f2",border:"1px solid #fecaca",borderRadius:10,padding:"14px 18px",marginBottom:16}}>
              <div style={{fontWeight:700,fontSize:13,color:"#dc2626",marginBottom:4}}>⚠️ Esta acción no se puede deshacer</div>
              <div style={{fontSize:12.5,color:"#1a2332",fontWeight:600}}>{patientLabel(anularModal)}</div>
              <div style={{fontSize:12,color:"#5a7a8a"}}>{anularModal.service} — {fmt(anularModal.date)}</div>
              <div style={{fontSize:18,fontWeight:800,color:"#dc2626",marginTop:6}}>{currency(anularModal.price)}</div>
              {(anularModal.orderItems||[]).length>0&&(
                <div style={{marginTop:8,fontSize:11.5,color:"#7c3aed",background:"#f5f3ff",borderRadius:6,padding:"6px 10px"}}>
                  📦 Se devolverá al stock: {anularModal.orderItems.map(i=>`${i.name} ×${i.qty||1}`).join(", ")}
                </div>
              )}
            </div>
            <Field label="Motivo de anulación *">
              <Inp value={anularMotivo} onChange={e=>setAnularMotivo(e.target.value)} placeholder="Ej: Error en monto, solicitud del cliente, doble cobro..."/>
            </Field>
            <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
              <Btn variant="secondary" onClick={()=>{setAnularModal(null);setAnularMotivo("");}}>Cancelar</Btn>
              <button onClick={()=>{if(!anularMotivo.trim()){alert("Ingrese el motivo de anulación");return;}anularVenta(anularModal,anularMotivo.trim());setAnularMotivo("");}} style={{padding:"8px 18px",borderRadius:9,background:"linear-gradient(135deg,#dc2626,#b91c1c)",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",display:"flex",alignItems:"center",gap:6}}>🚫 Confirmar Anulación</button>
            </div>
          </Modal>
        );
      })()}

      {/* Modal Detalle KPI */}
      {kpiDetailModal&&(
        <Modal title={kpiDetailModal.title} onClose={()=>setKpiDetailModal(null)} width={680}>
          <div style={{background:`${kpiDetailModal.color}11`,border:`1px solid ${kpiDetailModal.color}33`,borderRadius:10,padding:"12px 18px",marginBottom:16,display:"flex",alignItems:"center",justifyContent:"space-between"}}>
            <div style={{fontSize:13,color:"#5a7a8a"}}>Período: <b>{rangeLabel}</b> · {kpiDetailModal.rows.length} registros</div>
            <div style={{fontSize:22,fontWeight:800,color:kpiDetailModal.color}}>
              {kpiDetailModal.isCount?kpiDetailModal.total:(kpiDetailModal.isAvg?"Prom. "+currency(kpiDetailModal.total):currency(kpiDetailModal.total))}
            </div>
          </div>
          <div style={{maxHeight:400,overflowY:"auto"}}>
            {kpiDetailModal.rows.length===0?<div style={{textAlign:"center",padding:"32px 0",color:"#8a9aaa"}}>Sin registros en este período</div>:(
              <table style={{width:"100%",borderCollapse:"collapse",fontSize:12.5}}>
                <thead style={{position:"sticky",top:0,background:"#fff",zIndex:1}}>
                  <tr style={{background:"#f4f8fa"}}>{["Paciente","Fecha","Servicio","Método","Por","Monto"].map(h=><th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",borderBottom:"2px solid #eef2f7"}}>{h}</th>)}</tr>
                </thead>
                <tbody>
                  {kpiDetailModal.rows.map((r,i)=>(
                    <tr key={i} style={{borderBottom:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff"}}>
                      <td style={{padding:"8px 12px",fontWeight:600,fontSize:12}}>{r.name}</td>
                      <td style={{padding:"8px 12px",whiteSpace:"nowrap",color:"#5a7a8a"}}>{r.date}</td>
                      <td style={{padding:"8px 12px",maxWidth:160,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}}>{r.service}</td>
                      <td style={{padding:"8px 12px"}}><span style={{padding:"2px 8px",borderRadius:5,background:`${r.color}18`,color:r.color,fontWeight:700,fontSize:11}}>{r.method}</span></td>
                      <td style={{padding:"8px 12px",fontSize:11.5,color:"#8a9aaa"}}>{r.by}</td>
                      <td style={{padding:"8px 12px",fontWeight:800,color:r.color,textAlign:"right"}}>{currency(r.amount)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
          <div style={{display:"flex",justifyContent:"flex-end",marginTop:14,gap:8}}>
            <Btn variant="secondary" onClick={()=>setKpiDetailModal(null)}>Cerrar</Btn>
            <button onClick={printCobranza} style={{padding:"8px 18px",borderRadius:9,background:"linear-gradient(135deg,#2563eb,#1d4ed8)",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",display:"flex",alignItems:"center",gap:6}}>🖨️ Imprimir Reporte</button>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO BIBLIOTECA ────────────────────────────────────────────────────────
const LibraryModule=()=>{
  const DEF_PATHO_DB=[
    {name:"Onicomicosis",emoji:"🦠",desc:"Infección fúngica de las uñas causada por dermatofitos.",tags:["hongos","uñas","tratamiento"]},
    {name:"Uña Encarnada",emoji:"😣",desc:"La uña penetra en los tejidos blandos circundantes, causando dolor e infección.",tags:["ungueal","cirugía","dolor"]},
    {name:"Hallux Valgus",emoji:"🦷",desc:"Deformidad del primer dedo con desviación medial y juanete doloroso.",tags:["deformidad","cirugía","ortopedia"]},
    {name:"Fascitis Plantar",emoji:"👣",desc:"Inflamación de la fascia plantar. Dolor en el talón especialmente al levantarse.",tags:["dolor","talón","inflamación"]},
    {name:"Verruga Plantar",emoji:"🔵",desc:"Lesión cutánea por el virus del papiloma humano (VPH).",tags:["viral","tratamiento","VPH"]},
    {name:"Heloma",emoji:"🔴",desc:"Callo circunscrito con núcleo central que produce dolor agudo.",tags:["callo","presión","dolor"]},
    {name:"Pie Plano",emoji:"🦶",desc:"Pérdida del arco plantar longitudinal.",tags:["arco","ortopedia","biomecánica"]},
    {name:"Pie Cavo",emoji:"🦶",desc:"Arco plantar anormalmente elevado.",tags:["arco","ortopedia","biomecánica"]},
    {name:"Metatarsalgia",emoji:"💥",desc:"Dolor en la región metatarsal del antepié.",tags:["dolor","metatarso","antepié"]},
    {name:"Espolón Calcáneo",emoji:"🦴",desc:"Calcificación en la inserción de la fascia plantar.",tags:["calcificación","talón"]},
    {name:"Neuropatía Diabética",emoji:"⚡",desc:"Daño nervioso por diabetes con pérdida de sensibilidad.",tags:["diabetes","nervios","úlceras"]},
    {name:"Callosidad",emoji:"🟤",desc:"Engrosamiento difuso de la piel por fricción crónica.",tags:["piel","presión","fricción"]},
  ];
  const[search,setSearch]=useState("");
  const[sel,setSel]=useState(null);
  const[customDB,setCustomDB]=useState(()=>safeJson(localStorage.getItem("pmb_custom_patho"),[]));
  const[addModal,setAddModal]=useState(false);
  const[newEntry,setNewEntry]=useState({name:"",emoji:"🦶",desc:"",tags:""});

  const allDB=[...DEF_PATHO_DB,...customDB];
  const filtered=allDB.filter(p=>!search||p.name.toLowerCase().includes(search.toLowerCase())||p.tags.some(t=>t.toLowerCase().includes(search.toLowerCase())));

  const saveCustom=()=>{
    if(!newEntry.name.trim()){alert("Ingrese el nombre");return}
    const entry={...newEntry,tags:newEntry.tags.split(",").map(t=>t.trim()).filter(Boolean),isCustom:true};
    const updated=[...customDB,entry];
    setCustomDB(updated);
    localStorage.setItem("pmb_custom_patho",JSON.stringify(updated));
    setAddModal(false);setNewEntry({name:"",emoji:"🦶",desc:"",tags:""});
  };

  const openInternetSearch=(p,engine)=>{
    const queries={
      PubMed:`https://pubmed.ncbi.nlm.nih.gov/?term=${encodeURIComponent(p.name+" podología")}`,
      SciELO:`https://scielo.org/search?q=${encodeURIComponent(p.name)}`,
      Scholar:`https://scholar.google.com/scholar?q=${encodeURIComponent("podología "+p.name)}`,
      Google:`https://www.google.com/search?q=${encodeURIComponent("podología "+p.name+" tratamiento")}`,
    };
    window.open(queries[engine],"_blank");
  };

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Biblioteca Podológica</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>{allDB.length} patologías · Búsqueda en bases científicas</div>
        </div>
        <Btn onClick={()=>setAddModal(true)}><Icon name="plus" size={14}/>Nueva Patología</Btn>
      </div>
      <Card style={{marginBottom:16,padding:"10px 16px"}}>
        <div style={{position:"relative"}}>
          <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar patología o tag..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
        </div>
      </Card>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(280px,1fr))",gap:12}}>
        {filtered.map(p=>(
          <Card key={p.name} style={{cursor:"pointer",transition:"transform .15s,box-shadow .15s",border:`2px solid ${sel?.name===p.name?"#4a9d8f":"transparent"}`}} onClick={()=>setSel(sel?.name===p.name?null:p)} onMouseOver={e=>{e.currentTarget.style.transform="translateY(-2px)";e.currentTarget.style.boxShadow="0 8px 24px rgba(0,0,0,0.1)"}} onMouseOut={e=>{e.currentTarget.style.transform="none";e.currentTarget.style.boxShadow=""}}>
            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:8}}>
              <div style={{fontSize:28}}>{p.emoji}</div>
              <div>
                <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{p.name}</div>
                {p.isCustom&&<Badge color="purple">Personalizada</Badge>}
              </div>
            </div>
            <div style={{fontSize:12.5,color:"#5a7a8a",lineHeight:1.6,marginBottom:10}}>{p.desc}</div>
            <div style={{display:"flex",gap:4,flexWrap:"wrap"}}>{p.tags.map(t=><Badge key={t} color="teal">{t}</Badge>)}</div>
            {sel?.name===p.name&&(
              <div style={{marginTop:14,paddingTop:12,borderTop:"1px solid #eef2f7"}}>
                <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",marginBottom:8,textTransform:"uppercase"}}>🌐 Buscar en Internet</div>
                <div style={{display:"flex",gap:5,flexWrap:"wrap"}}>
                  {[["PubMed","#2563eb"],["SciELO","#059669"],["Scholar","#7c3aed"],["Google","#e05050"]].map(([eng,color])=>(
                    <button key={eng} onClick={e=>{e.stopPropagation();openInternetSearch(p,eng)}} style={{padding:"5px 12px",borderRadius:7,background:`${color}18`,color,fontSize:11.5,fontWeight:700,border:`1px solid ${color}33`,cursor:"pointer"}}>{eng} →</button>
                  ))}
                </div>
              </div>
            )}
          </Card>
        ))}
      </div>
      {addModal&&(
        <Modal title="Agregar Nueva Patología" onClose={()=>setAddModal(false)} width={480}>
          <div style={{display:"grid",gridTemplateColumns:"60px 1fr",gap:"0 14px"}}>
            <Field label="Emoji"><Inp value={newEntry.emoji} onChange={e=>setNewEntry(p=>({...p,emoji:e.target.value}))} style={{textAlign:"center",fontSize:22}}/></Field>
            <Field label="Nombre *"><Inp value={newEntry.name} onChange={e=>setNewEntry(p=>({...p,name:e.target.value}))} placeholder="Nombre de la patología"/></Field>
          </div>
          <Field label="Descripción"><TA value={newEntry.desc} onChange={e=>setNewEntry(p=>({...p,desc:e.target.value}))} placeholder="Descripción clínica..." style={{minHeight:70}}/></Field>
          <Field label="Tags (separados por coma)"><Inp value={newEntry.tags} onChange={e=>setNewEntry(p=>({...p,tags:e.target.value}))} placeholder="dolor, tratamiento, cirugía"/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>setAddModal(false)}>Cancelar</Btn><Btn onClick={saveCustom}><Icon name="check" size={13}/>Guardar</Btn></div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO DOCUMENTOS ────────────────────────────────────────────────────────
const DocumentsModule=()=>{
  const DOCS=[
    {id:1,name:"Consentimiento Informado — Cirugía Ungueal",cat:"Consentimiento",emoji:"📝",desc:"Formato de consentimiento para procedimientos quirúrgicos ungueales"},
    {id:2,name:"Consentimiento — Onicomicosis",cat:"Consentimiento",emoji:"📝",desc:"Formato de consentimiento para tratamiento de onicomicosis"},
    {id:3,name:"Consentimiento — Plantillas Ortopédicas",cat:"Consentimiento",emoji:"📝",desc:"Consentimiento para elaboración de plantillas personalizadas"},
    {id:4,name:"Constancia de Atención Podológica",cat:"Constancia",emoji:"🏥",desc:"Documento oficial de atención para paciente"},
    {id:5,name:"Indicaciones Post-Operatorias",cat:"Indicaciones",emoji:"💊",desc:"Cuidados e indicaciones tras procedimiento quirúrgico"},
    {id:6,name:"Plan de Tratamiento Podológico",cat:"Plan",emoji:"📋",desc:"Formato de plan de tratamiento personalizado"},
    {id:7,name:"Referencia a Especialista",cat:"Referencia",emoji:"🔗",desc:"Carta de referencia para médico especialista"},
    {id:8,name:"Historia Clínica en Blanco",cat:"Registro",emoji:"📄",desc:"Formato de historia clínica para llenado manual"},
  ];
  const[search,setSearch]=useState("");
  const[filterCat,setFilterCat]=useState("all");
  const cats=["all",...new Set(DOCS.map(d=>d.cat))];
  const filtered=DOCS.filter(d=>{
    const matchS=!search||d.name.toLowerCase().includes(search.toLowerCase());
    const matchC=filterCat==="all"||d.cat===filterCat;
    return matchS&&matchC;
  });
  const printDoc=(doc)=>alert(`📄 Generando: "${doc.name}"\n\nEsta función conecta con el generador de PDF de tu sistema.`);
  return(
    <div className="slide-in">
      <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em",marginBottom:6}}>Documentos</h2>
      <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:18}}>Formatos usados en podología: constancias, consentimientos según procedimiento y documentos propios.</div>
      <Card style={{marginBottom:16,padding:"10px 16px"}}>
        <div style={{display:"flex",gap:10,flexWrap:"wrap",alignItems:"center"}}>
          <div style={{position:"relative",flex:1,minWidth:200}}>
            <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
            <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar documento..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
          </div>
          <div style={{display:"flex",gap:4}}>
            {cats.map(c=><button key={c} onClick={()=>setFilterCat(c)} style={{padding:"6px 12px",borderRadius:7,border:`1.5px solid ${filterCat===c?"#4a9d8f":"#d4dde5"}`,background:filterCat===c?"#4a9d8f":"#fff",color:filterCat===c?"#fff":"#5a7a8a",fontWeight:600,fontSize:12,cursor:"pointer"}}>{c==="all"?"Todos":c}</button>)}
          </div>
        </div>
      </Card>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(300px,1fr))",gap:12}}>
        {filtered.map(d=>(
          <Card key={d.id} style={{display:"flex",gap:14,alignItems:"flex-start",transition:"transform .15s"}} onMouseOver={e=>e.currentTarget.style.transform="translateY(-2px)"} onMouseOut={e=>e.currentTarget.style.transform="none"}>
            <div style={{fontSize:32,flexShrink:0}}>{d.emoji}</div>
            <div style={{flex:1}}>
              <div style={{fontWeight:700,fontSize:13.5,color:"#1a2332",marginBottom:3}}>{d.name}</div>
              <div style={{fontSize:12,color:"#8a9aaa",marginBottom:10}}>{d.desc}</div>
              <div style={{display:"flex",gap:6}}>
                <Badge color="blue">{d.cat}</Badge>
                <Btn size="xs" onClick={()=>printDoc(d)}><Icon name="file" size={11}/>Imprimir</Btn>
              </div>
            </div>
          </Card>
        ))}
      </div>
    </div>
  );
};

// ─── MÓDULO LABORATORIO ────────────────────────────────────────────────────────
const LaboratoryModule=({patients})=>{
  const SK_LAB="pmb_laboratory";
  const[studies,setStudies]=useState(db.get(SK_LAB)||[]);
  const[modal,setModal]=useState(false);
  const[form,setForm]=useState({patientId:"",type:"KOH",date:todayStr(),result:"",notes:"",status:"pendiente"});
  const LAB_TYPES=["KOH","Cultivo Fúngico","Biometría Hemática","Glucosa","Radiografía","Urocultivo","Cultivo Bacteriano","Dermatoscopia","Otro"];
  const saveStudy=async()=>{
    if(!form.patientId||!form.type){alert("Complete los campos requeridos");return}
    const tempId=genId(studies);
    const local={...form,id:tempId,patientId:form.patientId,patient_id:form.patientId};
    try{
      await saveCrudAndSync('laboratory',local,SK_LAB,setStudies,tempId);
      setModal(false);
      setForm({patientId:"",type:"KOH",date:todayStr(),result:"",notes:"",status:"pendiente"});
      alert("✅ Estudio guardado en la base de datos");
    }catch(e){alert("No se guardó el estudio en la base de datos: "+e.message);}
  };
  const statusC={pendiente:"orange",en_proceso:"blue",completado:"green",cancelado:"gray"};
  const statusL={pendiente:"Pendiente",en_proceso:"En proceso",completado:"Completado",cancelado:"Cancelado"};
  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Laboratorio</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Control de estudios: Cultivos, KOH, radiografías, biometrías hemáticas, etc.</div>
        </div>
        <Btn onClick={()=>setModal(true)}><Icon name="plus" size={14}/>Nuevo Estudio</Btn>
      </div>
      <Card style={{padding:0,overflow:"hidden"}}>
        <div style={{overflowX:"auto"}}>
          <table style={{width:"100%",borderCollapse:"collapse",minWidth:700}}>
            <thead><tr style={{background:"linear-gradient(90deg,#f4f8fa,#eef3f7)"}}>{["Paciente","Tipo","Fecha","Resultado","Estado","Notas"].map(h=><th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em"}}>{h}</th>)}</tr></thead>
            <tbody>
              {studies.length===0&&<tr><td colSpan={6} style={{textAlign:"center",padding:36,color:"#8a9aaa",fontSize:13}}>No hay estudios registrados</td></tr>}
              {studies.map((s,i)=>{
                const p=patients.find(x=>x.id===parseInt(s.patientId));
                return(
                  <tr key={s.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff"}}>
                    <td style={{padding:"10px 14px",fontWeight:600,fontSize:13}}>{p?`${p.firstName} ${p.lastName}`:"—"}</td>
                    <td style={{padding:"10px 14px"}}><Badge color="blue">{s.type}</Badge></td>
                    <td style={{padding:"10px 14px",fontSize:13,whiteSpace:"nowrap"}}>{fmt(s.date)}</td>
                    <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a",maxWidth:200}}>{s.result||"—"}</td>
                    <td style={{padding:"10px 14px"}}><Badge color={statusC[s.status]||"gray"}>{statusL[s.status]||s.status}</Badge></td>
                    <td style={{padding:"10px 14px",fontSize:12.5,color:"#8a9aaa",maxWidth:200}}>{s.notes||"—"}</td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </Card>
      {modal&&(
        <Modal title="Nuevo Estudio de Laboratorio" onClose={()=>setModal(false)} width={500}>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
            <Field label="Paciente *" col="1/-1">
              <PatientSearchSelect
                patients={patients}
                value={form.patientId}
                onChange={v=>setForm(p=>({...p,patientId:v}))}
              />
            </Field>
            <Field label="Tipo de Estudio *">
              <Sel value={form.type} onChange={e=>setForm(p=>({...p,type:e.target.value}))}>
                {LAB_TYPES.map(t=><option key={t}>{t}</option>)}
              </Sel>
            </Field>
            <Field label="Fecha"><Inp type="date" value={form.date} onChange={e=>setForm(p=>({...p,date:e.target.value}))}/></Field>
            <Field label="Estado" col="1/-1">
              <Sel value={form.status} onChange={e=>setForm(p=>({...p,status:e.target.value}))}>
                <option value="pendiente">Pendiente</option>
                <option value="en_proceso">En proceso</option>
                <option value="completado">Completado</option>
              </Sel>
            </Field>
          </div>
          <Field label="Resultado"><TA value={form.result} onChange={e=>setForm(p=>({...p,result:e.target.value}))} placeholder="Resultado del estudio..." style={{minHeight:70}}/></Field>
          <Field label="Notas"><TA value={form.notes} onChange={e=>setForm(p=>({...p,notes:e.target.value}))} style={{minHeight:55}}/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setModal(false)}>Cancelar</Btn>
            <Btn onClick={saveStudy}><Icon name="check" size={13}/>Guardar</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO CONTROL DE FOTOS ──────────────────────────────────────────────────
const PhotosModule=({patients})=>{
  const SK_PHOTOS="pmb_photos";
  const photoRows=useStore(SK_PHOTOS,[]);
  const attendanceRows=useStore(SK.attendances,[]);
  const[modal,setModal]=useState(false);
  const[saving,setSaving]=useState(false);
  const[loadingPhotos,setLoadingPhotos]=useState(false);
  const[photoLoadError,setPhotoLoadError]=useState("");
  const[lightboxSrc,setLightboxSrc]=React.useState(null);
  const[form,setForm]=useState({patientId:"",title:"",photos:[],date:todayStr(),notes:""});
  const fileRef=useRef();
  const safePatients=Array.isArray(patients)?patients:[];
  const loadAllPhotos=useCallback(async()=>{
    setLoadingPhotos(true);setPhotoLoadError("");
    try{
      await api.get('attendances',{strict:true});
      await api.get('photos',{strict:true});
    }catch(e){setPhotoLoadError(e.message||"No se pudieron cargar las fotografías");}
    finally{setLoadingPhotos(false);}
  },[]);
  useEffect(()=>{loadAllPhotos();},[loadAllPhotos]);
  const normalizePhotos=(value,date)=>{
    let list=value;
    if(typeof list==="string"){
      try{list=JSON.parse(list);}catch{list=list.startsWith("data:image/")?[list]:[];}
    }
    if(!Array.isArray(list))return[];
    return list.filter(Boolean).map((ph,index)=>{
      if(typeof ph==="string")return{name:`Foto ${index+1}`,data:ph,date};
      return{...ph,name:ph.name||`Foto ${index+1}`,data:ph.data||ph.src||ph.url||"",date:ph.date||date};
    }).filter(ph=>typeof ph.data==="string"&&ph.data.length>0);
  };
  const cases=useMemo(()=>{
    const groups={};
    const addCase=(row,photos,index,source)=>{
      if(!row||typeof row!=="object")return;
      const patientId=row.patientId||row.patient_id||"";
      const date=row.date||todayStr();
      const title=row.title||row.service||"Control Fotográfico";
      const notes=row.notes||row.note||"";
      // Patient + date + service identifies one photographic session. Notes
      // are deliberately excluded because legacy tables stored them differently.
      const key=[patientId,date,String(title).trim().toLowerCase()].join("|");
      if(!groups[key])groups[key]={id:`${source}-${row.id||index}`,patientId,patientName:row.patientName||row.patient_name||"",title,date,notes,photos:[]};
      if(!groups[key].notes&&notes)groups[key].notes=notes;
      if(!groups[key].patientName&&(row.patientName||row.patient_name))groups[key].patientName=row.patientName||row.patient_name;
      const seen=new Set(groups[key].photos.map(ph=>ph.data));
      photos.forEach(ph=>{if(ph.data&&!seen.has(ph.data)){seen.add(ph.data);groups[key].photos.push(ph);}});
    };
    (Array.isArray(photoRows)?photoRows:[]).forEach((row,index)=>{
      if(!row||typeof row!=="object")return;
      // Compatibility with older browser-only records that already used cases.
      if(Array.isArray(row.photos)){
        addCase(row,normalizePhotos(row.photos,row.date),index,"legacy");
        return;
      }
      const src=row.src||row.data||"";
      addCase(row,src?[{id:row.id,name:row.name||"Foto",data:src,date:row.date}]:[],index,"photo");
    });
    // Historical images were stored inside clinical attendances.
    (Array.isArray(attendanceRows)?attendanceRows:[]).forEach((row,index)=>{
      const photos=normalizePhotos(row?.photos,row?.date);
      if(photos.length>0)addCase(row,photos,index,"attendance");
    });
    return Object.values(groups).sort((a,b)=>String(b.date||"").localeCompare(String(a.date||"")));
  },[photoRows,attendanceRows]);
  const totalPhotos=cases.reduce((sum,c)=>sum+(Array.isArray(c.photos)?c.photos.length:0),0);
  const handleFiles=e=>{
    const files=Array.from(e.target.files);
    Promise.all(files.map(f=>new Promise((resolve,reject)=>{const rd=new FileReader();rd.onload=()=>resolve({name:f.name,data:rd.result,date:todayStr()});rd.onerror=reject;rd.readAsDataURL(f)})))
      .then(imgs=>setForm(p=>({...p,photos:[...(Array.isArray(p.photos)?p.photos:[]),...imgs]})))
      .catch(()=>alert("No se pudieron leer una o más imágenes."));
    e.target.value="";
  };
  const saveCase=async()=>{
    if(!form.patientId){alert("Seleccione un paciente");return}
    if(!Array.isArray(form.photos)||form.photos.length===0){alert("Agregue al menos una foto");return}
    setSaving(true);
    const p=safePatients.find(x=>String(x.id)===String(form.patientId));
    try{
      const created=[];
      for(const ph of form.photos){
        const row=await crudApi.create('photos',{
          patient_id:parseInt(form.patientId)||null,
          patient_name:p?`${p.firstName||p.first_name||""} ${p.lastName||p.last_name||""}`.trim():"",
          date:form.date||todayStr(),
          src:ph.data,
          note:form.notes||"",
          service:form.title||"Control Fotográfico"
        });
        created.push(row);
      }
      const current=Array.isArray(db.get(SK_PHOTOS))?db.get(SK_PHOTOS):[];
      db.set(SK_PHOTOS,[...current,...created]);
    // Adicionar a historia clínica del paciente como atención
    const SK_ATT="pmb_attendances";
    const allAtt=db.get(SK_ATT)||[];
    if(p){
      const attEntry={
        id:genId(allAtt),
        patientId:form.patientId,
        patientName:`${p.firstName||p.first_name||""} ${p.lastName||p.last_name||""}`.trim(),
        date:form.date,
        time:new Date().toLocaleTimeString("es-PE",{hour:"2-digit",minute:"2-digit",hour12:false}),
        registeredAt:new Date().toISOString(),
        service:"Control Fotográfico",
        notes:`Caso: ${form.title||"Sin título"}. ${form.notes||""}`.trim(),
        photos:form.photos,
        price:0,
        payStatus:"gratuito",
        closed:true,
        attendedBy:"—",
        photoCase:true,
        photoCaseId:created[0]?.id||null
      };
      db.set(SK_ATT,[...allAtt,attEntry]);
      crudApi.create('attendances',{
        patient_id:parseInt(form.patientId)||null,
        patient_name:attEntry.patientName,
        date:attEntry.date,time:attEntry.time,service:attEntry.service,
        notes:attEntry.notes,photos:attEntry.photos,price:0,
        pay_status:"pagado",closed:1,attended_by:"—"
      }).catch(()=>{});
    }
    setModal(false);
    setForm({patientId:"",title:"",photos:[],date:todayStr(),notes:""});
    }catch(e){
      alert("No se pudo guardar el caso fotográfico: "+(e.message||"Error del servidor"));
    }finally{setSaving(false);}
  };
  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Control de Fotos</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Seguimiento visual · {totalPhotos} fotos recuperadas en {cases.length} casos</div>
        </div>
        <div style={{display:"flex",gap:8}}>
          <Btn variant="ghost" onClick={loadAllPhotos} disabled={loadingPhotos}>{loadingPhotos?"Cargando...":"↻ Recargar todas"}</Btn>
          <Btn onClick={()=>setModal(true)}><Icon name="plus" size={14}/>Nuevo Caso Fotográfico</Btn>
        </div>
      </div>
      {photoLoadError&&<div style={{background:"#fff4e5",border:"1px solid #f59e0b",borderRadius:9,padding:"9px 12px",marginBottom:12,color:"#8a4b08",fontSize:12.5}}>No se pudieron actualizar las fotos: {photoLoadError}</div>}
      {cases.length===0?(
        <Card style={{textAlign:"center",padding:60}}>
          <div style={{fontSize:48,marginBottom:12}}>📷</div>
          <div style={{fontSize:16,fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin casos fotográficos</div>
          <div style={{fontSize:13,color:"#8a9aaa",marginBottom:20}}>Registra el seguimiento visual de tus pacientes</div>
          <Btn onClick={()=>setModal(true)}><Icon name="plus" size={14}/>Crear Primer Caso</Btn>
        </Card>
      ):(
        <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(320px,1fr))",gap:14}}>
          {cases.map(c=>{
            const photos=Array.isArray(c.photos)?c.photos:[];
            const p=safePatients.find(x=>String(x.id)===String(c.patientId));
            return(
              <Card key={c.id}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:10}}>
                  <div>
                    <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{c.title||"Sin título"}</div>
                    <div style={{fontSize:12,color:"#4a9d8f",fontWeight:600}}>{p?`${p.firstName||p.first_name||""} ${p.lastName||p.last_name||""}`.trim():(c.patientName||"—")}</div>
                    <div style={{fontSize:11,color:"#8a9aaa"}}>{fmt(c.date)}</div>
                  </div>
                  <Badge color="teal">{photos.length} foto{photos.length!==1?"s":""}</Badge>
                </div>
                <div style={{display:"flex",gap:5,flexWrap:"wrap",marginBottom:8}}>
                  {photos.slice(0,4).map((ph,i)=>(
                    <img key={i} src={ph.data} alt="" onClick={()=>setLightboxSrc(ph.data)} style={{width:72,height:72,objectFit:"cover",borderRadius:8,border:"2px solid #e8edf2",cursor:"zoom-in"}}/>
                  ))}
                  {photos.length>4&&<div onClick={()=>setLightboxSrc(photos[4].data)} style={{width:72,height:72,borderRadius:8,background:"#f0f4f8",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:700,color:"#5a7a8a",cursor:"zoom-in"}}>+{photos.length-4}</div>}
                  {photos.length===0&&<div style={{fontSize:11.5,color:"#8a9aaa",padding:"8px 0"}}>Registro antiguo sin imagen disponible</div>}
                </div>
                {c.notes&&<div style={{fontSize:12,color:"#5a7a8a",lineHeight:1.5}}>{c.notes}</div>}
              </Card>
            );
          })}
        </div>
      )}
      {modal&&(
        <Modal title="Nuevo Caso Fotográfico" onClose={()=>setModal(false)} width={520}>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
            <Field label="Paciente *" col="1/-1">
              <PatientSearchSelect
                patients={safePatients}
                value={form.patientId}
                onChange={v=>setForm(p=>({...p,patientId:v}))}
              />
            </Field>
            <Field label="Título del Caso" col="1/-1"><Inp value={form.title} onChange={e=>setForm(p=>({...p,title:e.target.value}))} placeholder="Ej: Seguimiento Onicomicosis"/></Field>
            <Field label="Fecha"><Inp type="date" value={form.date} onChange={e=>setForm(p=>({...p,date:e.target.value}))}/></Field>
          </div>
          <Field label="Fotos">
            <input ref={fileRef} type="file" accept="image/*" multiple onChange={handleFiles} style={{display:"none"}}/>
            <Btn variant="ghost" size="sm" onClick={()=>fileRef.current.click()}><Icon name="photo" size={13}/>Agregar Fotos</Btn>
            {form.photos.length>0&&(
              <div style={{display:"flex",gap:6,flexWrap:"wrap",marginTop:8}}>
                {form.photos.map((ph,i)=>(
                  <div key={i} style={{position:"relative"}}>
                    <img src={ph.data} alt="" style={{width:72,height:72,objectFit:"cover",borderRadius:7,border:"2px solid #d0dce5"}}/>
                    <button onClick={()=>setForm(p=>({...p,photos:p.photos.filter((_,j)=>j!==i)}))} style={{position:"absolute",top:-5,right:-5,background:"#e05050",border:"none",borderRadius:"50%",width:17,height:17,cursor:"pointer",color:"#fff",fontSize:11,display:"flex",alignItems:"center",justifyContent:"center"}}>×</button>
                  </div>
                ))}
              </div>
            )}
          </Field>
          <Field label="Notas"><TA value={form.notes} onChange={e=>setForm(p=>({...p,notes:e.target.value}))}/></Field>
          <div style={{background:"#f0faf7",borderRadius:8,padding:"9px 12px",marginBottom:4,fontSize:12,color:"#4a9d8f",display:"flex",alignItems:"center",gap:6}}>
            <Icon name="check" size={12}/>
            Al guardar, el caso se añadirá automáticamente a la historia clínica del paciente.
          </div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:10}}>
            <Btn variant="secondary" onClick={()=>setModal(false)}>Cancelar</Btn>
            <Btn onClick={saveCase} disabled={saving}><Icon name="check" size={13}/>{saving?"Guardando...":"Guardar Caso"}</Btn>
          </div>
        </Modal>
      )}
      {lightboxSrc&&(
        <div onClick={()=>setLightboxSrc(null)} style={{position:"fixed",inset:0,zIndex:12000,background:"rgba(0,0,0,.88)",display:"flex",alignItems:"center",justifyContent:"center",padding:24,cursor:"zoom-out"}}>
          <img src={lightboxSrc} alt="Foto ampliada" style={{maxWidth:"95vw",maxHeight:"92vh",objectFit:"contain",borderRadius:10,boxShadow:"0 20px 60px rgba(0,0,0,.5)"}}/>
          <button onClick={()=>setLightboxSrc(null)} style={{position:"fixed",top:18,right:22,width:38,height:38,borderRadius:"50%",border:"none",background:"#fff",fontSize:20,cursor:"pointer"}}>×</button>
        </div>
      )}
    </div>
  );
};

// ─── MÓDULO INVENTARIOS ────────────────────────────────────────────────────────
const InventoryModule=({currentUser})=>{
  const[inv,setInv]=useState((db.get(SK.inventory)||[]).map(p=>({
    ...p,
    code:      p.code||'',
    code_type: p.code_type||'',
    price:     parseFloat(p.price||p.price_sell||0),
    cost:    parseFloat(p.cost||p.price_buy||0),
    stock:   parseInt(p.stock||0),
    minStock:parseInt(p.minStock||p.min_stock||0),
    unit:    p.unit||'unidad',
  })));
  const[modal,setModal]=useState(false);
  const[search,setSearch]=useState("");
  const[form,setForm]=useState({name:"",code:"",category:"Medicamento",stock:0,minStock:5,unit:"unidad",price:0,cost:0,description:"",commission_rate:0});
  const[editItem,setEditItem]=useState(null);
  const[movModal,setMovModal]=useState(null);
  const[movForm,setMovForm]=useState({type:"entrada",qty:1,note:""});
  const CATS=["Medicamento","Instrumental","Consumible","Ortopédico","Cosmético","Otro"];

  const blank={name:"",code:"",category:"Medicamento",stock:0,minStock:5,unit:"unidad",price:0,cost:0,description:"",commission_rate:0};
  useEffect(()=>{
    api.get('inventory').then(rows=>{
      if(Array.isArray(rows)&&rows.length>0){
        const norm=rows.map(p=>({...p,
          code:p.code||'',
          price:parseFloat(p.price||p.price_sell||0),
          cost:parseFloat(p.cost||p.price_buy||0),
          stock:parseInt(p.stock||0),
          minStock:parseInt(p.minStock||p.min_stock||0),
          unit:p.unit||'unidad',
        }));
        setInv(norm);
        _cache['inventory']=norm;
      }
    }).catch(()=>{});
  },[]);

  const saveProduct=async()=>{
    if(!form.name){alert("Ingrese nombre");return}
    const local={...form,id:editItem?.id||genId(inv),stock:parseInt(form.stock)||0,minStock:parseInt(form.minStock)||0,price:parseFloat(form.price)||0,cost:parseFloat(form.cost)||0,commission_rate:parseFloat(form.commission_rate)||0,moves:editItem?.moves||[]};
    if(!editItem)local.minStock=parseInt(form.minStock)||5;
    try{
      await saveCrudAndSync('inventory',local,SK.inventory,setInv,editItem?undefined:local.id);
      setModal(false);setEditItem(null);setForm(blank);
      alert("✅ Producto guardado en la base de datos");
    }catch(e){alert("No se guardó el producto en la base de datos: "+e.message);}
  };
  const openEdit=p=>{setEditItem(p);setForm({...p});setModal(true)};
  const saveMov=async()=>{
    const qty=parseInt(movForm.qty)||0;if(qty<=0){alert("Cantidad inválida");return}
    const all=inv.map(p=>{
      if(p.id!==movModal.id)return p;
      const ns=movForm.type==="entrada"?p.stock+qty:Math.max(0,p.stock-qty);
      const m={type:movForm.type,qty,note:movForm.note,date:todayStr(),after:ns};
      return{...p,stock:ns,moves:[...(p.moves||[]),m]};
    });
    const updated=all.find(p=>p.id===movModal.id);
    try{
      if(updated)await crudApi.update('inventory',updated.id,serverPayload('inventory',updated));
      setInv(all);db.set(SK.inventory,all);setMovModal(null);setMovForm({type:"entrada",qty:1,note:""});
      alert("✅ Movimiento guardado en la base de datos");
    }catch(e){alert("No se guardó el movimiento en la base de datos: "+e.message);}
  };
  const totalValue=inv.reduce((s,p)=>s+(p.stock*p.price),0);
  const lowStock=inv.filter(p=>p.stock<=p.minStock);
  const filtered=inv.filter(p=>!search||`${p.name} ${p.code} ${p.category}`.toLowerCase().includes(search.toLowerCase()));

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Inventarios</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Entradas y salidas · {inv.length} productos · Valor: {currency(totalValue)}</div>
          <div style={{display:"flex",gap:8,marginTop:4}}>
            <span style={{fontSize:10.5,background:"#eff6ff",color:"#1d4ed8",border:"1px solid #bfdbfe",borderRadius:4,padding:"1px 7px",fontWeight:600}}>🌐 ATC/ISO Internacional — Código WHO reconocido mundialmente</span>
            <span style={{fontSize:10.5,background:"#f5f3ff",color:"#6d28d9",border:"1px solid #ddd6fe",borderRadius:4,padding:"1px 7px",fontWeight:600}}>📋 Generado — Código interno por nombre del producto</span>
          </div>
        </div>
        <Btn onClick={()=>{setEditItem(null);setForm(blank);setModal(true)}}><Icon name="plus" size={14}/>Nuevo Producto</Btn>
      </div>
      {lowStock.length>0&&(
        <div style={{background:"#fff3e8",border:"1px solid #f59223",borderRadius:10,padding:"10px 16px",marginBottom:14,display:"flex",alignItems:"center",gap:10}}>
          <span style={{fontSize:18}}>⚠️</span>
          <div style={{fontSize:12.5,color:"#8a4f00"}}>
            <b>{lowStock.length} producto(s) con stock bajo mínimo:</b> {lowStock.map(p=>p.name).join(", ")}
          </div>
        </div>
      )}
      <Card style={{marginBottom:14,padding:"10px 16px"}}>
        <div style={{position:"relative"}}>
          <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar por nombre, código o categoría..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
        </div>
      </Card>
      <Card style={{padding:0,overflow:"hidden"}}>
        <div style={{overflowX:"auto"}}>
          <table style={{width:"100%",borderCollapse:"collapse"}}>
            <thead><tr style={{background:"#f4f8fa"}}>{["Código","Producto","Categoría","Stock","Mínimo","Costo","Precio","Valor","Acciones"].map(h=><th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",whiteSpace:"nowrap"}}>{h}</th>)}</tr></thead>
            <tbody>
              {filtered.length===0&&<tr><td colSpan={9} style={{textAlign:"center",padding:36,color:"#8a9aaa"}}>Sin productos</td></tr>}
              {filtered.map((p,i)=>(
                <tr key={p.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff"}}>
                  <td style={{padding:"10px 14px"}}>
                    {p.code?(<>
                      <div style={{fontFamily:"monospace",fontSize:11.5,fontWeight:700,
                        color:String(p.code).startsWith("INT-")?"#2563eb":"#7c3aed",letterSpacing:"0.02em"}}>
                        {p.code}
                      </div>
                      <div style={{marginTop:2}}>
                        <span style={{fontSize:9,fontWeight:700,padding:"1px 5px",borderRadius:3,
                          background:String(p.code).startsWith("INT-")?"#eff6ff":"#f5f3ff",
                          color:String(p.code).startsWith("INT-")?"#1d4ed8":"#6d28d9",
                          border:`1px solid ${String(p.code).startsWith("INT-")?"#bfdbfe":"#ddd6fe"}`}}>
                          {String(p.code).startsWith("INT-")?"🌐 ATC/ISO Internacional":"📋 Generado"}
                        </span>
                      </div>
                    </>):<span style={{color:"#d4dde5",fontSize:13}}>—</span>}
                  </td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{fontWeight:600,fontSize:13.5}}>{p.name}</div>
                    {p.description&&<div style={{fontSize:11,color:"#8a9aaa"}}>{p.description.substring(0,40)}</div>}
                  </td>
                  <td style={{padding:"10px 14px"}}><Badge color="blue">{p.category}</Badge></td>
                  <td style={{padding:"10px 14px"}}>
                    <span style={{fontWeight:700,fontSize:14,color:p.stock<=p.minStock?"#e05050":p.stock<=p.minStock*2?"#f59223":"#2ea87e"}}>{p.stock}</span>
                    <span style={{fontSize:11,color:"#8a9aaa",marginLeft:4}}>{p.unit}</span>
                  </td>
                  <td style={{padding:"10px 14px",fontSize:13,color:"#8a9aaa"}}>{p.minStock}</td>
                  <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a"}}>{currency(p.cost)}</td>
                  <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a"}}>{currency(p.price)}</td>
                  <td style={{padding:"10px 14px",fontWeight:700,fontSize:13,color:"#059669"}}>{currency(p.stock*p.price)}</td>
                  <td style={{padding:"10px 14px"}}>
                    <div style={{display:"flex",gap:4}}>
                      <Btn size="xs" variant="ghost" onClick={()=>openEdit(p)}><Icon name="edit" size={11}/></Btn>
                      <Btn size="xs" variant="success" onClick={()=>setMovModal(p)}>+/- Stock</Btn>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>
      {modal&&(
        <Modal title={editItem?"Editar Producto de Inventario":"Nuevo Producto de Inventario"} onClose={()=>{setModal(false);setEditItem(null)}} width={520}>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
            <Field label="Nombre *" col="1/-1">
              <Inp value={form.name} onChange={e=>{
                const v=e.target.value;
                setForm(p=>({...p,name:v}));
                // Auto-generate code from name if code is empty or was auto-generated
                if(v.trim().length>2){
                  clearTimeout(window._invCodeTimer);
                  window._invCodeTimer=setTimeout(async()=>{
                    // Generar prefijo: primeras 5 letras del nombre (sin espacios/especiales)
                    const clean=v.trim().toUpperCase().replace(/[^A-Z0-9]/g,'');
                    const prefix=clean.slice(0,5)||'PROD';
                    // Obtener correlativo desde BD (cantidad de productos existentes)
                    var seq=1;
                    try{
                      var tok=localStorage.getItem('podo_token')||'';
                      var base=window.location.pathname.replace(/\/[^\/]*$/,'/');
                      var r=await fetch(base+'api/crud.php?entity=inventory&limit=1000',{headers:{'X-Auth-Token':tok}});
                      var d=await r.json().catch(function(){return[];});
                      var items=Array.isArray(d)?d:(d.data||[]);
                      // Buscar el mayor correlativo existente con el mismo prefijo
                      var maxN=0;
                      items.forEach(function(it){
                        var c=String(it.code||'');
                        var m=c.match(new RegExp('^GEN-'+prefix+'-(\\d+)$'));
                        if(m) maxN=Math.max(maxN,parseInt(m[1]));
                      });
                      seq=maxN+1;
                    }catch(e){}
                    var seqStr=String(seq).padStart(3,'0');
                    const autoCode='GEN-'+prefix+'-'+seqStr;
                    setForm(p=>(!p.code||p.code.startsWith('GEN-')||p.code.startsWith('INT-'))?{...p,code:autoCode,code_type:'GEN',_codeMsg:'🔶 Código generado: '+autoCode+' (editable)'}:p);
                  },700);
                }
              }}/>
            </Field>
            <Field label="Código (para búsqueda en ventas)">
              <Inp value={form.code||""} onChange={e=>setForm(p=>({...p,code:e.target.value,_codeMsg:''}))} placeholder="Ej: UREA20, ONIXA, o se genera auto"/>
              {form._codeMsg&&<div style={{fontSize:10,color:form.code&&form.code.startsWith('INT-')?'#2563eb':'#f59223',marginTop:2,display:'flex',alignItems:'center',gap:4}}>{form._codeMsg}</div>}
            </Field>
            <Field label="Categoría"><Sel value={form.category} onChange={e=>setForm(p=>({...p,category:e.target.value}))}>{CATS.map(c=><option key={c}>{c}</option>)}</Sel></Field>
            <Field label="Unidad"><Inp value={form.unit} onChange={e=>setForm(p=>({...p,unit:e.target.value}))}/></Field>
            <Field label="Stock Inicial"><Inp type="number" value={form.stock} onChange={e=>setForm(p=>({...p,stock:e.target.value}))}/></Field>
            <Field label="Stock Mínimo"><Inp type="number" value={form.minStock} onChange={e=>setForm(p=>({...p,minStock:e.target.value}))}/></Field>
            <Field label="Costo Unitario"><Inp type="number" value={form.cost||""} onChange={e=>setForm(p=>({...p,cost:e.target.value}))} placeholder="0.00"/></Field>
            <Field label="Precio Unitario"><Inp type="number" value={form.price} onChange={e=>setForm(p=>({...p,price:e.target.value}))}/></Field>
            <Field label="Comisión Producto (%)" ><Inp type="number" min="0" max="100" value={form.commission_rate||""} onChange={e=>setForm(p=>({...p,commission_rate:e.target.value}))} placeholder="0" disabled={currentUser?.role!=="Super Admin"} style={{opacity:currentUser?.role!=="Super Admin"?0.5:1,cursor:currentUser?.role!=="Super Admin"?"not-allowed":"text"}}/>{currentUser?.role!=="Super Admin"&&<div style={{fontSize:10,color:"#e05050",marginTop:2}}>🔒 Solo Super Admin puede asignar comisión por producto</div>}</Field>
            <Field label="Descripción" col="1/-1"><Inp value={form.description||""} onChange={e=>setForm(p=>({...p,description:e.target.value}))} placeholder="Descripción opcional"/></Field>
          </div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>{setModal(false);setEditItem(null)}}>Cancelar</Btn><Btn onClick={saveProduct}><Icon name="check" size={13}/>Guardar</Btn></div>
        </Modal>
      )}
      {movModal&&(
        <Modal title={`Movimiento de Stock — ${movModal.name}`} onClose={()=>setMovModal(null)} width={380}>
          <div style={{background:"#f4f9f7",borderRadius:8,padding:"10px 14px",marginBottom:14,display:"flex",justifyContent:"space-between"}}>
            <span style={{fontSize:13,color:"#3a5a6a"}}>Stock actual:</span>
            <span style={{fontSize:16,fontWeight:800,color:"#1a2332"}}>{movModal.stock} {movModal.unit}</span>
          </div>
          <Field label="Tipo">
            <div style={{display:"flex",gap:8}}>
              {[["entrada","Entrada ▲","#2ea87e"],["salida","Salida ▼","#e05050"]].map(([v,l,c])=>(
                <button key={v} onClick={()=>setMovForm(p=>({...p,type:v}))} style={{flex:1,padding:"8px 0",borderRadius:8,border:`2px solid ${movForm.type===v?c:"#d4dde5"}`,background:movForm.type===v?`${c}18`:"#fff",color:movForm.type===v?c:"#5a7a8a",fontWeight:700,cursor:"pointer",fontSize:13}}>{l}</button>
              ))}
            </div>
          </Field>
          <Field label="Cantidad"><Inp type="number" min="1" value={movForm.qty} onChange={e=>setMovForm(p=>({...p,qty:e.target.value}))}/></Field>
          <Field label="Motivo"><Inp value={movForm.note} onChange={e=>setMovForm(p=>({...p,note:e.target.value}))} placeholder="Compra, merma, uso clínico..."/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>setMovModal(null)}>Cancelar</Btn><Btn onClick={saveMov}><Icon name="check" size={13}/>Registrar</Btn></div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO COMISIONES ────────────────────────────────────────────────────────
const CommissionsModule=({patients,currentUser})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const[lightboxSrc,setLightboxSrc]=React.useState(null);
  const[scheme,setScheme]=useState(db.get("pmb_commission_scheme")||{pct:15,salesPct:10});
  const[pctInput,setPctInput]=useState(String(scheme.pct));
  const[salesPctInput,setSalesPctInput]=useState(String(scheme.salesPct??10));
  const[savingScheme,setSavingScheme]=useState(false);
  const attendances=db.get(SK.attendances)||[];
  const salesOrders=db.get(SK.salesOrders)||[];
  const users=db.get(SK.users)||DEF_USERS;
  const allStaff=users.filter(u=>u.active);
  const[range,setRange]=useState("month");
  const now=new Date();

  const inRange=d=>{
    const dt=new Date(d+"T00:00:00");
    if(range==="today")return d===todayStr();
    if(range==="week"){const w=new Date(now);w.setDate(w.getDate()-7);return dt>=w}
    if(range==="month")return dt.getMonth()===now.getMonth()&&dt.getFullYear()===now.getFullYear();
    return true;
  };

  const filtAtt=attendances.filter(a=>inRange(a.date)&&(a.payStatus==="pagado"||a.closed));
  // Ventas de productos: atenciones tipo 'venta' que tienen orderItems con productos
  // O salesOrders cobrados (si existen)
  const filtOrders=salesOrders.filter(o=>inRange(o.date)&&o.status==="cobrado");
  // Atenciones con productos vendidos (tipo venta con orderItems)
  const filtProdAtts=filtAtt.filter(a=>
    (a.type==="venta"||a.orderCode)&&
    Array.isArray(a.orderItems)&&
    a.orderItems.some(it=>it._type==="product")
  );

  const schemeExists=!!db.get("pmb_commission_scheme");
  useEffect(()=>{
    api.get('commission_scheme',{refresh:true}).then(s=>{
      if(!s)return;
      const normalized={pct:parseFloat(s.pct)||0,salesPct:parseFloat(s.salesPct??s.sales_pct)||0};
      setScheme(normalized);
      setPctInput(String(normalized.pct));
      setSalesPctInput(String(normalized.salesPct));
      db.set("pmb_commission_scheme",normalized);
    }).catch(()=>{});
  },[]);

  const saveScheme=async()=>{
    const _isSAcomm=currentUser?.role==="Super Admin";
    if(schemeExists&&!_isSAcomm){alert("🔒 Solo el Super Admin puede modificar el esquema de comisiones.");return;}
    const s={pct:parseFloat(pctInput)||0,salesPct:parseFloat(salesPctInput)||0};
    if(s.pct<0||s.pct>100||s.salesPct<0||s.salesPct>100){alert("Ingrese porcentajes entre 0 y 100.");return;}
    setSavingScheme(true);
    try{
      const saved=await apiFetch('/special?action=commission_scheme',{method:'PUT',body:JSON.stringify(s)});
      if(!saved||saved.ok===false)throw new Error(saved?.error||"No se confirmó el guardado en la BD");
      const normalized={pct:parseFloat(saved.pct)||0,salesPct:parseFloat(saved.salesPct??saved.sales_pct)||0};
      const verified=await api.get('commission_scheme',{refresh:true,force:true});
      const finalScheme={pct:parseFloat(verified?.pct??normalized.pct)||0,salesPct:parseFloat(verified?.salesPct??verified?.sales_pct??normalized.salesPct)||0};
      setScheme(finalScheme);
      setPctInput(String(finalScheme.pct));
      setSalesPctInput(String(finalScheme.salesPct));
      db.set("pmb_commission_scheme",finalScheme);
      alert("✅ Esquema de comisiones guardado en la base de datos");
    }catch(e){
      alert("No se pudo guardar en la base de datos. Revise la conexión, permisos de Super Admin y la tabla commission_scheme. Detalle: "+(e.message||e));
    }finally{
      setSavingScheme(false);
    }
  };

  const commissions=allStaff.map(u=>{
    // Atenciones clínicas (servicios)
    const uAtts=filtAtt.filter(a=>a.attendedBy===u.name&&a.type!=="venta");
    const attTotal=uAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
    const attComm=attTotal*(scheme.pct/100);
    // Ventas de productos (desde salesOrders cobrados)
    const orders=filtOrders.filter(o=>o.assignedTo===u.name);
    const ordersTotal=orders.reduce((s,o)=>s+(o.total||0),0);
    // Ventas de productos (desde atenciones tipo venta con orderItems)
    const prodAtts=filtProdAtts.filter(a=>a.attendedBy===u.name);
    const prodAttTotal=prodAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
    const ordersComm=(ordersTotal+prodAttTotal)*((scheme.salesPct??10)/100);
    const totalProdSales=ordersTotal+prodAttTotal;
    const totalProdCount=orders.length+prodAtts.length;
    return{user:u,attCount:uAtts.length,attTotal,attComm,ordersCount:totalProdCount,ordersTotal:totalProdSales,ordersComm,totalComm:attComm+ordersComm};
  });

  return(<>
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Comisiones</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Cálculo automático por atenciones y ventas de productos.</div>
        </div>
        <div style={{display:"flex",gap:6}}>
          {[["today","Hoy"],["week","Semana"],["month","Mes"],["all","Todo"]].map(([v,l])=>(
            <button key={v} onClick={()=>setRange(v)} style={{padding:"6px 14px",borderRadius:8,border:`1.5px solid ${range===v?"#4a9d8f":"#d4dde5"}`,background:range===v?"#4a9d8f":"#fff",color:range===v?"#fff":"#3a5a6a",fontWeight:600,fontSize:12,cursor:"pointer"}}>{l}</button>
          ))}
        </div>
      </div>
      <Card style={{marginBottom:16}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:12}}>⚙️ Esquema de Comisiones</div>
        {schemeExists&&!(currentUser?.role==="Super Admin")&&(
          <div style={{marginBottom:10,padding:"8px 14px",borderRadius:8,background:"#7c3aed14",border:"1.5px solid #7c3aed44",color:"#5a20c0",fontSize:12,fontWeight:600}}>
            🔒 Solo el <strong>Super Admin</strong> puede modificar el esquema de comisiones.
          </div>
        )}
        <div style={{display:"grid",gridTemplateColumns:"1fr 1fr auto",gap:14,alignItems:"flex-end"}}>
          <Field label="Comisión por Atención (%)"><Inp type="number" min="0" max="100" value={pctInput} onChange={e=>{if(schemeExists&&!(currentUser?.role==="Super Admin"))return;setPctInput(e.target.value)}} style={{opacity:(schemeExists&&!(currentUser?.role==="Super Admin"))?0.5:1,cursor:(schemeExists&&!(currentUser?.role==="Super Admin"))?"not-allowed":"text"}}/></Field>
          <Field label="Comisión por Venta de Productos (%)"><Inp type="number" min="0" max="100" value={salesPctInput} onChange={e=>{if(schemeExists&&!(currentUser?.role==="Super Admin"))return;setSalesPctInput(e.target.value)}} style={{opacity:(schemeExists&&!(currentUser?.role==="Super Admin"))?0.5:1,cursor:(schemeExists&&!(currentUser?.role==="Super Admin"))?"not-allowed":"text"}}/></Field>
          <div style={{marginBottom:14}}><Btn onClick={saveScheme} size="sm" disabled={savingScheme} style={{opacity:(schemeExists&&!(currentUser?.role==="Super Admin"))?0.5:1}}><Icon name="check" size={12}/>{savingScheme?"Guardando en BD...":"Guardar"}</Btn></div>
        </div>
      </Card>
      {/* Detalle de ventas comisionadas */}
      <Card style={{marginBottom:16}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:12}}>📦 Ventas Consideradas en Comisiones</div>
        {filtOrders.length===0&&filtProdAtts.length===0
          ?<div style={{color:"#8a9aaa",fontSize:13,textAlign:"center",padding:"16px 0"}}>No hay ventas cobradas en el período seleccionado</div>
          :<div style={{overflowX:"auto"}}><table style={{width:"100%",borderCollapse:"collapse"}}>
            <thead><tr style={{background:"#f4f8fa"}}>{["Orden/Ref","Fecha","Cliente","Vendedor/a","Productos Vendidos","Total Venta","Comisión"].map(h=>
              <th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",whiteSpace:"nowrap"}}>{h}</th>
            )}</tr></thead>
            <tbody>
              {filtOrders.map((o,i)=>{
                const comm=(o.total||0)*((scheme.salesPct??10)/100);
                return(
                  <tr key={"ord-"+o.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff"}}>
                    <td style={{padding:"8px 12px",fontFamily:"monospace",fontSize:12,color:"#4a9d8f",fontWeight:700}}>{o.code||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:12,whiteSpace:"nowrap"}}>{fmt(o.date)}</td>
                    <td style={{padding:"8px 12px",fontSize:12}}>{o.razonSocial||o.dniRuc||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:12,color:"#2563eb",fontWeight:600}}>{o.assignedTo||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:11.5,maxWidth:200}}>
                      {(o.items||[]).filter(it=>it._type==="product").map(it=>(
                        <span key={it._id} style={{display:"inline-block",background:"#4a9d8f18",color:"#4a9d8f",borderRadius:5,padding:"1px 7px",fontSize:10.5,fontWeight:600,marginRight:3,marginBottom:2}}>
                          📦 {it.name} ×{it.qty}
                        </span>
                      ))}
                    </td>
                    <td style={{padding:"8px 12px",fontWeight:700,color:"#059669"}}>{currency(o.total||0)}</td>
                    <td style={{padding:"8px 12px",fontWeight:700,color:"#2563eb"}}>{currency(comm)}</td>
                  </tr>
                );
              })}
              {filtProdAtts.map((a,i)=>{
                const prodItems=(a.orderItems||[]).filter(it=>it._type==="product");
                const comm=(parseFloat(a.price)||0)*((scheme.salesPct??10)/100);
                return(
                  <tr key={"att-"+a.id} style={{borderTop:"1px solid #f0f4f8",background:(filtOrders.length+i)%2?"#fafcfd":"#fff"}}>
                    <td style={{padding:"8px 12px",fontFamily:"monospace",fontSize:12,color:"#7c3aed",fontWeight:700}}>{a.orderCode||"ATN-"+a.id}</td>
                    <td style={{padding:"8px 12px",fontSize:12,whiteSpace:"nowrap"}}>{fmt(a.date)}</td>
                    <td style={{padding:"8px 12px",fontSize:12}}>{a.patientName||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:12,color:"#7c3aed",fontWeight:600}}>{a.attendedBy||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:11.5,maxWidth:200}}>
                      {prodItems.map((it,j)=>(
                        <span key={j} style={{display:"inline-block",background:"#7c3aed18",color:"#7c3aed",borderRadius:5,padding:"1px 7px",fontSize:10.5,fontWeight:600,marginRight:3,marginBottom:2}}>
                          📦 {it.name||it.code} ×{it.qty}
                        </span>
                      ))}
                    </td>
                    <td style={{padding:"8px 12px",fontWeight:700,color:"#059669"}}>{currency(parseFloat(a.price)||0)}</td>
                    <td style={{padding:"8px 12px",fontWeight:700,color:"#7c3aed"}}>{currency(comm)}</td>
                  </tr>
                );
              })}
            </tbody>
            <tfoot><tr style={{background:"#f0f9f7",borderTop:"2px solid #4a9d8f33"}}>
              <td colSpan={5} style={{padding:"8px 12px",fontWeight:700,fontSize:13,color:"#1a2332"}}>TOTALES ({filtOrders.length+filtProdAtts.length} ventas)</td>
              <td style={{padding:"8px 12px",fontWeight:800,color:"#059669"}}>{currency(
                filtOrders.reduce((s,o)=>s+(o.total||0),0)+
                filtProdAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0)
              )}</td>
              <td style={{padding:"8px 12px",fontWeight:800,color:"#2563eb"}}>{currency((
                filtOrders.reduce((s,o)=>s+(o.total||0),0)+
                filtProdAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0)
              )*((scheme.salesPct??10)/100))}</td>
            </tr></tfoot>
          </table></div>
        }
      </Card>

      {/* Proyección de comisiones por producto de inventario */}
      <Card style={{marginBottom:16}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>📊 Proyección de Comisiones por Producto (Inventario)</div>
        <div style={{fontSize:12,color:"#8a9aaa",marginBottom:12}}>Comisión esperada por cada venta de producto del inventario al {scheme.salesPct??10}%</div>
        <div style={{display:"flex",flexWrap:"wrap",gap:8}}>
          {(db.get(SK.inventory)||[]).filter(p=>parseFloat(p.price||p.price_sell||0)>0).map(p=>{
            const precio=parseFloat(p.price||p.price_sell||0);
            const comm=precio*((scheme.salesPct??10)/100);
            return(
              <div key={p.id} style={{background:"#f8fafc",border:"1px solid #e8edf2",borderRadius:10,padding:"10px 14px",minWidth:160,flex:"0 0 auto"}}>
                <div style={{fontSize:10,color:"#8a9aaa",fontFamily:"monospace",marginBottom:2}}>{p.code||"—"}</div>
                <div style={{fontWeight:700,fontSize:12.5,color:"#1a2332",marginBottom:4,lineHeight:1.3}}>{p.name}</div>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                  <div>
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Precio</div>
                    <div style={{fontWeight:700,color:"#059669",fontSize:13}}>{currency(precio)}</div>
                  </div>
                  <div style={{textAlign:"right"}}>
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Comisión</div>
                    <div style={{fontWeight:700,color:"#2563eb",fontSize:13}}>{currency(comm)}</div>
                  </div>
                </div>
                <div style={{marginTop:6,fontSize:10.5,color:p.stock<=0?"#e05050":p.stock<=(p.minStock||p.min_stock||0)?"#f59223":"#2ea87e",fontWeight:600}}>
                  Stock: {p.stock||0} {p.unit||""}
                </div>
              </div>
            );
          })}
        </div>
      </Card>

      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(320px,1fr))",gap:14}}>
        {commissions.map(({user,attCount,attTotal,attComm,ordersCount,ordersTotal,ordersComm,totalComm})=>(
          <Card key={user.id} style={{border:`2px solid ${totalComm>0?"#2ea87e33":"#f0f4f8"}`}}>
            <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:14}}>
              <div style={{width:44,height:44,borderRadius:"50%",background:"#4a9d8f22",border:"2px solid #4a9d8f44",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,fontWeight:700,color:"#4a9d8f"}}>{user.name[0]}</div>
              <div>
                <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{user.name}</div>
                <Badge color={user.role==="Podólogo"?"blue":user.role==="Administrador"?"red":"green"}>{user.role}</Badge>
              </div>
            </div>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8,marginBottom:12}}>
              <div style={{background:"#f4f8fa",borderRadius:8,padding:"10px 12px"}}>
                <div style={{fontSize:9.5,color:"#8a9aaa",textTransform:"uppercase",marginBottom:2}}>Atenciones ({attCount})</div>
                <div style={{fontSize:14,fontWeight:700,color:"#1a2332"}}>{currency(attTotal)}</div>
                <div style={{fontSize:11,color:"#4a9d8f",fontWeight:700}}>+{currency(attComm)} ({scheme.pct}%)</div>
              </div>
              <div style={{background:"#f4f8fa",borderRadius:8,padding:"10px 12px"}}>
                <div style={{fontSize:9.5,color:"#8a9aaa",textTransform:"uppercase",marginBottom:2}}>Ventas ({ordersCount})</div>
                <div style={{fontSize:14,fontWeight:700,color:"#1a2332"}}>{currency(ordersTotal)}</div>
                <div style={{fontSize:11,color:"#2563eb",fontWeight:700}}>+{currency(ordersComm)} ({scheme.salesPct??10}%)</div>
              </div>
            </div>
            <div style={{background:"#2ea87e14",borderRadius:8,padding:"10px 14px",border:"1.5px solid #2ea87e33",display:"flex",justifyContent:"space-between",alignItems:"center"}}>
              <div style={{fontSize:11,color:"#1a8060",fontWeight:700,textTransform:"uppercase"}}>Comisión Total</div>
              <div style={{fontSize:20,fontWeight:800,color:"#1a8060"}}>{currency(totalComm)}</div>
            </div>
          </Card>
        ))}
      </div>
    </div>
    {lightboxSrc&&<PhotoLightbox src={lightboxSrc} onClose={()=>setLightboxSrc(null)}/>}
  </>);
};

// ─── MÓDULO CORTE ─────────────────────────────────────────────────────────────
const CorteModule=({patients,currentUser,onLinkPatient})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const resolvePt=(patientId)=>{
    if(!patientId)return null;
    const pid=String(patientId).trim();
    const combined=[...safePatients,...(_cache['patients']||[]),...(db.get(SK.patients)||[])];
    const seen=new Set();
    const unique=combined.filter(x=>{
      const k=String(x.id||x.dni||'');
      if(!k||seen.has(k))return false;
      seen.add(k);
      return true;
    });
    return unique.find(x=>String(x.id)===pid||String(x.dni||'')===pid)||null;
  };
  const getPatientName=(a)=>{
    const p=resolvePt(a.patientId||a.patient_id)||resolvePt(a.patientDni||a.patient_dni);
    const fromPatient=p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`.trim():'';
    const fromAttendance=a.patientName||a.patient_name||`${a.first_name||''} ${a.last_name||''}`.trim();
    return fromPatient||fromAttendance||"Falta vincular paciente: registre Nombres, Apellidos y DNI";
  };
  const needsPatientLink=a=>getPatientName(a).startsWith("Falta vincular paciente");
  const attendances=useStore(SK.attendances,[]);

  const[date,setDate]=useState(todayStr());
  const adminPrincipalBlocked=isAdminPrincipalUser(currentUser);
  const[partialModal,setPartialModal]=useState(false);
  const[partialNote,setPartialNote]=useState("");
  const[dayAttendances,setDayAttendances]=useState(null);
  const[corteLoading,setCorteLoading]=useState(false);
  const normalizeCorteAtt=a=>{
    const closed=a.closed===true||a.closed===1||["1","true","si","sí","cerrado"].includes(String(a.closed||"").trim().toLowerCase());
    const payStatus=String(a.payStatus||a.pay_status||"pendiente").trim().toLowerCase();
    const payMethod=a.payMethod||a.pay_method||a.paidMethod||a.paid_method||"Efectivo";
    const attendedBy=a.attendedBy||a.attended_by||"—";
    const rawDate=String(a.date||a.registeredAt||a.registered_at||"").slice(0,10);
    return{...a,
      patientId:a.patientId||a.patient_id||null,
      patient_id:a.patient_id||a.patientId||null,
      patientDni:String(a.patientDni||a.patient_dni||""),
      patientName:a.patientName||a.patient_name||`${a.first_name||''} ${a.last_name||''}`.trim()||"",
      attendedBy,
      attended_by:attendedBy,
      payMethod,
      pay_method:payMethod,
      payStatus,
      pay_status:payStatus,
      date:rawDate,
      closed
    };
  };
  const mergeCorteRows=(serverRows,localRows)=>{
    const merged=[];
    const seen=new Set();
    [...(serverRows||[]),...(localRows||[])].map(normalizeCorteAtt).forEach(a=>{
      const key=a.orderCode
        ?["order",a.orderCode,a.service,a.patientDni||a.patientId,a.price,a.date,a.time].join("|")
        :["id",a.id||"",a.patientId||a.patientDni||a.patientName,a.service,a.price,a.date,a.time].join("|");
      if(seen.has(key))return;
      seen.add(key);
      merged.push(a);
    });
    return merged;
  };
  useEffect(()=>{
    if(!(_cache['patients']||_cache[SK.patients]||[]).length)api.get('patients').catch(()=>{});
  },[]);
  useEffect(()=>{
    let alive=true;
    setCorteLoading(true);
    crudApi.list('attendances',{date,limit:500})
      .then(rows=>{if(alive)setDayAttendances((Array.isArray(rows)?rows:[]).map(normalizeCorteAtt));})
      .catch(e=>{console.warn('corte attendances',e.message);if(alive)setDayAttendances(null);})
      .finally(()=>{if(alive)setCorteLoading(false);});
    return()=>{alive=false;};
  },[date]);
  const corteSource=Array.isArray(dayAttendances)?mergeCorteRows(dayAttendances,attendances):attendances.map(normalizeCorteAtt);
  const att=corteSource.filter(a=>String(a.date||"").slice(0,10)===date&&(a.payStatus==="pagado"||a.closed)&&a.payStatus!=="anulado");
  const total=att.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const byMethod={};att.forEach(a=>{const m=a.payMethod||"Efectivo";byMethod[m]=(byMethod[m]||0)+(parseFloat(a.price)||0)});
  const byVendor={};att.forEach(a=>{const v=a.attendedBy||"—";byVendor[v]=(byVendor[v]||0)+(parseFloat(a.price)||0)});
  const bySvc={};att.forEach(a=>{if(a.service){bySvc[a.service]=(bySvc[a.service]||0)+1}});
  const topSvc=Object.entries(bySvc).sort((a,b)=>b[1]-a[1]).slice(0,5);
  const partialCuts=db.get(SK.partialCuts)||[];
  const todayPartials=partialCuts.filter(c=>c.date===date);
  const setAllowedDate=nextDate=>{
    if(adminPrincipalBlocked&&nextDate<todayStr()){
      alert("ACCIÓN NO PERMITIDO");
      setDate(todayStr());
      return;
    }
    setDate(nextDate);
  };

  const exportWABusinessCSV=()=>{
    const rows=[["Nombre completo","Número de teléfono"]];
    att.forEach(a=>{
      const p=resolvePt(a.patientId||a.patient_id||a.patientDni||a.patient_dni);
      const name=getPatientName(a);
      const phone=(p?.phone||"").replace(/\D/g,"");
      if(phone)rows.push([name,"51"+phone]);
    });
    const csv=rows.map(r=>r.map(c=>`"${String(c).replace(/"/g,'""')}"`).join(",")).join("\n");
    const blob=new Blob([csv],{type:"text/csv;charset=utf-8"});
    const url=URL.createObjectURL(blob);
    const a=document.createElement("a");a.href=url;a.download=`wa_business_corte_${date}.csv`;a.click();URL.revokeObjectURL(url);
  };

  const exportCorte=()=>{
    const lines=[`CORTE DEL DÍA — ${fmt(date)}`,`Total: ${getCurrency()} ${total.toFixed(2)}`,`Atenciones: ${att.length}`,``,`POR FORMA DE PAGO:`,...Object.entries(byMethod).map(([m,v])=>`  ${m}: ${getCurrency()} ${v.toFixed(2)}`),``,`POR COLABORADORA:`,...Object.entries(byVendor).map(([v,tot])=>`  ${v}: ${getCurrency()} ${tot.toFixed(2)}`),``,`TOP SERVICIOS:`,...topSvc.map(([s,n])=>`  ${s}: ${n} atenciones`),``,`TICKETS:`,...att.map(a=>`  ${a.time||"—"} | ${getPatientName(a)} | ${a.service||"—"} | ${getCurrency()} ${parseFloat(a.price||0).toFixed(2)} | ${a.payMethod||"—"}`)];
    const blob=new Blob([lines.join("\n")],{type:"text/plain;charset=utf-8"});
    const url=URL.createObjectURL(blob);const a=document.createElement("a");a.href=url;a.download=`corte_${date}.txt`;a.click();URL.revokeObjectURL(url);
  };

  const savePartialCut=async()=>{
    const cuts=db.get(SK.partialCuts)||[];
    const newCut={id:genId(cuts),date,time:new Date().toLocaleTimeString("es-PE"),total,byMethod:{...byMethod},byVendor:{...byVendor},note:partialNote,createdBy:""};
    try{
      await saveCrudAndSync('cashbox_cuts',newCut,SK.partialCuts,null,newCut.id);
      setPartialModal(false);setPartialNote("");
      alert(`✅ Corte parcial guardado en la base de datos — ${fmt(date)} a las ${newCut.time}\nTotal al momento: ${getCurrency()} ${total.toFixed(2)}`);
    }catch(e){alert("No se guardó el corte parcial en la base de datos: "+e.message);}
  };

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Corte del Día</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Reportes diarios de operaciones, totales por forma de pago y colaboradora.</div>
        </div>
        <div style={{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"}}>
          <Inp type="date" value={date} onChange={e=>setAllowedDate(e.target.value)} style={{width:"auto"}}/>
          <Btn variant="ghost" onClick={()=>setPartialModal(true)}><Icon name="scissors" size={13}/>Corte Parcial</Btn>
          <Btn variant="secondary" onClick={exportCorte}><Icon name="file" size={13}/>Exportar TXT</Btn>
          <Btn variant="ghost" onClick={exportWABusinessCSV} style={{background:"#25D36618",color:"#1a8040",border:"1.5px solid #25D36644"}}><span style={{fontSize:13}}>📋</span> CSV WhatsApp</Btn>
        </div>
      </div>
      <style>{`@media(max-width:1100px){.corte-layout{grid-template-columns:1fr!important}.corte-detail{position:static!important;max-height:none!important}}`}</style>
      <div className="corte-layout" style={{display:"grid",gridTemplateColumns:"minmax(0,1fr) 350px",gap:16,alignItems:"start"}}>
        <div>
          <div style={{background:"linear-gradient(135deg,#0f3a2a,#1a4a5a)",borderRadius:16,padding:"24px 28px",marginBottom:20,color:"#fff"}}>
            <div style={{fontSize:12,color:"rgba(255,255,255,0.5)",textTransform:"uppercase",letterSpacing:"0.1em",marginBottom:8}}>Total del Día — {fmt(date)}</div>
            <div style={{fontSize:42,fontWeight:800,letterSpacing:"-0.02em",color:"#5dd4c6"}}>S/ {total.toFixed(2)}</div>
            <div style={{fontSize:13,color:"rgba(255,255,255,0.55)",marginTop:6}}>{corteLoading?"Actualizando corte...":`${att.length} atenciones cobradas`}</div>
          </div>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(240px,1fr))",gap:16,marginBottom:16}}>
            <Card>
              <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>💳 Por Forma de Pago</div>
              {Object.keys(byMethod).length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos para esta fecha</div>:
                Object.entries(byMethod).sort((a,b)=>b[1]-a[1]).map(([m,v])=>{
                  const pct=total>0?Math.round((v/total)*100):0;
                  return(<div key={m} style={{marginBottom:12}}>
                    <div style={{display:"flex",justifyContent:"space-between",fontSize:12.5,marginBottom:4}}><span style={{fontWeight:600,color:"#1a2332"}}>{m}</span><span style={{fontWeight:700,color:"#059669"}}>{currency(v)}</span></div>
                    <div style={{background:"#eef2f7",borderRadius:4,height:8}}><div className="bar-fill" style={{width:`${pct}%`,height:"100%",background:"linear-gradient(90deg,#4a9d8f,#5dd4c6)",borderRadius:4}}/></div>
                    <div style={{fontSize:10,color:"#8a9aaa",marginTop:2}}>{pct}%</div>
                  </div>);
                })
              }
            </Card>
            <Card>
              <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>👩‍⚕️ Por Colaboradora</div>
              {Object.keys(byVendor).length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>:
                Object.entries(byVendor).sort((a,b)=>b[1]-a[1]).map(([v,tot])=>(
                  <div key={v} style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"9px 0",borderBottom:"1px solid #f0f4f8"}}>
                    <span style={{fontSize:13,fontWeight:600,color:"#1a2332"}}>{v}</span>
                    <span style={{fontSize:14,fontWeight:700,color:"#059669"}}>{currency(tot)}</span>
                  </div>
                ))
              }
            </Card>
          </div>
          <Card>
            <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>🏆 Servicios más Vendidos del Día</div>
            {topSvc.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>:
              topSvc.map(([s,n],i)=>(
                <div key={s} style={{display:"flex",alignItems:"center",gap:12,padding:"8px 0",borderBottom:"1px solid #f0f4f8"}}>
                  <div style={{width:28,height:28,borderRadius:"50%",background:`hsl(${i*60+150},55%,55%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,color:"#fff",flexShrink:0}}>{i+1}</div>
                  <span style={{flex:1,fontSize:13,fontWeight:600,color:"#1a2332"}}>{s}</span>
                  <Badge color="teal">{n} atención{n!==1?"es":""}</Badge>
                </div>
              ))
            }
          </Card>
        </div>
        <Card className="corte-detail" style={{position:"sticky",top:18,maxHeight:"calc(100vh - 150px)",overflowY:"auto"}}>
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",gap:8,marginBottom:12}}>
            <div style={{fontWeight:800,fontSize:14,color:"#1a2332"}}>📋 Detalle de Atenciones</div>
            <Badge color="teal">{corteLoading?"...":att.length}</Badge>
          </div>
          {att.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"28px 8px"}}>Sin atenciones cobradas para esta fecha</div>:
            att.map(a=>{
              const patientName=getPatientName(a);
              const needsLink=needsPatientLink(a);
              return(
                <div key={a.id} style={{padding:"11px 0",borderTop:"1px solid #edf2f5"}}>
                  <div style={{display:"flex",justifyContent:"space-between",gap:10,alignItems:"flex-start"}}>
                    <div style={{minWidth:0}}>
                      <button
                        onClick={()=>needsLink&&onLinkPatient&&onLinkPatient(a)}
                        title={needsLink?"Clic para registrar o vincular paciente":"Paciente vinculado"}
                        style={{fontSize:12.5,fontWeight:700,color:needsLink?"#8a4b08":"#1a2332",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",display:"block",maxWidth:"100%",background:needsLink?"#fff7ed":"transparent",border:needsLink?"1px solid #f59e0b55":"none",borderRadius:6,padding:needsLink?"3px 6px":0,cursor:needsLink?"pointer":"default",textAlign:"left"}}
                      >{patientName}</button>
                      <div style={{fontSize:11,color:"#5a7a8a",marginTop:2}}>{a.time||"—"} · {a.service||"Sin servicio"}</div>
                    </div>
                    <div style={{fontSize:13,fontWeight:800,color:"#059669",whiteSpace:"nowrap"}}>{currency(a.price)}</div>
                  </div>
                  <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",gap:8,marginTop:7}}>
                    <Badge color="teal">{a.payMethod||"Sin método"}</Badge>
                    <span style={{fontSize:10.5,color:"#4a9d8f",fontWeight:600,textAlign:"right"}}>{a.attendedBy||"Sin responsable"}</span>
                  </div>
                </div>
              );
            })
          }
        </Card>
      </div>
       {partialModal&&(
        <Modal title="Corte Parcial de Caja" onClose={()=>setPartialModal(false)} width={420}>
          <div style={{background:"#f0f9f7",borderRadius:10,padding:"14px 18px",marginBottom:16}}>
            <div style={{fontSize:12,color:"#5a7a8a",marginBottom:4}}>Monto acumulado al {fmt(date)}:</div>
            <div style={{fontSize:28,fontWeight:800,color:"#059669"}}>S/ {total.toFixed(2)}</div>
            <div style={{fontSize:12.5,color:"#5a7a8a",marginTop:6}}>{att.length} atenciones cobradas</div>
            {todayPartials.length>0&&<div style={{fontSize:11,color:"#f59223",marginTop:4}}>Cortes parciales previos hoy: {todayPartials.length}</div>}
          </div>
          <div style={{marginBottom:14}}>
            {Object.entries(byMethod).map(([m,v])=>(
              <div key={m} style={{display:"flex",justifyContent:"space-between",fontSize:13,padding:"5px 0",borderBottom:"1px solid #f0f4f8"}}>
                <span style={{fontWeight:600}}>{m}</span><span style={{fontWeight:700,color:"#059669"}}>S/ {v.toFixed(2)}</span>
              </div>
            ))}
          </div>
          <Field label="Nota del corte parcial"><Inp value={partialNote} onChange={e=>setPartialNote(e.target.value)} placeholder="Motivo o turno del corte..."/></Field>
          <div style={{fontSize:11,color:"#8a9aaa",marginBottom:12}}>⚠️ El corte parcial NO cierra el día. Solo registra el estado actual.</div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end"}}>
            <Btn variant="secondary" onClick={()=>setPartialModal(false)}>Cancelar</Btn>
            <Btn onClick={savePartialCut}><Icon name="scissors" size={13}/>Guardar Corte Parcial</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
};
// ─── MÓDULO RECORDATORIOS ─────────────────────────────────────────────────────
const RemindersModule=({patients})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const appointments=useStore(SK.appointments,[]);
  const setAppointments=(rows)=>db.set(SK.appointments,Array.isArray(rows)?rows:[]);
  const[filterDate,setFilterDate]=useState(todayStr());
  const today=todayStr();
  const[showContactsPanel,setShowContactsPanel]=useState(false);
  const[broadcastMsg,setBroadcastMsg]=useState("");
  const[selectedContacts,setSelectedContacts]=useState([]);
  const[showGroupWAModal,setShowGroupWAModal]=useState(false);
  const[broadcastSent,setBroadcastSent]=useState([]);
  const[sent,setSent]=useState({});

  // ── CUMPLEAÑOS ──
  const[showBirthdayPanel,setShowBirthdayPanel]=useState(true);
  const[selectedBirthday,setSelectedBirthday]=useState([]);
  const[bdaySent,setBdaySent]=useState([]);
  const[waStatus,setWaStatus]=useState("unknown"); // unknown|checking|active|inactive
  const[bdayMsg,setBdayMsg]=useState("🎂 ¡Feliz Cumpleaños {nombre}! De parte de todo el equipo de Podología te deseamos un maravilloso día. ¡Que lo disfrutes mucho! 🦶✨");
  const waWindowRef=React.useRef(null);

  const now=new Date();
  const currentMonth=now.getMonth();
  const currentYear=now.getFullYear();
  const monthNames=["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"];

  const birthdayPatients=safePatients.filter(p=>{
    if(!p.dob)return false;
    const d=new Date(p.dob+"T00:00:00");
    return d.getMonth()===currentMonth;
  }).sort((a,b)=>{
    const da=new Date(a.dob+"T00:00:00").getDate();
    const db2=new Date(b.dob+"T00:00:00").getDate();
    return da-db2;
  });

  const todayBdays=birthdayPatients.filter(p=>new Date(p.dob+"T00:00:00").getDate()===now.getDate());

  const toggleBday=(id)=>setSelectedBirthday(prev=>prev.includes(id)?prev.filter(x=>x!==id):[...prev,id]);
  const selectAllBday=()=>setSelectedBirthday(birthdayPatients.filter(p=>p.phone&&String(p.phone||'').trim()).map(p=>p.id));
  const clearBday=()=>setSelectedBirthday([]);

  const checkWaWeb=()=>{
    setWaStatus("checking");
    waWindowRef.current=window.open("https://web.whatsapp.com","_waWeb");
    setTimeout(()=>{
      if(waWindowRef.current&&!waWindowRef.current.closed){
        setWaStatus("active");
      } else {
        setWaStatus("inactive");
      }
    },3500);
  };

  const sendBirthdayWA=(p)=>{
    const phone=(p.phone||"").replace(/\D/g,"");
    if(!phone){alert("El paciente no tiene teléfono registrado");return;}
    const msg=bdayMsg.replace(/\{nombre\}/g,p.firstName||p.first_name||'').replace(/\{apellido\}/g,p.lastName||p.last_name||'');
    window.open(`https://wa.me/51${phone}?text=${encodeURIComponent(msg)}`,"_blank");
    setBdaySent(prev=>[...prev,p.id]);
  };

  const sendBirthdayBroadcast=()=>{
    if(!bdayMsg.trim()){alert("Escriba el mensaje de cumpleaños");return;}
    const sel=birthdayPatients.filter(p=>selectedBirthday.includes(p.id)&&p.phone&&String(p.phone||'').trim());
    if(!sel.length){alert("Seleccione al menos un paciente con teléfono");return;}
    alert(`Se abrirán ${sel.length} conversaciones de WhatsApp en ${(sel.length*1.5).toFixed(0)} segundos.\nAsegúrese de tener WhatsApp Web abierto.`);
    const newSent=[];
    sel.forEach((p,i)=>{
      const phone=(p.phone||"").replace(/\D/g,"");
      if(!phone)return;
      const msg=bdayMsg.replace(/\{nombre\}/g,p.firstName||p.first_name||'').replace(/\{apellido\}/g,p.lastName||p.last_name||'');
      setTimeout(()=>{window.open(`https://wa.me/51${phone}?text=${encodeURIComponent(msg)}`,"_blank");},i*1500);
      newSent.push(p.id);
    });
    setBdaySent(prev=>[...prev,...newSent]);
  };

  const sendGroupWABirthday=()=>{
    const monthName=monthNames[currentMonth].charAt(0).toUpperCase()+monthNames[currentMonth].slice(1);
    const company=db.get(SK.company)||{name:"Podología Más Bela"};
    const names=birthdayPatients.map(p=>`• ${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''} (día ${new Date(p.dob+"T00:00:00").getDate()})`).join("\n");
    const groupMsg=`🎂 *Cumpleañeros de ${monthName} — ${company.name}* 🎂\n\n${names||"Sin cumpleaños este mes"}\n\n🦶 ¡Felicitamos a todos nuestros pacientes que cumplen años este mes! 🎉\n\n_${company.name}_`;
    window.open("https://web.whatsapp.com","_waGroupBday");
    setShowGroupWAModal(true);
    window._groupBdayMsg=groupMsg;
  };

  const exportBirthdayWACSV=()=>{
    const rows=[["Nombre completo","Número de teléfono"]];
    birthdayPatients.forEach(p=>{
      const phone=(p.phone||"").replace(/\D/g,"");
      if(phone)rows.push([`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`,"51"+phone]);
    });
    const csv=rows.map(r=>r.map(c=>`"${String(c).replace(/"/g,'""')}"`).join(",")).join("\n");
    const blob=new Blob([csv],{type:"text/csv;charset=utf-8"});
    const url=URL.createObjectURL(blob);
    const a=document.createElement("a");a.href=url;
    const monthName=monthNames[currentMonth].charAt(0).toUpperCase()+monthNames[currentMonth].slice(1);
    a.download=`wa_business_cumpleanos_${monthName}.csv`;a.click();URL.revokeObjectURL(url);
  };

  // ── CITAS ──
  const dateAppts=appointments.filter(a=>(a.status==="pending"||a.status==="confirmed")&&a.date===filterDate);
  const patientsWithPhone=safePatients.filter(p=>p.phone&&String(p.phone||'').trim()&&p.status==="active");
  const toggleContact=(id)=>setSelectedContacts(prev=>prev.includes(id)?prev.filter(x=>x!==id):[...prev,id]);
  const selectAllContacts=()=>setSelectedContacts(patientsWithPhone.map(p=>p.id));
  const clearContacts=()=>setSelectedContacts([]);

  const exportContactsWACSV=()=>{
    const rows=[["Nombre completo","Número de teléfono"]];
    patientsWithPhone.forEach(p=>{
      const phone=(p.phone||"").replace(/\D/g,"");
      if(phone)rows.push([`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`,"51"+phone]);
    });
    const csv=rows.map(r=>r.map(c=>`"${String(c).replace(/"/g,'""')}"`).join(",")).join("\n");
    const blob=new Blob([csv],{type:"text/csv;charset=utf-8"});
    const url=URL.createObjectURL(blob);
    const a=document.createElement("a");a.href=url;a.download=`wa_business_contactos_${todayStr()}.csv`;a.click();URL.revokeObjectURL(url);
  };

  const sendBroadcast=()=>{
    if(!broadcastMsg.trim()){alert("Escriba el mensaje a enviar");return;}
    if(!selectedContacts.length){alert("Seleccione al menos un contacto");return;}
    const sel=patientsWithPhone.filter(p=>selectedContacts.includes(p.id));
    const newSent=[];
    sel.forEach((p,i)=>{
      const phone=(p.phone||"").replace(/\D/g,"");
      if(!phone)return;
      const msg=broadcastMsg.replace("{nombre}",p.firstName||p.first_name||'').replace("{apellido}",p.lastName||p.last_name||'').replace("{dni}",p.dni||"");
      setTimeout(()=>{window.open(`https://wa.me/51${phone}?text=${encodeURIComponent(msg)}`,"_blank");},i*1500);
      newSent.push(p.id);
    });
    setBroadcastSent(newSent);
    alert(`Se abrirán ${sel.length} conversaciones de WhatsApp en ${sel.length*1.5} segundos. Asegúrese de tener WhatsApp Web abierto.`);
  };

  const openWhatsAppBroadcast=()=>window.open("https://web.whatsapp.com","_blank");

  const sendWA=(a,action)=>{
    const p=patients.find(x=>x.id===parseInt(a.patientId));
    const name=p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"Paciente";
    const phone=(p?.phone||"").replace(/\D/g,"");
    const msgs={
      confirm:`✅ ¡Hola ${name}! Tu cita del ${fmt(a.date)} a las ${a.time} está CONFIRMADA. Te esperamos en Podología. 🦶`,
      reschedule:`📅 Hola ${name}, necesitamos REAGENDAR tu cita del ${fmt(a.date)} a las ${a.time}. Por favor contáctanos para coordinar. — Podología`,
      cancel:`❌ Hola ${name}, lamentamos informarte que tu cita del ${fmt(a.date)} a las ${a.time} ha sido CANCELADA. Contáctanos para reagendar. — Podología`,
      remind:`🔔 Recordatorio: ${name}, tienes una cita MAÑANA ${fmt(a.date)} a las ${a.time}. Te esperamos. — Podología`,
    };
    if(!phone){alert("El paciente no tiene teléfono registrado");return;}
    window.open(`https://wa.me/51${phone}?text=${encodeURIComponent(msgs[action]||msgs.remind)}`,"_blank");
    setSent(s=>({...s,[`${a.id}_${action}`]:true}));
  };

  const confirmAppt=async(id)=>{
    try{
      const saved=await crudApi.update('appointments',id,{status:"confirmed"});
      const all=appointments.map(a=>a.id===id?{...a,...saved,status:"confirmed"}:a);
      setAppointments(all);db.set(SK.appointments,all);
      setSent(s=>({...s,[`${id}_sys_confirm`]:true}));
    }catch(e){alert("No se guardó la confirmación en la base de datos: "+e.message);}
  };
  const cancelAppt=async(id)=>{
    if(!window.confirm("¿Cancelar esta cita?"))return;
    try{
      const saved=await crudApi.update('appointments',id,{status:"cancelled"});
      const all=appointments.map(a=>a.id===id?{...a,...saved,status:"cancelled"}:a);
      setAppointments(all);db.set(SK.appointments,all);
    }catch(e){alert("No se guardó la cancelación en la base de datos: "+e.message);}
  };

  const totalToday=appointments.filter(a=>a.date===filterDate).length;
  const confirmed=appointments.filter(a=>a.date===filterDate&&a.status==="confirmed").length;
  const pending=appointments.filter(a=>a.date===filterDate&&a.status==="pending").length;
  const cancelled=appointments.filter(a=>a.date===filterDate&&a.status==="cancelled").length;

  const waStatusInfo={
    unknown:{color:"#8a9aaa",bg:"#f0f4f8",icon:"⚪",label:"Sin verificar"},
    checking:{color:"#f59e0b",bg:"#fef3c7",icon:"⏳",label:"Verificando..."},
    active:{color:"#16a34a",bg:"#dcfce7",icon:"🟢",label:"WhatsApp Web activo"},
    inactive:{color:"#dc2626",bg:"#fee2e2",icon:"🔴",label:"WhatsApp Web inactivo"},
  }[waStatus];

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Recordatorios de Citas</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Envíe recordatorios por WhatsApp · Confirme o cancele citas</div>
        </div>
        <div style={{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"}}>
          <button onClick={()=>setShowBirthdayPanel(!showBirthdayPanel)} style={{background:showBirthdayPanel?"linear-gradient(135deg,#f97316,#ea580c)":"#fff3ed",color:showBirthdayPanel?"#fff":"#c2410c",border:`2px solid ${showBirthdayPanel?"#ea580c":"#fed7aa"}`,borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12.5,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>
            🎂 Cumpleaños del Mes ({birthdayPatients.length}) {showBirthdayPanel?"▲":"▼"}
          </button>
          <button onClick={()=>setShowContactsPanel(!showContactsPanel)} style={{background:showContactsPanel?"#25D366":"#25D36618",color:showContactsPanel?"#fff":"#1a8040",border:"2px solid #25D366",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12.5,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>
            📱 Contactos WhatsApp {showContactsPanel?"▲":"▼"}
          </button>
          <button onClick={openWhatsAppBroadcast} style={{background:"#25D366",color:"#fff",border:"none",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12.5,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>
            🌐 Abrir WhatsApp Web
          </button>
          <Inp type="date" value={filterDate} onChange={e=>setFilterDate(e.target.value)} style={{width:"auto"}}/>
        </div>
      </div>

      {/* ── PANEL CUMPLEAÑOS DEL MES ────────────────────────────────────── */}
      {showBirthdayPanel&&(
        <div className="fade-in" style={{background:"#fff",border:"2px solid #fed7aa",borderRadius:14,padding:20,marginBottom:16,boxShadow:"0 4px 24px rgba(249,115,22,0.10)"}}>
          {/* Header */}
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:10}}>
            <div style={{display:"flex",alignItems:"center",gap:12}}>
              <div style={{width:42,height:42,borderRadius:12,background:"linear-gradient(135deg,#f97316,#ea580c)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:20}}>🎂</div>
              <div>
                <div style={{fontWeight:800,fontSize:15,color:"#1a2332"}}>Cumpleaños de {monthNames[currentMonth].charAt(0).toUpperCase()+monthNames[currentMonth].slice(1)}</div>
                <div style={{fontSize:11.5,color:"#8a9aaa"}}>{birthdayPatients.length} paciente{birthdayPatients.length!==1?"s":""} cumplen años este mes</div>
              </div>
            </div>
            {/* WhatsApp Web Status */}
            <div style={{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"}}>
              <div style={{display:"flex",alignItems:"center",gap:6,background:waStatusInfo.bg,border:`1.5px solid ${waStatusInfo.color}33`,borderRadius:8,padding:"5px 12px"}}>
                <span style={{fontSize:12}}>{waStatusInfo.icon}</span>
                <span style={{fontSize:11.5,fontWeight:700,color:waStatusInfo.color}}>{waStatusInfo.label}</span>
              </div>
              <button onClick={checkWaWeb} disabled={waStatus==="checking"} style={{background:waStatus==="active"?"#dcfce7":"#f0f9ff",color:waStatus==="active"?"#16a34a":"#0369a1",border:`1.5px solid ${waStatus==="active"?"#16a34a44":"#0369a144"}`,borderRadius:8,padding:"5px 12px",cursor:waStatus==="checking"?"not-allowed":"pointer",fontSize:11.5,fontWeight:700,opacity:waStatus==="checking"?0.6:1}}>
                {waStatus==="checking"?"⏳ Verificando...":"🔍 Verificar WA Web"}
              </button>
              <button onClick={sendGroupWABirthday} title="Enviar lista de cumpleañeros al grupo de WhatsApp" style={{background:"linear-gradient(135deg,#f97316,#ea580c)",color:"#fff",border:"none",borderRadius:8,padding:"5px 14px",cursor:"pointer",fontSize:11.5,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>
                👥 Enviar a Grupo WA
              </button>
              <button onClick={exportBirthdayWACSV} title="Exportar CSV para WhatsApp Business" style={{background:"#25D36618",color:"#1a8040",border:"1.5px solid #25D36644",borderRadius:8,padding:"5px 12px",cursor:"pointer",fontSize:11.5,fontWeight:700,display:"flex",alignItems:"center",gap:5}}>
                📋 CSV WA Business
              </button>
            </div>
          </div>

          {/* Today's birthdays highlight */}
          {todayBdays.length>0&&(
            <div style={{background:"linear-gradient(135deg,#f97316,#ea580c)",borderRadius:10,padding:"10px 16px",marginBottom:12,display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"}}>
              <span style={{fontSize:22}}>🎉</span>
              <div>
                <div style={{fontWeight:800,fontSize:13,color:"#fff"}}>¡Hoy cumplen años!</div>
                <div style={{fontSize:12,color:"rgba(255,255,255,0.85)"}}>
                  {todayBdays.map(p=>`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`).join(", ")}
                </div>
              </div>
            </div>
          )}

          {/* Controls for bulk selection */}
          {birthdayPatients.length>2&&(
            <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:10,flexWrap:"wrap"}}>
              <button onClick={selectAllBday} style={{background:"#fff3ed",color:"#c2410c",border:"1.5px solid #fed7aa",borderRadius:7,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700}}>
                ☑ Seleccionar todos ({birthdayPatients.filter(p=>p.phone&&String(p.phone||'').trim()).length} con teléfono)
              </button>
              <button onClick={clearBday} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1.5px solid #d4dde5",borderRadius:7,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700}}>
                ☐ Ninguno
              </button>
              {selectedBirthday.length>0&&(
                <span style={{fontSize:12,color:"#ea580c",fontWeight:700}}>{selectedBirthday.length} seleccionado{selectedBirthday.length!==1?"s":""}</span>
              )}
            </div>
          )}

          {/* Birthday patient list */}
          {birthdayPatients.length===0?(
            <div style={{textAlign:"center",padding:"20px 0",color:"#8a9aaa",fontSize:13}}>
              Sin cumpleaños este mes 🎂
            </div>
          ):(
            <div style={{maxHeight:260,overflowY:"auto",border:"1px solid #fed7aa55",borderRadius:10,marginBottom:14}}>
              {birthdayPatients.map(p=>{
                const d=new Date(p.dob+"T00:00:00");
                const dayNum=d.getDate();
                const isToday=dayNum===now.getDate();
                const isPast=dayNum<now.getDate();
                const hasPhone=!!(p.phone&&String(p.phone||'').trim());
                const isSelected=selectedBirthday.includes(p.id);
                const wasSent=bdaySent.includes(p.id);
                return(
                  <div key={p.id} style={{display:"flex",alignItems:"center",gap:10,padding:"9px 14px",borderBottom:"1px solid #fff3ed",background:isToday?"#fff7ed":isSelected?"#fef9f0":"#fff",cursor:hasPhone?"pointer":"default"}} onClick={()=>hasPhone&&toggleBday(p.id)}>
                    {/* Checkbox */}
                    <div style={{width:20,height:20,borderRadius:4,border:`2px solid ${isSelected?"#ea580c":"#d4dde5"}`,background:isSelected?"#ea580c":"#fff",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0,opacity:hasPhone?1:0.3}}>
                      {isSelected&&<span style={{color:"#fff",fontSize:13}}>✓</span>}
                    </div>
                    {/* Day badge */}
                    <div style={{width:36,height:36,borderRadius:9,background:isToday?"linear-gradient(135deg,#f97316,#ea580c)":isPast?"#f0f4f8":"linear-gradient(135deg,#fbbf24,#f59e0b)",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
                      <span style={{fontSize:14,fontWeight:800,color:isToday?"#fff":isPast?"#8a9aaa":"#78350f"}}>{dayNum}</span>
                    </div>
                    {/* Patient info */}
                    <div style={{flex:1,minWidth:0}}>
                      <div style={{fontWeight:700,fontSize:13,color:"#1a2332",display:"flex",alignItems:"center",gap:6}}>
                        {p.firstName||p.first_name||''} {p.lastName||p.last_name||''}
                        {isToday&&<span style={{fontSize:10,background:"#f97316",color:"#fff",borderRadius:4,padding:"1px 5px",fontWeight:700}}>HOY</span>}
                        {!hasPhone&&<span style={{fontSize:10,background:"#fee2e2",color:"#dc2626",borderRadius:4,padding:"1px 5px",fontWeight:700}}>Sin tel.</span>}
                      </div>
                      <div style={{fontSize:11,color:"#8a9aaa",marginTop:1}}>
                        {hasPhone?`📱 ${p.phone}`:"Sin teléfono"} · {currentYear-new Date(p.dob+"T00:00:00").getFullYear()} años
                      </div>
                    </div>
                    {/* Individual send button */}
                    {hasPhone&&(
                      wasSent?(
                        <span style={{fontSize:11,color:"#16a34a",fontWeight:700,flexShrink:0}}>✓ Enviado</span>
                      ):(
                        <button onClick={e=>{e.stopPropagation();sendBirthdayWA(p);}} style={{background:"#25D36618",color:"#1a8040",border:"1.5px solid #25D36644",borderRadius:7,padding:"4px 10px",cursor:"pointer",fontSize:11.5,fontWeight:700,flexShrink:0,display:"flex",alignItems:"center",gap:4}}>
                          🎂 Felicitar
                        </button>
                      )
                    )}
                  </div>
                );
              })}
            </div>
          )}

          {/* Bulk message & send */}
          {birthdayPatients.length>0&&(
            <div style={{borderTop:"1px solid #fed7aa",paddingTop:14}}>
              <div style={{fontWeight:600,fontSize:13,color:"#1a2332",marginBottom:8,display:"flex",alignItems:"center",gap:6}}>
                🎁 Mensaje de cumpleaños
                <span style={{fontSize:11,color:"#8a9aaa",fontWeight:400}}> · Usa {"{nombre}"} para personalizar</span>
              </div>
              <textarea
                value={bdayMsg}
                onChange={e=>setBdayMsg(e.target.value)}
                style={{width:"100%",border:"1.5px solid #fed7aa",borderRadius:8,padding:"10px 12px",fontSize:13,minHeight:72,resize:"vertical",outline:"none",fontFamily:"inherit",boxSizing:"border-box",background:"#fffbf5"}}
              />
              <div style={{display:"flex",gap:8,marginTop:10,justifyContent:"flex-end",flexWrap:"wrap",alignItems:"center"}}>
                {selectedBirthday.length===0&&birthdayPatients.length>0&&(
                  <span style={{fontSize:11.5,color:"#8a9aaa",flex:1}}>💡 Selecciona pacientes para envío masivo, o usa el botón individual de cada uno</span>
                )}
                {selectedBirthday.length>0&&(
                  <>
                    <button onClick={()=>{setBdayMsg("🎂 ¡Feliz Cumpleaños {nombre}! De parte de todo el equipo de Podología te deseamos un maravilloso día. ¡Que lo disfrutes mucho! 🦶✨");setBdaySent([]);}} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1.5px solid #d4dde5",borderRadius:7,padding:"6px 14px",cursor:"pointer",fontSize:12,fontWeight:600}}>
                      Restaurar
                    </button>
                    <button onClick={sendBirthdayBroadcast} style={{background:"linear-gradient(135deg,#f97316,#ea580c)",color:"#fff",border:"none",borderRadius:8,padding:"6px 18px",cursor:"pointer",fontSize:13,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>
                      🎂 Enviar a {selectedBirthday.length} seleccionado{selectedBirthday.length!==1?"s":""}
                    </button>
                  </>
                )}
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── WHATSAPP CONTACTS PANEL ──────────────────────────────────── */}
      {showContactsPanel&&(
        <div className="fade-in" style={{background:"#fff",border:"1.5px solid #25D36633",borderRadius:12,padding:18,marginBottom:16,boxShadow:"0 4px 20px rgba(37,211,102,0.1)"}}>
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:8}}>
            <div style={{display:"flex",alignItems:"center",gap:10}}>
              <div style={{width:38,height:38,borderRadius:10,background:"linear-gradient(135deg,#25D366,#1aa84a)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18}}>📱</div>
              <div>
                <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>Lista de Contactos — Pacientes Activos</div>
                <div style={{fontSize:11.5,color:"#8a9aaa"}}>{patientsWithPhone.length} pacientes con teléfono registrado</div>
              </div>
            </div>
            <div style={{display:"flex",gap:6}}>
              <button onClick={selectAllContacts} style={{background:"#25D36618",color:"#1a8040",border:"1.5px solid #25D36644",borderRadius:7,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700}}>
                ☑ Todos
              </button>
              <button onClick={clearContacts} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1.5px solid #d4dde5",borderRadius:7,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700}}>
                ☐ Ninguno
              </button>
              <button onClick={exportContactsWACSV} title="Exportar lista de contactos para WhatsApp Business" style={{background:"#25D36618",color:"#1a8040",border:"1.5px solid #25D36644",borderRadius:7,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700,display:"flex",alignItems:"center",gap:4}}>
                📋 CSV WA
              </button>
            </div>
          </div>
          <div style={{maxHeight:220,overflowY:"auto",marginBottom:14,border:"1px solid #e8edf2",borderRadius:8}}>
            {patientsWithPhone.length===0?(
              <div style={{textAlign:"center",padding:24,color:"#8a9aaa",fontSize:13}}>No hay pacientes activos con teléfono registrado</div>
            ):(
              patientsWithPhone.map(p=>{
                const phone=(p.phone||"").replace(/\D/g,"");
                const isSelected=selectedContacts.includes(p.id);
                const wasSent=broadcastSent.includes(p.id);
                return(
                  <div key={p.id} style={{display:"flex",alignItems:"center",gap:10,padding:"8px 12px",borderBottom:"1px solid #f0f4f8",background:isSelected?"#f0fff8":"#fff",cursor:"pointer"}} onClick={()=>toggleContact(p.id)}>
                    <div style={{width:20,height:20,borderRadius:4,border:`2px solid ${isSelected?"#25D366":"#d4dde5"}`,background:isSelected?"#25D366":"#fff",display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0}}>
                      {isSelected&&<span style={{color:"#fff",fontSize:13}}>✓</span>}
                    </div>
                    <div style={{width:34,height:34,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontWeight:700,fontSize:14,flexShrink:0}}>
                      {p.firstName||p.first_name||''[0]||"?"}
                    </div>
                    <div style={{flex:1,minWidth:0}}>
                      <div style={{fontWeight:600,fontSize:13,color:"#1a2332",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}}>{p.firstName||p.first_name||''} {p.lastName||p.last_name||''}</div>
                      <div style={{fontSize:11.5,color:"#8a9aaa"}}>{p.phone} {p.dni?`· DNI: ${p.dni}`:""}</div>
                    </div>
                    {wasSent&&<span style={{fontSize:11,color:"#25D366",fontWeight:700,flexShrink:0}}>✓ Enviado</span>}
                    <button onClick={e=>{e.stopPropagation();const phone2=(p.phone||"").replace(/\D/g,"");window.open(`https://wa.me/51${phone2}`,"_blank");}} style={{background:"#25D36618",color:"#1a8040",border:"1px solid #25D36644",borderRadius:6,padding:"3px 8px",cursor:"pointer",fontSize:11,fontWeight:700,flexShrink:0}}>
                      Abrir
                    </button>
                  </div>
                );
              })
            )}
          </div>
          {selectedContacts.length>0&&(
            <div style={{borderTop:"1px solid #e8edf2",paddingTop:14}}>
              <div style={{fontWeight:600,fontSize:13,color:"#1a2332",marginBottom:8}}>
                📢 Mensaje para {selectedContacts.length} contacto(s) seleccionado(s)
                <span style={{fontSize:11,color:"#8a9aaa",fontWeight:400,marginLeft:8}}>Usa {"{nombre}"} para personalizar</span>
              </div>
              <textarea
                value={broadcastMsg}
                onChange={e=>setBroadcastMsg(e.target.value)}
                placeholder={"Hola {nombre}, le recordamos que tiene una cita próximamente en Podología Más Bela. Para confirmar o reagendar contáctenos. 🦶"}
                style={{width:"100%",border:"1.5px solid #d4dde5",borderRadius:8,padding:"10px 12px",fontSize:13,minHeight:80,resize:"vertical",outline:"none",fontFamily:"inherit",boxSizing:"border-box"}}
              />
              <div style={{display:"flex",gap:8,marginTop:10,justifyContent:"flex-end",flexWrap:"wrap"}}>
                <button onClick={()=>{setBroadcastMsg("");setBroadcastSent([]);}} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1.5px solid #d4dde5",borderRadius:7,padding:"6px 14px",cursor:"pointer",fontSize:12.5,fontWeight:600}}>
                  Limpiar
                </button>
                <button onClick={sendBroadcast} style={{background:"linear-gradient(135deg,#25D366,#1aa84a)",color:"#fff",border:"none",borderRadius:8,padding:"6px 18px",cursor:"pointer",fontSize:13,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>
                  📤 Enviar por WhatsApp ({selectedContacts.length})
                </button>
              </div>
            </div>
          )}
        </div>
      )}

      <div style={{background:"linear-gradient(135deg,#25D366,#1aa84a)",borderRadius:12,padding:"12px 20px",marginBottom:14,display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:10}}>
        <div style={{display:"flex",alignItems:"center",gap:12}}>
          <div style={{fontSize:26}}>📱</div>
          <div>
            <div style={{fontWeight:700,fontSize:14,color:"#fff"}}>WhatsApp Business Integration</div>
            <div style={{fontSize:11.5,color:"rgba(255,255,255,0.8)"}}>Los botones abren WhatsApp con mensaje pre-llenado. Los botones de sistema confirman/cancelan en el sistema.</div>
          </div>
        </div>
        <div style={{display:"flex",gap:8,flexWrap:"wrap"}}>
          {[["Total",totalToday,"#fff"],["Confirmadas",confirmed,"#a7f3c0"],["Pendientes",pending,"#fde68a"],["Canceladas",cancelled,"#fca5a5"]].map(([l,v,c])=>(
            <div key={l} style={{background:"rgba(0,0,0,0.15)",borderRadius:8,padding:"6px 12px",textAlign:"center"}}>
              <div style={{fontSize:16,fontWeight:800,color:c}}>{v}</div>
              <div style={{fontSize:10,color:"rgba(255,255,255,0.8)",textTransform:"uppercase"}}>{l}</div>
            </div>
          ))}
        </div>
      </div>

      {dateAppts.length===0?(
        <Card style={{textAlign:"center",padding:48}}>
          <div style={{fontSize:40,marginBottom:10}}>📅</div>
          <div style={{fontSize:15,fontWeight:700,color:"#3a5a6a",marginBottom:6}}>
            {filterDate===today?`Sin citas pendientes hoy`:`Sin citas pendientes el ${fmt(filterDate)}`}
          </div>
          <div style={{fontSize:13,color:"#8a9aaa"}}>
            {filterDate===today?"No hay citas para recordar en este momento":"Cambie la fecha para ver otras citas"}
          </div>
        </Card>
      ):(
        <div style={{display:"flex",flexDirection:"column",gap:10}}>
          {dateAppts.map(a=>{
            const p=patients.find(x=>x.id===parseInt(a.patientId));
            const isConfirmed=a.status==="confirmed"||sent[`${a.id}_sys_confirm`];
            return(
              <Card key={a.id}>
                <div style={{display:"flex",alignItems:"flex-start",gap:14,flexWrap:"wrap"}}>
                  <div style={{background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",borderRadius:9,padding:"8px 16px",fontSize:16,fontWeight:800,flexShrink:0,minWidth:70,textAlign:"center"}}>
                    {a.time||"—"}
                  </div>
                  <div style={{flex:1,minWidth:160}}>
                    <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A"}</div>
                    <div style={{fontSize:12,color:"#8a9aaa",marginTop:2}}>{a.service||"Sin servicio"} · {p?.phone||"Sin teléfono"}</div>
                    {a.podologa&&<div style={{fontSize:11,color:"#4a9d8f",marginTop:1}}>👩‍⚕️ {a.podologa}</div>}
                  </div>
                  <div style={{display:"flex",gap:5,flexWrap:"wrap",alignItems:"center"}}>
                    <Badge color={isConfirmed?"green":"orange"}>{isConfirmed?"Confirmada":"Pendiente"}</Badge>
                  </div>
                </div>
                <div style={{display:"flex",gap:6,flexWrap:"wrap",marginTop:12,paddingTop:10,borderTop:"1px solid #f0f4f8"}}>
                  <div style={{fontSize:10.5,color:"#8a9aaa",fontWeight:700,textTransform:"uppercase",display:"flex",alignItems:"center",marginRight:4}}>📱 WhatsApp:</div>
                  <button onClick={()=>sendWA(a,"confirm")} style={{background:sent[`${a.id}_confirm`]?"#2ea87e18":"#25D36618",color:sent[`${a.id}_confirm`]?"#2ea87e":"#1a8040",border:`1.5px solid ${sent[`${a.id}_confirm`]?"#2ea87e":"#25D366"}`,borderRadius:8,padding:"5px 11px",cursor:"pointer",fontSize:11.5,fontWeight:700}}>
                    {sent[`${a.id}_confirm`]?"✓ Recordatorio Enviado":"💬 Recordatorio"}
                  </button>
                  <button onClick={()=>sendWA(a,"remind")} style={{background:"#2563eb10",color:"#2563eb",border:"1.5px solid #2563eb44",borderRadius:8,padding:"5px 11px",cursor:"pointer",fontSize:11.5,fontWeight:700}}>
                    🔔 Aviso Previo
                  </button>
                  <button onClick={()=>sendWA(a,"reschedule")} style={{background:"#f5922310",color:"#c06010",border:"1.5px solid #f5922344",borderRadius:8,padding:"5px 11px",cursor:"pointer",fontSize:11.5,fontWeight:700}}>
                    ↻ Reagendar
                  </button>
                  <div style={{width:1,background:"#e8edf2",margin:"0 4px"}}/>
                  <div style={{fontSize:10.5,color:"#8a9aaa",fontWeight:700,textTransform:"uppercase",display:"flex",alignItems:"center",marginRight:4}}>⚙️ Sistema:</div>
                  {!isConfirmed&&(
                    <button onClick={()=>confirmAppt(a.id)} style={{background:"#2ea87e18",color:"#2ea87e",border:"1.5px solid #2ea87e44",borderRadius:8,padding:"5px 11px",cursor:"pointer",fontSize:11.5,fontWeight:700}}>
                      ✅ Confirmar
                    </button>
                  )}
                  <button onClick={()=>cancelAppt(a.id)} style={{background:"#e0505010",color:"#c03030",border:"1.5px solid #e0505044",borderRadius:8,padding:"5px 11px",cursor:"pointer",fontSize:11.5,fontWeight:700}}>
                    ✕ Cancelar
                  </button>
                </div>
              </Card>
            );
          })}
        </div>
      )}
      {showGroupWAModal&&(
        <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",zIndex:2000,display:"flex",alignItems:"center",justifyContent:"center",padding:20}} onClick={e=>e.target===e.currentTarget&&setShowGroupWAModal(false)}>
          <div style={{background:"#fff",borderRadius:16,width:"100%",maxWidth:480,boxShadow:"0 20px 60px rgba(0,0,0,0.3)"}}>
            <div style={{background:"linear-gradient(135deg,#f97316,#ea580c)",borderRadius:"16px 16px 0 0",padding:"16px 22px",display:"flex",alignItems:"center",justifyContent:"space-between"}}>
              <div style={{display:"flex",alignItems:"center",gap:10}}>
                <span style={{fontSize:22}}>🎂</span>
                <div>
                  <div style={{fontWeight:800,fontSize:15,color:"#fff"}}>Enviar a Grupo WhatsApp</div>
                  <div style={{fontSize:11,color:"rgba(255,255,255,0.7)"}}>Cumpleañeros del Mes - Podología Más BELA</div>
                </div>
              </div>
              <button onClick={()=>setShowGroupWAModal(false)} style={{background:"rgba(255,255,255,0.2)",border:"none",borderRadius:7,width:30,height:30,cursor:"pointer",color:"#fff",fontSize:16,fontWeight:700}}>✕</button>
            </div>
            <div style={{padding:"20px 22px"}}>
              <div style={{background:"#fff7ed",border:"1px solid #fed7aa",borderRadius:10,padding:"12px 14px",marginBottom:16,fontSize:13,color:"#7c2d12"}}>
                <b>Instrucciones:</b><br/>
                1. WhatsApp Web se abrió en otra pestaña.<br/>
                2. Abre el grupo <b>"Cumpleañeros del Mes - Podología Más BELA"</b> (o el nombre de tu grupo).<br/>
                3. Copia el mensaje de abajo y pégalo en el grupo.
              </div>
              <div style={{fontSize:12,fontWeight:700,color:"#5a7a8a",marginBottom:6,textTransform:"uppercase"}}>Mensaje a copiar:</div>
              <div style={{background:"#f8fafc",border:"1.5px solid #e8edf2",borderRadius:8,padding:"12px 14px",fontSize:13,color:"#1a2332",lineHeight:1.7,whiteSpace:"pre-wrap",maxHeight:200,overflowY:"auto"}}>{window._groupBdayMsg||""}</div>
              <div style={{display:"flex",gap:8,marginTop:14,justifyContent:"flex-end"}}>
                <button onClick={()=>setShowGroupWAModal(false)} style={{background:"#f0f4f8",color:"#5a7a8a",border:"1.5px solid #d4dde5",borderRadius:8,padding:"7px 18px",cursor:"pointer",fontSize:13,fontWeight:600}}>Cerrar</button>
                <button onClick={()=>{navigator.clipboard&&navigator.clipboard.writeText(window._groupBdayMsg||"").then(()=>alert("✅ Mensaje copiado al portapapeles. Pégalo en tu grupo de WhatsApp."));}} style={{background:"linear-gradient(135deg,#25D366,#1aa84a)",color:"#fff",border:"none",borderRadius:8,padding:"7px 18px",cursor:"pointer",fontSize:13,fontWeight:700,display:"flex",alignItems:"center",gap:6}}>📋 Copiar Mensaje</button>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

// ─── MÓDULO PORTAL DE CITAS ────────────────────────────────────────────────────
const PortalModule=({patients})=>{
  const[portalStep,setPortalStep]=useState("select");
  const[portalForm,setPortalForm]=useState({patientId:"",date:todayStr(),time:"09:00",service:"",podologa:""});
  const services=db.get(SK.services)||DEF_SERVICES;
  const users=db.get(SK.users)||DEF_USERS;
  const podologas=users.filter(u=>u.active&&u.role==="Podólogo");
  const portalAppts=useStore(SK.appointments,[]);
  const portalAtts=useStore(SK.attendances,[]);
  const[myAppts,setMyAppts]=useState([]);
  const[myAtts,setMyAtts]=useState([]);
  const[portalPatient,setPortalPatient]=useState(null);
  const[findDni,setFindDni]=useState("");
  useEffect(()=>{api.get('appointments').catch(()=>{});api.get('attendances').catch(()=>{});},[]);
  const bookAppt=async()=>{
    if(!portalForm.patientId||!portalForm.date||!portalForm.time){alert("Complete los campos");return}
    const tempId=genId(portalAppts);
    const local={...portalForm,id:tempId,status:"pending",createdBy:"Portal",created_by:"Portal",patient_id:portalForm.patientId};
    try{
      await saveCrudAndSync('appointments',local,SK.appointments,null,tempId);
      setPortalStep("success");
    }catch(e){alert("No se guardó la cita en la base de datos: "+e.message);}
  };
  const findAppts=()=>{
    const q=findDni.trim().toLowerCase();
    const p=patients.find(x=>{
      const full=`${x.firstName||x.first_name||""} ${x.lastName||x.last_name||""}`.toLowerCase();
      return String(x.dni||"").toLowerCase()===q||full.includes(q);
    });
    if(!p){alert("No se encontró paciente con ese DNI");return}
    const appts=portalAppts.filter(a=>String(a.patientId||a.patient_id||"")===String(p.id));
    const atts=portalAtts.filter(a=>String(a.patientId||a.patient_id||"")===String(p.id));
    setPortalPatient(p);setMyAtts(atts);
    setMyAppts(appts);setPortalStep("myAppts");
  };
  return(
    <div className="slide-in">
      <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em",marginBottom:6}}>Portal de Citas</h2>
      <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:18}}>El paciente agenda su cita desde su dispositivo. Selecciona fecha, hora y podóloga. Puede modificar o cancelar.</div>
      <div style={{display:"grid",gridTemplateColumns:"2fr 1fr",gap:16}}>
        <Card style={{background:"linear-gradient(160deg,#0a1f2e,#0f3a2a)",padding:0,overflow:"hidden"}}>
          <div style={{padding:"20px 24px",borderBottom:"1px solid rgba(255,255,255,0.08)"}}>
            <div style={{fontFamily:"'Lora',serif",fontSize:16,color:"#5dd4c6",fontStyle:"italic"}}>Portal de Autogestión</div>
            <div style={{fontSize:11.5,color:"rgba(255,255,255,0.45)",marginTop:2}}>Podología Más Bela</div>
          </div>
          <div style={{padding:"24px"}}>
            {portalStep==="select"&&(
              <div className="fade-in">
                <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12}}>
                  <button onClick={()=>setPortalStep("book")} style={{background:"rgba(93,212,198,0.1)",border:"1.5px solid rgba(93,212,198,0.3)",borderRadius:12,padding:"20px 16px",cursor:"pointer",color:"#5dd4c6",textAlign:"center",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="rgba(93,212,198,0.18)"} onMouseOut={e=>e.currentTarget.style.background="rgba(93,212,198,0.1)"}>
                    <div style={{fontSize:28,marginBottom:8}}>📅</div>
                    <div style={{fontWeight:700,fontSize:13}}>Agendar Cita</div>
                    <div style={{fontSize:11,opacity:.6,marginTop:4}}>Nueva cita</div>
                  </button>
                  <button onClick={()=>setPortalStep("findAppts")} style={{background:"rgba(93,212,198,0.1)",border:"1.5px solid rgba(93,212,198,0.3)",borderRadius:12,padding:"20px 16px",cursor:"pointer",color:"#5dd4c6",textAlign:"center",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="rgba(93,212,198,0.18)"} onMouseOut={e=>e.currentTarget.style.background="rgba(93,212,198,0.1)"}>
                    <div style={{fontSize:28,marginBottom:8}}>🔍</div>
                    <div style={{fontWeight:700,fontSize:13}}>Mis Citas</div>
                    <div style={{fontSize:11,opacity:.6,marginTop:4}}>Ver o cancelar</div>
                  </button>
                </div>
              </div>
            )}
            {portalStep==="book"&&(
              <div className="fade-in">
                <div style={{color:"rgba(255,255,255,0.7)",fontSize:13,marginBottom:16}}>Complete los datos para su cita:</div>
                <Field label="Paciente">
                  <Sel value={portalForm.patientId} onChange={e=>setPortalForm(p=>({...p,patientId:e.target.value}))}>
                    <option value="">Seleccionar...</option>
                    {patients.filter(p=>p.status==="active").map(p=><option key={p.id} value={p.id}>{p.firstName||p.first_name||''} {p.lastName||p.last_name||''}</option>)}
                  </Sel>
                </Field>
                <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}}>
                  <Field label="Fecha"><Inp type="date" value={portalForm.date} onChange={e=>setPortalForm(p=>({...p,date:e.target.value}))}/></Field>
                  <Field label="Hora"><Inp type="time" value={portalForm.time} onChange={e=>setPortalForm(p=>({...p,time:e.target.value}))}/></Field>
                </div>
                <Field label="Servicio">
                  <Sel value={portalForm.service} onChange={e=>setPortalForm(p=>({...p,service:e.target.value}))}>
                    <option value="">Seleccionar...</option>
                    {services.filter(s=>s.active).map(s=><option key={s.id}>{s.name} — S/ {s.price}</option>)}
                  </Sel>
                </Field>
                <Field label="Podóloga">
                  <Sel value={portalForm.podologa} onChange={e=>setPortalForm(p=>({...p,podologa:e.target.value}))}>
                    <option value="">Sin preferencia</option>
                    {podologas.map(u=><option key={u.id} value={u.name}>{u.name}</option>)}
                  </Sel>
                </Field>
                <div style={{display:"flex",gap:8,marginTop:8}}>
                  <Btn variant="secondary" size="sm" onClick={()=>setPortalStep("select")}>← Volver</Btn>
                  <Btn onClick={bookAppt}><Icon name="check" size={13}/>Confirmar Cita</Btn>
                </div>
              </div>
            )}
            {portalStep==="findAppts"&&(
              <div className="fade-in">
                <div style={{color:"rgba(255,255,255,0.7)",fontSize:13,marginBottom:16}}>Ingrese DNI, nombre o apellidos para ver citas y atenciones:</div>
                <Field label="DNI / Nombre / Apellidos">
                  <Inp value={findDni} onChange={e=>setFindDni(e.target.value)} placeholder="DNI, nombre o apellidos"/>
                </Field>
                <div style={{display:"flex",gap:8,marginTop:8}}>
                  <Btn variant="secondary" size="sm" onClick={()=>setPortalStep("select")}>← Volver</Btn>
                  <Btn onClick={findAppts}><Icon name="search" size={13}/>Buscar</Btn>
                </div>
              </div>
            )}
            {portalStep==="myAppts"&&(
              <div className="fade-in">
                <div style={{color:"rgba(255,255,255,0.7)",fontSize:13,marginBottom:12}}>Sus próximas citas:</div>
                {myAppts.length===0?<div style={{color:"rgba(255,255,255,0.4)",fontSize:13,textAlign:"center",padding:"16px 0"}}>No tiene citas registradas</div>:
                  myAppts.map(a=>(
                    <div key={a.id} style={{background:"rgba(255,255,255,0.06)",borderRadius:10,padding:"12px 14px",marginBottom:8,border:"1px solid rgba(255,255,255,0.1)"}}>
                      <div style={{fontWeight:700,color:"#5dd4c6",fontSize:13}}>{fmt(a.date)} — {a.time}</div>
                      <div style={{fontSize:12,color:"rgba(255,255,255,0.55)",marginTop:3}}>{a.service||"Sin servicio"} · {a.podologa||"Sin asignar"}</div>
                    </div>
                  ))
                }
                <Btn variant="ghost" size="sm" onClick={()=>setPortalStep("select")} style={{marginTop:8,color:"#5dd4c6",borderColor:"#5dd4c6"}}>← Volver</Btn>
              </div>
            )}
            {portalStep==="success"&&(
              <div className="fade-in" style={{textAlign:"center",padding:"16px 0"}}>
                <div style={{fontSize:48,marginBottom:12}}>✅</div>
                <div style={{fontSize:17,fontWeight:700,color:"#5dd4c6",marginBottom:6}}>¡Cita agendada!</div>
                <div style={{fontSize:13,color:"rgba(255,255,255,0.55)",marginBottom:20}}>Te esperamos el {fmt(portalForm.date)} a las {portalForm.time}</div>
                <Btn onClick={()=>{setPortalStep("select");setPortalForm({patientId:"",date:todayStr(),time:"09:00",service:"",podologa:""})}} size="sm">Agendar otra cita</Btn>
              </div>
            )}
          </div>
        </Card>
        <div>
          <Card>
            <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:12}}>📊 Estadísticas del Portal</div>
            <div style={{display:"flex",flexDirection:"column",gap:10}}>
              <div style={{background:"#f4f8fa",borderRadius:8,padding:"10px 12px"}}>
                <div style={{fontSize:10.5,color:"#8a9aaa",textTransform:"uppercase"}}>Citas via Portal</div>
                <div style={{fontSize:22,fontWeight:800,color:"#4a9d8f",marginTop:3}}>{portalAppts.filter(a=>a.createdBy==="Portal").length}</div>
              </div>
              <div style={{background:"#f4f8fa",borderRadius:8,padding:"10px 12px"}}>
                <div style={{fontSize:10.5,color:"#8a9aaa",textTransform:"uppercase"}}>Total Citas</div>
                <div style={{fontSize:22,fontWeight:800,color:"#2563eb",marginTop:3}}>{portalAppts.length}</div>
              </div>
            </div>
          </Card>
        </div>
      </div>
      {portalStep==="myAppts"&&portalPatient&&(
        <Modal title={`Citas y atenciones - ${(portalPatient.firstName||portalPatient.first_name||"")} ${(portalPatient.lastName||portalPatient.last_name||"")}`} onClose={()=>setPortalStep("select")} width={720}>
          <div style={{fontSize:12.5,color:"#5a7a8a",marginBottom:12}}>DNI: <b>{portalPatient.dni||"---"}</b> · Teléfono: <b>{portalPatient.phone||"---"}</b></div>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
            <div>
              <div style={{fontWeight:800,fontSize:13,color:"#1a2332",marginBottom:8}}>Citas ({myAppts.length})</div>
              {myAppts.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,padding:"14px",background:"#f8fafc",borderRadius:8}}>Sin citas registradas</div>:myAppts.map(a=>{
                const st=appointmentStatusOf(a,portalAtts);
                return(
                  <div key={a.id} style={{border:"1px solid #e8edf2",borderRadius:9,padding:"10px 12px",marginBottom:8}}>
                    <div style={{display:"flex",justifyContent:"space-between",gap:8}}>
                      <b style={{fontSize:13,color:"#1a2332"}}>{fmt(a.date)} {a.time||""}</b>
                      <Badge color={appointmentStatusColor[st]||"gray"}>{appointmentStatusLabel[st]||st}</Badge>
                    </div>
                    <div style={{fontSize:12,color:"#5a7a8a",marginTop:4}}>{a.service||"Sin servicio"} · {appointmentPodologa(a,portalAtts)||"Sin podóloga"}</div>
                  </div>
                );
              })}
            </div>
            <div>
              <div style={{fontWeight:800,fontSize:13,color:"#1a2332",marginBottom:8}}>Atenciones ({myAtts.length})</div>
              {myAtts.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,padding:"14px",background:"#f8fafc",borderRadius:8}}>Sin atenciones registradas</div>:myAtts.slice().sort((a,b)=>String(b.date).localeCompare(String(a.date))).map(a=>(
                <div key={a.id} style={{border:"1px solid #e8edf2",borderRadius:9,padding:"10px 12px",marginBottom:8}}>
                  <div style={{display:"flex",justifyContent:"space-between",gap:8}}>
                    <b style={{fontSize:13,color:"#1a2332"}}>{fmt(a.date)} {a.time||""}</b>
                    <Badge color={(a.closed||a.payStatus==="pagado")?"green":"orange"}>{(a.closed||a.payStatus==="pagado")?"Pagada":"Pendiente"}</Badge>
                  </div>
                  <div style={{fontSize:12,color:"#5a7a8a",marginTop:4}}>{a.service||"Sin servicio"} · {a.attendedBy||a.attended_by||"Sin podóloga"}</div>
                  {a.notes&&<div style={{fontSize:11.5,color:"#3a5a6a",marginTop:6,background:"#f4f8fa",borderRadius:7,padding:"7px 9px"}}>{a.notes}</div>}
                </div>
              ))}
            </div>
          </div>
        </Modal>
      )}
    </div>
  );
};
// ─── AVANZADO TAB — solo Admin ────────────────────────────────────────────────
const AvanzadoTab=({currentUser})=>{
  const isAdmin=currentUser?.role==="Administrador"||isSA(currentUser);
  const[kpi,setKpi]=useState(()=>{
    const s=db.get(SK.kpiSettings)||{};
    return{hideAtencionesHoy:!!s.hideAtencionesHoy,hidePorCobrar:!!s.hidePorCobrar};
  });
  const[dbModal,setDbModal]=useState(false);
  const[dbTab,setDbTab]=useState("attendances");
  const[dbSearch,setDbSearch]=useState("");
  const[cleanMsg,setCleanMsg]=useState({atencionesHoy:null,porCobrar:null});

  const saveKpi=(key,val)=>{
    const next={...kpi,[key]:val};
    setKpi(next);
    db.set(SK.kpiSettings,next);
  };

  // ── Limpieza de Atenciones de Hoy ──────────────────────────────────────────
  const limpiarAtencionesHoy=()=>{
    if(!window.confirm("⚠️ ¿Eliminar TODAS las atenciones registradas hoy? Esta acción no se puede deshacer."))return;
    const hoy=todayStr();
    const all=db.get(SK.attendances)||[];
    const sinHoy=all.filter(a=>a.date!==hoy);
    all.filter(a=>a.date===hoy&&a.id).forEach(a=>crudApi.remove('attendances',a.id).catch(()=>{}));
    db.set(SK.attendances,sinHoy);
    const eliminadas=all.length-sinHoy.length;
    setCleanMsg(p=>({...p,atencionesHoy:`✅ ${eliminadas} atención${eliminadas!==1?"es":""} eliminada${eliminadas!==1?"s":""} del día de hoy.`}));
    setTimeout(()=>setCleanMsg(p=>({...p,atencionesHoy:null})),5000);
  };

  // ── Limpieza de Por Cobrar ──────────────────────────────────────────────────
  const limpiarPorCobrar=()=>{
    const all=db.get(SK.attendances)||[];
    const pendientes=all.filter(a=>!a.closed||a.payStatus!=="pagado");
    if(pendientes.length===0){setCleanMsg(p=>({...p,porCobrar:"ℹ️ No hay registros pendientes de cobro."}));setTimeout(()=>setCleanMsg(p=>({...p,porCobrar:null})),3000);return;}
    if(!window.confirm(`⚠️ ¿Eliminar los ${pendientes.length} registro${pendientes.length!==1?"s":""} pendiente${pendientes.length!==1?"s":""} de cobro? Esta acción no se puede deshacer.`))return;
    const limpias=all.filter(a=>a.closed&&a.payStatus==="pagado");
    pendientes.filter(a=>a.id).forEach(a=>crudApi.remove('attendances',a.id).catch(()=>{}));
    db.set(SK.attendances,limpias);
    setCleanMsg(p=>({...p,porCobrar:`✅ ${pendientes.length} registro${pendientes.length!==1?"s":""} pendiente${pendientes.length!==1?"s":""} eliminado${pendientes.length!==1?"s":""}.`}));
    setTimeout(()=>setCleanMsg(p=>({...p,porCobrar:null})),5000);
  };

  // ── Vista de Base de Datos ──────────────────────────────────────────────────
  const DB_COLLECTIONS=[
    {key:"attendances",label:"🩺 Atenciones",sk:SK.attendances},
    {key:"patients",label:"👥 Pacientes",sk:SK.patients},
    {key:"appointments",label:"📅 Citas",sk:SK.appointments},
    {key:"payments",label:"💳 Pagos",sk:SK.payments},
    {key:"cashbox",label:"💰 Caja",sk:SK.cashbox},
    {key:"salesProducts",label:"🛒 Ventas Productos",sk:SK.salesProducts},
    {key:"salesServices",label:"🛒 Ventas Servicios",sk:SK.salesServices},
    {key:"inventory",label:"📦 Inventario",sk:SK.inventory},
    {key:"users",label:"👤 Usuarios",sk:SK.users},
    {key:"services",label:"🏥 Servicios",sk:SK.services},
    {key:"commissions",label:"💹 Comisiones",sk:SK.commissions},
  ];
  const DbModal=()=>{
    const col=DB_COLLECTIONS.find(c=>c.key===dbTab);
    const[dbData,setDbData]=React.useState(null);
    const[dbLoading,setDbLoading]=React.useState(false);
    React.useEffect(()=>{
      if(!col)return;
      var cached=db.get(col.sk);
      if(Array.isArray(cached)&&cached.length>0){setDbData(cached);return;}
      setDbLoading(true);
      api.get(col.key).then(function(d){
        var rows=Array.isArray(d)?d:(d&&d.data?d.data:[]);
        setDbData(rows);
      }).catch(function(){setDbData([]);}).finally(function(){setDbLoading(false);});
    },[dbTab]);
    var cached2=db.get(col&&col.sk);
    var rawData=dbData!==null?dbData:(Array.isArray(cached2)?cached2:[]);
    const data=Array.isArray(rawData)?rawData:[rawData];
    const q=dbSearch.toLowerCase().trim();
    const filtered=q?data.filter(row=>JSON.stringify(row).toLowerCase().includes(q)):data;
    const cols=filtered.length>0?Object.keys(filtered[0]).slice(0,8):[];
    return(
      <>
        <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.55)",zIndex:9990}} onClick={()=>setDbModal(false)}/>
        <div style={{position:"fixed",inset:"2vh 2vw",background:"#f0f4f8",borderRadius:18,zIndex:9991,display:"flex",flexDirection:"column",boxShadow:"0 32px 80px rgba(0,0,0,0.4)",overflow:"hidden",fontFamily:"'Outfit',sans-serif"}}>
          {/* Header */}
          <div style={{background:"linear-gradient(135deg,#1a2332,#0f3a2a)",padding:"16px 24px",display:"flex",alignItems:"center",justifyContent:"space-between",flexShrink:0}}>
            <div style={{display:"flex",alignItems:"center",gap:12}}>
              <div style={{fontSize:24}}>🗄️</div>
              <div>
                <div style={{fontWeight:800,fontSize:16,color:"#fff"}}>Explorador de Base de Datos</div>
                <div style={{fontSize:11,color:"rgba(255,255,255,0.5)",marginTop:1}}>Solo lectura — Vista de administrador</div>
              </div>
            </div>
            <div style={{display:"flex",alignItems:"center",gap:10}}>
              <div style={{background:"rgba(255,255,255,0.08)",borderRadius:8,padding:"6px 14px",fontSize:12,color:"rgba(255,255,255,0.6)"}}>
                {filtered.length} registro{filtered.length!==1?"s":""}
              </div>
              <button onClick={()=>setDbModal(false)} style={{width:32,height:32,borderRadius:"50%",background:"rgba(255,255,255,0.1)",border:"none",color:"#fff",fontSize:18,cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",lineHeight:1}}>×</button>
            </div>
          </div>
          {/* Collection tabs */}
          <div style={{display:"flex",gap:0,background:"#1a2332",padding:"0 16px",overflowX:"auto",flexShrink:0}}>
            {DB_COLLECTIONS.map(c=>(
              <button key={c.key} onClick={()=>{setDbTab(c.key);setDbSearch("");}}
                style={{padding:"10px 14px",border:"none",background:dbTab===c.key?"#fff":"transparent",color:dbTab===c.key?"#1a2332":"rgba(255,255,255,0.5)",fontWeight:dbTab===c.key?700:400,fontSize:11.5,cursor:"pointer",fontFamily:"'Outfit',sans-serif",borderRadius:"8px 8px 0 0",whiteSpace:"nowrap",transition:"all .15s",marginRight:2}}>
                {c.label}
              </button>
            ))}
          </div>
          {/* Search bar */}
          <div style={{padding:"12px 16px",background:"#fff",borderBottom:"1px solid #e8edf2",flexShrink:0}}>
            <input value={dbSearch} onChange={e=>setDbSearch(e.target.value)}
              placeholder="🔍 Buscar en esta colección..." style={{width:"100%",padding:"8px 14px",borderRadius:8,border:"1.5px solid #d4dde5",fontSize:13,fontFamily:"'Outfit',sans-serif",outline:"none",background:"#f8fafc"}}/>
          </div>
          {/* Table */}
          <div style={{flex:1,overflow:"auto",padding:"0"}}>
            {filtered.length===0?(
              dbLoading?<div style={{textAlign:"center",padding:"48px 0",color:"#8a9aaa",fontSize:14}}>Cargando datos...</div>:
              <div style={{textAlign:"center",padding:"48px 0",color:"#8a9aaa",fontSize:14}}>Sin registros{q?" que coincidan con la búsqueda":""}</div>
            ):(
              <table style={{width:"100%",borderCollapse:"collapse",fontSize:12}}>
                <thead style={{position:"sticky",top:0,zIndex:1}}>
                  <tr style={{background:"#f0f4f8"}}>
                    <th style={{padding:"10px 16px",textAlign:"left",fontWeight:700,color:"#5a7a8a",fontSize:11,borderBottom:"2px solid #e0eaf0",whiteSpace:"nowrap"}}>#</th>
                    {cols.map(c=>(
                      <th key={c} style={{padding:"10px 16px",textAlign:"left",fontWeight:700,color:"#5a7a8a",fontSize:11,borderBottom:"2px solid #e0eaf0",whiteSpace:"nowrap"}}>{c}</th>
                    ))}
                    {Object.keys(filtered[0]||{}).length>8&&<th style={{padding:"10px 16px",color:"#8a9aaa",fontSize:11,borderBottom:"2px solid #e0eaf0"}}>...</th>}
                  </tr>
                </thead>
                <tbody>
                  {filtered.slice(0,200).map((row,i)=>(
                    <tr key={i} style={{background:i%2===0?"#fff":"#f8fafc",borderBottom:"1px solid #f0f4f8"}}>
                      <td style={{padding:"8px 16px",color:"#8a9aaa",fontWeight:600,fontSize:11}}>{i+1}</td>
                      {cols.map(c=>{
                        const val=row[c];
                        const str=val===null||val===undefined?"":Array.isArray(val)?`[${val.length}]`:typeof val==="object"?"{…}":String(val);
                        const trunc=str.length>60?str.slice(0,60)+"…":str;
                        const isId=c==="id";
                        const isBool=typeof val==="boolean";
                        const isNum=typeof val==="number"&&!isId;
                        return(
                          <td key={c} style={{padding:"8px 16px",maxWidth:200,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",color:isId?"#4a9d8f":isBool?(val?"#059669":"#e05050"):isNum?"#7c3aed":"#1a2332",fontWeight:isId?700:400}} title={str}>
                            {isBool?(val?"✓":"✗"):trunc||<span style={{color:"#ccc"}}>—</span>}
                          </td>
                        );
                      })}
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
            {filtered.length>200&&<div style={{textAlign:"center",padding:"12px 0",fontSize:12,color:"#8a9aaa",background:"#f8fafc"}}>Mostrando 200 de {filtered.length} registros. Use la búsqueda para filtrar.</div>}
          </div>
          {/* Footer */}
          <div style={{padding:"10px 20px",background:"#fff",borderTop:"1px solid #e8edf2",display:"flex",justifyContent:"space-between",alignItems:"center",flexShrink:0}}>
            <div style={{fontSize:11.5,color:"#8a9aaa"}}>
              Total en colección: <strong>{data.length}</strong> · Mostrando: <strong>{Math.min(filtered.length,200)}</strong>
            </div>
            <button onClick={()=>{
              const blob=new Blob([JSON.stringify(data,null,2)],{type:"application/json"});
              const url=URL.createObjectURL(blob);
              const a=document.createElement("a");a.href=url;
              a.download=`${dbTab}_${todayStr()}.json`;a.click();URL.revokeObjectURL(url);
            }} style={{padding:"6px 16px",borderRadius:8,background:"#f0f4f8",border:"1px solid #d4dde5",fontSize:12,fontWeight:700,cursor:"pointer",color:"#3a5a6a",fontFamily:"'Outfit',sans-serif"}}>
              ⬇ Exportar JSON
            </button>
          </div>
        </div>
      </>
    );
  };

  const TogRow=({label,desc,icon,keyName,disabled})=>(
    <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",background:disabled?"#f8f8f8":"#fff",borderRadius:12,border:"1.5px solid",borderColor:kpi[keyName]?"#4a9d8f33":"#e8edf2",marginBottom:10,opacity:disabled?0.5:1}}>
      <div style={{display:"flex",alignItems:"center",gap:12}}>
        <div style={{width:42,height:42,borderRadius:10,background:kpi[keyName]?"linear-gradient(135deg,#4a9d8f22,#2a7a6a11)":"#f0f4f8",display:"flex",alignItems:"center",justifyContent:"center",fontSize:20,border:`1.5px solid ${kpi[keyName]?"#4a9d8f44":"#e0eaf0"}`}}>{icon}</div>
        <div>
          <div style={{fontWeight:700,fontSize:13.5,color:"#1a2332"}}>{label}</div>
          <div style={{fontSize:11.5,color:"#8a9aaa",marginTop:2}}>{desc}</div>
        </div>
      </div>
      <button
        disabled={disabled}
        onClick={()=>saveKpi(keyName,!kpi[keyName])}
        style={{width:52,height:28,borderRadius:14,background:kpi[keyName]?"linear-gradient(135deg,#4a9d8f,#2a7a6a)":"#d4dde5",border:"none",cursor:disabled?"not-allowed":"pointer",position:"relative",transition:"background .2s",flexShrink:0}}>
        <div style={{position:"absolute",top:3,left:kpi[keyName]?26:3,width:22,height:22,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 4px rgba(0,0,0,0.2)",transition:"left .2s"}}/>
      </button>
    </div>
  );

  const CleanBlock=({title,desc,icon,btnLabel,btnColor,onClean,msg,disabled})=>(
    <div style={{background:disabled?"#f8f8f8":"#fff",borderRadius:12,border:`1.5px solid ${btnColor}22`,padding:"18px 20px",marginBottom:12,opacity:disabled?0.55:1}}>
      <div style={{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:12}}>
        <div style={{display:"flex",alignItems:"center",gap:12}}>
          <div style={{width:44,height:44,borderRadius:10,background:`${btnColor}15`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:22,flexShrink:0}}>{icon}</div>
          <div>
            <div style={{fontWeight:700,fontSize:13.5,color:"#1a2332"}}>{title}</div>
            <div style={{fontSize:11.5,color:"#8a9aaa",marginTop:2,lineHeight:1.4}}>{desc}</div>
          </div>
        </div>
        <button disabled={disabled} onClick={onClean}
          style={{flexShrink:0,padding:"8px 16px",borderRadius:10,background:disabled?"#e0e8f0":`linear-gradient(135deg,${btnColor},${btnColor}cc)`,color:"#fff",border:"none",fontWeight:700,fontSize:12.5,cursor:disabled?"not-allowed":"pointer",fontFamily:"'Outfit',sans-serif",whiteSpace:"nowrap",boxShadow:disabled?"none":`0 2px 8px ${btnColor}44`}}>
          🗑 {btnLabel}
        </button>
      </div>
      {msg&&<div style={{marginTop:12,padding:"8px 14px",borderRadius:8,background:msg.startsWith("✅")?"#f0faf7":"#f0f4ff",border:`1px solid ${msg.startsWith("✅")?"#4a9d8f33":"#2563eb22"}`,fontSize:12.5,color:msg.startsWith("✅")?"#2a7a6a":"#1a50c0",fontWeight:600}}>{msg}</div>}
    </div>
  );

  return(
    <div className="fade-in">
      <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:22,padding:"16px 20px",borderRadius:14,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff"}}>
        <div style={{fontSize:28}}>⚙️</div>
        <div>
          <div style={{fontWeight:800,fontSize:16}}>Configuración Avanzada</div>
          <div style={{fontSize:12,opacity:.7,marginTop:2}}>Gestión de datos, limpieza y visibilidad de KPIs</div>
        </div>
        {!isAdmin&&<div style={{marginLeft:"auto",padding:"6px 16px",borderRadius:20,background:"rgba(224,80,80,0.25)",border:"1.5px solid rgba(224,80,80,0.5)",color:"#ff9999",fontSize:11,fontWeight:700}}>🔒 Solo Administrador</div>}
      </div>

      {!isAdmin&&(
        <div style={{background:"#fff8e1",border:"1px solid #fde68a",borderRadius:12,padding:"14px 18px",marginBottom:18,fontSize:13,color:"#92400e",display:"flex",gap:10,alignItems:"center"}}>
          <span style={{fontSize:20}}>🔒</span>
          <span>Solo el <strong>Administrador</strong> puede acceder a estas opciones.</span>
        </div>
      )}

      {/* ── Ver Base de Datos ──────────────────────────────────────── */}
      <div style={{background:"#fff",borderRadius:14,padding:"20px 22px",border:"1px solid #e8edf2",marginBottom:16}}>
        <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:4}}>
          <div>
            <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>🗄️ Explorador de Base de Datos</div>
            <div style={{fontSize:12.5,color:"#8a9aaa",marginTop:2}}>Visualiza y exporta cualquier colección del sistema. Solo lectura.</div>
          </div>
          <button disabled={!isAdmin} onClick={()=>setDbModal(true)}
            style={{padding:"9px 20px",borderRadius:10,background:isAdmin?"linear-gradient(135deg,#1a2332,#0f3a2a)":"#d4dde5",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:isAdmin?"pointer":"not-allowed",fontFamily:"'Outfit',sans-serif",display:"flex",alignItems:"center",gap:6,flexShrink:0,boxShadow:isAdmin?"0 2px 8px rgba(26,35,50,0.3)":"none"}}>
            🗄️ Ver Base de Datos
          </button>
        </div>
      </div>

      {/* ── Limpieza de Datos ──────────────────────────────────────── */}
      <div style={{background:"#fff",borderRadius:14,padding:"20px 22px",border:"1px solid #e8edf2",marginBottom:16}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>🧹 Limpieza de Datos</div>
        <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:18}}>Elimina registros del sistema de forma permanente. Las eliminaciones no se pueden deshacer.</div>

        <div style={{background:"#fff8e1",border:"1px solid #fde68a",borderRadius:10,padding:"10px 14px",marginBottom:16,fontSize:12,color:"#92400e",display:"flex",gap:8,alignItems:"center"}}>
          <span>⚠️</span><span>Estas acciones son <strong>permanentes</strong>. Realiza un backup antes de proceder.</span>
        </div>

        <CleanBlock
          title="Limpiar — Atenciones de Hoy"
          desc="Elimina todas las atenciones registradas en el día de hoy (cobradas y pendientes)."
          icon="🩺"
          btnLabel="Limpiar Atenciones Hoy"
          btnColor="#dc2626"
          onClean={limpiarAtencionesHoy}
          msg={cleanMsg.atencionesHoy}
          disabled={!isAdmin}
        />
        <CleanBlock
          title="Limpiar — Por Cobrar (Pendientes)"
          desc="Elimina todos los registros de atenciones que no han sido marcados como pagados (en cualquier fecha)."
          icon="⏳"
          btnLabel="Limpiar Por Cobrar"
          btnColor="#f59223"
          onClean={limpiarPorCobrar}
          msg={cleanMsg.porCobrar}
          disabled={!isAdmin}
        />
      </div>

      {/* ── KPIs del Dashboard ─────────────────────────────────────── */}
      <div style={{background:"#fff",borderRadius:14,padding:"20px 22px",border:"1px solid #e8edf2",marginBottom:16}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>📊 KPIs del Dashboard — Visibilidad</div>
        <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:18}}>Oculta indicadores sensibles en la pantalla de inicio durante la jornada.</div>
        <TogRow
          label="Ocultar — Atenciones Hoy"
          desc="El KPI de atenciones del día se mostrará en blanco (—)"
          icon="🩺"
          keyName="hideAtencionesHoy"
          disabled={!isAdmin}
        />
        <TogRow
          label="Ocultar — Por Cobrar (Pendiente)"
          desc="El monto pendiente de cobro se mostrará en blanco (—)"
          icon="⏳"
          keyName="hidePorCobrar"
          disabled={!isAdmin}
        />
      </div>

      {isAdmin&&(
        <div style={{background:"#f0faf7",borderRadius:12,padding:"12px 18px",border:"1px solid #4a9d8f33",fontSize:12.5,color:"#2a7a6a",display:"flex",gap:10,alignItems:"center"}}>
          <span style={{fontSize:16}}>💡</span>
          <span>Los cambios se aplican inmediatamente. Haz un <strong>backup</strong> antes de limpiar datos.</span>
        </div>
      )}

      {dbModal&&isAdmin&&<DbModal/>}
    </div>
  );
};
// ─── PERMS TAB (sub-componente para evitar useState en IIFE) ─────────────────
// ─── LICENCIAS TAB ────────────────────────────────────────────────────────────
const LicenciasTab=({currentUser})=>{
  const SA=isSA(currentUser);
  const isAdmin=currentUser?.role==="Administrador"||SA;
  const SK_LIC="pmb_licenses";
  const initLic=()=>{
    const saved=typeof db!=="undefined"?db.get(SK_LIC):null;
    if(saved)return saved;
    return Object.fromEntries(SYSTEM_TOOLS.map(t=>[t.id,true]));
  };
  const[lic,setLic]=useState(initLic);
  const[licKey,setLicKey]=useState("");
  const[curKey,setCurKey]=useState("");
  const[licStatus,setLicStatus]=useState(null);
  const[loadingLic,setLoadingLic]=useState(false);
  const[showKey,setShowKey]=useState(false);

  React.useEffect(()=>{
    fetch(API_BASE+'/auth.php?action=license_verify')
      .then(r=>r.json())
      .then(d=>{if(d.valid&&d.key)setCurKey(d.key);})
      .catch(()=>{});
  },[]);

  const activarLicencia=async()=>{
    if(!licKey.trim()){setLicStatus({ok:false,msg:"Ingresa una clave de licencia."});return;}
    setLoadingLic(true);setLicStatus(null);
    try{
      const r=await fetch(API_BASE+'/auth.php?action=license_activate',{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:licKey.trim()})});
      const d=await r.json();
      if(d.ok){
        setCurKey(licKey.trim().toUpperCase());
        setLicKey("");
        setLicStatus({ok:true,msg:"✅ Licencia activada correctamente. Recarga la página para aplicar los cambios."});
      }else{
        setLicStatus({ok:false,msg:d.error||"Clave inválida. Verifica e intenta de nuevo."});
      }
    }catch(e){
      setLicStatus({ok:false,msg:"Error al conectar con el servidor backend."});
    }
    setLoadingLic(false);
  };

  const toggle=(id)=>{
    if(!isAdmin){alert("Solo Administrador o Super Admin puede gestionar licencias.");return;}
    const next={...lic,[id]:!lic[id]};
    setLic(next);
    if(typeof db!=="undefined")db.set(SK_LIC,next);
  };
  const toggleAll=(val)=>{
    if(!isAdmin){alert("Solo Administrador o Super Admin puede gestionar licencias.");return;}
    const next=Object.fromEntries(SYSTEM_TOOLS.map(t=>[t.id,val]));
    setLic(next);
    if(typeof db!=="undefined")db.set(SK_LIC,next);
  };
  const cats=[...new Set(SYSTEM_TOOLS.map(t=>t.category))];
  const active=Object.values(lic).filter(Boolean).length;
  const total=SYSTEM_TOOLS.length;
  return(
    <div className="fade-in">
      <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:22,padding:"16px 20px",borderRadius:14,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff"}}>
        <div style={{fontSize:28}}>🔑</div>
        <div>
          <div style={{fontWeight:800,fontSize:16}}>Activación de Licencias</div>
          <div style={{fontSize:12,opacity:.7,marginTop:2}}>Gestiona la licencia del sistema y los módulos disponibles.</div>
        </div>
      </div>

      {/* ── Clave de Activación ─────────────────────────── */}
      <div style={{background:"#fff",borderRadius:14,border:"1.5px solid #e8edf2",padding:"20px 22px",marginBottom:18}}>
        <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>🔐 Clave de Activación del Sistema</div>
        <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:16}}>Ingresa o actualiza la clave para activar PodoCLINIC en este equipo.</div>

        {curKey&&(
          <div style={{background:"#f0faf7",border:"1.5px solid #4a9d8f44",borderRadius:10,padding:"12px 16px",marginBottom:16,display:"flex",alignItems:"center",justifyContent:"space-between",gap:12}}>
            <div style={{display:"flex",alignItems:"center",gap:10}}>
              <span style={{fontSize:20}}>✅</span>
              <div>
                <div style={{fontWeight:700,fontSize:12.5,color:"#2a7a6a"}}>Licencia activa</div>
                <div style={{fontFamily:"monospace",fontSize:13,color:"#1a2332",marginTop:2,letterSpacing:"0.05em"}}>
                  {showKey?curKey:curKey.slice(0,4)+"••••-••••-••••-"+curKey.slice(-4)}
                </div>
              </div>
            </div>
            <button onClick={()=>setShowKey(p=>!p)} style={{background:"none",border:"1px solid #4a9d8f55",borderRadius:8,padding:"5px 12px",fontSize:11.5,color:"#2a7a6a",cursor:"pointer",fontWeight:600,fontFamily:"inherit",whiteSpace:"nowrap"}}>
              {showKey?"🙈 Ocultar":"👁 Ver clave"}
            </button>
          </div>
        )}

        {isAdmin?(
          <div>
            <div style={{fontSize:12.5,fontWeight:600,color:"#5a7a8a",marginBottom:8}}>{curKey?"Cambiar clave de licencia:":"Activar nueva licencia:"}</div>
            <div style={{display:"flex",gap:10,alignItems:"stretch"}}>
              <input
                value={licKey}
                onChange={e=>setLicKey(e.target.value.toUpperCase())}
                onKeyDown={e=>e.key==="Enter"&&activarLicencia()}
                placeholder="XXXX-XXXX-XXXX-XXXX-XXXX"
                maxLength={29}
                style={{flex:1,padding:"11px 14px",borderRadius:10,border:"1.5px solid #d4dde5",fontSize:13.5,fontFamily:"monospace",letterSpacing:"0.08em",outline:"none",color:"#1a2332",background:"#fafcfd"}}
              />
              <button
                onClick={activarLicencia}
                disabled={loadingLic}
                style={{padding:"0 22px",borderRadius:10,background:loadingLic?"#d4dde5":"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff",border:"none",fontWeight:700,fontSize:13.5,cursor:loadingLic?"wait":"pointer",fontFamily:"inherit",whiteSpace:"nowrap",flexShrink:0}}>
                {loadingLic?"Verificando...":"🔑 Activar"}
              </button>
            </div>
            {licStatus&&(
              <div style={{marginTop:10,padding:"10px 14px",borderRadius:8,background:licStatus.ok?"#f0faf7":"#fff5f5",border:`1px solid ${licStatus.ok?"#4a9d8f44":"#dc262644"}`,fontSize:12.5,color:licStatus.ok?"#2a7a6a":"#b91c1c",fontWeight:600}}>
                {licStatus.msg}
              </div>
            )}
            <div style={{fontSize:11,color:"#8a9aaa",marginTop:8}}>💡 Formato: <code style={{background:"#f0f4f8",padding:"1px 5px",borderRadius:4,fontFamily:"monospace"}}>PROF-XXXX-XXXX-XXXX-XXXX</code>. Contacta al proveedor si no tienes una clave.</div>
          </div>
        ):(
          <div style={{background:"#fff8e1",border:"1px solid #fde68a",borderRadius:10,padding:"10px 14px",fontSize:12.5,color:"#92400e",display:"flex",gap:8,alignItems:"center"}}>
            <span>🔒</span><span>Solo <strong>Administrador</strong> o <strong>Super Admin</strong> puede activar licencias.</span>
          </div>
        )}
      </div>

      {/* ── Herramientas ─────────────────────────────────── */}
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:10}}>
        <div>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>🛠️ Herramientas del Sistema</div>
          <div style={{fontSize:12.5,color:"#8a9aaa",marginTop:2}}>Activa o desactiva módulos para todos los usuarios.</div>
        </div>
        {isAdmin&&(
          <div style={{display:"flex",gap:8}}>
            <button onClick={()=>toggleAll(true)} style={{padding:"8px 16px",borderRadius:10,background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",color:"#fff",border:"none",fontWeight:700,fontSize:12.5,cursor:"pointer",fontFamily:"inherit"}}>✅ Activar todo</button>
            <button onClick={()=>toggleAll(false)} style={{padding:"8px 16px",borderRadius:10,background:"linear-gradient(135deg,#dc2626,#b91c1c)",color:"#fff",border:"none",fontWeight:700,fontSize:12.5,cursor:"pointer",fontFamily:"inherit"}}>⊘ Desactivar todo</button>
          </div>
        )}
      </div>
      {!isAdmin&&(
        <div style={{background:"#fff8e1",border:"1px solid #fde68a",borderRadius:10,padding:"12px 16px",marginBottom:16,fontSize:13,color:"#92400e",display:"flex",gap:10,alignItems:"center"}}>
          <span>🔒</span><span>Solo <strong>Administrador</strong> o <strong>Super Admin</strong> puede modificar herramientas.</span>
        </div>
      )}
      <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:10,marginBottom:20}}>
        {[{label:"Activas",val:active,color:"#4a9d8f"},{label:"Inactivas",val:total-active,color:"#dc2626"},{label:"Total",val:total,color:"#2563eb"}].map(s=>(
          <div key={s.label} style={{background:"#fff",borderRadius:12,padding:"14px 18px",border:"1px solid #e8edf2",textAlign:"center"}}>
            <div style={{fontSize:28,fontWeight:800,color:s.color}}>{s.val}</div>
            <div style={{fontSize:11.5,color:"#8a9aaa",marginTop:2,textTransform:"uppercase",letterSpacing:"0.05em"}}>{s.label}</div>
          </div>
        ))}
      </div>
      {cats.map(cat=>(
        <div key={cat} style={{marginBottom:18}}>
          <div style={{fontSize:11,fontWeight:700,color:"#8a9aaa",textTransform:"uppercase",letterSpacing:"0.08em",marginBottom:8,paddingLeft:2}}>{cat}</div>
          {SYSTEM_TOOLS.filter(t=>t.category===cat).map(t=>(
            <div key={t.id} style={{background:"#fff",borderRadius:12,border:`1.5px solid ${lic[t.id]?"#4a9d8f33":"#e8edf2"}`,padding:"14px 18px",marginBottom:8,display:"flex",alignItems:"center",justifyContent:"space-between",transition:"all .2s"}}>
              <div style={{display:"flex",alignItems:"center",gap:12}}>
                <div style={{width:44,height:44,borderRadius:10,background:lic[t.id]?"#4a9d8f15":"#f4f8fa",display:"flex",alignItems:"center",justifyContent:"center",fontSize:22,transition:"all .2s"}}>{t.icon}</div>
                <div>
                  <div style={{fontWeight:700,fontSize:13.5,color:"#1a2332"}}>{t.label}</div>
                  <div style={{fontSize:11.5,color:lic[t.id]?"#4a9d8f":"#8a9aaa",marginTop:2,fontWeight:600}}>{lic[t.id]?"✓ Activa":"✗ Inactiva"}</div>
                </div>
              </div>
              <button
                onClick={()=>toggle(t.id)}
                disabled={!isAdmin}
                style={{width:52,height:28,borderRadius:14,background:lic[t.id]?"linear-gradient(135deg,#4a9d8f,#2a7a6a)":"#d4dde5",border:"none",cursor:isAdmin?"pointer":"not-allowed",position:"relative",transition:"all .2s",flexShrink:0,opacity:!isAdmin?0.5:1}}>
                <div style={{position:"absolute",top:3,left:lic[t.id]?26:3,width:22,height:22,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 4px rgba(0,0,0,0.2)",transition:"left .2s"}}/>
              </button>
            </div>
          ))}
        </div>
      ))}
    </div>
  );
};
// ─── KPIS TAB ─────────────────────────────────────────────────────────────────
const KpisTab=({currentUser,users})=>{
  const SA=isSA(currentUser);
  const isAdmin=currentUser?.role==="Administrador"||SA;
  const[kpiView,setKpiView]=useState("global");
  const[selUser,setSelUser]=useState(users?.[0]?.id||null);

  // Global KPI settings (hide/show)
  const[globalKpi,setGlobalKpi]=useState(()=>{
    const s=typeof db!=="undefined"?db.get(SK.kpiSettings)||{}:{};
    return Object.fromEntries(SYSTEM_KPIS.map(k=>[k.id,s[k.id]===undefined?true:!s[`hide${k.id.charAt(0).toUpperCase()+k.id.slice(1)}`]]));
  });

  // Per-user KPI settings
  const SK_USER_KPIS="pmb_user_kpis";
  const initUserKpis=()=>{
    const saved=typeof db!=="undefined"?db.get(SK_USER_KPIS):null;
    if(saved)return saved;
    const obj={};
    (users||[]).forEach(u=>{obj[u.id]=Object.fromEntries(SYSTEM_KPIS.map(k=>[k.id,true]));});
    return obj;
  };
  const[userKpis,setUserKpis]=useState(initUserKpis);

  const toggleGlobal=(id)=>{
    if(!isAdmin){alert("Solo Administrador o Super Admin.");return;}
    const next={...globalKpi,[id]:!globalKpi[id]};
    setGlobalKpi(next);
    // Persist using existing SK.kpiSettings format
    const cfg=typeof db!=="undefined"?db.get(SK.kpiSettings)||{}:{};
    SYSTEM_KPIS.forEach(k=>{cfg[`hide${k.id.charAt(0).toUpperCase()+k.id.slice(1)}`]=!next[k.id];});
    if(typeof db!=="undefined")db.set(SK.kpiSettings,cfg);
  };

  const toggleAllGlobal=(val)=>{
    if(!isAdmin)return;
    const next=Object.fromEntries(SYSTEM_KPIS.map(k=>[k.id,val]));
    setGlobalKpi(next);
    const cfg={};
    SYSTEM_KPIS.forEach(k=>{cfg[`hide${k.id.charAt(0).toUpperCase()+k.id.slice(1)}`]=!val;});
    if(typeof db!=="undefined")db.set(SK.kpiSettings,cfg);
  };

  const toggleUserKpi=(userId,kpiId)=>{
    if(!isAdmin)return;
    const next={...userKpis,[userId]:{...(userKpis[userId]||{}),[kpiId]:!(userKpis[userId]?.[kpiId]!==false)}};
    setUserKpis(next);
    if(typeof db!=="undefined")db.set(SK_USER_KPIS,next);
  };

  const toggleAllUserKpis=(userId,val)=>{
    if(!isAdmin)return;
    const next={...userKpis,[userId]:Object.fromEntries(SYSTEM_KPIS.map(k=>[k.id,val]))};
    setUserKpis(next);
    if(typeof db!=="undefined")db.set(SK_USER_KPIS,next);
  };

  const activeCount=Object.values(globalKpi).filter(Boolean).length;

  const TogItem=({id,label,icon,desc,val,onToggle,disabled})=>(
    <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",borderBottom:"1px solid #f0f4f8"}}>
      <div style={{display:"flex",alignItems:"center",gap:12}}>
        <span style={{fontSize:20}}>{icon}</span>
        <div>
          <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{label}</div>
          {desc&&<div style={{fontSize:11.5,color:"#8a9aaa",marginTop:1}}>{desc}</div>}
        </div>
      </div>
      <div style={{display:"flex",alignItems:"center",gap:10}}>
        <span style={{fontSize:12,color:val?"#4a9d8f":"#8a9aaa",fontWeight:600}}>{val?"Visible":"Oculto"}</span>
        <button onClick={onToggle} disabled={disabled} style={{width:52,height:28,borderRadius:14,background:val?"linear-gradient(135deg,#4a9d8f,#2a7a6a)":"#d4dde5",border:"none",cursor:disabled?"not-allowed":"pointer",position:"relative",transition:"all .2s",opacity:disabled?0.5:1,flexShrink:0}}>
          <div style={{position:"absolute",top:3,left:val?26:3,width:22,height:22,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 4px rgba(0,0,0,0.2)",transition:"left .2s"}}/>
        </button>
      </div>
    </div>
  );

  return(
    <div className="fade-in">
      <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:20,padding:"16px 20px",borderRadius:14,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff"}}>
        <div style={{fontSize:28}}>📊</div>
        <div>
          <div style={{fontWeight:800,fontSize:16}}>Configuración de KPIs</div>
          <div style={{fontSize:12,opacity:.7,marginTop:2}}>Activa o desactiva métricas para toda la organización o por usuario.</div>
        </div>
        {!isAdmin&&<div style={{marginLeft:"auto",padding:"6px 16px",borderRadius:20,background:"rgba(224,80,80,0.25)",border:"1.5px solid rgba(224,80,80,0.5)",color:"#ff9999",fontSize:11,fontWeight:700}}>🔒 Solo Admin</div>}
      </div>
      {/* View selector */}
      <div style={{display:"flex",gap:8,marginBottom:20}}>
        {[{id:"global",label:"🌐 KPIs Globales"},{id:"byUser",label:"👤 Por Usuario"}].map(v=>(
          <button key={v.id} onClick={()=>setKpiView(v.id)} style={{padding:"9px 18px",borderRadius:10,background:kpiView===v.id?"linear-gradient(135deg,#1a2332,#0f3a2a)":"#fff",color:kpiView===v.id?"#fff":"#5a7a8a",border:`1.5px solid ${kpiView===v.id?"#1a2332":"#e8edf2"}`,fontWeight:700,fontSize:13,cursor:"pointer",fontFamily:"inherit",transition:"all .2s"}}>{v.label}</button>
        ))}
      </div>
      {kpiView==="global"&&(
        <div>
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:8}}>
            <div style={{fontSize:13,color:"#5a7a8a"}}>
              <span style={{fontWeight:700,color:"#4a9d8f"}}>{activeCount}</span>/{SYSTEM_KPIS.length} KPIs visibles globalmente
            </div>
            {isAdmin&&(
              <div style={{display:"flex",gap:8}}>
                <button onClick={()=>toggleAllGlobal(true)} style={{padding:"7px 14px",borderRadius:8,background:"#4a9d8f22",color:"#2a7a6a",border:"1.5px solid #4a9d8f44",fontWeight:700,fontSize:12,cursor:"pointer",fontFamily:"inherit"}}>Activar todos</button>
                <button onClick={()=>toggleAllGlobal(false)} style={{padding:"7px 14px",borderRadius:8,background:"#dc262622",color:"#b91c1c",border:"1.5px solid #dc262644",fontWeight:700,fontSize:12,cursor:"pointer",fontFamily:"inherit"}}>Desactivar todos</button>
              </div>
            )}
          </div>
          <Card style={{padding:0,overflow:"hidden"}}>
            {SYSTEM_KPIS.map((k,i)=>(
              <TogItem key={k.id} id={k.id} label={k.label} icon={k.icon} desc={k.desc}
                val={globalKpi[k.id]!==false}
                onToggle={()=>toggleGlobal(k.id)}
                disabled={!isAdmin}
              />
            ))}
          </Card>
        </div>
      )}
      {kpiView==="byUser"&&(
        <div style={{display:"grid",gridTemplateColumns:"220px 1fr",gap:16}}>
          <div>
            <div style={{fontSize:11,fontWeight:700,color:"#8a9aaa",textTransform:"uppercase",letterSpacing:"0.06em",marginBottom:10}}>Seleccionar usuario</div>
            {(users||[]).map(u=>(
              <div key={u.id} onClick={()=>setSelUser(u.id)}
                style={{padding:"10px 12px",borderRadius:10,cursor:"pointer",marginBottom:4,background:selUser===u.id?"#4a9d8f15":"#fff",border:`1.5px solid ${selUser===u.id?"#4a9d8f66":"#e8edf2"}`,transition:"all .15s",display:"flex",alignItems:"center",gap:8}}>
                <div style={{width:30,height:30,borderRadius:"50%",background:selUser===u.id?"#4a9d8f22":"#f4f8fa",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:700,color:"#4a9d8f",flexShrink:0}}>{u.name[0]}</div>
                <div>
                  <div style={{fontSize:12.5,fontWeight:600,color:"#1a2332"}}>{u.name.split(" ")[0]}</div>
                  <div style={{fontSize:10.5,color:"#8a9aaa"}}>{Object.values(userKpis[u.id]||{}).filter(Boolean).length}/{SYSTEM_KPIS.length} activos</div>
                </div>
              </div>
            ))}
          </div>
          <div>
            {selUser&&(()=>{
              const u=users?.find(x=>x.id===selUser);
              const uKpi=userKpis[selUser]||Object.fromEntries(SYSTEM_KPIS.map(k=>[k.id,true]));
              return(
                <div>
                  <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:8}}>
                    <div style={{fontSize:13,color:"#5a7a8a"}}>KPIs de <strong style={{color:"#1a2332"}}>{u?.name}</strong></div>
                    {isAdmin&&(
                      <div style={{display:"flex",gap:8}}>
                        <button onClick={()=>toggleAllUserKpis(selUser,true)} style={{padding:"7px 14px",borderRadius:8,background:"#4a9d8f22",color:"#2a7a6a",border:"1.5px solid #4a9d8f44",fontWeight:700,fontSize:12,cursor:"pointer",fontFamily:"inherit"}}>Activar todos</button>
                        <button onClick={()=>toggleAllUserKpis(selUser,false)} style={{padding:"7px 14px",borderRadius:8,background:"#dc262622",color:"#b91c1c",border:"1.5px solid #dc262644",fontWeight:700,fontSize:12,cursor:"pointer",fontFamily:"inherit"}}>Desactivar todos</button>
                      </div>
                    )}
                  </div>
                  <Card style={{padding:0,overflow:"hidden"}}>
                    {SYSTEM_KPIS.map(k=>{
                      const globalOff=globalKpi[k.id]===false;
                      const userVal=uKpi[k.id]!==false;
                      return(
                        <div key={k.id} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"12px 16px",borderBottom:"1px solid #f0f4f8"}}>
                          <div style={{display:"flex",alignItems:"center",gap:12}}>
                            <span style={{fontSize:20}}>{k.icon}</span>
                            <div>
                              <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{k.label}</div>
                              {globalOff&&<div style={{fontSize:10.5,color:"#dc2626",background:"#dc262615",border:"1px solid #dc262633",borderRadius:4,padding:"1px 6px",display:"inline-block",marginTop:2,fontWeight:600}}>Desactivado globalmente</div>}
                            </div>
                          </div>
                          <div style={{display:"flex",alignItems:"center",gap:10}}>
                            <span style={{fontSize:12,color:userVal&&!globalOff?"#4a9d8f":"#8a9aaa",fontWeight:600}}>{userVal?"Visible":"Oculto"}</span>
                            <button onClick={()=>toggleUserKpi(selUser,k.id)} disabled={!isAdmin||globalOff} style={{width:52,height:28,borderRadius:14,background:userVal&&!globalOff?"linear-gradient(135deg,#4a9d8f,#2a7a6a)":"#d4dde5",border:"none",cursor:(!isAdmin||globalOff)?"not-allowed":"pointer",position:"relative",transition:"all .2s",opacity:(!isAdmin||globalOff)?0.5:1,flexShrink:0}}>
                              <div style={{position:"absolute",top:3,left:userVal?26:3,width:22,height:22,borderRadius:"50%",background:"#fff",boxShadow:"0 1px 4px rgba(0,0,0,0.2)",transition:"left .2s"}}/>
                            </button>
                          </div>
                        </div>
                      );
                    })}
                  </Card>
                </div>
              );
            })()}
          </div>
        </div>
      )}
    </div>
  );
};

const PermsTab=({currentUser})=>{
  const _isSA=currentUser?.role==="Super Admin";
  const ALL_MODULES=[
    {id:"dashboard",label:"🏠 Inicio"},{id:"admin",label:"🛡️ Panel Admin"},
    {id:"patients",label:"👥 Pacientes"},{id:"appointments",label:"📅 Agenda"},
    {id:"ventas",label:"🛒 Ventas"},{id:"suppliers",label:"🚚 Proveedores"},
    {id:"cashbox",label:"💰 Caja"},{id:"laboratory",label:"🔬 Laboratorio"},
    {id:"photos",label:"📷 Fotos"},{id:"inventory",label:"📦 Inventario"},
    {id:"commissions",label:"💹 Comisiones"},{id:"corte",label:"✂️ Corte"},
    {id:"reminders",label:"🔔 Recordatorios"},{id:"portal",label:"🌐 Portal"},
    {id:"library",label:"📚 Biblioteca"},{id:"documents",label:"📄 Documentos"},
    {id:"reports",label:"📊 Reportes"},{id:"config",label:"⚙️ Config"},
  ];
  const ADMIN_ONLY=["config"];
  const SA_ONLY_REACTIVATE=true; // Super Admin es el ÚNICO que puede reactivar módulos

  const roleDefaults={
    "Super Admin":ALL_MODULES.map(m=>m.id),
    Administrador:ALL_MODULES.map(m=>m.id),
    "Podólogo":["dashboard","patients","appointments","reports","laboratory","photos"],
    Recepcionista:["dashboard","patients","appointments","cashbox","reminders","portal"],
  };

  // Cargamos la BD de permisos desactivados (solo SA puede borrarlo)
  const saved=db.get(SK.modulePerms)||{};
  // "lockedOff" guarda los módulos que SA desactivó explícitamente — nadie más puede activarlos
  const savedLockedOff=db.get("pmb_module_locked_off")||{};

  const[rolePerms,setRolePerms]=useState({
    "Super Admin":saved["Super Admin"]||roleDefaults["Super Admin"],
    Administrador:saved.Administrador||roleDefaults.Administrador,
    "Podólogo":saved["Podólogo"]||roleDefaults["Podólogo"],
    Recepcionista:saved.Recepcionista||roleDefaults.Recepcionista,
  });
  // lockedOff: {Administrador: ["cashbox","inventory"], ...}
  const[lockedOff,setLockedOff]=useState(savedLockedOff);
  const[pending,setPending]=useState(false); // hay cambios sin guardar
  const[saving,setSaving]=useState(false);
  const[saveMsg,setSaveMsg]=useState("");
  const roleColors={"Super Admin":"#7c3aed",Administrador:"#e05050","Podólogo":"#2563eb",Recepcionista:"#2ea87e"};

  const togglePerm=(role,mod)=>{
    if(ADMIN_ONLY.includes(mod))return;
    if(role==="Super Admin")return;
    const cur=rolePerms[role]||[];
    const hasNow=cur.includes(mod);
    const isLockedOff=(lockedOff[role]||[]).includes(mod);

    // Si está en lockedOff (SA lo desactivó) y quien intenta reactivar NO es SA → bloquear
    if(!hasNow&&isLockedOff&&!_isSA){
      setSaveMsg("🔒 Este módulo fue desactivado por el Super Admin. Solo él puede reactivarlo.");
      setTimeout(()=>setSaveMsg(""),4000);
      return;
    }
    // Si no tiene el módulo y no está en lockedOff pero tampoco es SA → también bloquear reactivación
    if(!hasNow&&!isLockedOff&&!_isSA){
      setSaveMsg("🔒 Solo el Super Admin puede reactivar módulos desactivados.");
      setTimeout(()=>setSaveMsg(""),4000);
      return;
    }

    const newPerms=hasNow?cur.filter(x=>x!==mod):[...cur,mod];
    let newLockedOff={...lockedOff};
    if(_isSA){
      // SA desactiva → agregar a lockedOff para ese rol
      if(hasNow){
        newLockedOff[role]=[...new Set([...(newLockedOff[role]||[]),mod])];
      } else {
        // SA reactiva → quitar de lockedOff
        newLockedOff[role]=(newLockedOff[role]||[]).filter(x=>x!==mod);
      }
    }
    setRolePerms(p=>({...p,[role]:newPerms}));
    setLockedOff(newLockedOff);
    setPending(true);
    setSaveMsg("");
  };

  const savePerms=async()=>{
    setSaving(true);setSaveMsg("");
    try{
      // Persistir en servidor vía API
      await apiFetch('/special?action=module_perms',{
        method:'POST',
        body:JSON.stringify({perms:rolePerms,lockedOff})
      });
      db.set(SK.modulePerms,rolePerms);
      db.set("pmb_module_locked_off",lockedOff);
      localStorage.setItem('pmb_module_locked_off',JSON.stringify(lockedOff));
      localStorage.setItem('pmb_module_perms',JSON.stringify(rolePerms));
      _cache['pmb_module_locked_off']=lockedOff;
      _cache['pmb_module_perms']=rolePerms;
      _cache[SK.modulePerms]=rolePerms;
      setPending(false);
      setSaveMsg("✅ Permisos guardados correctamente en la base de datos.");
    }catch(e){
      setSaveMsg("No se guardó en la base de datos: "+(e.message||e));
    }
    setSaving(false);
    setTimeout(()=>setSaveMsg(""),4000);
  };

  return(
    <div className="fade-in">
      {/* HEADER con info + botón guardar */}
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:16,flexWrap:"wrap",gap:10}}>
        <div>
          <div style={{fontSize:13,fontWeight:700,color:"#1a2332",marginBottom:3}}>Control de Módulos por Rol</div>
          <div style={{fontSize:12,color:"#5a7a8a"}}>
            El <strong>Super Admin</strong> es el único que puede desactivar y reactivar módulos del <strong>Administrador</strong>.
            Los cambios no aplican hasta guardar.
          </div>
        </div>
        <button onClick={savePerms} disabled={!pending||saving}
          style={{display:"flex",alignItems:"center",gap:7,padding:"9px 20px",borderRadius:10,border:"none",
            background:pending?"linear-gradient(135deg,#4a9d8f,#3a8d80)":"#e8edf2",
            color:pending?"#fff":"#8a9aaa",fontWeight:700,fontSize:13,cursor:pending?"pointer":"not-allowed",
            fontFamily:"'Outfit',sans-serif",transition:"all .2s",flexShrink:0}}>
          {saving
            ?<><span style={{animation:"spin 1s linear infinite",display:"inline-block"}}>⏳</span>Guardando...</>
            :<><Icon name="check" size={14}/>{pending?"Guardar Cambios":"Sin cambios"}</>
          }
        </button>
      </div>

      {/* Mensaje de estado */}
      {saveMsg&&(
        <div className="pop-in" style={{
          background:saveMsg.startsWith("✅")?"#f0faf5":"#fff3cd",
          border:`1px solid ${saveMsg.startsWith("✅")?"#4a9d8f44":"#ffc10755"}`,
          borderRadius:10,padding:"10px 16px",fontSize:13,marginBottom:14,
          color:saveMsg.startsWith("✅")?"#1a6a4a":"#856404",fontWeight:500
        }}>{saveMsg}</div>
      )}

      {/* Leyenda de colores */}
      <div style={{display:"flex",gap:12,flexWrap:"wrap",marginBottom:16}}>
        <div style={{display:"flex",alignItems:"center",gap:5,fontSize:11,color:"#5a7a8a"}}>
          <div style={{width:12,height:12,borderRadius:3,background:"#4a9d8f"}}/>Activo
        </div>
        <div style={{display:"flex",alignItems:"center",gap:5,fontSize:11,color:"#5a7a8a"}}>
          <div style={{width:12,height:12,borderRadius:3,background:"#e8edf2",border:"1px solid #d4dde5"}}/>Inactivo
        </div>
        <div style={{display:"flex",alignItems:"center",gap:5,fontSize:11,color:"#5a7a8a"}}>
          <div style={{width:12,height:12,borderRadius:3,background:"#fee2e2",border:"1px solid #f5b0b0"}}/>🔒 Bloqueado por Super Admin
        </div>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(320px,1fr))",gap:16}}>
        {Object.entries(rolePerms).map(([role,perms])=>(
          <Card key={role} style={{border:`2px solid ${roleColors[role]||"#d4dde5"}33`}}>
            <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:14}}>
              <Badge color={role==="Super Admin"?"purple":role==="Administrador"?"red":role==="Podólogo"?"blue":"green"}>{role}</Badge>
              <span style={{fontSize:12,color:"#8a9aaa"}}>{perms.length} activos</span>
              {role==="Super Admin"&&<span style={{fontSize:11,color:"#7c3aed",fontWeight:600}}>👑 inmutable</span>}
              {role!=="Super Admin"&&_isSA&&<span style={{fontSize:10,color:"#7c3aed",marginLeft:"auto"}}>editable</span>}
              {role==="Administrador"&&!_isSA&&<span style={{fontSize:10,color:"#e05050",marginLeft:"auto"}}>solo lectura</span>}
            </div>
            <div style={{display:"flex",flexWrap:"wrap",gap:5}}>
              {ALL_MODULES.map(m=>{
                const has=perms.includes(m.id);
                const isAdminOnly=ADMIN_ONLY.includes(m.id);
                const isSARow=role==="Super Admin";
                const isLocked=(lockedOff[role]||[]).includes(m.id);
                // Bloquear toggle para Admin si el que mira es Administrador (no SA)
                const adminRowBlockedForAdmin=(role==="Administrador"&&!_isSA);
                const canToggle=!isAdminOnly&&!isSARow&&!adminRowBlockedForAdmin;
                // Estilo especial para módulos bloqueados por SA
                const bg=has?(roleColors[role]||"#4a9d8f")+"18":isLocked?"#fee2e2":"#f8fafc";
                const borderColor=has?(roleColors[role]||"#4a9d8f"):isLocked?"#f5b0b0":"#d4dde5";
                const textColor=has?(roleColors[role]||"#4a9d8f"):isLocked?"#c03030":"#8a9aaa";
                return(
                  <button key={m.id} onClick={()=>canToggle&&togglePerm(role,m.id)}
                    style={{padding:"4px 10px",borderRadius:20,
                      border:`1.5px solid ${borderColor}`,background:bg,color:textColor,
                      fontSize:11,fontWeight:600,
                      cursor:canToggle?"pointer":"not-allowed",
                      opacity:isAdminOnly?0.4:1,
                      position:"relative"}}
                    title={
                      isAdminOnly?"Solo Super Admin":
                      isSARow?"👑 Inmutable":
                      isLocked&&!_isSA?"🔒 Bloqueado por Super Admin":
                      adminRowBlockedForAdmin?"🔒 Solo Super Admin puede cambiar permisos del Administrador":
                      has?"Clic para desactivar":"Clic para activar"
                    }
                  >
                    {isLocked&&!has&&"🔒 "}{m.label}
                  </button>
                );
              })}
            </div>
          </Card>
        ))}
      </div>

      {pending&&(
        <div style={{marginTop:20,padding:"12px 16px",background:"#fff3cd",border:"1px solid #ffc10755",
          borderRadius:10,fontSize:12.5,color:"#856404",display:"flex",alignItems:"center",gap:8}}>
          ⚠️ Tienes cambios sin guardar. Haz clic en <strong>Guardar Cambios</strong> para aplicarlos.
        </div>
      )}
    </div>
  );
};

const ConfigModule=({currentUser})=>{
  const[tab,setTab]=useState("empresa");
  const[savedDataDir,setSavedDataDir]=useState("");
  const[memberships,setMemberships]=useState(db.get(SK.memberships)||[]);
  const[mModal,setMModal]=useState(false);const[editM,setEditM]=useState(null);
  const[mF,setMF]=useState({name:"",monthlyFee:"",annualFee:"",benefits:"",discountPct:""});
  useEffect(()=>{setSavedDataDir('(Datos en MySQL - cPanel)');},[]);
  const[users,setUsers]=useState(()=>{ const c=db.get(SK.users); return (Array.isArray(c)&&c.length>0)?c:[]; });
  const[services,setServices]=useState(db.get(SK.services)||DEF_SERVICES);
  const[categories,setCategories]=useState(db.get(SK.categories)||DEF_CATEGORIES);
  const[company,setCompany]=useState(db.get(SK.company)||{name:"Podología Más Bela",logo:null,address:"",phone:"",email:"",currency:"S/",currencyCode:"PEN"});
  const[usersLoading,setUsersLoading]=useState(true);
  // Cargar datos frescos desde API al abrir Configuración
  useEffect(()=>{
    setUsersLoading(true);
    apiFetch('/crud?entity=users&limit=500')
      .then(r=>{
        const rows=Array.isArray(r)?r:(r.data||[]);
        setUsers(rows);
        if(rows.length>0){_cache['users']=rows;_cache[SK.users]=rows;}
      })
      .catch(()=>{})
      .finally(()=>setUsersLoading(false));
    api.get('services').then(rows=>{if(Array.isArray(rows)&&rows.length>0)setServices(rows);}).catch(()=>{});
    api.get('categories').then(rows=>{if(Array.isArray(rows)&&rows.length>0)setCategories(rows);}).catch(()=>{});
    apiFetch('/special?action=company').then(d=>{if(d&&d.name)setCompany({...d,currencyCode:d.currencyCode||d.currency_code||"PEN",aiApiKey:d.aiApiKey||d.ai_api_key||""});}).catch(()=>{});
  },[]);
  const[uModal,setUModal]=useState(false);const[sModal,setSModal]=useState(false);
  const[pwdModal,setPwdModal]=useState(false);const[pwdUser,setPwdUser]=useState(null);
  const[pwdF,setPwdF]=useState({pwd:'',pwd2:''});const[pwdErr,setPwdErr]=useState('');
  const changePwd=async()=>{
    if(!pwdF.pwd||pwdF.pwd.length<4){setPwdErr('Minimo 4 caracteres');return;}
    if(pwdF.pwd!==pwdF.pwd2){setPwdErr('Las contrasenas no coinciden');return;}
    try{
      await apiFetch('/crud?entity=users&id='+pwdUser.id,{method:'PUT',body:JSON.stringify({password:pwdF.pwd})});
      setPwdModal(false);setPwdUser(null);setPwdF({pwd:'',pwd2:''});setPwdErr('');
      alert('Contrasena actualizada para '+pwdUser.name);
      reloadUsers();
    }catch(e){setPwdErr('Error: '+e.message);}
  };
  const[catModal,setCatModal]=useState(false);const[editCat,setEditCat]=useState(null);
  const[editUser,setEditUser]=useState(null);
  const[uF,setUF]=useState({username:"",password:"",name:"",dni:"",address:"",cellphone:"",email:"",role:"Recepcionista",active:true,podoFunctions:[]});
  const[sF,setSF]=useState({name:"",price:"",duration:"",category:"",active:true,code:"",description:""});
  const[catF,setCatF]=useState({name:"",color:"#4a9d8f",type:"service"});
  const logoRef=useRef();

  const CURRENCIES=[
    {code:"PEN",symbol:"S/",name:"Sol Peruano"},
    {code:"USD",symbol:"$",name:"Dólar Americano"},
    {code:"EUR",symbol:"€",name:"Euro"},
    {code:"COP",symbol:"$",name:"Peso Colombiano"},
    {code:"MXN",symbol:"$",name:"Peso Mexicano"},
    {code:"CLP",symbol:"$",name:"Peso Chileno"},
    {code:"ARS",symbol:"$",name:"Peso Argentino"},
    {code:"BRL",symbol:"R$",name:"Real Brasileño"},
  ];

  const saveCompany=async()=>{
    try{
      const saved=await apiFetch('/special?action=company',{method:'PUT',body:JSON.stringify(serverPayload('company',company))});
      if(saved&&saved.name){db.set(SK.company,{...company,...saved});setCompany(c=>({...c,...saved}));}
      alert("✅ Datos de empresa guardados en la base de datos");
    }catch(e){alert("No se pudo guardar empresa en la base de datos: "+e.message);}
  };
  const saveDataDir=async()=>{
    if(!savedDataDir.trim()){alert("Ingrese una ruta válida");return}
    try{
      alert("ℹ️ En la versión web (cPanel), los datos se almacenan en MySQL.\nNo es necesario configurar carpeta de datos.");
    }catch(e){alert("Error al guardar: "+e.message)}
  };
  const handleLogo=e=>{const f=e.target.files[0];if(!f)return;const rd=new FileReader();rd.onload=()=>setCompany(p=>({...p,logo:rd.result}));rd.readAsDataURL(f)};
  const removeLogo=()=>setCompany(p=>({...p,logo:null}));

  const reloadUsers=()=>{
    apiFetch('/crud?entity=users&limit=500').then(r=>{
      const rows=Array.isArray(r)?r:(r.data||[]);
      setUsers(rows);_cache[SK.users]=rows;_cache['users']=rows;
    }).catch(()=>{});
  };
  const saveU=async()=>{
    if(!uF.username||!uF.name){alert("Complete nombre y usuario");return}
    if(!editUser&&!uF.password){alert("Ingrese contraseña para el nuevo usuario");return}
    try{
      if(editUser){
        const body={...uF};
        if(!uF.password)delete body.password;
        await apiFetch('/crud?entity=users&id='+editUser.id,{method:'PUT',body:JSON.stringify(body)});
      }else{
        await apiFetch('/crud?entity=users',{method:'POST',body:JSON.stringify(uF)});
      }
      setUModal(false);setEditUser(null);
      setUF({username:"",password:"",name:"",dni:"",address:"",cellphone:"",email:"",role:"Recepcionista",active:true,podoFunctions:[]});
      reloadUsers();
    }catch(e){alert("Error al guardar usuario: "+e.message);}
  };
  const openEditUser=u=>{setEditUser(u);setUF({...u,password:""});setUModal(true)};
  const delUser=async(id)=>{
    const target=users.find(u=>u.id===id);
    if(target?.role==="Super Admin"){alert("No se puede eliminar al Super Admin.");return;}
    if(!isSA(currentUser)&&target?.role==="Administrador"){alert("Solo un Super Admin puede eliminar un Administrador.");return;}
    if(window.confirm("¿Eliminar usuario?")){
      try{
        await apiFetch('/crud?entity=users&id='+id,{method:'DELETE',body:JSON.stringify({id})});
        reloadUsers();
      }catch(e){alert("Error al eliminar: "+e.message);}
    }
  };
  const saveS=async()=>{
    if(!sF.name||!sF.price){alert("Complete nombre y precio");return}
    const tempId=genId(services);
    const local={...sF,id:tempId,price:parseFloat(sF.price),duration:parseInt(sF.duration)||30};
    try{
      await saveCrudAndSync('services',local,SK.services,setServices,tempId);
      setSModal(false);setSF({name:"",price:"",duration:"",category:"",active:true,code:"",description:""});
      alert("✅ Servicio guardado en la base de datos");
    }catch(e){alert("No se guardó el servicio en la base de datos: "+e.message);}
  };
  const togU=async(id)=>{
    const u=users.find(x=>x.id===id);if(!u)return;
    try{
      await apiFetch('/crud?entity=users&id='+id,{method:'PUT',body:JSON.stringify({active:u.active?0:1})});
      reloadUsers();
    }catch(e){alert("Error: "+e.message);}
  };
  const togS=async id=>{
    const row=services.find(s=>s.id===id);if(!row)return;
    const nextRow={...row,active:!row.active};
    try{
      const saved=await crudApi.update('services',id,serverPayload('services',nextRow));
      const all=services.map(s=>s.id===id?{...nextRow,...saved}:s);
      setServices(all);db.set(SK.services,all);
    }catch(e){alert("No se guardó el cambio del servicio en la base de datos: "+e.message);}
  };
  const delS=id=>{if(window.confirm("¿Eliminar servicio?"))removeCrudAndSync('services',id,SK.services,setServices).catch(e=>alert("No se pudo eliminar en la base de datos: "+e.message))};
  const savePodoFns=async(userId,fns)=>{
    try{
      await apiFetch('/crud?entity=users&id='+userId,{method:'PUT',body:JSON.stringify({podoFunctions:fns})});
      reloadUsers();
    }catch(e){alert("Error al guardar permisos: "+e.message);}
  };

  const saveCat=async()=>{
    if(!catF.name){alert("Ingrese nombre");return}
    try{
      if(editCat){
        const saved=await crudApi.update('categories',editCat.id,serverPayload('categories',{...editCat,...catF}));
        const all=categories.map(c=>c.id===editCat.id?{...c,...catF,...saved}:c);
        setCategories(all);db.set(SK.categories,all);
      }else{
        const tempId=genId(categories);
        const local={...catF,id:tempId};
        await saveCrudAndSync('categories',local,SK.categories,setCategories,tempId);
      }
      setCatModal(false);setEditCat(null);setCatF({name:"",color:"#4a9d8f",type:"service"});
      alert("✅ Categoría guardada en la base de datos");
    }catch(e){alert("No se guardó la categoría en la base de datos: "+e.message);}
  };
  const delCat=id=>{if(window.confirm("¿Eliminar categoría?"))removeCrudAndSync('categories',id,SK.categories,setCategories).catch(e=>alert("No se pudo eliminar la categoría en la base de datos: "+e.message))};
  const openEditCat=c=>{setEditCat(c);setCatF({name:c.name,color:c.color,type:c.type});setCatModal(true)};
  const saveMembership=async()=>{
    if(!mF.name.trim()){alert("Ingrese nombre");return}
    const local={...mF,id:editM?.id||genId(memberships),monthlyFee:parseFloat(mF.monthlyFee||0)||0,annualFee:parseFloat(mF.annualFee||0)||0,discountPct:parseFloat(mF.discountPct||0)||0};
    try{
      await saveCrudAndSync('memberships',local,SK.memberships,setMemberships,editM?undefined:local.id);
      setMModal(false);setEditM(null);
      setMF({name:"",monthlyFee:"",annualFee:"",benefits:"",discountPct:""});
      alert("✅ Membresía guardada en la base de datos");
    }catch(e){alert("No se guardó la membresía en la base de datos: "+e.message);}
  };
  const delMembership=id=>{if(window.confirm("¿Eliminar membresía?"))removeCrudAndSync('memberships',id,SK.memberships,setMemberships).catch(e=>alert("No se pudo eliminar la membresía en la base de datos: "+e.message));};

  const roleColors={"Super Admin":"purple",Administrador:"red",Podólogo:"blue",Recepcionista:"green"};
  const podologas=users.filter(u=>u.role==="Podólogo");

  return(
    <div className="slide-in">
      <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em",marginBottom:18}}>Configuración</h2>
      <Tabs tabs={[
        {id:"empresa",label:"🏢 Empresa"},
        {id:"users",label:"👥 Usuarios & Roles"},
        {id:"podologas",label:"🩺 Podólogas"},
        {id:"services",label:"🏥 Servicios"},
        {id:"categories",label:"🎨 Categorías"},
        {id:"memberships",label:"⭐ Membresías"},
        {id:"currency",label:"💱 Moneda"},
        {id:"perms",label:"🛡️ Permisos"},
        {id:"licencias",label:"🔑 Licencias"},
        {id:"kpis",label:"📊 KPIs"},
        {id:"integraciones",label:"🔌 Integraciones"},
        {id:"avanzado",label:"⚙️ Avanzado"},
      ]} active={tab} onChange={setTab}/>

      {tab==="empresa"&&(
        <div className="fade-in">
          <div style={{display:"grid",gridTemplateColumns:"auto 1fr",gap:32,alignItems:"start"}}>
            <div style={{textAlign:"center"}}>
              <div style={{width:130,height:130,borderRadius:16,border:"2px dashed #d4dde5",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",background:"#f8fafc",marginBottom:10,position:"relative"}}>
                {company.logo
                  ?<img src={company.logo} alt="logo" style={{width:"100%",height:"100%",objectFit:"contain"}}/>
                  :<div style={{textAlign:"center",color:"#9aacb8"}}><div style={{fontSize:32}}>🏥</div><div style={{fontSize:11}}>Sin logo</div></div>
                }
              </div>
              <input ref={logoRef} type="file" accept="image/*" onChange={handleLogo} style={{display:"none"}}/>
              <div style={{display:"flex",gap:6,justifyContent:"center",flexWrap:"wrap"}}>
                <Btn size="sm" variant="ghost" onClick={()=>logoRef.current.click()}><Icon name="image" size={12}/>Subir Logo</Btn>
                {company.logo&&<Btn size="sm" variant="danger" onClick={removeLogo}><Icon name="trash" size={12}/></Btn>}
              </div>
              <div style={{fontSize:10.5,color:"#9aacb8",marginTop:6}}>PNG, JPG — max 2MB</div>
            </div>
            <div>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 18px"}}>
                <Field label="Nombre de la Empresa" required col="1/-1"><Inp value={company.name} onChange={e=>setCompany(p=>({...p,name:e.target.value}))}/></Field>
                <Field label="Dirección"><Inp value={company.address||""} onChange={e=>setCompany(p=>({...p,address:e.target.value}))} placeholder="Av. Principal 123, Ciudad"/></Field>
                <Field label="Teléfono"><Inp value={company.phone||""} onChange={e=>setCompany(p=>({...p,phone:e.target.value}))} placeholder="+51 999 000 000"/></Field>
                <Field label="Correo Electrónico" col="1/-1"><Inp value={company.email||""} onChange={e=>setCompany(p=>({...p,email:e.target.value}))} placeholder="contacto@empresa.com"/></Field>
              </div>
              <div style={{display:"flex",justifyContent:"flex-end",marginTop:8}}>
                <Btn onClick={saveCompany}><Icon name="check" size={13}/>Guardar Empresa</Btn>
              </div>
              <Field label="🤖 Clave API Claude (Asistente IA)" col="1/-1">
                <div style={{display:"flex",gap:8}}>
                  <Inp type="password" value={company.aiApiKey||""} onChange={e=>setCompany(p=>({...p,aiApiKey:e.target.value}))} placeholder="sk-ant-api..."/>
                  <a href="https://console.anthropic.com" target="_blank" rel="noopener noreferrer" style={{display:"flex",alignItems:"center",padding:"0 10px",background:"#f0f4f8",border:"1px solid #d4dde5",borderRadius:8,fontSize:11.5,color:"#4a9d8f",fontWeight:700,textDecoration:"none",whiteSpace:"nowrap"}}>Obtener clave →</a>
                </div>
                <div style={{fontSize:10.5,color:"#8a9aaa",marginTop:4}}>Necesaria para el Asistente IA en historias clínicas</div>
              </Field>
              <div style={{display:"none"}}>
              </div>
            </div>
          </div>
        <Card style={{marginTop:14,border:"2px solid #4a9d8f33"}}>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:12}}>🗂️ Carpeta de Datos (Almacenamiento)</div>
          <div style={{fontSize:12.5,color:"#5a7a8a",marginBottom:12,background:"#f0f9f7",borderRadius:8,padding:"10px 14px"}}>
            Los datos se guardan automáticamente en esta carpeta del computador. Ejemplo: <code style={{fontFamily:"monospace",background:"#e0f0ec",padding:"2px 6px",borderRadius:4}}>C:\podibela</code>
          </div>
          <div style={{display:"flex",gap:10,alignItems:"flex-end"}}>
            <Field label="Ruta de la carpeta de datos" style={{flex:1,marginBottom:0}}>
              <Inp value={savedDataDir} onChange={e=>setSavedDataDir(e.target.value)} placeholder="C:\podibela  o  /home/usuario/podibela"/>
            </Field>
            <Btn onClick={saveDataDir} style={{flexShrink:0,marginBottom:14}}><Icon name="check" size={13}/>Guardar Ruta</Btn>
          </div>
          <div style={{fontSize:11,color:"#8a9aaa",marginTop:6}}>💡 Después de cambiar la ruta, el servidor se reiniciará con la nueva ubicación.</div>
        </Card>

          {company.logo&&(
            <Card style={{marginTop:20,background:"#f8fafc",border:"1px solid #eef2f7"}}>
              <div style={{fontSize:12,fontWeight:700,color:"#5a7a8a",marginBottom:8}}>Vista previa del logo en documentos</div>
              <div style={{display:"flex",alignItems:"center",gap:12,background:"#fff",borderRadius:10,padding:"12px 16px",border:"1px solid #e8edf2"}}>
                <img src={company.logo} alt="logo" style={{height:44,objectFit:"contain"}}/>
                <div>
                  <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{company.name}</div>
                  {company.address&&<div style={{fontSize:11.5,color:"#8a9aaa"}}>{company.address}</div>}
                  {company.phone&&<div style={{fontSize:11.5,color:"#8a9aaa"}}>{company.phone}</div>}
                </div>
              </div>
            </Card>
          )}
        </div>
      )}

      {tab==="users"&&(
        <div>
          {isSA(currentUser)&&(
            <div style={{background:"linear-gradient(135deg,#7c3aed15,#5b21b610)",border:"1.5px solid #7c3aed44",borderRadius:12,padding:"12px 18px",marginBottom:14,display:"flex",alignItems:"center",gap:10,fontSize:13}}>
              <span style={{fontSize:20}}>👑</span>
              <div><strong style={{color:"#7c3aed"}}>Modo Super Admin activo</strong><span style={{color:"#5a7a8a",marginLeft:8}}>Puedes editar, modificar y eliminar cualquier usuario y sus permisos.</span></div>
            </div>
          )}
          <div style={{display:"flex",justifyContent:"flex-end",marginBottom:12}}><Btn onClick={()=>{setEditUser(null);setUF({username:"",password:"",name:"",dni:"",address:"",cellphone:"",email:"",role:"Recepcionista",active:true,podoFunctions:[]});setUModal(true)}}><Icon name="plus" size={13}/>Nuevo Usuario</Btn></div>
          <Card style={{padding:0,overflow:"hidden"}}>
            {usersLoading&&<div style={{padding:"24px",textAlign:"center",color:"#8a9aaa",fontSize:13}}>⏳ Cargando usuarios...</div>}
            {!usersLoading&&users.length===0&&<div style={{padding:"24px",textAlign:"center",color:"#e05050",fontSize:13}}>⚠️ No hay usuarios en la base de datos. Importe el SQL desde phpMyAdmin.</div>}
            <div style={{overflowX:"auto",display:usersLoading||users.length===0?"none":"block"}}>
              <table style={{width:"100%",borderCollapse:"collapse"}}>
                <thead><tr style={{background:"#f4f8fa"}}>{["Nombre","DNI","Usuario","Celular","Rol","Estado","Acción"].map(h=><th key={h} style={{padding:"10px 14px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em"}}>{h}</th>)}</tr></thead>
                <tbody>
                  {users.map((u,i)=>{
                    const canEdit=isSA(currentUser)||(u.role!=="Super Admin"&&u.role!=="Administrador")||currentUser?.role==="Administrador";
                    const canDel=isSA(currentUser)&&u.role!=="Super Admin";
                    return(
                    <tr key={u.id} style={{borderTop:"1px solid #f0f4f8",background:u.role==="Super Admin"?"#7c3aed08":i%2?"#fafcfd":"#fff"}}>
                      <td style={{padding:"10px 14px"}}>
                        <div style={{fontWeight:600,fontSize:13.5,display:"flex",alignItems:"center",gap:6}}>
                          {u.role==="Super Admin"&&<span title="Super Admin" style={{fontSize:14}}>👑</span>}
                          {u.name}
                        </div>
                        {u.email&&<div style={{fontSize:11,color:"#8a9aaa"}}>{u.email}</div>}
                      </td>
                      <td style={{padding:"10px 14px",fontSize:13,color:"#3a5a6a"}}>{u.dni||"—"}</td>
                      <td style={{padding:"10px 14px",fontSize:13,color:"#4a9d8f",fontFamily:"monospace"}}>{u.username}</td>
                      <td style={{padding:"10px 14px",fontSize:13}}>{u.cellphone||"—"}</td>
                      <td style={{padding:"10px 14px"}}><Badge color={roleColors[u.role]||"gray"}>{u.role}</Badge></td>
                      <td style={{padding:"10px 14px"}}><Badge color={u.active?"green":"gray"}>{u.active?"Activo":"Inactivo"}</Badge></td>
                      <td style={{padding:"10px 14px"}}>
                        <div style={{display:"flex",gap:4}}>
                          <Btn size="sm" variant="ghost" onClick={()=>{if(!canEdit&&!isSA(currentUser)){alert("No tienes permisos para editar este usuario.");return;}openEditUser(u)}} title={!canEdit?"Solo Super Admin puede editar este rol":""} style={{opacity:(!canEdit&&!isSA(currentUser))?0.4:1}}><Icon name="edit" size={11}/></Btn>
                          <Btn size="sm" variant="ghost" title="Cambiar contrasena" onClick={()=>{setPwdUser(u);setPwdF({pwd:'',pwd2:''});setPwdErr('');setPwdModal(true);}}>🔑</Btn>
                          <Btn size="sm" variant={u.active?"secondary":"success"} onClick={()=>{if(u.role==="Super Admin"&&!isSA(currentUser)){alert("No puedes desactivar al Super Admin.");return;}togU(u.id)}}>{u.active?"Desact.":"Activar"}</Btn>
                          {canDel&&<Btn size="sm" variant="danger" onClick={()=>delUser(u.id)}><Icon name="trash" size={11}/></Btn>}
                        </div>
                      </td>
                    </tr>
                  )})}
                </tbody>
              </table>
            </div>
          </Card>
          {pwdModal&&pwdUser&&(
            <Modal title={"Cambiar Contrasena: "+pwdUser.name} onClose={()=>{setPwdModal(false);setPwdUser(null)}} width={400}>
              <div style={{marginBottom:14,padding:"10px 14px",background:"#f0f4f8",borderRadius:8,fontSize:13,color:"#3a5a6a"}}>
                Usuario: <strong>{pwdUser.username}</strong> &nbsp;|&nbsp; Rol: <strong>{pwdUser.role}</strong>
              </div>
              <Field label="Nueva Contrasena" required>
                <Inp type="password" value={pwdF.pwd} onChange={e=>setPwdF(p=>({...p,pwd:e.target.value}))} placeholder="Minimo 4 caracteres" autoFocus/>
              </Field>
              <Field label="Confirmar Contrasena" required>
                <Inp type="password" value={pwdF.pwd2} onChange={e=>setPwdF(p=>({...p,pwd2:e.target.value}))} placeholder="Repite la contrasena"
                  onKeyDown={e=>e.key==="Enter"&&changePwd()}/>
              </Field>
              {pwdErr&&<div style={{color:"#e05050",fontSize:12.5,marginTop:-6,marginBottom:8}}>⚠ {pwdErr}</div>}
              <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:16}}>
                <Btn variant="secondary" onClick={()=>{setPwdModal(false);setPwdUser(null);}}>Cancelar</Btn>
                <Btn onClick={changePwd}><Icon name="check" size={13}/>Guardar Contrasena</Btn>
              </div>
            </Modal>
          )}
          {uModal&&(
            <Modal title={editUser?"Editar Usuario":"Nuevo Usuario"} onClose={()=>{setUModal(false);setEditUser(null)}} width={560}>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
                <Field label="Nombre Completo" required col="1/-1"><Inp value={uF.name} onChange={e=>setUF(p=>({...p,name:e.target.value}))}/></Field>
                <Field label="DNI"><Inp value={uF.dni||""} onChange={e=>setUF(p=>({...p,dni:e.target.value.replace(/[^0-9]/g,"").slice(0,8)}))} maxLength={8} placeholder="00000000"/></Field>
                <Field label="Nro. Celular"><Inp value={uF.cellphone||""} onChange={e=>setUF(p=>({...p,cellphone:e.target.value}))} placeholder="+51 999 000 000"/></Field>
                <Field label="Correo Electrónico" col="1/-1"><Inp value={uF.email||""} onChange={e=>setUF(p=>({...p,email:e.target.value}))} placeholder="correo@ejemplo.com"/></Field>
                <Field label="Dirección" col="1/-1"><Inp value={uF.address||""} onChange={e=>setUF(p=>({...p,address:e.target.value}))} placeholder="Av. Principal 123"/></Field>
                <Field label="Usuario" required><Inp value={uF.username} onChange={e=>setUF(p=>({...p,username:e.target.value}))}/></Field>
                <Field label={editUser?"Nueva Contraseña":"Contraseña *"}><Inp type="password" value={uF.password||""} onChange={e=>setUF(p=>({...p,password:e.target.value}))}/></Field>
              </div>
              <Field label="Rol">
                <Sel value={uF.role} onChange={e=>setUF(p=>({...p,role:e.target.value}))}>
                  {Object.keys(ROLES).filter(r=>isSA(currentUser)||r!=="Super Admin").map(r=><option key={r}>{r}</option>)}
                </Sel>
              </Field>
              {uF.role==="Podólogo"&&(
                <Field label="Funciones Asignadas">
                  <div style={{display:"flex",gap:5,flexWrap:"wrap",marginTop:2}}>
                    {PODO_FUNCTIONS.map(fn=>(
                      <button key={fn} onClick={()=>setUF(p=>({...p,podoFunctions:p.podoFunctions.includes(fn)?p.podoFunctions.filter(x=>x!==fn):[...p.podoFunctions,fn]}))} style={{padding:"4px 11px",borderRadius:20,border:`1.5px solid ${uF.podoFunctions.includes(fn)?"#4a9d8f":"#d4dde5"}`,background:uF.podoFunctions.includes(fn)?"#4a9d8f":"#fff",color:uF.podoFunctions.includes(fn)?"#fff":"#5a7a8a",fontSize:11,fontWeight:600,cursor:"pointer"}}>{fn}</button>
                    ))}
                  </div>
                </Field>
              )}
              {/* Super Admin: editar permisos granulares por usuario */}
              {isSA(currentUser)&&uF.role!=="Super Admin"&&(
                <div style={{marginTop:14,background:"#f8f4ff",borderRadius:10,padding:"14px 16px",border:"1.5px solid #7c3aed22"}}>
                  <div style={{fontWeight:700,fontSize:13,color:"#5b21b6",marginBottom:10}}>👑 Permisos Individuales (Super Admin)</div>
                  <div style={{display:"flex",flexWrap:"wrap",gap:5}}>
                    {SYSTEM_TOOLS.map(t=>{
                      const defPerms=ROLES[uF.role]?.perms||[];
                      const saved=db.get(SK.modulePerms)||{};
                      const roleP=saved[uF.role]||defPerms;
                      const hasP=roleP.includes(t.id);
                      return(
                        <button key={t.id}
                          onClick={()=>{
                            const cur=db.get(SK.modulePerms)||{};
                            const rp=cur[uF.role]||(ROLES[uF.role]?.perms||[]);
                            const next=rp.includes(t.id)?rp.filter(x=>x!==t.id):[...rp,t.id];
                            const updated={...cur,[uF.role]:next};
                            db.set(SK.modulePerms,updated);
                            // Force re-render
                            setUF(p=>({...p,_ts:Date.now()}));
                          }}
                          style={{padding:"3px 9px",borderRadius:20,border:`1.5px solid ${hasP?"#7c3aed":"#d4dde5"}`,background:hasP?"#7c3aed22":"#fff",color:hasP?"#7c3aed":"#8a9aaa",fontSize:11,fontWeight:600,cursor:"pointer",transition:"all .15s"}}>
                          {t.icon} {t.label}
                        </button>
                      );
                    })}
                  </div>
                  <div style={{fontSize:11,color:"#8a9aaa",marginTop:8}}>💡 Los cambios de permisos aplican al rol completo, no solo a este usuario.</div>
                </div>
              )}
              <div style={{background:"#f4f9f7",borderRadius:8,padding:"10px 14px",marginTop:4,fontSize:12,color:"#3a7a6a"}}>
                <b>Accesos del rol:</b> {(ROLES[uF.role]?.perms||[]).join(", ")}
              </div>
              <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:16}}><Btn variant="secondary" onClick={()=>{setUModal(false);setEditUser(null)}}>Cancelar</Btn><Btn onClick={saveU}><Icon name="check" size={13}/>Guardar</Btn></div>
            </Modal>
          )}
        </div>
      )}

      {tab==="podologas"&&(
        <div>
          <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:16}}>Configure las funciones que puede realizar cada podóloga.</div>
          {podologas.length===0?(
            <Card style={{textAlign:"center",padding:40}}>
              <div style={{fontSize:36,marginBottom:10}}>🩺</div>
              <div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin podólogas registradas</div>
              <Btn onClick={()=>setTab("users")} variant="ghost">Ir a Usuarios →</Btn>
            </Card>
          ):(
            <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(320px,1fr))",gap:14}}>
              {podologas.map(u=>(
                <Card key={u.id} style={{border:"2px solid #4a9d8f22"}}>
                  <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:14}}>
                    <div style={{width:44,height:44,borderRadius:"50%",background:"#4a9d8f22",border:"2px solid #4a9d8f55",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,fontWeight:700,color:"#4a9d8f"}}>{u.name[0]}</div>
                    <div>
                      <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{u.name}</div>
                      <div style={{fontSize:11,color:"#8a9aaa",display:"flex",gap:5,alignItems:"center"}}>@{u.username} · <Badge color={u.active?"green":"gray"}>{u.active?"Activa":"Inactiva"}</Badge></div>
                    </div>
                  </div>
                  <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",marginBottom:8}}>Funciones</div>
                  <div style={{display:"flex",gap:5,flexWrap:"wrap"}}>
                    {PODO_FUNCTIONS.map(fn=>{
                      const has=(u.podoFunctions||[]).includes(fn);
                      return(<button key={fn} onClick={()=>{const fns=has?(u.podoFunctions||[]).filter(x=>x!==fn):[...(u.podoFunctions||[]),fn];savePodoFns(u.id,fns)}} style={{padding:"4px 10px",borderRadius:20,border:`1.5px solid ${has?"#4a9d8f":"#d4dde5"}`,background:has?"#4a9d8f":"#fff",color:has?"#fff":"#8a9aaa",fontSize:11,fontWeight:600,cursor:"pointer",transition:"all .15s"}}>{fn}</button>);
                    })}
                  </div>
                </Card>
              ))}
            </div>
          )}
        </div>
      )}

      {tab==="services"&&(
        <div>
          <div style={{display:"flex",justifyContent:"flex-end",marginBottom:12}}><Btn onClick={()=>setSModal(true)}><Icon name="plus" size={13}/>Nuevo Servicio</Btn></div>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(260px,1fr))",gap:12}}>
            {services.map(s=>{
              const cat=categories.find(c=>c.name===s.category);
              const catColor=cat?.color||"#4a9d8f";
              return(
                <Card key={s.id} style={{transition:"transform .15s",borderTop:`3px solid ${catColor}`}} onMouseOver={e=>e.currentTarget.style.transform="translateY(-2px)"} onMouseOut={e=>e.currentTarget.style.transform="none"}>
                  <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start"}}>
                    <div>
                      {s.code&&<div style={{fontSize:10,color:"#8a9aaa",marginBottom:3,fontFamily:"monospace"}}>#{s.code}</div>}
                      <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{s.name}</div>
                      {s.category&&<Badge color="blue" style={{background:catColor+"22",color:catColor}}>{s.category}</Badge>}
                      <div style={{fontSize:26,fontWeight:800,color:catColor,marginTop:6,letterSpacing:"-0.02em"}}>{getCurrency()} {parseFloat(s.price).toFixed(2)}</div>
                      <div style={{fontSize:12,color:"#8a9aaa"}}>{s.duration} min</div>
                    </div>
                    <Badge color={s.active?"green":"gray"}>{s.active?"Activo":"Inactivo"}</Badge>
                  </div>
                  {s.description&&<div style={{fontSize:11.5,color:"#5a7a8a",marginTop:8,lineHeight:1.5}}>{s.description}</div>}
                  <div style={{display:"flex",gap:6,marginTop:12}}>
                    <Btn size="sm" variant={s.active?"secondary":"success"} onClick={()=>togS(s.id)}>{s.active?"Desactivar":"Activar"}</Btn>
                    <Btn size="sm" variant="danger" onClick={()=>delS(s.id)}><Icon name="trash" size={11}/></Btn>
                  </div>
                </Card>
              );
            })}
          </div>
          {sModal&&(
            <Modal title="Nuevo Servicio" onClose={()=>setSModal(false)} width={480}>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
                <Field label="Nombre del Servicio" required col="1/-1"><Inp value={sF.name} onChange={e=>setSF(p=>({...p,name:e.target.value}))}/></Field>
                <Field label="Código"><Inp value={sF.code||""} onChange={e=>setSF(p=>({...p,code:e.target.value}))} placeholder="QUIR"/></Field>
                <Field label="Categoría">
                  <Sel value={sF.category} onChange={e=>setSF(p=>({...p,category:e.target.value}))}>
                    <option value="">Introduzca la categoría...</option>
                    {categories.filter(c=>c.type==="service"||!c.type).map(c=><option key={c.id} value={c.name}>{c.name}</option>)}
                  </Sel>
                </Field>
                <Field label="Precio" required><Inp type="number" value={sF.price} onChange={e=>setSF(p=>({...p,price:e.target.value}))}/></Field>
                <Field label="Duración (min)"><Inp type="number" value={sF.duration} onChange={e=>setSF(p=>({...p,duration:e.target.value}))}/></Field>
              </div>
              <Field label="Descripción"><TA value={sF.description||""} onChange={e=>setSF(p=>({...p,description:e.target.value}))} placeholder="Descripción del servicio..." style={{minHeight:70}}/></Field>
              <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>setSModal(false)}>Cerrar</Btn><Btn onClick={saveS}><Icon name="check" size={13}/>Guardar Servicio</Btn></div>
            </Modal>
          )}
        </div>
      )}

      {tab==="categories"&&(
        <div>
          <div style={{display:"flex",justifyContent:"flex-end",marginBottom:12}}><Btn onClick={()=>{setEditCat(null);setCatF({name:"",color:"#4a9d8f",type:"service"});setCatModal(true)}}><Icon name="plus" size={13}/>Nueva Categoría</Btn></div>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:12}}>
            {categories.map(c=>(
              <Card key={c.id} style={{borderLeft:`4px solid ${c.color}`}}>
                <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:8}}>
                  <div style={{width:18,height:18,borderRadius:4,background:c.color,flexShrink:0}}/>
                  <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{c.name}</div>
                </div>
                <Badge color={c.type==="service"?"blue":"teal"}>{c.type==="service"?"Servicio":"Producto"}</Badge>
                <div style={{display:"flex",gap:6,marginTop:10}}>
                  <Btn size="sm" variant="ghost" onClick={()=>openEditCat(c)}><Icon name="edit" size={11}/>Editar</Btn>
                  <Btn size="sm" variant="danger" onClick={()=>delCat(c.id)}><Icon name="trash" size={11}/></Btn>
                </div>
              </Card>
            ))}
          </div>
          {catModal&&(
            <Modal title={editCat?"Editar Categoría":"Nueva Categoría"} onClose={()=>{setCatModal(false);setEditCat(null)}} width={400}>
              <Field label="Nombre" required><Inp value={catF.name} onChange={e=>setCatF(p=>({...p,name:e.target.value}))}/></Field>
              <Field label="Color Identificador">
                <div style={{display:"flex",gap:10,alignItems:"center"}}>
                  <input type="color" value={catF.color} onChange={e=>setCatF(p=>({...p,color:e.target.value}))} style={{width:44,height:36,borderRadius:8,border:"2px solid #d4dde5",cursor:"pointer",padding:2}}/>
                  <div style={{background:catF.color,borderRadius:8,padding:"6px 16px",color:"#fff",fontWeight:700,fontSize:13}}>{catF.name||"Vista previa"}</div>
                </div>
                <div style={{display:"flex",gap:6,flexWrap:"wrap",marginTop:10}}>
                  {["#4a9d8f","#2563eb","#7c3aed","#e05050","#f59223","#2ea87e","#0891b2","#dc2626","#be185d","#059669"].map(col=>(
                    <button key={col} onClick={()=>setCatF(p=>({...p,color:col}))} style={{width:24,height:24,borderRadius:"50%",background:col,border:catF.color===col?"3px solid #1a2332":"2px solid transparent",cursor:"pointer"}}/>
                  ))}
                </div>
              </Field>
              <Field label="Tipo">
                <div style={{display:"flex",gap:8}}>
                  {[["service","Servicio"],["product","Producto"]].map(([v,l])=>(
                    <button key={v} onClick={()=>setCatF(p=>({...p,type:v}))} style={{flex:1,padding:"8px 0",borderRadius:8,border:`2px solid ${catF.type===v?"#4a9d8f":"#d4dde5"}`,background:catF.type===v?"#4a9d8f18":"#fff",color:catF.type===v?"#4a9d8f":"#5a7a8a",fontWeight:600,cursor:"pointer",fontSize:13}}>{l}</button>
                  ))}
                </div>
              </Field>
              <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>{setCatModal(false);setEditCat(null)}}>Cancelar</Btn><Btn onClick={saveCat}><Icon name="check" size={13}/>Guardar</Btn></div>
            </Modal>
          )}
        </div>
      )}

      {tab==="currency"&&(
        <div className="fade-in">
          <Card style={{maxWidth:560}}>
            <div style={{fontWeight:700,fontSize:16,color:"#1a2332",marginBottom:4}}>💱 Configuración de Moneda</div>
            <div style={{fontSize:13,color:"#8a9aaa",marginBottom:20}}>Seleccione la moneda que se usará en todo el sistema, incluyendo impresiones y reportes.</div>
            <div style={{display:"grid",gap:10,marginBottom:20}}>
              {CURRENCIES.map(c=>(
                <button key={c.code} onClick={()=>setCompany(p=>({...p,currency:c.symbol,currencyCode:c.code,currencyName:c.name}))} style={{display:"flex",alignItems:"center",gap:14,padding:"12px 16px",borderRadius:12,border:`2px solid ${company.currencyCode===c.code?"#4a9d8f":"#e8edf2"}`,background:company.currencyCode===c.code?"#f0faf8":"#fff",cursor:"pointer",textAlign:"left",transition:"all .15s"}}>
                  <div style={{width:40,height:40,borderRadius:10,background:company.currencyCode===c.code?"#4a9d8f":"#f0f4f8",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,fontWeight:800,color:company.currencyCode===c.code?"#fff":"#5a7a8a",flexShrink:0}}>{c.symbol}</div>
                  <div>
                    <div style={{fontWeight:700,fontSize:13.5,color:"#1a2332"}}>{c.name}</div>
                    <div style={{fontSize:11.5,color:"#8a9aaa"}}>{c.code} · Símbolo: {c.symbol}</div>
                  </div>
                  {company.currencyCode===c.code&&<div style={{marginLeft:"auto",width:20,height:20,borderRadius:"50%",background:"#4a9d8f",display:"flex",alignItems:"center",justifyContent:"center"}}><Icon name="check" size={11}/></div>}
                </button>
              ))}
            </div>
            <div style={{background:"#f4f9f7",borderRadius:10,padding:"12px 16px",marginBottom:16,display:"flex",justifyContent:"space-between",alignItems:"center"}}>
              <span style={{fontSize:13,color:"#3a7a6a"}}>Vista previa:</span>
              <span style={{fontSize:20,fontWeight:800,color:"#2ea87e"}}>{company.currency||"S/"} 150.00</span>
            </div>
            <Btn onClick={saveCompany} style={{width:"100%",justifyContent:"center"}}><Icon name="check" size={13}/>Guardar Configuración de Moneda</Btn>
          </Card>
        </div>
      )}

            

{tab==="memberships"&&(
        <div className="fade-in">
          <div style={{display:"flex",justifyContent:"flex-end",marginBottom:12}}>
            <Btn onClick={()=>{setEditM(null);setMF({name:"",monthlyFee:"",annualFee:"",benefits:"",discountPct:""});setMModal(true)}}><Icon name="plus" size={13}/>Nueva Membresía</Btn>
          </div>
          {memberships.length===0&&<Card style={{textAlign:"center",padding:40}}><div style={{fontSize:36,marginBottom:8}}>⭐</div><div style={{fontWeight:700,color:"#3a5a6a"}}>Sin membresías. Cree la primera para afiliados.</div></Card>}
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(280px,1fr))",gap:14}}>
            {memberships.map(m=>(
              <Card key={m.id} style={{borderTop:"3px solid #7c3aed"}}>
                <div style={{fontWeight:700,fontSize:16,color:"#1a2332",marginBottom:10}}>{m.name}</div>
                <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8,marginBottom:8}}>
                  <div style={{background:"#f8fafc",borderRadius:8,padding:"8px 12px"}}>
                    <div style={{fontSize:9.5,color:"#8a9aaa",textTransform:"uppercase",marginBottom:2}}>Cuota Mensual</div>
                    <div style={{fontSize:16,fontWeight:700,color:"#7c3aed"}}>{currency(m.monthlyFee||0)}</div>
                  </div>
                  <div style={{background:"#f8fafc",borderRadius:8,padding:"8px 12px"}}>
                    <div style={{fontSize:9.5,color:"#8a9aaa",textTransform:"uppercase",marginBottom:2}}>Descuento</div>
                    <div style={{fontSize:16,fontWeight:700,color:"#059669"}}>{m.discountPct||0}%</div>
                  </div>
                </div>
                {m.benefits&&<div style={{fontSize:12,color:"#5a7a8a",marginBottom:10,lineHeight:1.5}}>{m.benefits}</div>}
                <div style={{display:"flex",gap:6}}>
                  <Btn size="sm" variant="ghost" onClick={()=>{setEditM(m);setMF({...m});setMModal(true)}}><Icon name="edit" size={11}/>Editar</Btn>
                  <Btn size="sm" variant="danger" onClick={()=>delMembership(m.id)}>
                    <Icon name="trash" size={11}/>
                  </Btn>
                </div>
              </Card>
            ))}
          </div>
          {mModal&&(
            <Modal title={editM?"Editar Membresía":"Nueva Membresía"} onClose={()=>{setMModal(false);setEditM(null)}} width={460}>
              <Field label="Nombre del Plan *"><Inp value={mF.name} onChange={e=>setMF(p=>({...p,name:e.target.value}))} placeholder="Plan Básico, Plan Gold..."/></Field>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
                <Field label="Cuota Mensual"><Inp type="number" value={mF.monthlyFee||""} onChange={e=>setMF(p=>({...p,monthlyFee:e.target.value}))} placeholder="0.00"/></Field>
                <Field label="Cuota Anual"><Inp type="number" value={mF.annualFee||""} onChange={e=>setMF(p=>({...p,annualFee:e.target.value}))} placeholder="0.00"/></Field>
                <Field label="Descuento en servicios (%)" col="1/-1"><Inp type="number" value={mF.discountPct||""} onChange={e=>setMF(p=>({...p,discountPct:e.target.value}))} placeholder="10"/></Field>
              </div>
              <Field label="Beneficios incluidos"><TA value={mF.benefits||""} onChange={e=>setMF(p=>({...p,benefits:e.target.value}))} placeholder="Describe los beneficios de esta membresía..."/></Field>
              <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
                <Btn variant="secondary" onClick={()=>{setMModal(false);setEditM(null)}}>Cancelar</Btn>
                <Btn onClick={saveMembership}><Icon name="check" size={13}/>Guardar Membresía</Btn>
              </div>
            </Modal>
          )}
        </div>
      )}

      {tab==="licencias"&&<LicenciasTab currentUser={currentUser}/>}
      {tab==="kpis"&&<KpisTab currentUser={currentUser} users={users}/>}
      {tab==="integraciones"&&(
        <div className="fade-in">
          <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:22,padding:"16px 20px",borderRadius:14,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff"}}>
            <div style={{fontSize:32}}>🔌</div>
            <div>
              <div style={{fontWeight:800,fontSize:16}}>Integraciones con Sistemas Externos</div>
              <div style={{fontSize:12,opacity:.7,marginTop:2}}>Conecta PodoCLINIC con plataformas externas para automatizar procesos</div>
            </div>
            <div style={{marginLeft:"auto",padding:"6px 16px",borderRadius:20,background:"rgba(255,165,0,0.2)",border:"1.5px solid rgba(255,165,0,0.5)",color:"#ffd070",fontSize:11,fontWeight:700,letterSpacing:".05em"}}>🚧 EN DESARROLLO</div>
          </div>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(300px,1fr))",gap:16}}>
            {[
              {icon:"🏛️",name:"SUNAT — Facturación Electrónica",desc:"Emisión automática de boletas y facturas electrónicas, declaración de IGV, integración con OSE/PSE autorizado por SUNAT.",tags:["Boletas","Facturas","IGV","RUC"],color:"#e05050"},
              {icon:"🏦",name:"Pasarelas de Pago",desc:"Integración con Yape, Plin, Visa, Mastercard y transferencias bancarias para cobros automáticos desde la app.",tags:["Yape","Plin","Visa","BCP"],color:"#2563eb"},
              {icon:"💬",name:"WhatsApp Business API",desc:"Envío automático de recordatorios de citas, confirmaciones y mensajes personalizados a pacientes vía WhatsApp.",tags:["Recordatorios","Confirmaciones","Bot"],color:"#25d366"},
              {icon:"📧",name:"Email Marketing",desc:"Campañas de email automatizadas, seguimiento de pacientes inactivos y newsletters con Mailchimp o SendGrid.",tags:["Mailchimp","SendGrid","Campañas"],color:"#f59223"},
              {icon:"📊",name:"Google Analytics / BI",desc:"Exportación de datos a Google Sheets, Power BI o Tableau para análisis avanzado de indicadores del negocio.",tags:["Google Sheets","Power BI","Tableau"],color:"#4285F4"},
              {icon:"🗓️",name:"Google Calendar / Outlook",desc:"Sincronización bidireccional de citas con Google Calendar y Microsoft Outlook para colaboradoras.",tags:["Google","Outlook","Sync"],color:"#0078d4"},
              {icon:"💊",name:"Sistemas de Farmacia / Laboratorio",desc:"Integración con sistemas de farmacias y laboratorios clínicos para pedidos y resultados en línea.",tags:["Laboratorio","Farmacia","Resultados"],color:"#7c3aed"},
              {icon:"📱",name:"App Móvil para Pacientes",desc:"Portal móvil (Android/iOS) para que pacientes agenden citas, vean su historial y reciban notificaciones push.",tags:["Android","iOS","Portal"],color:"#059669"},
            ].map(int=>(
              <div key={int.name} style={{background:"#fff",borderRadius:14,padding:"18px 20px",border:"2px dashed #d4dde5",position:"relative",overflow:"hidden"}}>
                <div style={{position:"absolute",top:12,right:12,padding:"3px 10px",borderRadius:20,background:"#fff8e1",border:"1.5px solid #f59223",color:"#b45309",fontSize:10,fontWeight:700}}>PRÓXIMAS IMPLEMENTACIONES</div>
                <div style={{fontSize:28,marginBottom:10}}>{int.icon}</div>
                <div style={{fontWeight:800,fontSize:13.5,color:"#1a2332",marginBottom:6,paddingRight:140}}>{int.name}</div>
                <div style={{fontSize:12,color:"#5a7a8a",lineHeight:1.5,marginBottom:12}}>{int.desc}</div>
                <div style={{display:"flex",flexWrap:"wrap",gap:5}}>
                  {int.tags.map(t=><span key={t} style={{padding:"2px 8px",borderRadius:10,background:`${int.color}12`,border:`1px solid ${int.color}30`,color:int.color,fontSize:10,fontWeight:700}}>{t}</span>)}
                </div>
              </div>
            ))}
          </div>
          <div style={{marginTop:20,padding:"14px 18px",borderRadius:12,background:"#f0f9f7",border:"1px solid #4a9d8f33",fontSize:12.5,color:"#2a7a6a"}}>
            💡 <strong>¿Tienes una integración que necesitas urgente?</strong> Contacta al desarrollador: <strong>johwes04@gmail.com</strong> — Cel: <strong>986634330</strong>
          </div>
        </div>
      )}
      {tab==="avanzado"&&<AvanzadoTab currentUser={currentUser}/>}
      {tab==="perms"&&<PermsTab currentUser={currentUser}/>}
    </div>
  );
};

// ─── MÓDULO REPORTES ──────────────────────────────────────────────────────────
const KPIReportModal=({patients,range,onClose})=>{
  const attendances=db.get(SK.attendances)||[];
  const appointments=db.get(SK.appointments)||[];
  const users=db.get(SK.users)||DEF_USERS;
  const now=new Date();
  const inRange=d=>{const dt=new Date(d+"T00:00:00");if(range==="today")return d===todayStr();if(range==="week"){const w=new Date(now);w.setDate(w.getDate()-7);return dt>=w}if(range==="month")return dt.getMonth()===now.getMonth()&&dt.getFullYear()===now.getFullYear();return true};
  const filtAtt=attendances.filter(a=>inRange(a.date));
  const closedAtt=filtAtt.filter(a=>a.closed||a.payStatus==="pagado");
  const totalRev=closedAtt.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const avgTicket=closedAtt.length?totalRev/closedAtt.length:0;
  const newPats=patients.filter(p=>inRange(p.registrationDate)).length;
  const podologas=users.filter(u=>u.active&&u.role==="Podólogo");
  const bench=podologas.map(u=>{const atts=closedAtt.filter(a=>a.attendedBy===u.name);return{name:u.name,count:atts.length,rev:atts.reduce((s,a)=>s+(parseFloat(a.price)||0),0)}}).sort((a,b)=>b.rev-a.rev);
  const conv=appointments.filter(a=>inRange(a.date)).length>0?Math.round((closedAtt.length/appointments.filter(a=>inRange(a.date)).length)*100):0;
  const company=db.get(SK.company)||{name:"Podología Más Bela"};

  const printReport=()=>{
    const win=window.open("","_blank");
    const cur=getCurrency();
    const rangeLabel=range==="today"?"Hoy":range==="week"?"Última semana":range==="month"?"Este mes":"Todo";
    const benchRows=bench.map((b,i)=>'<tr><td>'+(i+1)+'</td><td>'+b.name+'</td><td>'+b.count+'</td><td>'+cur+' '+b.rev.toFixed(2)+'</td></tr>').join('');
    const kpiBoxes=[
      ["🩺","Atenciones",filtAtt.length],["💰","Ingresos",cur+" "+totalRev.toFixed(2)],
      ["🎫","Ticket Prom.",cur+" "+avgTicket.toFixed(2)],["👤","Nuevos Pac.",newPats],
      ["📈","Conversión",conv+"%"],["✅","Cerradas",closedAtt.length]
    ].map(([e,l,v])=>'<div class="kpi"><div class="kv">'+v+'</div><div class="kl">'+e+' '+l+'</div></div>').join('');
    const html=`<!DOCTYPE html><html><head><meta charset="UTF-8">
<title>Reporte KPI</title>
<style>
body{font-family:Arial,sans-serif;padding:24px;color:#1a2332}
h1{color:#0f3a2a;border-bottom:3px solid #4a9d8f;padding-bottom:8px}
.kpi{display:inline-block;background:#f4f9f7;border:1px solid #4a9d8f33;border-radius:8px;padding:14px 20px;margin:6px;min-width:140px;text-align:center}
.kv{font-size:22px;font-weight:800;color:#4a9d8f}.kl{font-size:10px;color:#5a7a8a;font-weight:700;margin-top:4px}
table{width:100%;border-collapse:collapse;margin-top:16px}
th,td{padding:8px 12px;text-align:left;border-bottom:1px solid #e8edf2}
th{background:#f4f8fa;font-size:10px;font-weight:700;text-transform:uppercase}
@media print{body{padding:10px}}
</style></head><body>
<div style="display:flex;align-items:center;gap:14px;padding-bottom:10px;margin-bottom:12px;border-bottom:3px solid #4a9d8f">
  <div style="width:54px;height:54px;border-radius:50%;background:linear-gradient(135deg,#4a9d8f,#0f3a2a);display:flex;align-items:center;justify-content:center;font-size:22px">🩺</div>
  <div><h1 style="margin:0;font-size:20px;color:#0f3a2a">Reporte de KPIs — ${company.name}</h1>
  <p style="margin:3px 0 0;color:#8a9aaa;font-size:12px">Período: ${rangeLabel} · ${new Date().toLocaleString('es-PE')}</p></div>
</div>
<div>${kpiBoxes}</div>
<h2 style="margin-top:20px">Benchmarking por Colaboradora</h2>
<table><thead><tr><th>#</th><th>Nombre</th><th>Atenciones</th><th>Ingresos</th></tr></thead>
<tbody>${benchRows}</tbody></table>
</body></html>`
    win.document.write(html);
    win.document.close();
    setTimeout(()=>{win.print();win.close()},400);
  };

  return(
    <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",zIndex:1000,display:"flex",alignItems:"center",justifyContent:"center",padding:20}} onClick={e=>e.target===e.currentTarget&&onClose()}>
      <div style={{background:"#fff",borderRadius:18,width:"100%",maxWidth:700,maxHeight:"90vh",overflow:"auto",boxShadow:"0 24px 64px rgba(0,0,0,0.25)"}}>
        <div style={{background:"linear-gradient(135deg,#0f3a2a,#1a4a5a)",borderRadius:"18px 18px 0 0",padding:"18px 24px",display:"flex",alignItems:"center",justifyContent:"space-between"}}>
          <div style={{fontSize:17,fontWeight:800,color:"#fff"}}>📊 Reporte KPI</div>
          <div style={{display:"flex",gap:8}}>
            <button onClick={printReport} style={{background:"rgba(255,255,255,0.15)",color:"#fff",border:"1px solid rgba(255,255,255,0.3)",borderRadius:9,padding:"7px 14px",cursor:"pointer",fontSize:12,fontWeight:700}}>🖨️ Imprimir PDF</button>
            <button onClick={onClose} style={{background:"rgba(224,80,80,0.25)",color:"#fff",border:"none",borderRadius:9,padding:"7px 12px",cursor:"pointer",fontSize:14,fontWeight:700}}>✕</button>
          </div>
        </div>
        <div style={{padding:"20px 24px"}}>
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(140px,1fr))",gap:10,marginBottom:20}}>
            {[["🩺","Atenciones",filtAtt.length,"#4a9d8f"],["💰","Ingresos",currency(totalRev),"#059669"],["🎫","Ticket Prom.",currency(avgTicket),"#7c3aed"],["👤","Nuevos Pac.",newPats,"#2563eb"],["📈","Conversión",conv+"%","#f59223"],["✅","Cerradas",closedAtt.length,"#2ea87e"]].map(([e,l,v,c])=>(
              <div key={l} style={{background:`${c}12`,border:`1px solid ${c}30`,borderRadius:10,padding:"12px 14px",textAlign:"center"}}>
                <div style={{fontSize:24}}>{e}</div>
                <div style={{fontSize:20,fontWeight:800,color:c}}>{v}</div>
                <div style={{fontSize:10,color:"#5a7a8a",textTransform:"uppercase",fontWeight:700,marginTop:3}}>{l}</div>
              </div>
            ))}
          </div>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:12}}>👩‍⚕️ Benchmarking por Colaboradora</div>
          {bench.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0"}}>Sin datos</div>:bench.map(({name,count,rev},idx)=>(
            <div key={name} style={{marginBottom:12}}>
              <div style={{display:"flex",justifyContent:"space-between",marginBottom:4}}>
                <div style={{display:"flex",alignItems:"center",gap:8}}>
                  <div style={{width:26,height:26,borderRadius:"50%",background:`hsl(${idx*80+160},55%,48%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:800,color:"#fff"}}>{idx+1}</div>
                  <span style={{fontWeight:700,fontSize:13}}>{name}</span>
                </div>
                <div style={{display:"flex",gap:10,alignItems:"center"}}>
                  <span style={{fontSize:12,color:"#8a9aaa"}}>{count} atenciones</span>
                  <span style={{fontSize:14,fontWeight:800,color:"#059669"}}>{currency(rev)}</span>
                </div>
              </div>
              {bench[0].rev>0&&<div style={{background:"#eef2f7",borderRadius:6,height:8,overflow:"hidden"}}><div className="bar-fill" style={{width:`${(rev/bench[0].rev)*100}%`,height:"100%",background:`linear-gradient(90deg,hsl(${idx*80+160},55%,45%),hsl(${idx*80+175},55%,60%))`,borderRadius:6}}/></div>}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

const ReportsModule=({patients})=>{
  const safePatients=Array.isArray(patients)?patients:[];
  const[showKPI,setShowKPI]=useState(false);
  const[range,setRange]=useState("today");
  const attendances=useStore(SK.attendances,[]);
  const appointments=useStore(SK.appointments,[]);
  const now=new Date();
  useEffect(()=>{
    api.get('attendances').catch(()=>{});
    api.get('appointments').catch(()=>{});
  },[]);
  const dateOnly=v=>String(v||"").slice(0,10);
  const statusOf=a=>String(a?.status||"").trim().toLowerCase();
  const isPendingAppointment=a=>["pending","confirmed","pendiente","confirmado","confirmada"].includes(statusOf(a));
  const isConfirmedAppointment=a=>["confirmed","confirmado","confirmada"].includes(statusOf(a));
  const isCancelledAppointment=a=>["cancelled","cancelado","cancelada"].includes(statusOf(a));
  const isRescheduledAppointment=a=>a?.rescheduled===true||a?.rescheduled===1||a?.rescheduled==="1"||String(a?.rescheduled||"").trim().toLowerCase()==="true";

  const inRange=d=>{
    const ds=dateOnly(d);
    const dt=new Date(ds+"T00:00:00");
    if(range==="today")return ds===todayStr();
    if(range==="week"){const w=new Date(now);w.setDate(w.getDate()-7);return dt>=w}
    if(range==="month")return dt.getMonth()===now.getMonth()&&dt.getFullYear()===now.getFullYear();
    return true;
  };

  const filtAtt=attendances.filter(a=>inRange(a.date));
  const filtAppt=appointments.filter(a=>inRange(a.date));
  const pendingAppts=appointments.filter(a=>isPendingAppointment(a)&&inRange(a.date));
  const rescheduledAppts=filtAppt.filter(isRescheduledAppointment);
  const pendingRescheduledAppts=pendingAppts.filter(isRescheduledAppointment);
  const closedAtt=filtAtt.filter(a=>a.closed);
  const totalRevenue=closedAtt.reduce((s,a)=>s+(parseFloat(a.price)||0),0);

  const patCount={};
  attendances.forEach(a=>{patCount[a.patientId]=(patCount[a.patientId]||0)+1});
  const frequent=Object.entries(patCount).sort((a,b)=>b[1]-a[1]).slice(0,8).map(([id,c])=>({patient:patients.find(x=>x.id===parseInt(id)),count:c})).filter(x=>x.patient);

  // Resumen por día
  const byDay={};
  closedAtt.forEach(a=>{
    if(!byDay[a.date])byDay[a.date]={count:0,total:0};
    byDay[a.date].count++;byDay[a.date].total+=parseFloat(a.price)||0;
  });
  const dayRows=Object.entries(byDay).sort((a,b)=>b[0]>a[0]?1:-1).slice(0,14);

  // Últimos 7 días para sparkline
  const last7=Array.from({length:7},(_,i)=>{
    const d=new Date(now);d.setDate(d.getDate()-6+i);
    const ds=d.toLocaleDateString("en-CA",{timeZone:"America/Lima"});
    return{label:d.getDate(),value:attendances.filter(a=>a.date===ds).length};
  });

  // Patologías más frecuentes
  const pathCount={};
  patients.forEach(p=>(p.pathologies||[]).forEach(pt=>{pathCount[pt]=(pathCount[pt]||0)+1}));
  const topPath=Object.entries(pathCount).sort((a,b)=>b[1]-a[1]).slice(0,6).map(([l,v])=>({label:l.split(" ").slice(0,2).join(" "),value:v}));

  // Helper for detail tables
  const TblHdr=({cols})=><thead><tr style={{background:"#f4f8fa"}}>{cols.map(c=><th key={c} style={{padding:"6px 10px",textAlign:"left",fontSize:10,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.05em",whiteSpace:"nowrap"}}>{c}</th>)}</tr></thead>;
  const TblRow=({cells,striped})=><tr style={{borderTop:"1px solid #f0f4f8",background:striped?"#fafcfd":"#fff"}}>{cells.map((c,i)=><td key={i} style={{padding:"6px 10px",fontSize:12,color:"#1a2332"}}>{c}</td>)}</tr>;
  const tblStyle={width:"100%",borderCollapse:"collapse",fontSize:12.5};
  const rangeLabel={today:"Hoy",week:"Últimos 7 días",month:"Este mes",all:"Todo el historial"}[range];
  const newPats=patients.filter(p=>inRange(p.registrationDate));

  // Tooltip: Atenciones
  const tooltipAtt=(
    <div>
      <div style={{display:"flex",gap:16,marginBottom:14}}>
        {[["Total",filtAtt.length,"#4a9d8f"],["Abiertas",filtAtt.filter(a=>!a.closed).length,"#f59223"],["Cerradas",closedAtt.length,"#2ea87e"]].map(([l,v,c])=>(
          <div key={l} style={{flex:1,textAlign:"center",padding:"10px 8px",borderRadius:10,background:`${c}12`,border:`1px solid ${c}30`}}>
            <div style={{fontSize:22,fontWeight:800,color:c}}>{v}</div>
            <div style={{fontSize:10,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginTop:2}}>{l}</div>
          </div>
        ))}
      </div>
      <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8,letterSpacing:".04em"}}>Período: {rangeLabel}</div>
      {filtAtt.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin atenciones en este período</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Paciente","Fecha","Hora","Servicio","Atendido por","Estado"]}/>
          <tbody>{filtAtt.slice(0,20).map((a,i)=>{const p=patients.find(x=>x.id===parseInt(a.patientId));return<TblRow key={a.id} striped={i%2===1} cells={[p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A",fmt(a.date),a.time||"—",a.service||"—",a.attendedBy||"—",a.closed?"✅ Cerrada":"🔵 Abierta"]}/>})}</tbody>
        </table></div>
      )}
      {filtAtt.length>20&&<div style={{fontSize:11,color:"#8a9aaa",textAlign:"center",marginTop:8}}>Mostrando 20 de {filtAtt.length} atenciones</div>}
    </div>
  );

  // Tooltip: Citas Programadas
  const tooltipCitas=(
    <div>
      <div style={{display:"flex",gap:16,marginBottom:14}}>
        {[["Total",filtAppt.length,"#2563eb"],["Confirmadas",filtAppt.filter(isConfirmedAppointment).length,"#2ea87e"],["Pendientes",filtAppt.filter(isPendingAppointment).length,"#f59223"],["Canceladas",filtAppt.filter(isCancelledAppointment).length,"#ef4444"]].map(([l,v,c])=>(
          <div key={l} style={{flex:1,textAlign:"center",padding:"8px 4px",borderRadius:10,background:`${c}12`,border:`1px solid ${c}30`}}>
            <div style={{fontSize:18,fontWeight:800,color:c}}>{v}</div>
            <div style={{fontSize:9,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginTop:2}}>{l}</div>
          </div>
        ))}
      </div>
      <div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8,letterSpacing:".04em"}}>Período: {rangeLabel}</div>
      {filtAppt.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin citas en este período</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Paciente","Fecha","Hora","Motivo","Estado"]}/>
          <tbody>{filtAppt.slice(0,20).map((a,i)=>{const p=patients.find(x=>x.id===parseInt(a.patientId));const st=statusOf(a);const stMap={confirmed:"✅ Confirmada",confirmado:"✅ Confirmada",confirmada:"✅ Confirmada",pending:"⏳ Pendiente",pendiente:"⏳ Pendiente",cancelled:"❌ Cancelada",cancelado:"❌ Cancelada",cancelada:"❌ Cancelada"};return<TblRow key={a.id} striped={i%2===1} cells={[p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A",fmt(a.date),a.time||"—",a.reason||a.service||"—",stMap[st]||a.status]}/>})}</tbody>
        </table></div>
      )}
    </div>
  );

  // Tooltip: Pendientes
  const tooltipPend=(
    <div>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(130px,1fr))",gap:10,marginBottom:14}}>
        <div style={{padding:"10px 14px",borderRadius:10,background:"#fff8ed",border:"1px solid #f59223",fontSize:12.5,color:"#92400e",fontWeight:700}}>
          <div style={{fontSize:22,fontWeight:800,color:"#f59223"}}>{pendingAppts.length}</div>
          Pendientes de atenciÃ³n
        </div>
        <div style={{padding:"10px 14px",borderRadius:10,background:"#eef6ff",border:"1px solid #60a5fa",fontSize:12.5,color:"#1d4e89",fontWeight:700}}>
          <div style={{fontSize:22,fontWeight:800,color:"#2563eb"}}>{pendingRescheduledAppts.length}</div>
          Pendientes reprogramadas
        </div>
      </div>
      <div style={{padding:"10px 14px",borderRadius:10,background:"#fff8ed",border:"1px solid #f59223",marginBottom:14,fontSize:12.5,color:"#92400e",fontWeight:600}}>
        ⚠️ {pendingAppts.length} cita{pendingAppts.length!==1?"s":""} pendiente{pendingAppts.length!==1?"s":""} de confirmar en este período
      </div>
      {pendingAppts.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin pendientes 🎉</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Paciente","Fecha","Hora","Motivo","Teléfono"]}/>
          <tbody>{pendingAppts.slice(0,20).map((a,i)=>{const p=patients.find(x=>x.id===parseInt(a.patientId));return<TblRow key={a.id} striped={i%2===1} cells={[p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A",fmt(a.date),a.time||"—",a.reason||a.service||"—",p?.phone||"—"]}/>})}</tbody>
        </table></div>
      )}
    </div>
  );

  // Tooltip: Reprogramadas
  const tooltipReprogramadas=(
    <div>
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(130px,1fr))",gap:10,marginBottom:14}}>
        <div style={{padding:"10px 14px",borderRadius:10,background:"#eef6ff",border:"1px solid #60a5fa",fontSize:12.5,color:"#1d4e89",fontWeight:700}}>
          <div style={{fontSize:22,fontWeight:800,color:"#2563eb"}}>{rescheduledAppts.length}</div>
          Reprogramadas
        </div>
        <div style={{padding:"10px 14px",borderRadius:10,background:"#fff8ed",border:"1px solid #f59223",fontSize:12.5,color:"#92400e",fontWeight:700}}>
          <div style={{fontSize:22,fontWeight:800,color:"#f59223"}}>{pendingRescheduledAppts.length}</div>
          Aun pendientes
        </div>
      </div>
      {rescheduledAppts.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin citas reprogramadas en este periodo</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Paciente","Fecha","Hora","Motivo","Estado"]}/>
          <tbody>{rescheduledAppts.slice(0,20).map((a,i)=>{const p=patients.find(x=>x.id===parseInt(a.patientId));const st=statusOf(a);const stMap={confirmed:"Confirmada",confirmado:"Confirmada",confirmada:"Confirmada",pending:"Pendiente",pendiente:"Pendiente",cancelled:"Cancelada",cancelado:"Cancelada",cancelada:"Cancelada"};return<TblRow key={a.id} striped={i%2===1} cells={[p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A",fmt(a.date),a.time||"---",a.reason||a.service||"---",stMap[st]||a.status||"---"]}/>})}</tbody>
        </table></div>
      )}
      {rescheduledAppts.length>20&&<div style={{fontSize:11,color:"#8a9aaa",textAlign:"center",marginTop:8}}>Mostrando 20 de {rescheduledAppts.length} reprogramadas</div>}
    </div>
  );

  // Tooltip: Nuevos Pacientes
  const tooltipNewPats=(
    <div>
      <div style={{padding:"10px 14px",borderRadius:10,background:"#f5f3ff",border:"1px solid #8b5cf6",marginBottom:14,fontSize:12.5,color:"#5b21b6",fontWeight:600}}>
        👤 {newPats.length} nuevo{newPats.length!==1?"s":""} paciente{newPats.length!==1?"s":""} registrado{newPats.length!==1?"s":""} — {rangeLabel}
      </div>
      {newPats.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin nuevos registros en este período</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Nombre","DNI","Teléfono","Fecha Registro"]}/>
          <tbody>{newPats.slice(0,20).map((p,i)=><TblRow key={p.id} striped={i%2===1} cells={[`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`,p.dni||"—",p.phone||"—",fmt(p.registrationDate)]}/>)}</tbody>
        </table></div>
      )}
    </div>
  );

  // Tooltip: Cerradas
  const tooltipCerradas=(
    <div>
      <div style={{display:"flex",gap:16,marginBottom:14}}>
        {[["Cerradas",closedAtt.length,"#2ea87e"],["Pagadas",closedAtt.filter(a=>a.payStatus==="pagado").length,"#059669"],["Por cobrar",closedAtt.filter(a=>a.payStatus!=="pagado").length,"#f59223"]].map(([l,v,c])=>(
          <div key={l} style={{flex:1,textAlign:"center",padding:"10px 8px",borderRadius:10,background:`${c}12`,border:`1px solid ${c}30`}}>
            <div style={{fontSize:22,fontWeight:800,color:c}}>{v}</div>
            <div style={{fontSize:9.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginTop:2}}>{l}</div>
          </div>
        ))}
      </div>
      {closedAtt.length===0?<div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0",fontSize:12}}>Sin atenciones cerradas en este período</div>:(
        <div style={{overflowX:"auto"}}><table style={tblStyle}>
          <TblHdr cols={["Paciente","Fecha","Hora","Servicio","Monto","Pago"]}/>
          <tbody>{closedAtt.slice(0,20).map((a,i)=>{const p=patients.find(x=>x.id===parseInt(a.patientId));return<TblRow key={a.id} striped={i%2===1} cells={[p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A",fmt(a.date),a.time||"—",a.service||"—",currency(a.price),a.payStatus==="pagado"?"✅ Pagado":"⏳ Pendiente"]}/>})}</tbody>
        </table></div>
      )}
    </div>
  );

  // Tooltip: Ingresos
  const byService={};closedAtt.filter(a=>a.payStatus==="pagado").forEach(a=>{const svc=a.service||"Otro";if(!byService[svc])byService[svc]={count:0,total:0};byService[svc].count++;byService[svc].total+=parseFloat(a.price)||0;});
  const svcRows=Object.entries(byService).sort((a,b)=>b[1].total-a[1].total).slice(0,8);
  const byMethod={};closedAtt.filter(a=>a.payStatus==="pagado").forEach(a=>{const m=a.payMethod||"No especificado";byMethod[m]=(byMethod[m]||0)+(parseFloat(a.price)||0);});
  const paidTotal=closedAtt.filter(a=>a.payStatus==="pagado").reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const tooltipIngresos=(
    <div>
      <div style={{display:"flex",gap:12,marginBottom:14}}>
        {[["Total",currency(totalRevenue),"#059669"],["Cobrado",currency(paidTotal),"#2ea87e"],["Por cobrar",currency(totalRevenue-paidTotal),"#f59223"]].map(([l,v,c])=>(
          <div key={l} style={{flex:1,textAlign:"center",padding:"10px 8px",borderRadius:10,background:`${c}12`,border:`1px solid ${c}30`}}>
            <div style={{fontSize:16,fontWeight:800,color:c}}>{v}</div>
            <div style={{fontSize:9.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginTop:2}}>{l}</div>
          </div>
        ))}
      </div>
      {svcRows.length>0&&<><div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8}}>Por Servicio</div>
      <table style={{...tblStyle,marginBottom:14}}><TblHdr cols={["Servicio","Cant.","Monto"]}/>
        <tbody>{svcRows.map(([svc,d],i)=><TblRow key={svc} striped={i%2===1} cells={[svc,d.count,<span style={{fontWeight:700,color:"#059669"}}>{currency(d.total)}</span>]}/>)}</tbody>
      </table></>}
      {Object.keys(byMethod).length>0&&<><div style={{fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:8}}>Por Método de Pago</div>
      <table style={tblStyle}><TblHdr cols={["Método","Total"]}/>
        <tbody>{Object.entries(byMethod).sort((a,b)=>b[1]-a[1]).map(([m,v],i)=><TblRow key={m} striped={i%2===1} cells={[m,<span style={{fontWeight:700,color:"#2ea87e"}}>{currency(v)}</span>]}/>)}</tbody>
      </table></>}
    </div>
  );

  const stats=[
    {emoji:"🩺",label:"Atenciones",value:filtAtt.length,color:"#4a9d8f",sub:"Total período",tooltip:tooltipAtt},
    {emoji:"📅",label:"Citas Prog.",value:filtAppt.length,color:"#2563eb",sub:"En agenda",tooltip:tooltipCitas},
    {emoji:"⏳",label:"Pendientes",value:pendingAppts.length,color:"#f59223",sub:"Por atender",tooltip:tooltipPend},
    {emoji:"🔁",label:"Reprogramadas",value:rescheduledAppts.length,color:"#2563eb",sub:`${pendingRescheduledAppts.length} pendientes`,tooltip:tooltipReprogramadas},
    {emoji:"👤",label:"Nuevos Pac.",value:newPats.length,color:"#8b5cf6",sub:"Registros",tooltip:tooltipNewPats},
    {emoji:"✅",label:"Cerradas",value:closedAtt.length,color:"#2ea87e",sub:"Facturables",tooltip:tooltipCerradas},
    {emoji:"💰",label:"Ingresos",value:currency(totalRevenue),color:"#059669",sub:"Atenciones cerradas",tooltip:tooltipIngresos},
  ];

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Reportes</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Análisis de rendimiento y KPIs</div>
        </div>
        <div style={{display:"flex",gap:6}}>
          <Btn variant="success" onClick={()=>setShowKPI(true)}><Icon name="trend" size={13}/>Ver KPIs</Btn>
          {[["today","Hoy"],["week","Semana"],["month","Mes"],["all","Todo"]].map(([v,l])=>(
            <button key={v} onClick={()=>setRange(v)} style={{padding:"6px 14px",borderRadius:8,border:`1.5px solid ${range===v?"#4a9d8f":"#d4dde5"}`,background:range===v?"#4a9d8f":"#fff",color:range===v?"#fff":"#3a5a6a",fontWeight:600,fontSize:12,cursor:"pointer"}}>{l}</button>
          ))}
        </div>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(190px,1fr))",gap:12,marginBottom:22}}>
        {stats.map(s=><Stat key={s.label} emoji={s.emoji} label={s.label} value={s.value} sub={s.sub} color={s.color} tooltip={s.tooltip}/>)}
      </div>

      <div style={{display:"grid",gridTemplateColumns:"2fr 1fr",gap:16,marginBottom:16}}>
        <Card>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:14}}>
            <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>📈 Atenciones — Últimos 7 días</div>
            <Sparkline data={last7.map(d=>d.value)} color="#4a9d8f" width={120}/>
          </div>
          <BarChart data={last7} color="#4a9d8f" valueFormatter={v=>v}/>
        </Card>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>🦶 Patologías Frecuentes</div>
          {topPath.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>:
            topPath.map(({label,value},i)=>(
              <div key={label} style={{marginBottom:10}}>
                <div style={{display:"flex",justifyContent:"space-between",fontSize:12,marginBottom:3}}>
                  <span style={{fontWeight:600,color:"#1a2332",fontSize:11.5}}>{label}</span>
                  <span style={{fontWeight:700,color:"#4a9d8f"}}>{value}</span>
                </div>
                <div style={{background:"#eef2f7",borderRadius:4,height:6}}>
                  <div className="bar-fill" style={{width:`${(value/topPath[0].value)*100}%`,height:"100%",background:`linear-gradient(90deg,hsl(${160+i*15},55%,45%),hsl(${170+i*15},55%,55%))`,borderRadius:4}}/>
                </div>
              </div>
            ))
          }
        </Card>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16,marginBottom:16}}>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332",display:"flex",alignItems:"center",gap:8}}><Icon name="dollar" size={15}/>Resumen por Día</div>
          {dayRows.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin atenciones cerradas</div>:(
            <div style={{overflowX:"auto"}}>
              <table style={{width:"100%",borderCollapse:"collapse",fontSize:12.5}}>
                <thead><tr style={{background:"#f4f8fa"}}>{["Fecha","Atenciones","Monto"].map(h=><th key={h} style={{padding:"7px 10px",textAlign:"left",color:"#5a7a8a",fontWeight:700,fontSize:10.5,textTransform:"uppercase",letterSpacing:"0.04em"}}>{h}</th>)}</tr></thead>
                <tbody>
                  {dayRows.map(([d,v])=>(
                    <tr key={d} style={{borderTop:"1px solid #f0f4f8"}}>
                      <td style={{padding:"7px 10px",fontWeight:600}}>{fmt(d)}</td>
                      <td style={{padding:"7px 10px",textAlign:"center"}}><Badge color="blue">{v.count}</Badge></td>
                      <td style={{padding:"7px 10px",fontWeight:700,color:"#2ea87e"}}>{currency(v.total)}</td>
                    </tr>
                  ))}
                  <tr style={{borderTop:"2px solid #e8edf2",background:"#f8fafc"}}>
                    <td style={{padding:"8px 10px",fontWeight:700}}>TOTAL</td>
                    <td style={{padding:"8px 10px",textAlign:"center",fontWeight:700}}>{dayRows.reduce((s,[,v])=>s+v.count,0)}</td>
                    <td style={{padding:"8px 10px",fontWeight:800,color:"#059669"}}>{currency(dayRows.reduce((s,[,v])=>s+v.total,0))}</td>
                  </tr>
                </tbody>
              </table>
            </div>
          )}
        </Card>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>🏆 Pacientes Frecuentes</div>
          {frequent.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos</div>:
            frequent.map((f,i)=>(
              <div key={f.patient.id} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"7px 0",borderBottom:"1px solid #f0f4f8"}}>
                <div style={{display:"flex",alignItems:"center",gap:9}}>
                  <div style={{width:26,height:26,borderRadius:"50%",background:`hsl(${i*40+150},55%,52%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,color:"#fff",flexShrink:0}}>{i+1}</div>
                  <div>
                    <div style={{fontSize:12.5,fontWeight:600}}>{f.patient.firstName} {f.patient.lastName}</div>
                    <div style={{fontSize:10.5,color:"#8a9aaa"}}>DNI: {f.patient.dni}</div>
                  </div>
                </div>
                <Badge color="teal">{f.count} visitas</Badge>
              </div>
            ))
          }
        </Card>
      </div>

      <Card>
        <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>📋 Detalle de Atenciones</div>
        {filtAtt.length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin atenciones en este período</div>:(
          <div style={{overflowX:"auto"}}>
            <table style={{width:"100%",borderCollapse:"collapse",fontSize:12.5}}>
              <thead><tr style={{background:"#f4f8fa"}}>{["Paciente","Fecha","Hora","Servicio","Atendido por","Monto","Pago","Estado"].map(h=><th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",whiteSpace:"nowrap",letterSpacing:"0.04em"}}>{h}</th>)}</tr></thead>
              <tbody>
                {filtAtt.slice(0,30).map(a=>{
                  const p=patients.find(x=>x.id===parseInt(a.patientId));
                  return(
                    <tr key={a.id} style={{borderTop:"1px solid #f0f4f8"}}>
                      <td style={{padding:"8px 12px",fontWeight:600}}>{p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`:"N/A"}</td>
                      <td style={{padding:"8px 12px",whiteSpace:"nowrap"}}>{fmt(a.date)}</td>
                      <td style={{padding:"8px 12px",whiteSpace:"nowrap",color:"#5a7a8a"}}>{a.time||"—"}</td>
                      <td style={{padding:"8px 12px"}}>{a.service||"—"}</td>
                      <td style={{padding:"8px 12px",color:"#4a9d8f",fontWeight:600}}>{a.attendedBy||"—"}</td>
                      <td style={{padding:"8px 12px",fontWeight:700,color:"#2ea87e"}}>{currency(a.price)}</td>
                      <td style={{padding:"8px 12px"}}><Badge color={a.payStatus==="pagado"?"green":"orange"}>{a.payStatus==="pagado"?"Pagado":"Pendiente"}</Badge></td>
                      <td style={{padding:"8px 12px"}}><Badge color={a.closed?"green":"blue"}>{a.closed?"Cerrado":"Abierto"}</Badge></td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    {showKPI&&<KPIReportModal patients={patients} range={range} onClose={()=>setShowKPI(false)}/>}
    </div>
  );
};

// ─── PANEL ADMIN ──────────────────────────────────────────────────────────────
const AdminPanel=({patients,user})=>{
  const currentUser=user; // alias — ImportModal y subcomponentes esperan currentUser
  const[importModal,setImportModal]=useState(false);
  const[importResult,setImportResult]=useState(null);
  const importRef=useRef();

  const handleImport=e=>{
    const file=e.target.files[0];
    if(!file)return;
    const ext=file.name.split('.').pop().toLowerCase();
    const reader=new FileReader();
    reader.onload=async ev=>{
      try{
        const text=ev.target.result;
        if(ext==='json'){
          const data=JSON.parse(text);
          // Detectar tipo: backup del servidor (tiene _version) o datos del sistema local (PC)
          const isServerBackup=!!(data._version);
          const isLocalData=!!(data.patients||data.attendances||data.modulePerms||data.users);
          if(!isServerBackup&&!isLocalData){
            setImportResult({ok:false,msg:'Archivo JSON no reconocido. Use un backup exportado desde PodoCLINIC.'});
            return;
          }
          const action=isServerBackup?'restore':'import_local';
          const label=isServerBackup?'Backup del servidor':'Datos del sistema local (PC)';
          setImportResult({ok:true,msg:`⏳ Importando ${label}...`});
          apiFetch('/special?action='+action,{method:'POST',body:JSON.stringify(data)})
            .then(r=>{
              if(r.ok){
                const rlist=r.results?Object.entries(r.results).map(([k,v])=>`${k}: ${v}`).join(' | '):'';
                setImportResult({ok:true,msg:`✓ Importación completada. ${rlist}. Recargando en 3s...`});
                setTimeout(()=>window.location.reload(),3000);
              } else {
                setImportResult({ok:false,msg:'Error: '+(r.error||'No se pudo importar')});
              }
            })
            .catch(e=>setImportResult({ok:false,msg:'Error de conexión: '+e.message}));
        } else if(ext==='csv'){
          const lines=text.split('\n').filter(l=>l.trim());
          if(lines.length<2){setImportResult({ok:false,msg:'CSV vacío o sin cabecera'});return}
          const quote=/"/g;
          const headers=lines[0].split(',').map(h=>h.trim().replace(quote,''));
          const rows=lines.slice(1).map(line=>{
            const vals=line.split(',').map(v=>v.trim().replace(quote,''));
            const obj={};
            headers.forEach((h,i)=>{obj[h]=vals[i]||'';});
            return obj;
          });
          const existing=db.get(SK.patients)||[];
          const maxId=existing.length?Math.max(...existing.map(p=>p.id||0)):0;
          const newPats=rows.map((r,i)=>({
            ...emptyPt(),
            id:maxId+i+1,
            firstName:r.firstName||r.Nombres||r.nombre||"",
            lastName:r.lastName||r.Apellidos||r.apellido||"",
            dni:r.dni||r.DNI||"",
            phone:r.phone||r.celular||r.Celular||r.telefono||"",
            email:r.email||r.Email||r.correo||"",
            dob:r.dob||r.fecha_nacimiento||r["Fecha Nacimiento"]||"",
            sex:r.sex||r.Sexo||r.genero||"",
            address:r.address||r.Direccion||r["Dirección"]||"",
            occupation:r.occupation||r.Ocupacion||r["Profesión"]||"",
            weight:r.weight||r.Peso||"",
            height:r.height||r.Talla||"",
            shoeSize:r.shoeSize||r["N° Calzado"]||"",
            notes:r.notes||r.Observaciones||"",
            registrationDate:todayStr(),
            status:"active"
          })).filter(p=>p.firstName||p.dni);
          db.set(SK.patients,[...existing,...newPats]);
          let saved=0,failed=0;
          for(const p0 of newPats){
            const p={...p0,firstName:p0.firstName||"-",lastName:p0.lastName||"-",dni:String(p0.dni||`SIN-${String(p0.id).padStart(5,"0")}`).trim()};
            try{await crudApi.create('patients',serverPayload('patients',p));saved++;}catch(e){failed++;}
          }
          setImportResult({ok:failed===0,msg:'Se importaron '+newPats.length+' pacientes desde CSV. Guardados en base: '+saved+(failed?' · No guardados: '+failed:'')});
        } else {
          setImportResult({ok:false,msg:'Formato no soportado. Use .json (backup) o .csv (pacientes)'});
        }
      }catch(err){
        setImportResult({ok:false,msg:'Error al procesar: '+err.message});
      }
    };
    reader.readAsText(file);
  };

  // Cargar datos frescos para el panel admin
  const[attendances,setAttendances]=useState(_cache['attendances']||[]);
  useEffect(()=>{
    const unsub=_subscribe(SK.attendances,(rows)=>{if(Array.isArray(rows)&&rows.length>0)setAttendances(rows);});
    const cur=_cache['attendances']||_cache[SK.attendances];
    if(Array.isArray(cur)&&cur.length>0)setAttendances(cur);
    return unsub;
  },[]);
  const[appointments,setAppointments]=useState(db.get(SK.appointments)||[]);
  const[adminUsers,setAdminUsers]=useState(db.get(SK.users)||DEF_USERS);
  const[salesOrders,setSalesOrders]=useState(db.get(SK.salesOrders)||[]);
  const[selectedMonth,setSelectedMonth]=useState(null); // null = todos los 6 meses

  useEffect(()=>{
    // Suscribirse al store reactivo — actualiza automáticamente sin refrescar
    const unsubs=[
      _subscribe(SK.attendances,(rows)=>{if(Array.isArray(rows)&&rows.length>0)setAttendances(rows);}),
      _subscribe(SK.appointments,(rows)=>{if(Array.isArray(rows)&&rows.length>0)setAppointments(rows);}),
      _subscribe(SK.users,(rows)=>{if(Array.isArray(rows)&&rows.length>0)setAdminUsers(rows);}),
      _subscribe(SK.salesOrders,(rows)=>{if(Array.isArray(rows)&&rows.length>0)setSalesOrders(rows);}),
    ];
    // Leer datos ya en cache
    const cur={
      att:_cache['attendances']||_cache[SK.attendances]||[],
      appt:_cache['appointments']||_cache[SK.appointments]||[],
      usr:_cache['users']||_cache[SK.users]||[],
      ord:_cache['sales_orders']||_cache[SK.salesOrders]||[],
    };
    if(cur.att.length>0)setAttendances(cur.att);
    if(cur.appt.length>0)setAppointments(cur.appt);
    if(cur.usr.length>0)setAdminUsers(cur.usr);
    if(cur.ord.length>0)setSalesOrders(cur.ord);
    // Si no hay datos aún, cargar del servidor
    if(cur.att.length===0)api.get('attendances').catch(()=>{});
    if(cur.appt.length===0)api.get('appointments').catch(()=>{});
    if(cur.usr.length===0)api.get('users').catch(()=>{});
    if(cur.ord.length===0)api.get('sales_orders').catch(()=>{});
    return ()=>unsubs.forEach(u=>u());
  },[]);

  const exportBackup=async()=>{
    try{
      const data=await apiFetch('/special?action=backup');
      const json=JSON.stringify(data,null,2);
      const blob=new Blob([json],{type:'application/json'});
      const url=URL.createObjectURL(blob);
      const a=document.createElement('a');
      a.href=url;a.download='podoclinic_backup_'+todayStr()+'.json';
      a.click();URL.revokeObjectURL(url);
    }catch(e){alert('Error al generar backup: '+e.message);}
  };
  const importBackup=async(data)=>{
    if(!window.confirm('¿Restaurar backup? Se REEMPLAZARÁN todos los datos actuales.')) return;
    try{
      const r=await apiFetch('/special?action=restore',{method:'POST',body:JSON.stringify(data)});
      if(r.ok){alert('✓ Backup restaurado exitosamente. Recargando...');window.location.reload();}
      else{alert('Error: '+(r.error||'No se pudo restaurar'));}
    }catch(e){alert('Error al restaurar: '+e.message);}
  };

  const exportCSVTemplate=()=>{
    const headers='firstName,lastName,dni,phone,dob,address,sex,occupation,patientType';
    const example='Juan,Perez,12345678,999888777,1985-03-15,Av. Lima 123,M,Contador,publico';
    const csv=headers+'\n'+example;
    const blob=new Blob([csv],{type:'text/csv;charset=utf-8'});
    const url=URL.createObjectURL(blob);
    const a=document.createElement('a');
    a.href=url;a.download='plantilla_pacientes.csv';
    a.click();URL.revokeObjectURL(url);
  };
  const users=adminUsers;

  // Ingresos últimos 6 meses
  const now=new Date();
  const monthlyData=Array.from({length:6},(_,i)=>{
    const d=new Date(now.getFullYear(),now.getMonth()-5+i,1);
    const m=d.getMonth(),y=d.getFullYear();
    const key=`${y}-${String(m+1).padStart(2,'0')}`;
    // Ingresos clínicos (atenciones pagadas)
    const clinRev=attendances.filter(a=>{
      if(!a.date)return false;
      const dk=a.date.substring(0,7);
      return dk===key&&(a.closed||a.payStatus==='pagado')&&a.payStatus!=='anulado';
    }).reduce((s,a)=>s+(parseFloat(a.price)||0),0);
    // Ingresos por ventas (salesOrders cobrados)
    const salesRev=salesOrders.filter(o=>{
      if(!o.date)return false;
      return o.date.substring(0,7)===key&&o.status==='cobrado';
    }).reduce((s,o)=>s+(parseFloat(o.total)||0),0);
    return{label:monthName(m),value:Math.round(clinRev+salesRev),clinRev:Math.round(clinRev),salesRev:Math.round(salesRev),key,m,y};
  });
  // Atenciones filtradas por mes seleccionado
  const attForDisplay=selectedMonth
    ?attendances.filter(a=>a.date&&a.date.startsWith(selectedMonth))
    :attendances;
  const todayAtts=attendances.filter(a=>a.date===todayStr());
  const isAnulledAdmin=a=>["anulado","anulada","cancelado","cancelada"].includes(String(a.payStatus||a.pay_status||a.status||"").trim().toLowerCase())||a.anuladoAt||a.anulado_at||a.anuladoMotivo||a.anulado_motivo;
  const activeTodayAtts=todayAtts.filter(a=>!isAnulledAdmin(a));

  // KPIs totales / por mes seleccionado
  const baseAtts=attForDisplay||attendances;
  const totalRevAll=baseAtts.filter(a=>!isAnulledAdmin(a)&&(a.closed||a.payStatus==='pagado')).reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const avgPerPatient=patients.length?totalRevAll/patients.length:0;
  const pendingPayments=baseAtts.filter(a=>!a.closed&&a.payStatus!=='pagado'&&a.payStatus!=='anulado').reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const baseAppts=selectedMonth?appointments.filter(a=>a.date&&a.date.startsWith(selectedMonth)):appointments;
  const conversionRate=baseAppts.length?Math.round((baseAppts.filter(a=>a.status==='done'||a.status==='atendida').length/baseAppts.length)*100):0;
  // Atenciones de hoy
  const todayAttCount=activeTodayAtts.length;
  const todayRev=activeTodayAtts.filter(a=>a.closed||a.payStatus==='pagado').reduce((s,a)=>s+(parseFloat(a.price)||0),0);

  // Distribución por sexo
  const sexF=patients.filter(p=>p.sex==="F").length;
  const sexM=patients.filter(p=>p.sex==="M").length;
  const sexPct=patients.length?Math.round((sexF/patients.length)*100):0;

  // Usuarios activos
  const activeUsers=users.filter(u=>u.active);

  // Rendimiento por usuario (atenciones + ventas)
  const attByUser={};
  attendances.forEach(a=>{if(a.attendedBy)attByUser[a.attendedBy]=(attByUser[a.attendedBy]||0)+1});

  // Ventas de productos y servicios de caja por vendedor
  const salesProdsAll=db.get(SK.salesProducts)||[];
  const salesSvcsAll=db.get(SK.salesServices)||[];
  // salesOrders filtered by month
  const filtSalesOrders=selectedMonth
    ?salesOrders.filter(o=>o.date&&o.date.startsWith(selectedMonth))
    :salesOrders;
  // Calcular totales por profesional: atenciones clínicas + ventas de caja
  const profStats={};
  // --- atenciones clínicas (filtradas por mes si aplica) ---
  (attForDisplay||attendances).forEach(a=>{
    if(!a.attendedBy)return;
    if(!profStats[a.attendedBy])profStats[a.attendedBy]={atts:0,attRev:0,salesCount:0,salesRev:0};
    profStats[a.attendedBy].atts+=1;
    if(a.closed||a.payStatus==='pagado')profStats[a.attendedBy].attRev+=(parseFloat(a.price)||0);
  });
  // --- ventas de productos ---
  salesProdsAll.forEach(s=>{
    const seller=s.seller||s.vendedorNombre||s.attendedBy||null;
    if(!seller)return;
    if(!profStats[seller])profStats[seller]={atts:0,attRev:0,salesCount:0,salesRev:0};
    profStats[seller].salesCount+=parseInt(s.qty||s.quantity||1);
    profStats[seller].salesRev+=(parseFloat(s.total||s.price||0));
  });
  // --- ventas de servicios de caja ---
  salesSvcsAll.forEach(s=>{
    const seller=s.seller||s.vendedorNombre||s.attendedBy||null;
    if(!seller)return;
    if(!profStats[seller])profStats[seller]={atts:0,attRev:0,salesCount:0,salesRev:0};
    profStats[seller].salesCount+=1;
    profStats[seller].salesRev+=(parseFloat(s.total||s.price||0));
  });

  return(
    <div className="slide-in">
      <div style={{marginBottom:20}}>
        <div style={{display:"flex",alignItems:"center",gap:10}}>
          <div style={{width:44,height:44,borderRadius:12,background:"linear-gradient(135deg,#7c3aed,#5b21b6)",display:"flex",alignItems:"center",justifyContent:"center"}}><Icon name="shield" size={20}/></div>
          <div>
            <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:8}}>
              <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Panel Administrativo</h2>
              <div style={{display:"flex",gap:8}}>
              <Btn variant="ghost" onClick={exportBackup}><Icon name="file" size={13}/>Exportar Backup</Btn>
              <Btn variant="ghost" onClick={()=>{setImportResult(null);setImportModal(true)}}><Icon name="arrow" size={13}/>Importar Datos</Btn>
            </div>
            </div>
            <div style={{fontSize:12.5,color:"#8a9aaa"}}>Vista completa del negocio · Solo Administrador</div>
          </div>
        </div>
      </div>

      {/* KPI Grid */}
      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:12,marginBottom:22}}>
        <Stat emoji="💰" label={selectedMonth?`Ingresos ${selectedMonth}`:"Ingresos Totales"} value={currency(totalRevAll)} color="#059669" sub={selectedMonth?"Mes seleccionado":"Histórico completo"}/>
        <Stat emoji="🏥" label="Atenciones Hoy" value={todayAttCount} color="#2563eb" sub={`S/ ${todayRev.toFixed(2)} hoy`}/>
        <Stat emoji="📊" label="Ingreso Promedio/Pac." value={currency(avgPerPatient)} color="#2563eb" sub="Por paciente"/>
        <Stat emoji="⚠️" label="Por Cobrar" value={currency(pendingPayments)} color="#f59223" sub="Atenciones abiertas"/>
        <Stat emoji="🔄" label="Conversión Citas" value={`${conversionRate}%`} color="#7c3aed" sub="Citas → Atendidas"/>
        <Stat emoji="👥" label="Total Pacientes" value={patients.length} color="#4a9d8f" sub={`${sexF} F · ${sexM} M`}/>
        <Stat emoji="👤" label="Usuarios Activos" value={activeUsers.length} color="#0ea5e9" sub={`de ${users.length} registrados`}/>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"2fr 1fr",gap:16,marginBottom:16}}>
        <Card>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:14}}>
            <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:8}}>
              <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>📈 Ingresos — Últimos 6 Meses {selectedMonth&&<span style={{fontSize:12,color:"#4a9d8f",fontWeight:600}}>· Mostrando: {selectedMonth}</span>}</div>
              <div style={{display:"flex",gap:4,flexWrap:"wrap"}}>
                <button onClick={()=>setSelectedMonth(null)} style={{padding:"4px 10px",borderRadius:7,border:`1.5px solid ${!selectedMonth?"#4a9d8f":"#d4dde5"}`,background:!selectedMonth?"#4a9d8f":"#fff",color:!selectedMonth?"#fff":"#5a7a8a",fontWeight:600,fontSize:11,cursor:"pointer"}}>Todo</button>
                {monthlyData.map(m=>(
                  <button key={m.key} onClick={()=>setSelectedMonth(selectedMonth===m.key?null:m.key)} style={{padding:"4px 10px",borderRadius:7,border:`1.5px solid ${selectedMonth===m.key?"#4a9d8f":"#d4dde5"}`,background:selectedMonth===m.key?"#4a9d8f":"#fff",color:selectedMonth===m.key?"#fff":"#5a7a8a",fontWeight:600,fontSize:11,cursor:"pointer"}}>{m.label}</button>
                ))}
              </div>
            </div>
            <Sparkline data={monthlyData.map(d=>d.value)} color="#059669" width={100}/>
          </div>
          <BarChart data={monthlyData} color="#059669" valueFormatter={v=>v>999?`${(v/1000).toFixed(1)}k`:`${v}`}/>
          <div style={{display:"flex",justifyContent:"space-between",marginTop:12,paddingTop:12,borderTop:"1px solid #eef2f7"}}>
            <div style={{fontSize:12,color:"#5a7a8a"}}>Total período</div>
            <div style={{fontSize:15,fontWeight:800,color:"#059669"}}>{currency(monthlyData.reduce((s,d)=>s+d.value,0))}</div>
          </div>
        </Card>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>👫 Distribución por Sexo</div>
          <div style={{textAlign:"center",marginBottom:16}}>
            <div style={{position:"relative",width:120,height:120,margin:"0 auto"}}>
              <svg viewBox="0 0 36 36" style={{width:120,height:120,transform:"rotate(-90deg)"}}>
                <circle cx="18" cy="18" r="15.9" fill="none" stroke="#eef2f7" strokeWidth="3"/>
                <circle cx="18" cy="18" r="15.9" fill="none" stroke="#4a9d8f" strokeWidth="3" strokeDasharray={`${sexPct} ${100-sexPct}`} strokeLinecap="round"/>
                <circle cx="18" cy="18" r="15.9" fill="none" stroke="#2563eb" strokeWidth="3" strokeDasharray={`${100-sexPct} ${sexPct}`} strokeDashoffset={`${-sexPct}`} strokeLinecap="round"/>
              </svg>
              <div style={{position:"absolute",top:"50%",left:"50%",transform:"translate(-50%,-50%)",textAlign:"center"}}>
                <div style={{fontSize:20,fontWeight:800,color:"#1a2332"}}>{patients.length}</div>
                <div style={{fontSize:10,color:"#8a9aaa"}}>total</div>
              </div>
            </div>
          </div>
          <div style={{display:"flex",gap:16,justifyContent:"center"}}>
            <div style={{textAlign:"center"}}><div style={{width:12,height:12,borderRadius:"50%",background:"#4a9d8f",margin:"0 auto 4px"}}/><div style={{fontSize:11,color:"#5a7a8a"}}>Femenino</div><div style={{fontSize:16,fontWeight:800,color:"#4a9d8f"}}>{sexF}</div></div>
            <div style={{textAlign:"center"}}><div style={{width:12,height:12,borderRadius:"50%",background:"#2563eb",margin:"0 auto 4px"}}/><div style={{fontSize:11,color:"#5a7a8a"}}>Masculino</div><div style={{fontSize:16,fontWeight:800,color:"#2563eb"}}>{sexM}</div></div>
          </div>
        </Card>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16}}>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:4,color:"#1a2332"}}>👤 Rendimiento por Profesional</div>
          <div style={{fontSize:11.5,color:"#8a9aaa",marginBottom:14}}>Atenciones clínicas + ventas de productos/servicios</div>
          {Object.keys(profStats).length===0?<div style={{color:"#8a9aaa",fontSize:12.5,textAlign:"center",padding:"16px 0"}}>Sin datos de atenciones o ventas</div>:
            Object.entries(profStats).sort((a,b)=>(b[1].attRev+b[1].salesRev)-(a[1].attRev+a[1].salesRev)).map(([name,st],i)=>{
              const totalRev=st.attRev+st.salesRev;
              return(
                <div key={name} style={{padding:"11px 0",borderBottom:"1px solid #f0f4f8"}}>
                  <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:6}}>
                    <div style={{display:"flex",alignItems:"center",gap:10}}>
                      <div style={{width:34,height:34,borderRadius:"50%",background:`hsl(${i*70+150},50%,45%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,color:"#fff",fontWeight:700}}>{name[0]}</div>
                      <div>
                        <div style={{fontWeight:700,fontSize:13,color:"#1a2332"}}>{name}</div>
                        <div style={{fontSize:10.5,color:"#8a9aaa"}}>{st.atts} atenc. · {st.salesCount} ventas</div>
                      </div>
                    </div>
                    <div style={{textAlign:"right"}}>
                      <div style={{fontSize:14,fontWeight:800,color:"#059669"}}>{currency(totalRev)}</div>
                      <div style={{fontSize:10.5,color:"#8a9aaa"}}>total</div>
                    </div>
                  </div>
                  <div style={{display:"flex",gap:8}}>
                    <div style={{flex:1,background:"#f0faf7",borderRadius:8,padding:"5px 10px",display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                      <span style={{fontSize:10.5,color:"#5a7a8a",fontWeight:600}}>🩺 Atenciones</span>
                      <span style={{fontSize:11.5,fontWeight:700,color:"#2ea87e"}}>{currency(st.attRev)}</span>
                    </div>
                    <div style={{flex:1,background:"#f0f4ff",borderRadius:8,padding:"5px 10px",display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                      <span style={{fontSize:10.5,color:"#5a7a8a",fontWeight:600}}>🛒 Ventas</span>
                      <span style={{fontSize:11.5,fontWeight:700,color:"#2563eb"}}>{currency(st.salesRev)}</span>
                    </div>
                  </div>
                </div>
              );
            })
          }
        </Card>
        <Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:14,color:"#1a2332"}}>🔑 Usuarios del Sistema</div>
          {users.map(u=>(
            <div key={u.id} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"9px 0",borderBottom:"1px solid #f0f4f8"}}>
              <div style={{display:"flex",alignItems:"center",gap:10}}>
                <div style={{width:32,height:32,borderRadius:"50%",background:u.role==="Administrador"?"#e0505022":u.role==="Podólogo"?"#2563eb22":"#2ea87e22",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:700,color:u.role==="Administrador"?"#c03030":u.role==="Podólogo"?"#1a50c0":"#1a8060"}}>{u.name[0]}</div>
                <div><div style={{fontWeight:600,fontSize:13}}>{u.name}</div><div style={{fontSize:11,color:"#8a9aaa"}}>{u.username}</div></div>
              </div>
              <div style={{display:"flex",gap:6,alignItems:"center"}}>
                <Badge color={u.role==="Administrador"?"red":u.role==="Podólogo"?"blue":"green"}>{u.role}</Badge>
                <Badge color={u.active?"green":"gray"}>{u.active?"●":"○"}</Badge>
              </div>
            </div>
          ))}
        </Card>
      </div>

      {/* ── ATENCIONES DE HOY ─────────────────────────────────────────── */}
      <Card style={{marginBottom:16}}>
        <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:14,flexWrap:"wrap",gap:8}}>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>🏥 Atenciones de Hoy — {fmt(todayStr())}</div>
          <div style={{display:"flex",gap:10}}>
            <span style={{fontSize:13,fontWeight:700,color:"#4a9d8f"}}>{todayAtts.length} atenciones</span>
            <span style={{fontSize:13,fontWeight:700,color:"#059669"}}>{currency(todayRev)} cobrado</span>
          </div>
        </div>
        {todayAtts.length===0
          ?<div style={{color:"#8a9aaa",fontSize:13,textAlign:"center",padding:"16px 0"}}>No hay atenciones registradas hoy</div>
          :<div style={{overflowX:"auto"}}><table style={{width:"100%",borderCollapse:"collapse"}}>
            <thead><tr style={{background:"#f4f8fa"}}>{["Paciente","Servicio","Atendida por","Precio","Estado"].map(h=>(
              <th key={h} style={{padding:"8px 12px",textAlign:"left",fontSize:10.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em"}}>{h}</th>
            ))}</tr></thead>
            <tbody>
              {todayAtts.map((a,i)=>{
                const paid=a.closed||a.payStatus==="pagado";
                const pName=a.patientName||(()=>{
                  const all=_cache["patients"]||[];
                  const p=all.find(x=>String(x.id)===String(a.patientId)||String(x.dni||"")===String(a.patientId));
                  return p?(p.firstName||p.first_name||""+" "+(p.lastName||p.last_name||"")).trim():"—";
                })();
                return(
                  <tr key={a.id} style={{borderTop:"1px solid #f0f4f8",background:i%2?"#fafcfd":"#fff"}}>
                    <td style={{padding:"8px 12px",fontWeight:600,fontSize:13}}>{pName||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:12,color:"#5a7a8a"}}>{a.service||"—"}</td>
                    <td style={{padding:"8px 12px",fontSize:12,color:"#2563eb",fontWeight:600}}>{a.attendedBy||a.attended_by||"—"}</td>
                    <td style={{padding:"8px 12px",fontWeight:700,color:"#059669"}}>{currency(parseFloat(a.price)||0)}</td>
                    <td style={{padding:"8px 12px"}}>
                      <span style={{fontSize:11,fontWeight:700,padding:"2px 8px",borderRadius:12,
                        background:paid?"#e6f9f0":a.payStatus==="anulado"?"#fff0f0":"#fff8e6",
                        color:paid?"#1a7a4a":a.payStatus==="anulado"?"#c03030":"#92620a"}}>
                        {paid?"✓ Pagado":a.payStatus==="anulado"?"✗ Anulado":"⏳ Pendiente"}
                      </span>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table></div>
        }
      </Card>

      {/* ── BENCHMARKING ──────────────────────────────────────────────── */}
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16,marginBottom:16}}>
        <Card>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>🏆 Benchmarking — Rendimiento Comparativo</div>
          <div style={{fontSize:11.5,color:"#8a9aaa",marginBottom:14}}>{selectedMonth?`Mes: ${selectedMonth}`:"Últimos 6 meses"}</div>
          {(()=>{
            const maxRev=Math.max(...Object.values(profStats).map(s=>s.attRev+s.salesRev),1);
            const sorted=Object.entries(profStats)
              .map(([name,st])=>({name,total:st.attRev+st.salesRev,atts:st.atts,sales:st.salesCount}))
              .sort((a,b)=>b.total-a.total);
            if(sorted.length===0)return <div style={{color:"#8a9aaa",textAlign:"center",padding:"16px 0"}}>Sin datos</div>;
            return sorted.map(({name,total,atts,sales},i)=>(
              <div key={name} style={{marginBottom:12}}>
                <div style={{display:"flex",justifyContent:"space-between",marginBottom:4}}>
                  <div style={{display:"flex",alignItems:"center",gap:8}}>
                    <div style={{width:22,height:22,borderRadius:"50%",background:i===0?"#f59223":i===1?"#8a9aaa":"#c08060",display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,color:"#fff"}}>{i+1}</div>
                    <div style={{fontWeight:600,fontSize:13,color:"#1a2332"}}>{name}</div>
                  </div>
                  <div style={{fontWeight:800,fontSize:13,color:"#059669"}}>{currency(total)}</div>
                </div>
                <div style={{background:"#f0f4f8",borderRadius:20,height:10,overflow:"hidden",marginBottom:3}}>
                  <div style={{width:`${(total/maxRev)*100}%`,height:"100%",borderRadius:20,
                    background:i===0?"linear-gradient(90deg,#f59223,#f5a623)":i===1?"linear-gradient(90deg,#8a9aaa,#aab0ba)":"linear-gradient(90deg,#4a9d8f,#6abdb5)",
                    transition:"width .6s ease"}}/>
                </div>
                <div style={{fontSize:10.5,color:"#8a9aaa"}}>{atts} atenc. · {sales} ventas · {((total/maxRev)*100).toFixed(0)}% del top</div>
              </div>
            ));
          })()}
        </Card>

        <Card>
          <div style={{fontWeight:700,fontSize:14,color:"#1a2332",marginBottom:4}}>💼 Resumen de Caja</div>
          <div style={{fontSize:11.5,color:"#8a9aaa",marginBottom:14}}>{selectedMonth?`Mes: ${selectedMonth}`:"Histórico"}</div>
          {(()=>{
            const baseA=attForDisplay||attendances;
            const paidAtts=baseA.filter(a=>a.closed||a.payStatus==="pagado");
            const pendAtts=baseA.filter(a=>!a.closed&&a.payStatus!=="pagado"&&a.payStatus!=="anulado");
            const annulAtts=baseA.filter(a=>a.payStatus==="anulado");
            const paidTotal=paidAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
            const pendTotal=pendAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
            const byMethod={};
            paidAtts.forEach(a=>{const m=a.payMethod||a.pay_method||"Efectivo";byMethod[m]=(byMethod[m]||0)+(parseFloat(a.price)||0);});
            return(<>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8,marginBottom:14}}>
                <div style={{background:"#f0fdf4",borderRadius:10,padding:"10px 14px"}}>
                  <div style={{fontSize:10.5,color:"#5a7a8a",fontWeight:600}}>✅ COBRADO</div>
                  <div style={{fontSize:18,fontWeight:800,color:"#059669"}}>{currency(paidTotal)}</div>
                  <div style={{fontSize:10.5,color:"#8a9aaa"}}>{paidAtts.length} atenciones</div>
                </div>
                <div style={{background:"#fff8e6",borderRadius:10,padding:"10px 14px"}}>
                  <div style={{fontSize:10.5,color:"#92620a",fontWeight:600}}>⏳ POR COBRAR</div>
                  <div style={{fontSize:18,fontWeight:800,color:"#f59223"}}>{currency(pendTotal)}</div>
                  <div style={{fontSize:10.5,color:"#8a9aaa"}}>{pendAtts.length} atenciones</div>
                </div>
              </div>
              <div style={{fontSize:12,fontWeight:700,color:"#1a2332",marginBottom:8}}>Por método de pago:</div>
              {Object.entries(byMethod).sort((a,b)=>b[1]-a[1]).map(([m,v])=>(
                <div key={m} style={{display:"flex",justifyContent:"space-between",padding:"5px 0",borderBottom:"1px solid #f0f4f8",fontSize:12.5}}>
                  <span style={{color:"#5a7a8a"}}>{m}</span>
                  <span style={{fontWeight:700,color:"#1a2332"}}>{currency(v)}</span>
                </div>
              ))}
              {Object.keys(byMethod).length===0&&<div style={{color:"#8a9aaa",fontSize:12,textAlign:"center",padding:"8px 0"}}>Sin pagos registrados</div>}
              <div style={{marginTop:10,fontSize:11,color:"#8a9aaa"}}>Anuladas: {annulAtts.length} · {currency(annulAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0))}</div>
            </>);
          })()}
        </Card>
      </div>

      {importModal&&(
        <ImportModal onClose={()=>{setImportModal(false);setImportResult(null)}}
          importRef={importRef} handleImport={handleImport}
          importResult={importResult} setImportResult={setImportResult}
          exportCSVTemplate={exportCSVTemplate} currentUser={currentUser}/>
      )}
    </div>
  );
};

// ─── IMPORT MODAL ─────────────────────────────────────────────────────────────
// 4 tipos de backup: General, Pacientes, Caja, Historia Clínica
// + Importar desde sistema local (PC)

const BACKUP_TYPES=[
  {id:'general', icon:'💾', label:'Backup General',
   color:'#7c3aed', bg:'#f5f3ff', border:'#7c3aed',
   desc:'Todo el sistema: pacientes, atenciones, caja, usuarios, configuración'},
  {id:'patients', icon:'👥', label:'Backup Pacientes',
   color:'#2563eb', bg:'#eff6ff', border:'#2563eb',
   desc:'Solo pacientes, usuarios y catálogo de servicios'},
  {id:'cashbox', icon:'💰', label:'Backup Caja',
   color:'#16a34a', bg:'#f0fdf4', border:'#16a34a',
   desc:'Caja, atenciones, ventas, pagos y esquema de comisiones'},
  {id:'clinical', icon:'🏥', label:'Backup Historia Clínica',
   color:'#e05050', bg:'#fff5f5', border:'#e05050',
   desc:'Historias clínicas: pacientes, atenciones, laboratorio y fotos'},
];

const useBackupDownload=()=>{
  const[downloading,setDownloading]=useState(null);
  const download=async(type)=>{
    setDownloading(type);
    try{
      const data=await apiFetch('/special?action=backup&type='+type);
      const bt=BACKUP_TYPES.find(b=>b.id===type)||{label:type};
      const date=new Date().toLocaleDateString('en-CA',{timeZone:'America/Lima'});
      const json=JSON.stringify(data,null,2);
      const blob=new Blob([json],{type:'application/json'});
      const url=URL.createObjectURL(blob);
      const a=document.createElement('a');
      a.href=url;
      a.download=`podoclinic_${type}_${date}.json`;
      a.click();
      URL.revokeObjectURL(url);
    }catch(e){alert('Error al generar backup: '+e.message);}
    setDownloading(null);
  };
  return{downloading,download};
};

const ImportModal=({onClose,importRef,handleImport,importResult,setImportResult,exportCSVTemplate,currentUser})=>{
  const[screen,setScreen]=useState('menu'); // menu | backup_select | restore | local | csv
  const[localFiles,setLocalFiles]=useState({});
  const[merging,setMerging]=useState(false);
  const[localResult,setLocalResult]=useState(null);
  const{downloading,download}=useBackupDownload();

  const handleLocalFiles=async(e)=>{
    const files=[...e.target.files];
    if(!files.length)return;
    const parsed={};
    for(const file of files){
      try{parsed[file.name.replace('.json','')]=JSON.parse(await file.text());}catch{}
    }
    setLocalFiles(parsed);
  };

  const mergeToServer=async()=>{
    if(!Object.keys(localFiles).length){setLocalResult({ok:false,msg:'Selecciona archivos primero'});return;}
    setMerging(true);setLocalResult({ok:true,msg:'Preparando importación por lotes...'});
    try{
      const order=['categories','services','suppliers','salesProducts','salesServices','inventory','patients','appointments','attendances','photos','laboratory','memberships','salesOrders','payments','cashbox'];
      const keys=[...order.filter(k=>localFiles[k]!==undefined),...Object.keys(localFiles).filter(k=>!order.includes(k))];
      const totals=Object.fromEntries(keys.map(k=>[k,Array.isArray(localFiles[k])?localFiles[k].length:1]));
      const summary={};
      const errors=[];
      await apiFetch('/special?action=import_local',{method:'POST',timeoutMs:90000,body:JSON.stringify({_clear:true})});
      for(const key of keys){
        const value=localFiles[key];
        const rows=Array.isArray(value)?value:[value];
        const chunkSize=key==='attendances'?120:key==='appointments'?160:key==='patients'?120:220;
        let sent=0;
        for(let i=0;i<rows.length;i+=chunkSize){
          const chunk=rows.slice(i,i+chunkSize);
          setLocalResult({ok:true,msg:`Importando ${key}: ${Math.min(i+chunk.length,rows.length)} de ${rows.length} registros...`});
          const payload={_clear:false,[key]:Array.isArray(value)?chunk:chunk[0]};
          const r=await apiFetch('/special?action=import_local',{method:'POST',timeoutMs:90000,body:JSON.stringify(payload)});
          if(!r.ok)throw new Error(r.error||`No se pudo importar ${key}`);
          sent+=chunk.length;
          Object.assign(summary,r.results||{});
          if(r.errors&&r.errors.length)errors.push(...r.errors.slice(0,8));
        }
        summary[key]=`${sent} de ${totals[key]} registros`;
      }
      const lines=Object.entries(summary).filter(([k])=>k!=='_clear').map(([k,v])=>'• '+k+': '+v).join('\n');
      setLocalResult({ok:true,msg:'Importación exitosa.\n'+lines+(errors.length?'\nAdvertencias: '+errors.join(' | '):'\nRecargando...')});
      setTimeout(()=>window.location.reload(),3500);
    }catch(e){setLocalResult({ok:false,msg:'Error de conexión: '+e.message});}
    setMerging(false);
  };

  const Back=({to='menu'})=>(
    <button onClick={()=>{setScreen(to);setImportResult(null);setLocalResult(null);setLocalFiles({});}}
      style={{background:'none',border:'none',cursor:'pointer',fontSize:13,color:'#8a9aaa',display:'flex',alignItems:'center',gap:4,marginBottom:16,padding:0}}>
      ← Volver
    </button>
  );

  // ── MENÚ PRINCIPAL ─────────────────────────────────────────────────────────
  if(screen==='menu') return(
    <Modal title="Backup & Restaurar" onClose={onClose} width={620}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:10,marginBottom:16}}>
        {/* BACKUP SECTION */}
        <div style={{gridColumn:'1/-1',fontSize:11,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.1em',color:'#8a9aaa',marginBottom:4}}>
          ⬇ Exportar Backup
        </div>
        {BACKUP_TYPES.map(bt=>(
          <button key={bt.id} onClick={()=>download(bt.id)}
            disabled={!!downloading}
            style={{display:'flex',alignItems:'center',gap:10,padding:'11px 14px',
              background:bt.bg,border:`1.5px solid ${bt.border}44`,borderRadius:10,
              cursor:downloading?'wait':'pointer',textAlign:'left',transition:'all .15s',opacity:downloading&&downloading!==bt.id?0.5:1}}
            onMouseOver={e=>{if(!downloading){e.currentTarget.style.borderColor=bt.border;e.currentTarget.style.boxShadow=`0 4px 12px ${bt.border}22`;}}}
            onMouseOut={e=>{e.currentTarget.style.borderColor=bt.border+'44';e.currentTarget.style.boxShadow='none';}}>
            <div style={{fontSize:22,flexShrink:0}}>{downloading===bt.id?'⏳':bt.icon}</div>
            <div style={{flex:1,minWidth:0}}>
              <div style={{fontWeight:700,fontSize:12.5,color:bt.color,marginBottom:2}}>{bt.label}</div>
              <div style={{fontSize:11,color:'#6a8a9a',lineHeight:1.4}}>{bt.desc}</div>
            </div>
          </button>
        ))}

        {/* RESTORE SECTION */}
        <div style={{gridColumn:'1/-1',fontSize:11,fontWeight:700,textTransform:'uppercase',letterSpacing:'0.1em',color:'#8a9aaa',margin:'8px 0 4px'}}>
          ⬆ Restaurar / Importar
        </div>
        <button onClick={()=>setScreen('restore')}
          style={{display:'flex',alignItems:'center',gap:10,padding:'11px 14px',background:'#fff3cd',border:'1.5px solid #ffc10744',borderRadius:10,cursor:'pointer',textAlign:'left',gridColumn:'1/-1'}}
          onMouseOver={e=>{e.currentTarget.style.borderColor='#ffc107';}}
          onMouseOut={e=>{e.currentTarget.style.borderColor='#ffc10744';}}>
          <div style={{fontSize:22}}>📄</div>
          <div style={{flex:1}}>
            <div style={{fontWeight:700,fontSize:12.5,color:'#92620a',marginBottom:2}}>Restaurar Backup (.json)</div>
            <div style={{fontSize:11,color:'#6a8a9a',lineHeight:1.4}}>Restaura un backup general, de pacientes, caja o historia clínica exportado desde aquí</div>
          </div>
        </button>
        <button onClick={()=>setScreen('local')}
          style={{display:'flex',alignItems:'center',gap:10,padding:'11px 14px',background:'#f5f3ff',border:'1.5px solid #7c3aed44',borderRadius:10,cursor:'pointer',textAlign:'left'}}
          onMouseOver={e=>{e.currentTarget.style.borderColor='#7c3aed';}}
          onMouseOut={e=>{e.currentTarget.style.borderColor='#7c3aed44';}}>
          <div style={{fontSize:22}}>💻</div>
          <div style={{flex:1}}>
            <div style={{fontWeight:700,fontSize:12.5,color:'#7c3aed',marginBottom:2}}>Importar desde PC</div>
            <div style={{fontSize:11,color:'#6a8a9a',lineHeight:1.4}}>Archivos JSON del sistema instalado en la computadora</div>
          </div>
        </button>
        <button onClick={()=>setScreen('csv')}
          style={{display:'flex',alignItems:'center',gap:10,padding:'11px 14px',background:'#eff6ff',border:'1.5px solid #2563eb44',borderRadius:10,cursor:'pointer',textAlign:'left'}}
          onMouseOver={e=>{e.currentTarget.style.borderColor='#2563eb';}}
          onMouseOut={e=>{e.currentTarget.style.borderColor='#2563eb44';}}>
          <div style={{fontSize:22}}>📊</div>
          <div style={{flex:1}}>
            <div style={{fontWeight:700,fontSize:12.5,color:'#2563eb',marginBottom:2}}>Importar CSV / Excel</div>
            <div style={{fontSize:11,color:'#6a8a9a',lineHeight:1.4}}>Añadir pacientes desde una planilla Excel exportada como CSV</div>
          </div>
        </button>
      </div>
    </Modal>
  );

  // ── RESTAURAR BACKUP ───────────────────────────────────────────────────────
  if(screen==='restore') return(
    <Modal title="Restaurar Backup" onClose={onClose} width={500}>
      <Back/>
      <div style={{background:'#fff3cd',border:'1px solid #ffc107',borderRadius:10,padding:'12px 16px',marginBottom:14,fontSize:13,color:'#856404',lineHeight:1.6}}>
        ⚠️ <strong>Atención:</strong> Restaurar un backup <strong>reemplazará los datos actuales</strong> de las tablas incluidas en ese archivo. Asegúrate de tener un backup reciente antes de continuar.
      </div>
      <div style={{background:'#f0f4f8',borderRadius:8,padding:'10px 14px',marginBottom:14,fontSize:12.5,color:'#3a5a6a',lineHeight:1.6}}>
        Tipos de archivo aceptados:<br/>
        <strong>Backup General</strong> — restaura todo el sistema<br/>
        <strong>Backup Pacientes</strong> — restaura solo pacientes y catálogos<br/>
        <strong>Backup Caja</strong> — restaura movimientos de caja<br/>
        <strong>Backup Historia Clínica</strong> — restaura atenciones y fotos
      </div>
      {importResult&&(
        <div style={{background:importResult.ok?'#f0f9f7':'#fff3f3',border:`1px solid ${importResult.ok?'#4a9d8f':'#e05050'}`,borderRadius:10,padding:'12px 16px',marginBottom:12,fontSize:13,color:importResult.ok?'#1a5a4a':'#c03030',lineHeight:1.5}}>
          {importResult.msg}
        </div>
      )}
      <input ref={importRef} type="file" accept=".json" onChange={handleImport} style={{display:'none'}}/>
      <div style={{display:'flex',gap:10,justifyContent:'flex-end'}}>
        <Btn variant="secondary" onClick={()=>setScreen('menu')}>Cancelar</Btn>
        <Btn onClick={()=>importRef.current.click()}>
          <Icon name="arrow" size={13}/>Seleccionar archivo .json
        </Btn>
      </div>
    </Modal>
  );

  // ── IMPORTAR DESDE PC ──────────────────────────────────────────────────────
  if(screen==='local') return(
    <Modal title="Importar desde Sistema de PC" onClose={onClose} width={560}>
      <Back/>
      <div style={{background:'#f5f3ff',border:'1.5px solid #7c3aed33',borderRadius:10,padding:'12px 16px',marginBottom:14,fontSize:13,color:'#5b21b6',lineHeight:1.7}}>
        <strong>Instrucciones:</strong><br/>
        1. En la PC, abre la carpeta del sistema → carpeta <code style={{background:'#ede9fe',padding:'1px 6px',borderRadius:4}}>data/</code><br/>
        2. Selecciona <strong>todos los archivos .json</strong> de esa carpeta<br/>
        3. Haz clic en <em>Seleccionar archivos</em> y elige todos<br/>
        4. Luego clic en <em>Importar al Servidor</em>
      </div>
      {Object.keys(localFiles).length>0&&(
        <div style={{background:'#f0faf5',border:'1px solid #4a9d8f44',borderRadius:10,padding:'10px 14px',marginBottom:12}}>
          <div style={{fontSize:11.5,fontWeight:700,color:'#2a7a6a',marginBottom:6}}>Archivos cargados ({Object.keys(localFiles).length}):</div>
          <div style={{display:'flex',flexWrap:'wrap',gap:5}}>
            {Object.entries(localFiles).map(([k,v])=>(
              <span key={k} style={{background:'#4a9d8f18',border:'1px solid #4a9d8f33',borderRadius:20,padding:'3px 10px',fontSize:11,color:'#2a7a6a',fontWeight:600}}>
                {k} {Array.isArray(v)?`(${v.length})`:''}
              </span>
            ))}
          </div>
        </div>
      )}
      {localResult&&(
        <div style={{background:localResult.ok?'#f0faf5':'#fff3f3',border:`1px solid ${localResult.ok?'#4a9d8f':'#e05050'}`,borderRadius:10,padding:'12px 16px',marginBottom:12,fontSize:12.5,color:localResult.ok?'#1a5a4a':'#c03030',whiteSpace:'pre-wrap',lineHeight:1.5}}>
          {localResult.msg}
        </div>
      )}
      <input type="file" id="local-file-input" multiple accept=".json" onChange={handleLocalFiles} style={{display:'none'}}/>
      <div style={{display:'flex',gap:10,justifyContent:'flex-end'}}>
        <Btn variant="secondary" onClick={()=>setScreen('menu')}>Cancelar</Btn>
        <Btn variant="ghost" onClick={()=>document.getElementById('local-file-input').click()}>
          <Icon name="arrow" size={13}/>Seleccionar archivos
        </Btn>
        {Object.keys(localFiles).length>0&&(
          <Btn onClick={mergeToServer} disabled={merging}
            style={{background:'linear-gradient(135deg,#7c3aed,#5b21b6)',borderColor:'transparent',color:'#fff'}}>
            {merging?'⏳ Importando...':'⬆️ Importar al Servidor'}
          </Btn>
        )}
      </div>
    </Modal>
  );

  // ── CSV ────────────────────────────────────────────────────────────────────
  if(screen==='csv') return(
    <Modal title="Importar Pacientes CSV" onClose={onClose} width={500}>
      <Back/>
      <div style={{background:'#f0f4f8',borderRadius:8,padding:'10px 14px',marginBottom:12,display:'flex',justifyContent:'space-between',alignItems:'center',flexWrap:'wrap',gap:8}}>
        <span style={{fontSize:12.5,color:'#3a5a6a'}}><b>Columnas:</b> firstName, lastName, dni, phone, dob (YYYY-MM-DD), address, sex</span>
        <button onClick={exportCSVTemplate} style={{background:'#2563eb',color:'#fff',border:'none',borderRadius:7,padding:'5px 12px',cursor:'pointer',fontSize:11.5,fontWeight:700}}>⬇ Plantilla</button>
      </div>
      {importResult&&(
        <div style={{background:importResult.ok?'#f0f9f7':'#fff3f3',border:`1px solid ${importResult.ok?'#4a9d8f':'#e05050'}`,borderRadius:10,padding:'12px 16px',marginBottom:12,fontSize:13,color:importResult.ok?'#1a5a4a':'#c03030'}}>
          {importResult.msg}
        </div>
      )}
      <input ref={importRef} type="file" accept=".csv" onChange={handleImport} style={{display:'none'}}/>
      <div style={{display:'flex',gap:10,justifyContent:'flex-end'}}>
        <Btn variant="secondary" onClick={()=>setScreen('menu')}>Cancelar</Btn>
        <Btn onClick={()=>importRef.current.click()}><Icon name="arrow" size={13}/>Seleccionar CSV</Btn>
      </div>
    </Modal>
  );

  return null;
};

// ─── DASHBOARD ────────────────────────────────────────────────────────────────
// ─── GOAL SETTER INLINE ───────────────────────────────────────────────────────
const GoalSetterInline=({podologas})=>{
  const[open,setOpen]=React.useState(false);
  const[goals,setGoals]=React.useState({});
  const[saving,setSaving]=React.useState(false);
  const month=new Date().toISOString().slice(0,7);

  // Cargar metas desde BD al abrir
  React.useEffect(()=>{
    if(!open)return;
    apiFetch('/special?action=worker_goals&month='+month)
      .then(function(d){
        if(d&&d.goals){
          // Convertir {workerId:{goal_svc,goal_prod}} a {userName:{svc,prod}}
          var g={};
          (podologas||[]).forEach(function(u){
            var entry=d.goals[u.id];
            if(entry)g[u.name]={svc:entry.goal_svc||0,prod:entry.goal_prod||0};
          });
          setGoals(g);
        }
      }).catch(function(e){ alert('No se pudieron cargar metas desde la base de datos: '+e.message); });
  },[open]);

  const save=async()=>{
    setSaving(true);
    // Construir payload con worker_id
    var goalsArr=(podologas||[]).map(function(u){
      return{worker_id:u.id,goal_svc:goals[u.name]?.svc||0,goal_prod:goals[u.name]?.prod||0};
    });
    try{
      var d=await apiFetch('/special?action=worker_goals',{method:'POST',body:JSON.stringify({month:month,goals:goalsArr})});
      if(d.ok){
        setOpen(false);
        alert('✅ Metas guardadas en la base de datos correctamente');
      } else {
        alert('Error: '+(d.error||'No se pudo guardar'));
      }
    }catch(e){
      alert('No se guardaron las metas en la base de datos: '+(e.message||e));
    }
    setSaving(false);
  };
  return(
    <>
      <button onClick={()=>setOpen(true)} style={{marginLeft:8,padding:"3px 10px",fontSize:10,fontWeight:700,background:"#7c3aed18",border:"1px solid #7c3aed44",borderRadius:6,color:"#7c3aed",cursor:"pointer"}}>
        🎯 Metas
      </button>
      {open&&(
        <Modal title="🎯 Asignar Metas por Trabajador" onClose={()=>setOpen(false)} width={480}>
          <div style={{fontSize:12,color:"#5a7a8a",marginBottom:14}}>Define la meta mensual de ventas por servicio y por producto para cada trabajadora. Solo visible para Super Admin.</div>
          <table style={{width:"100%",borderCollapse:"collapse"}}>
            <thead>
              <tr style={{background:"#f4f8fa"}}>
                <th style={{padding:"6px 10px",textAlign:"left",fontSize:11,fontWeight:700,color:"#5a7a8a"}}>Trabajadora</th>
                <th style={{padding:"6px 10px",textAlign:"right",fontSize:11,fontWeight:700,color:"#2563eb"}}>Meta Vta Servicio (S/)</th>
                <th style={{padding:"6px 10px",textAlign:"right",fontSize:11,fontWeight:700,color:"#7c3aed"}}>Meta Vta Producto (S/)</th>
              </tr>
            </thead>
            <tbody>
              {podologas.map(u=>(
                <tr key={u.id} style={{borderTop:"1px solid #f0f4f8"}}>
                  <td style={{padding:"8px 10px",fontSize:12.5,fontWeight:600,color:"#1a2332"}}>{u.name}</td>
                  <td style={{padding:"8px 10px"}}>
                    <input type="number" min="0" value={goals[u.name]?.svc||""} onChange={e=>setGoals(g=>({...g,[u.name]:{...(g[u.name]||{}),svc:parseFloat(e.target.value)||0}}))}
                      placeholder="0.00" style={{width:"100%",padding:"5px 8px",border:"1px solid #bfdbfe",borderRadius:6,fontSize:12,textAlign:"right",outline:"none"}}/>
                  </td>
                  <td style={{padding:"8px 10px"}}>
                    <input type="number" min="0" value={goals[u.name]?.prod||""} onChange={e=>setGoals(g=>({...g,[u.name]:{...(g[u.name]||{}),prod:parseFloat(e.target.value)||0}}))}
                      placeholder="0.00" style={{width:"100%",padding:"5px 8px",border:"1px solid #ddd6fe",borderRadius:6,fontSize:12,textAlign:"right",outline:"none"}}/>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setOpen(false)}>Cancelar</Btn>
            <Btn onClick={save} disabled={saving}><Icon name="check" size={13}/>{saving?'Guardando...':'Guardar Metas'}</Btn>
          </div>
        </Modal>
      )}
    </>
  );
};

const Dashboard=({patients,user})=>{
  // Safety guard - ensure patients is always an array
  const safePatients=Array.isArray(patients)?patients:[];
  const hideBenchmarkForAdminPrincipal=(
    String(user?.username||'').trim().toLowerCase()==='admin'||
    String(user?.name||'').trim().toLowerCase()==='admin principal'
  );
  const attendances=useStore(SK.attendances,[]);
  const appointments=useStore(SK.appointments,[]);
  const[movementModal,setMovementModal]=useState(null);
  const users=db.get(SK.users)||DEF_USERS;
  const today=todayStr();
  useEffect(()=>{
    api.get('patients').catch(()=>{});
    api.get('appointments').catch(()=>{});
    api.get('attendances').catch(()=>{});
  },[]);
  const dateOnly=v=>String(v||"").slice(0,10);
  const resolveDashboardPatient=a=>{
    const combined=[...safePatients,...(_cache['patients']||[]),...(db.get(SK.patients)||[])];
    const seen=new Set();
    const unique=combined.filter(p=>{const k=String(p?.id||'')+'|'+String(p?.dni||'');if(seen.has(k))return false;seen.add(k);return true;});
    const patientId=String(a?.patientId||a?.patient_id||'').trim();
    const patientDni=String(a?.patientDni||a?.patient_dni||a?.dni||'').trim();
    return unique.find(p=>
      (patientId&&(String(p?.id)===patientId||String(p?.dni||'')===patientId))||
      (patientDni&&String(p?.dni||'')===patientDni)
    )||null;
  };
  const appointmentPatientName=(a)=>{
    const p=resolveDashboardPatient(a);
    const name=p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`.trim():String(a?.patientName||a?.patient_name||'').trim();
    return name||"Paciente sin vincular";
  };
  const isPendingAppointment=a=>{
    return ["pending","confirmed"].includes(appointmentStatusOf(a,attendances));
  };
  const now=new Date();
  const currentMonth=now.getMonth();
  const currentDay=now.getDate();

  const scheduledToday=appointments.filter(a=>dateOnly(a.date)===today);
  const attToday=attendances.filter(a=>dateOnly(a.date)===today);
  const pendingToday=scheduledToday.filter(isPendingAppointment);
  const salesOrdersAll=db.get(SK.salesOrders)||[];
  const isCancelledStatus=v=>["anulado","anulada","cancelado","cancelada"].includes(String(v||"").trim().toLowerCase());
  const relatedOrderForAttention=a=>a.orderCode?salesOrdersAll.find(o=>String(o.code||"")===String(a.orderCode)):null;
  const isCancelledAttendance=a=>{
    const ord=relatedOrderForAttention(a);
    return isCancelledStatus(a.payStatus)||isCancelledStatus(a.pay_status)||isCancelledStatus(a.status)||
      !!(a.anuladoAt||a.anulado_at||a.anuladoMotivo||a.anulado_motivo)||
      (ord&&isCancelledStatus(ord.status));
  };
  const isPaidAttendance=a=>!isCancelledAttendance(a)&&(a.closed||a.payStatus==="pagado"||a.pay_status==="pagado");
  const attentionState=a=>isCancelledAttendance(a)?"anulado":isPaidAttendance(a)?"pagado":"pendiente";
  const activeAttToday=attToday.filter(a=>attentionState(a)!=="anulado");
  const cancelledAttToday=attToday.filter(a=>attentionState(a)==="anulado");
  const paidAttToday=attToday.filter(a=>attentionState(a)==="pagado");
  const pendingAttToday=attToday.filter(a=>attentionState(a)==="pendiente");
  const revenueToday=paidAttToday.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const pendingRevToday=pendingAttToday.reduce((s,a)=>s+(parseFloat(a.price)||0),0);

  // Cumpleaños del mes
  const birthdayPatients=safePatients.filter(p=>{
    if(!p.dob)return false;
    const b=new Date(p.dob+"T00:00:00");
    return b.getMonth()===currentMonth;
  }).sort((a,b)=>{
    const da=new Date(a.dob+"T00:00:00").getDate();
    const db2=new Date(b.dob+"T00:00:00").getDate();
    return da-db2;
  });
  const todayBdays=birthdayPatients.filter(p=>new Date(p.dob+"T00:00:00").getDate()===currentDay);

  // Benchmarking por podóloga (mes actual)
  const monthStart=`${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,"0")}-01`;
  const monthAtt=attendances.filter(a=>a.date>=monthStart&&a.payStatus==="pagado");
  const podologas=users.filter(u=>u.role==="Podólogo"&&u.active);
  // Metas por trabajador (almacenadas en localStorage por SA)
  const workerGoals=safeJson(localStorage.getItem('podo_worker_goals'),{});
  const monthSalesOrders=salesOrdersAll.filter(o=>o.date>=monthStart&&o.status==="cobrado");
  const patientDisplayName=(p)=>p?`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`.trim():"";
  const attPatientName=(a)=>{
    const p=safePatients.find(x=>String(x.id)===String(a.patientId||a.patient_id)||String(x.dni||"")===String(a.patientDni||a.patient_dni||a.patientId||a.patient_id||""));
    return patientDisplayName(p)||a.patientName||a.patient_name||`${a.first_name||''} ${a.last_name||''}`.trim()||"Sin nombre";
  };
  const movementKey=(a)=>{
    const p=safePatients.find(x=>String(x.id)===String(a.patientId||a.patient_id)||String(x.dni||"")===String(a.patientDni||a.patient_dni||a.patientId||a.patient_id||""));
    const dni=String(a.patientDni||a.patient_dni||p?.dni||"").trim();
    const pid=String(a.patientId||a.patient_id||"").trim();
    const name=attPatientName(a).trim().toLowerCase();
    return{p,dni,pid,name};
  };
  const relatedMovementsFor=(target)=>{
    const key=movementKey(target);
    const samePatientAtt=a=>{
      const k=movementKey(a);
      return (key.pid&&k.pid&&key.pid===k.pid)||
        (key.dni&&k.dni&&key.dni===k.dni)||
        (key.name&&k.name&&key.name===k.name);
    };
    const samePatientOrder=o=>{
      const doc=String(o.dniRuc||o.dni_ruc||"").trim();
      const name=String(o.razonSocial||o.razon_social||"").trim().toLowerCase();
      return (key.dni&&doc&&key.dni===doc)||
        (key.name&&name&&key.name===name)||
        (target.orderCode&&String(o.code||"")===String(target.orderCode));
    };
    const attRows=attendances.filter(samePatientAtt).map(a=>{
      const st=attentionState(a);
      const ord=relatedOrderForAttention(a);
      const cancelReason=a.anuladoMotivo||a.anulado_motivo||ord?.anuladoMotivo||ord?.anulado_motivo||"";
      return{
      id:`att-${a.id}`,
      tipo:a.orderCode?"Venta / Atención":"Atención",
      fecha:a.date||"—",
      hora:a.time||"—",
      servicio:a.service||"—",
      monto:parseFloat(a.price||0),
      estado:st==="anulado"?"Anulado":st==="pagado"?"Cobrado":"Pendiente",
      metodo:a.payMethod||a.pay_method||"—",
      responsable:a.attendedBy||a.attended_by||"—",
      accion:st==="anulado"?`Anulado${cancelReason?": "+cancelReason:""}`:st==="pagado"?"Cobro registrado":"Pendiente de cobro",
      extra:a.orderCode?`Orden ${a.orderCode}${ord?.status?` · ${ord.status}`:""}`:(a.notes||""),
      color:st==="anulado"?"#dc2626":st==="pagado"?"#059669":"#f59223",
      raw:a
    }}); 
    const orderRows=salesOrdersAll.filter(samePatientOrder).map(o=>({
      id:`ord-${o.id||o.code}`,
      tipo:"Pre-venta / Orden",
      fecha:o.date||"—",
      hora:o.time||"—",
      servicio:(o.items||[]).map(i=>`${i.name} x${i.qty||1}`).join(", ")||"—",
      monto:parseFloat(o.total||0),
      estado:({cobrado:"Cobrado",pendiente:"Pendiente",procesando:"En caja",cancelado:"Cancelado",anulado:"Anulado"}[o.status]||o.status||"—"),
      metodo:o.payMethod||o.pay_method||o.paidMethod||o.paid_method||"—",
      responsable:o.assignedTo||o.assigned_to||"—",
      accion:o.status==="anulado"||o.status==="cancelado"?`Orden ${o.status}`:o.status==="cobrado"?"Orden cobrada":o.status==="procesando"?"Enviada a caja":"Pre-venta pendiente",
      extra:o.code||"",
      color:o.status==="anulado"||o.status==="cancelado"?"#dc2626":o.status==="cobrado"?"#059669":"#f59223",
      raw:o
    }));
    return[...attRows,...orderRows].sort((a,b)=>String(b.fecha+" "+b.hora).localeCompare(String(a.fecha+" "+a.hora)));
  };
  const benchData=podologas.map(u=>{
    const svcAtts=monthAtt.filter(a=>a.attendedBy===u.name&&a.type!=="venta"&&!a.orderCode);
    const prodAtts=monthAtt.filter(a=>a.attendedBy===u.name&&(a.type==="venta"||a.orderCode));
    const prodOrders=monthSalesOrders.filter(o=>o.assignedTo===u.name);
    const svcTotal=svcAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
    const prodTotal=prodAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0)+prodOrders.reduce((s,o)=>s+(o.total||0),0);
    const total=svcTotal+prodTotal;
    const count=svcAtts.length+prodAtts.length;
    const goal=workerGoals[u.name]||{svc:0,prod:0};
    return{name:u.name,count,total,svcTotal,prodTotal,svcCount:svcAtts.length,prodCount:prodAtts.length+prodOrders.length,goalSvc:goal.svc||0,goalProd:goal.prod||0};
  }).sort((a,b)=>b.count-a.count||b.total-a.total);
  const maxCount=benchData.length>0?benchData.reduce((m,b)=>Math.max(m,b.count),1):1;
  const maxTotal=benchData.length>0?benchData.reduce((m,b)=>Math.max(m,b.total),1):1;

  // Últimos 7 días sparkline
  const last7Att=Array.from({length:7},(_,i)=>{const d=new Date();d.setDate(d.getDate()-6+i);return attendances.filter(a=>a.date===d.toLocaleDateString("en-CA",{timeZone:"America/Lima"})&&attentionState(a)!=="anulado").length});

  // Tooltip content builders
  const mkTooltip=(rows,footer)=>(
    <div>
      {rows.map(([l,v,c])=>(
        <div key={l} style={{display:"flex",justifyContent:"space-between",padding:"7px 0",borderBottom:"1px solid #f0f4f8"}}>
          <span style={{fontSize:13,color:"#5a7a8a"}}>{l}</span>
          <span style={{fontSize:13,fontWeight:700,color:c||"#1a2332"}}>{v}</span>
        </div>
      ))}
      {footer&&<div style={{marginTop:10,fontSize:11.5,color:"#8a9aaa",background:"#f8fafc",borderRadius:8,padding:"8px 12px"}}>{footer}</div>}
    </div>
  );
  const byMethod2={};
  paidAttToday.forEach(a=>{const m=a.payMethod||a.pay_method||"Efectivo";byMethod2[m]=(byMethod2[m]||0)+(parseFloat(a.price)||0)});

  // KPI visibility settings (admin-controlled)
  const kpiCfg=db.get(SK.kpiSettings)||{};
  const hideAtencionesHoy=!!kpiCfg.hideAtencionesHoy;
  const hidePorCobrar=!!kpiCfg.hidePorCobrar;

  const stats=[
    {emoji:"👥",label:"Total Pacientes",value:safePatients.length,color:"#4a9d8f",sub:"registrados",
      tooltip:mkTooltip([
        ["Activos",safePatients.filter(p=>p.status==="active").length,"#2ea87e"],
        ["Cerrados",safePatients.filter(p=>p.status!=="active").length,"#8a9aaa"],
        ["Nuevos este mes",safePatients.filter(p=>p.registrationDate&&p.registrationDate.startsWith(new Date().toLocaleDateString("en-CA",{timeZone:"America/Lima"}).slice(0,7))).length,"#2563eb"],
        ["Con patologías",safePatients.filter(p=>p.pathologies?.length>0).length,"#7c3aed"],
      ],"Haga clic para ir a Pacientes")
    },
    {emoji:"🩺",label:"Atenciones Hoy",value:hideAtencionesHoy?"—":activeAttToday.length,color:"#2563eb",sub:hideAtencionesHoy?"restringido":"sin anuladas",hidden:hideAtencionesHoy,
      tooltip:(()=>{
        if(hideAtencionesHoy)return null;
        const svcCount={};
        activeAttToday.forEach(a=>{if(a.service){svcCount[a.service]=(svcCount[a.service]||0)+1;}});
        const svcRows=Object.entries(svcCount).sort((a,b)=>b[1]-a[1]).map(([s,n])=>[s,`x${n}`,"#4a9d8f"]);
        return mkTooltip([
          ["Total atenciones",activeAttToday.length,"#2563eb"],
          ["Cobradas",paidAttToday.length,"#059669"],
          ["Pendientes",pendingAttToday.length,"#f59223"],
          ["Anuladas",cancelledAttToday.length,"#dc2626"],
          ["Monto cobrado",currency(revenueToday),"#059669"],
          ["Por cobrar",currency(pendingRevToday),"#f59223"],
          ...svcRows,
        ],"Servicios y productos brindados hoy");
      })()
    },
    {emoji:"⏳",label:"Pendientes Hoy",value:hidePorCobrar?"—":pendingToday.length,color:"#f59223",sub:hidePorCobrar?"restringido":"por atender",hidden:hidePorCobrar,
      tooltip:hidePorCobrar?null:mkTooltip([
        ...pendingToday.slice(0,5).map(a=>{
          return [a.time||"—",appointmentPatientName(a),"#1a2332"];
        }),
        ...(pendingToday.length>5?[["...y "+(pendingToday.length-5)+" más","","#8a9aaa"]]:[]),
      ],"Citas confirmadas y pendientes de hoy")
    },
    {emoji:"💰",label:"Caja Hoy",value:currency(revenueToday),color:"#059669",sub:"cobrado",
      tooltip:mkTooltip([
        ["Total cobrado",currency(revenueToday),"#059669"],
        ["Por cobrar",hidePorCobrar?"—":currency(pendingRevToday),"#f59223"],
        ...Object.entries(byMethod2).map(([m,v])=>[m,currency(v),"#4a9d8f"]),
      ],"Resumen de caja del día")
    },
  ];

  const recent=safePatients.slice(-5).reverse();
  const monthNames=["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"];

  return(
    <div className="slide-in">
      <div style={{marginBottom:22}}>
        <div style={{fontFamily:"'Lora',serif",fontSize:24,color:"#1a3a4a",fontStyle:"italic",fontWeight:500}}>Bienvenido, {user.name}</div>
        <div style={{fontSize:12.5,color:"#8a9aaa",marginTop:2}}>{new Date().toLocaleDateString("es-PE",{weekday:"long",year:"numeric",month:"long",day:"numeric"})}</div>
      </div>

      {todayBdays.length>0&&(
        <div className="pop-in" style={{background:"linear-gradient(135deg,#f59223,#e07d10)",borderRadius:12,padding:"12px 18px",marginBottom:18,display:"flex",alignItems:"center",gap:12}}>
          <div style={{fontSize:28}}>🎂</div>
          <div>
            <div style={{fontWeight:700,fontSize:14,color:"#fff"}}>¡Cumpleaños de hoy!</div>
            <div style={{fontSize:12.5,color:"rgba(255,255,255,0.85)"}}>{todayBdays.map(p=>`${p.firstName||p.first_name||''} ${p.lastName||p.last_name||''}`).join(", ")}</div>
          </div>
        </div>
      )}

      <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(200px,1fr))",gap:12,marginBottom:22}}>
        {stats.map(s=><Stat key={s.label} {...s} tooltip={s.tooltip}/>)}
      </div>

      <div style={{display:"grid",gridTemplateColumns:"3fr 2fr",gap:16,marginBottom:16}}>
        <Card>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:14}}>
            <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>📋 Atenciones de Hoy</div>
            <div style={{display:"flex",alignItems:"center",gap:10}}>
              <Sparkline data={last7Att} color="#4a9d8f" width={80} height={32}/>
              <Badge color={activeAttToday.length>0?"blue":"gray"}>{activeAttToday.length}</Badge>
            </div>
          </div>
          {attToday.length===0?(
            <div style={{textAlign:"center",padding:"20px 0",color:"#8a9aaa",fontSize:13}}>
              <div style={{fontSize:36,marginBottom:8}}>🩺</div>Sin atenciones hoy
            </div>
          ):[...attToday].sort((a,b)=>{
            const rank={pagado:0,pendiente:1,anulado:2};
            return (rank[attentionState(a)]??1)-(rank[attentionState(b)]??1)||String(a.time||"").localeCompare(String(b.time||""));
          }).map(a=>{
            const p=safePatients.find(x=>x.id===parseInt(a.patientId));
            const state=attentionState(a);
            const paid=state==="pagado";
            const cancelled=state==="anulado";
            const openMovements=()=>setMovementModal({attention:a,patient:p,name:patientDisplayName(p)||attPatientName(a),rows:relatedMovementsFor(a)});
            return(
              <div key={a.id} onClick={!paid?openMovements:undefined} title={!paid?"Ver movimientos de esta paciente":"Atención cobrada"} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 0",borderBottom:"1px solid #f0f4f8",cursor:!paid?"pointer":"default",opacity:cancelled?0.82:1}}>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{fontSize:14,fontWeight:700,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}}>{patientDisplayName(p)||a.patientName||a.patient_name||"Sin nombre"}</div>
                  <div style={{fontSize:11,color:"#8a9aaa"}}>{a.service||"—"} · <span style={{color:"#4a9d8f",fontWeight:600}}>{a.attendedBy||"—"}</span></div>
                </div>
                <div style={{textAlign:"right",flexShrink:0,marginLeft:10}}>
                  <div style={{fontSize:12.5,fontWeight:700,color:"#2ea87e"}}>{currency(a.price)}</div>
                  {paid?<Badge color="green">Cobrado</Badge>:cancelled?(
                    <button onClick={e=>{e.stopPropagation();openMovements();}} style={{border:"none",background:"#fee2e2",color:"#b91c1c",borderRadius:999,padding:"4px 10px",fontSize:11.5,fontWeight:800,cursor:"pointer"}}>Anulado</button>
                  ):(
                    <button onClick={e=>{e.stopPropagation();openMovements();}} style={{border:"none",background:"#fff3e0",color:"#b45309",borderRadius:999,padding:"4px 10px",fontSize:11.5,fontWeight:800,cursor:"pointer"}}>Pendiente</button>
                  )}
                </div>
              </div>
            );
          })}
          {(revenueToday>0||pendingRevToday>0)&&(
            <div style={{marginTop:12,paddingTop:10,borderTop:"2px solid #eef2f7"}}>
              <div style={{display:"flex",justifyContent:"space-between",marginBottom:4}}>
                <span style={{fontSize:11.5,color:"#5a7a8a",fontWeight:700}}>Cobrado:</span>
                <span style={{fontSize:14,fontWeight:800,color:"#059669"}}>{hideAtencionesHoy?"—":currency(revenueToday)}</span>
              </div>
              {pendingRevToday>0&&<div style={{display:"flex",justifyContent:"space-between"}}>
                <span style={{fontSize:11.5,color:"#5a7a8a",fontWeight:700}}>Por cobrar:</span>
                <span style={{fontSize:13,fontWeight:700,color:"#f59223"}}>{hidePorCobrar?"—":currency(pendingRevToday)}</span>
              </div>}
            </div>
          )}
        </Card>

        <div style={{display:"flex",flexDirection:"column",gap:14}}>
          <Card>
            <div style={{fontWeight:700,fontSize:14,marginBottom:12,color:"#1a2332"}}>📅 Citas Pendientes Hoy</div>
            {pendingToday.length===0?(
              <div style={{textAlign:"center",padding:"12px 0",color:"#8a9aaa",fontSize:12.5}}>Sin citas pendientes hoy</div>
            ):pendingToday.slice(0,4).map(a=>{
              return(
                <div key={a.id} style={{display:"flex",alignItems:"center",gap:10,padding:"7px 0",borderBottom:"1px solid #f0f4f8"}}>
                  <div style={{background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",borderRadius:7,padding:"3px 9px",fontSize:12,fontWeight:700,whiteSpace:"nowrap"}}>{a.time}</div>
                  <div style={{flex:1,minWidth:0}}>
                    <div style={{fontSize:12.5,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}}>{appointmentPatientName(a)}</div>
                    <div style={{fontSize:10.5,color:"#8a9aaa"}}>{a.service||"Sin especificar"}</div>
                  </div>
                </div>
              );
            })}
          </Card>
          <Card>
            <div style={{fontWeight:700,fontSize:14,marginBottom:12,color:"#1a2332"}}>👥 Últimos Pacientes</div>
            {recent.map(p=>(
              <div key={p.id} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"6px 0",borderBottom:"1px solid #f5f5f5"}}>
                <div>
                  <div style={{fontSize:12.5,fontWeight:600}}>{p.firstName||p.first_name||''} {p.lastName||p.last_name||''}</div>
                  <div style={{fontSize:10.5,color:"#8a9aaa"}}>{fmt(p.registrationDate)}</div>
                </div>
                <Badge color="teal">#{padId(p.id)}</Badge>
              </div>
            ))}
          </Card>
        </div>
      </div>

      {/* BENCHMARKING POR PODÓLOGA */}
      <div style={{display:"grid",gridTemplateColumns:hideBenchmarkForAdminPrincipal?"1fr":"2fr 1fr",gap:16,marginBottom:16}}>
        {!hideBenchmarkForAdminPrincipal&&<Card>
          <div style={{fontWeight:700,fontSize:14,marginBottom:4,color:"#1a2332"}}>🏆 Benchmarking de Atención — {monthNames[currentMonth].charAt(0).toUpperCase()+monthNames[currentMonth].slice(1)}
              {user?.role==="Super Admin"&&<GoalSetterInline podologas={podologas}/>}
            </div>
          <div style={{fontSize:12,color:"#8a9aaa",marginBottom:14}}>Atenciones + ventas cobradas este mes · Metas: Servicio × Producto</div>
          {benchData.length===0?(
            <div style={{textAlign:"center",padding:"16px 0",color:"#8a9aaa",fontSize:12.5}}>Sin podólogas registradas</div>
          ):benchData.map((b2,idx)=>{
            const {name,count,total,svcTotal,prodTotal,svcCount,prodCount,goalSvc,goalProd}=b2;
            const hue=idx*80+160;
            const pctSvc=goalSvc>0?Math.min(100,Math.round((svcTotal/goalSvc)*100)):0;
            const pctProd=goalProd>0?Math.min(100,Math.round((prodTotal/goalProd)*100)):0;
            const isSA2=user?.role==="Super Admin";
            return(
            <div key={name} style={{marginBottom:12,background:"#f8fafc",borderRadius:10,padding:"10px 12px",border:"1px solid #e8edf2"}}>
              <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:8}}>
                <div style={{display:"flex",alignItems:"center",gap:8}}>
                  <div style={{width:26,height:26,borderRadius:"50%",background:`hsl(${hue},55%,48%)`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:800,color:"#fff",flexShrink:0}}>{idx+1}</div>
                  <span style={{fontWeight:700,fontSize:12.5,color:"#1a2332"}}>{name}</span>
                </div>
                <span style={{fontSize:11,fontWeight:800,color:"#059669"}}>{currency(total)}</span>
              </div>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:8}}>
                {/* Vta por Servicio */}
                <div style={{background:"#fff",borderRadius:8,padding:"8px 10px",border:"1px solid #e8edf2"}}>
                  <div style={{fontSize:9.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:3}}>Vta por Servicio</div>
                  <div style={{fontSize:13,fontWeight:800,color:"#2563eb"}}>{currency(svcTotal)}</div>
                  <div style={{fontSize:10,color:"#8a9aaa",marginBottom:4}}>{svcCount} atenc.</div>
                  {goalSvc>0?(<>
                    <div style={{display:"flex",justifyContent:"space-between",marginBottom:2}}>
                      <span style={{fontSize:9,color:"#8a9aaa"}}>Meta: {currency(goalSvc)}</span>
                      <span style={{fontSize:9,fontWeight:700,color:pctSvc>=100?"#16a34a":"#2563eb"}}>{pctSvc}%</span>
                    </div>
                    <div style={{background:"#eef2f7",borderRadius:4,height:5,overflow:"hidden"}}>
                      <div style={{width:`${Math.min(100,pctSvc)}%`,height:"100%",background:pctSvc>=100?"#16a34a":"linear-gradient(90deg,#2563eb,#60a5fa)",borderRadius:4}}/>
                    </div>
                  </>):(isSA2&&<div style={{fontSize:9,color:"#c4b5fd",fontStyle:"italic"}}>Sin meta asignada</div>)}
                </div>
                {/* Vta por Producto */}
                <div style={{background:"#fff",borderRadius:8,padding:"8px 10px",border:"1px solid #e8edf2"}}>
                  <div style={{fontSize:9.5,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",marginBottom:3}}>Vta por Producto</div>
                  <div style={{fontSize:13,fontWeight:800,color:"#7c3aed"}}>{currency(prodTotal)}</div>
                  <div style={{fontSize:10,color:"#8a9aaa",marginBottom:4}}>{prodCount} vtas.</div>
                  {goalProd>0?(<>
                    <div style={{display:"flex",justifyContent:"space-between",marginBottom:2}}>
                      <span style={{fontSize:9,color:"#8a9aaa"}}>Meta: {currency(goalProd)}</span>
                      <span style={{fontSize:9,fontWeight:700,color:pctProd>=100?"#16a34a":"#7c3aed"}}>{pctProd}%</span>
                    </div>
                    <div style={{background:"#eef2f7",borderRadius:4,height:5,overflow:"hidden"}}>
                      <div style={{width:`${Math.min(100,pctProd)}%`,height:"100%",background:pctProd>=100?"#16a34a":"linear-gradient(90deg,#7c3aed,#c4b5fd)",borderRadius:4}}/>
                    </div>
                  </>):(isSA2&&<div style={{fontSize:9,color:"#c4b5fd",fontStyle:"italic"}}>Sin meta asignada</div>)}
                </div>
              </div>
            </div>
            );
          })}
          {benchData.length>0&&benchData.every(b=>b.count===0)&&(
            <div style={{textAlign:"center",padding:"8px 0",color:"#8a9aaa",fontSize:12}}>Sin atenciones cobradas este mes todavía</div>
          )}
        </Card>}

        {/* Cumpleaños del mes */}
        <Card>
          <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:14}}>
            <span style={{fontSize:20}}>🎂</span>
            <div>
              <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>Cumpleaños del Mes</div>
              <div style={{fontSize:11,color:"#8a9aaa"}}>{monthNames[currentMonth].charAt(0).toUpperCase()+monthNames[currentMonth].slice(1)} · {birthdayPatients.length} pacientes</div>
            </div>
          </div>
          {birthdayPatients.length===0?(
            <div style={{textAlign:"center",padding:"12px 0",color:"#8a9aaa",fontSize:12.5}}>Sin cumpleaños este mes</div>
          ):birthdayPatients.slice(0,8).map(p=>{
            const bDay=new Date(p.dob+"T00:00:00").getDate();
            const isToday=bDay===currentDay;
            return(
              <div key={p.id} style={{display:"flex",alignItems:"center",gap:10,padding:"7px 0",borderBottom:"1px solid #f0f4f8",background:isToday?"#fff8e0":"transparent",borderRadius:isToday?8:0,paddingLeft:isToday?8:0}}>
                <div style={{width:30,height:30,borderRadius:"50%",background:isToday?"linear-gradient(135deg,#f59223,#e07d10)":"#f0f4f8",display:"flex",alignItems:"center",justifyContent:"center",fontSize:11,fontWeight:700,color:isToday?"#fff":"#5a7a8a",flexShrink:0}}>{bDay}</div>
                <div style={{flex:1,minWidth:0}}>
                  <div style={{fontSize:12.5,fontWeight:600,color:"#1a2332",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}}>{p.firstName||p.first_name||''} {p.lastName||p.last_name||''}</div>
                  {isToday&&<div style={{fontSize:10.5,color:"#f59223",fontWeight:700}}>🎉 ¡Hoy!</div>}
                </div>
                <div style={{fontSize:11,color:"#8a9aaa",flexShrink:0}}>{calcAge(p.dob)} años</div>
              </div>
            );
          })}
          {birthdayPatients.length>8&&<div style={{fontSize:11,color:"#8a9aaa",textAlign:"center",marginTop:8}}>+{birthdayPatients.length-8} más</div>}
        </Card>
      </div>
      {movementModal&&(
        <Modal title="Movimientos de la Paciente" onClose={()=>setMovementModal(null)} width={820}>
          <div style={{background:"#f8fafc",border:"1px solid #e8edf2",borderRadius:10,padding:"12px 16px",marginBottom:14}}>
            <div style={{fontSize:15,fontWeight:800,color:"#1a2332"}}>{movementModal.name||"Paciente sin nombre"}</div>
            <div style={{fontSize:12,color:"#5a7a8a",marginTop:3}}>
              {(()=>{const st=attentionState(movementModal.attention);return <>DNI: <b>{movementKey(movementModal.attention).dni||"—"}</b> · Atención seleccionada: <b>{movementModal.attention.service||"—"}</b> · Estado: <b style={{color:st==="anulado"?"#dc2626":st==="pagado"?"#059669":"#d97706"}}>{st==="anulado"?"Anulado":st==="pagado"?"Cobrado":"Pendiente"}</b></>})()}
            </div>
          </div>
          {movementModal.rows.length===0?(
            <div style={{textAlign:"center",padding:"28px 0",color:"#8a9aaa"}}>No se encontraron movimientos relacionados.</div>
          ):(
            <div style={{display:"grid",gap:10,maxHeight:"58vh",overflowY:"auto",paddingRight:4}}>
              {movementModal.rows.map((m,i)=>(
                <div key={m.id||i} style={{border:"1px solid #e8edf2",borderLeft:`4px solid ${m.color}`,borderRadius:10,padding:"11px 14px",background:"#fff"}}>
                  <div style={{display:"flex",justifyContent:"space-between",gap:12,alignItems:"flex-start",marginBottom:6}}>
                    <div>
                      <div style={{fontSize:13,fontWeight:800,color:"#1a2332"}}>{m.tipo}</div>
                      <div style={{fontSize:11.5,color:"#8a9aaa"}}>{fmt(m.fecha)} · {m.hora} · {m.responsable}</div>
                    </div>
                    <div style={{textAlign:"right",flexShrink:0}}>
                      <div style={{fontSize:14,fontWeight:900,color:m.color}}>{currency(m.monto)}</div>
                      <span style={{display:"inline-block",fontSize:10.5,fontWeight:800,color:m.color,background:m.color+"14",borderRadius:999,padding:"2px 8px"}}>{m.estado}</span>
                    </div>
                  </div>
                  <div style={{fontSize:12.5,color:"#1a2332",fontWeight:600,marginBottom:4}}>{m.servicio}</div>
                  <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fit,minmax(160px,1fr))",gap:8,fontSize:11.5,color:"#5a7a8a"}}>
                    <div><b>Acción:</b> {m.accion}</div>
                    <div><b>Método:</b> {m.metodo}</div>
                    <div><b>Referencia:</b> {m.extra||"—"}</div>
                  </div>
                  {(m.raw?.anuladoMotivo||m.raw?.anuladoPor||m.raw?.anuladoAt)&&(
                    <div style={{marginTop:8,background:"#fff5f5",border:"1px solid #fecaca",borderRadius:8,padding:"8px 10px",fontSize:11.5,color:"#991b1b"}}>
                      <b>Anulación:</b> {m.raw.anuladoMotivo||"Sin motivo"} · Por: {m.raw.anuladoPor||"—"} · Fecha: {m.raw.anuladoAt||"—"}
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}
          <div style={{display:"flex",justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setMovementModal(null)}>Cerrar</Btn>
          </div>
        </Modal>
      )}
    </div>
  );
};

// ─── LOGIN ────────────────────────────────────────────────────────────────────
const Login=({onLogin,notice=""})=>{
  const[mode,setMode]=useState(null);
  // worker fields
  const[u,setU]=useState("");
  const[p,setP]=useState("");
  const[err,setErr]=useState("");
  const[loading,setLoading]=useState(false);
  const[createMode,setCreateMode]=useState(false);
  const[pendingUser,setPendingUser]=useState(null);
  const[np,setNp]=useState("");const[np2,setNp2]=useState("");const[createErr,setCreateErr]=useState("");
  const[forgotMode,setForgotMode]=useState(false);
  const[fgUser,setFgUser]=useState("");const[fgPwd,setFgPwd]=useState("");const[fgPwd2,setFgPwd2]=useState("");
  const[fgErr,setFgErr]=useState("");const[fgOk,setFgOk]=useState("");const[fgLoading,setFgLoading]=useState(false);
  const MASTER_TOKEN="d2dfb22fea760ef522d8d6ffeec5d568a5d97e799882316165cb356fbbf73e0c";
  useEffect(()=>{if(notice)setErr(notice);},[notice]);
  const doForgot=async()=>{
    if(!fgUser){setFgErr("Ingresa tu usuario");return;}
    if(fgPwd.length<4){setFgErr("Minimo 4 caracteres");return;}
    if(fgPwd!==fgPwd2){setFgErr("Las contrasenas no coinciden");return;}
    setFgLoading(true);setFgErr("");
    try{
      const r=await fetch(API_BASE+"/auth.php?action=reset_password",{
        method:"POST",
        headers:{"Content-Type":"application/json"},
        body:JSON.stringify({username:fgUser,new_password:fgPwd,master_token:MASTER_TOKEN})
      });
      const d=await r.json();
      if(d.ok){setFgOk("Contrasena actualizada. Ya puedes ingresar.");setFgPwd("");setFgPwd2("");}
      else setFgErr(d.error||"Error al cambiar contrasena");
    }catch(e){setFgErr("Error de conexion");}
    setFgLoading(false);
  };
  // user list for dropdown
  const[userList,setUserList]=useState([]);
  const[showDrop,setShowDrop]=useState(false);
  // client fields
  const[clientName,setClientName]=useState("");
  const[clientDni,setClientDni]=useState("");
  const[clientPhone,setClientPhone]=useState("");
  const[clientMsg,setClientMsg]=useState("");
  const[clientErr,setClientErr]=useState("");
  const[existingPatient,setExistingPatient]=useState(null); // paciente encontrado en BD
  const[dniChecking,setDniChecking]=useState(false);

  // Fetch user list from API for dropdown
  useEffect(()=>{
    if(mode!=='worker') return;
    // Endpoint público — no requiere token de sesión
    fetch(API_BASE+'/auth.php?action=user_list')
      .then(r=>r.json())
      .then(r=>{
        const list=(r.users||[]);
        if(list.length>0) setUserList(list);
        else throw new Error('empty');
      })
      .catch(()=>{
        // fallback: lista del backup mientras BD no esté lista
        setUserList([
          {username:'superadmin',name:'Super Administrador',role:'Super Admin'},
          {username:'admin',name:'Admin Principal',role:'Administrador'},
          {username:'oriana',name:'Oriana Valera',role:'Podólogo'},
          {username:'Joycelyn',name:'Joycelyn Guisasola',role:'Podólogo'},
          {username:'marce',name:'Marcelina De La Cruz Llacua',role:'Podólogo'},
          {username:'isa',name:'Isabel Vásquez',role:'Podólogo'},
          {username:'katti',name:'Kattiuska Bardales',role:'Podólogo'},
          {username:'lady',name:'Lady Oroche',role:'Podólogo'},
          {username:'movil',name:'Acceso Móvil',role:'Administrador'},
        ]);
      });
  },[mode]);

  const selectUser=(username)=>{setU(username);setShowDrop(false);setErr("");};

  const go=async()=>{
    setErr("");
    if(!u){setErr("Seleccione o ingrese su usuario");return;}
    setLoading(true);
    try{
      const d=await apiFetch('/auth?action=check_user',{method:'POST',body:JSON.stringify({username:u})});
      if(!d.exists){setErr("Usuario '"+u+"' no encontrado");setLoading(false);return;}
      if(d.no_password){
        setPendingUser({id:d.id,username:u,name:d.name,role:d.role});
        setCreateMode(true);setLoading(false);return;
      }
      if(!p){setErr("Ingrese su contraseña");setLoading(false);return;}
      const d2=await apiFetch('/auth?action=login',{method:'POST',body:JSON.stringify({username:u,password:p})});
      if(d2.ok&&d2.token){
        // The token must be active before any authenticated data request.
        _authToken=d2.token;
        localStorage.setItem('podo_token',d2.token);
        const [loadedPatients]=await Promise.all([
          api.get('patients',{strict:true}),
          api.get('appointments',{strict:true}),
          api.get('users',{strict:true}),
          api.get('services'),
          api.get('categories'),
          api.get('commission_scheme'),
        ]);
        // Recargar permisos de módulos con token ya disponible (puede tener datos más frescos)
        try{
          const mpR=await fetch(API_BASE+'/special.php?action=module_perms');
          const mpD=await mpR.json();
          if(mpD&&mpD.perms&&Object.keys(mpD.perms).length>0){
            _cache['pmb_module_perms']=mpD.perms;
            _cache[SK.modulePerms]=mpD.perms;
            if(mpD.lockedOff){_cache['pmb_module_locked_off']=mpD.lockedOff;}
          }
        }catch{}
        onLogin(d2.user,d2.token,loadedPatients);
        warmupKeys(['inventory','sales_products','sales_services','sales_orders','suppliers',
           'photos','laboratory','payments','memberships','cashbox_cuts']);
      }else{setErr(d2.error||"Contraseña incorrecta");setLoading(false);}
    }catch(e){setErr(e.message||"No se pudo conectar");setLoading(false);}
  };

  const saveNewPassword=async()=>{
    setCreateErr("");
    if(np.length<6){setCreateErr("La contraseña debe tener al menos 6 caracteres");return;}
    if(np!==np2){setCreateErr("Las contraseñas no coinciden");return;}
    try{
      const d=await apiFetch('/auth?action=set_password',{method:'POST',body:JSON.stringify({username:pendingUser.username,password:np})});
      if(d.ok&&d.token){
        _authToken=d.token;
        localStorage.setItem('podo_token',d.token);
        const [loadedPatients]=await Promise.all([
          api.get('patients',{strict:true}),
          api.get('appointments',{strict:true}),
          api.get('users',{strict:true}),
          api.get('services'),
          api.get('categories'),
          api.get('commission_scheme'),
        ]);
        onLogin(d.user,d.token,loadedPatients);
        warmupKeys(['inventory','sales_products','sales_services','sales_orders','suppliers',
           'photos','laboratory','payments','memberships','cashbox_cuts']);
      }else{setCreateErr(d.error||"Error al guardar contraseña");}
    }catch(e){setCreateErr(e.message||"No se pudo conectar");}
  };

  const sendClientRequest=async()=>{
    setClientErr("");
    if(!clientName.trim()||!clientDni.trim()){setClientErr("Nombre y DNI son obligatorios");return;}
    if(clientDni.length!==8){setClientErr("DNI debe tener exactamente 8 dígitos");return;}
    // Check if DNI already has a pending visit today
    const todayVisits=safeJson(localStorage.getItem('podo_client_visits'),[]);
    const already=todayVisits.find(v=>v.dni===clientDni.trim());
    if(already){
      setClientErr("Ya existe una solicitud registrada para el DNI "+clientDni+". El personal le atenderá en breve.");
      return;
    }
    // Save visit
    todayVisits.push({name:clientName.trim(),dni:clientDni.trim(),phone:clientPhone.trim(),time:new Date().toLocaleTimeString('es-PE',{hour:'2-digit',minute:'2-digit'})});
    localStorage.setItem('podo_client_visits',JSON.stringify(todayVisits));
    setClientMsg("Solicitud enviada. El personal le atenderá en breve. Gracias.");
    setTimeout(()=>setMode(null),3500);
  };

  const roleColor={"Super Admin":"#7c3aed",Administrador:"#e05050",Podólogo:"#2563eb",Recepcionista:"#2ea87e"};

  const WRAP=(children)=>(
    <div style={{minHeight:"100vh",background:"linear-gradient(135deg,#0a1f2e 0%,#0f3a2a 45%,#1a4a5a 100%)",display:"flex",alignItems:"center",justifyContent:"center",padding:16,position:"relative",overflow:"hidden"}}>
      <div style={{position:"absolute",top:"-80px",left:"5%",width:300,height:300,borderRadius:"50%",background:"#5dd4c6",opacity:0.06,pointerEvents:"none"}}/>
      <div style={{position:"absolute",top:"auto",right:"-60px",width:200,height:200,borderRadius:"50%",background:"#4a9d8f",opacity:0.06,pointerEvents:"none"}}/>
      {children}
    </div>
  );

  // ── SELECTOR INICIAL ──────────────────────────────────────────────────────
  if(!mode) return WRAP(
    <div className="fade-in" style={{background:"rgba(255,255,255,0.97)",borderRadius:22,padding:"40px 36px",width:"100%",maxWidth:400,boxShadow:"0 32px 100px rgba(0,0,0,0.4)",textAlign:"center"}}>
      <Logo size={72} style={{marginBottom:12}}/>
      <div style={{fontFamily:"'Lora',serif",fontSize:20,fontWeight:600,color:"#1a3a4a",marginBottom:4}}>PodoCLINIC</div>
      <div style={{fontSize:11,color:"#8a9aaa",marginBottom:28,letterSpacing:"0.08em",textTransform:"uppercase"}}>Sistema de Gestión v4.0</div>
      <div style={{fontSize:13,color:"#5a7a8a",marginBottom:20,fontWeight:500}}>Seleccione cómo desea ingresar:</div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12}}>
        <button onClick={()=>setMode("worker")} style={{padding:"18px 12px",background:"linear-gradient(135deg,#0f3a2a,#1a5a3a)",border:"none",borderRadius:14,cursor:"pointer",color:"#fff",transition:"transform .15s"}}
          onMouseOver={e=>e.currentTarget.style.transform="scale(1.03)"}
          onMouseOut={e=>e.currentTarget.style.transform="scale(1)"}>
          <div style={{fontSize:28,marginBottom:8}}>👩‍⚕️</div>
          <div style={{fontSize:13,fontWeight:700,marginBottom:3}}>Trabajador</div>
          <div style={{fontSize:10.5,opacity:0.75}}>Personal de la clínica</div>
        </button>
        <button onClick={()=>setMode("client")} style={{padding:"18px 12px",background:"linear-gradient(135deg,#1a3a6a,#2a5a9a)",border:"none",borderRadius:14,cursor:"pointer",color:"#fff",transition:"transform .15s"}}
          onMouseOver={e=>e.currentTarget.style.transform="scale(1.03)"}
          onMouseOut={e=>e.currentTarget.style.transform="scale(1)"}>
          <div style={{fontSize:28,marginBottom:8}}>🧑‍🦯</div>
          <div style={{fontSize:13,fontWeight:700,marginBottom:3}}>Cliente</div>
          <div style={{fontSize:10.5,opacity:0.75}}>Registrar mi visita</div>
        </button>
      </div>
    </div>
  );

  // ── MODO CLIENTE ──────────────────────────────────────────────────────────
  if(mode==="client") return WRAP(
    <div className="fade-in" style={{background:"rgba(255,255,255,0.97)",borderRadius:22,padding:"36px 32px",width:"100%",maxWidth:400,boxShadow:"0 32px 100px rgba(0,0,0,0.4)"}}>
      <div style={{textAlign:"center",marginBottom:20}}>
        <Logo size={60} style={{marginBottom:10}}/>
        <div style={{fontFamily:"'Lora',serif",fontSize:17,fontWeight:600,color:"#1a3a4a",marginBottom:4}}>Registro de Visita</div>
        <div style={{fontSize:12,color:"#6a8a9a",lineHeight:1.5}}>Complete sus datos y el personal le atenderá.</div>
      </div>
      {clientErr&&<div className="pop-in" style={{background:"#fff3cd",border:"1px solid #ffc107",borderRadius:10,padding:"10px 14px",fontSize:12.5,color:"#856404",marginBottom:14,textAlign:"center"}}>{clientErr}</div>}
      {clientMsg&&<div className="pop-in" style={{background:"#f0faf5",border:"1px solid #4a9d8f",borderRadius:10,padding:"10px 14px",fontSize:12.5,color:"#1a6a4a",marginBottom:14,textAlign:"center"}}>✓ {clientMsg}</div>}
      {!clientMsg&&<>
        <Field label="Nombre completo *"><Inp value={clientName} onChange={e=>setClientName(e.target.value)} placeholder="Ingrese su nombre completo"/></Field>
        <Field label="DNI *">
          <Inp value={clientDni} onChange={e=>{
            const val=e.target.value.replace(/[^0-9]/g,'').slice(0,8);
            setClientDni(val);
            setExistingPatient(null);
            setClientErr('');
            if(val.length===8){
              setDniChecking(true);
              // Buscar en cache local primero
              const cached=_cache['patients']||[];
              const found=cached.find(p=>String(p.dni||'')===val);
              if(found){
                setExistingPatient(found);
                setDniChecking(false);
              } else {
                // Consultar servidor
                fetch(API_BASE+'/crud.php?entity=patients&dni='+val)
                  .then(r=>r.json())
                  .then(r=>{
                    const rows=Array.isArray(r)?r:(r.data||[]);
                    const hit=rows.find(p=>String(p.dni||'')===val);
                    if(hit)setExistingPatient(hit);
                  })
                  .catch(()=>{})
                  .finally(()=>setDniChecking(false));
              }
            }
          }} placeholder="Número de DNI (8 dígitos)" maxLength={8}/>
          {dniChecking&&<div style={{fontSize:11,color:'#8a9aaa',marginTop:4}}>⏳ Consultando base de datos...</div>}
        </Field>
        <Field label="Celular (opcional)"><Inp value={clientPhone} onChange={e=>setClientPhone(e.target.value)} placeholder="Número de celular" type="tel"/></Field>
        {/* Ventana flotante: paciente ya registrado en BD */}
        {existingPatient&&(
          <div className="pop-in" style={{background:'#f0fdf4',border:'2px solid #4a9d8f',borderRadius:14,padding:'14px 16px',marginBottom:10}}>
            <div style={{display:'flex',alignItems:'flex-start',gap:10}}>
              <div style={{fontSize:24,flexShrink:0}}>✅</div>
              <div style={{flex:1}}>
                <div style={{fontWeight:700,fontSize:13.5,color:'#1a5a3a',marginBottom:4}}>
                  Paciente registrado en el sistema
                </div>
                <div style={{fontSize:13,color:'#2a7a4a',marginBottom:2}}>
                  <strong>{((existingPatient.firstName||existingPatient.first_name||'')+' '+(existingPatient.lastName||existingPatient.last_name||'')).trim()}</strong>
                </div>
                <div style={{fontSize:11.5,color:'#5a7a6a'}}>
                  DNI: {existingPatient.dni} · {existingPatient.phone?'📱 '+existingPatient.phone:''}
                </div>
                <div style={{marginTop:6,fontSize:12,color:'#1a7a4a',fontWeight:600,background:'#d4f0e8',padding:'4px 10px',borderRadius:8,display:'inline-block'}}>
                  📋 Su historia clínica ya está registrada — el personal le atenderá directamente
                </div>
              </div>
            </div>
          </div>
        )}
        <Btn onClick={sendClientRequest} size="lg" style={{width:"100%",justifyContent:"center",marginTop:8,background:"linear-gradient(135deg,#1a3a6a,#2a5a9a)",borderColor:"transparent",color:"#fff"}}>
          <Icon name="check" size={15}/>{existingPatient?'Confirmar llegada':'Registrar mi visita'}
        </Btn>
      </>}
      <div style={{textAlign:"center",marginTop:14}}>
        <button onClick={()=>{setMode(null);setClientErr("");setClientMsg("");setClientName("");setClientDni("");setClientPhone("");}} style={{background:"none",border:"none",fontSize:12,color:"#8a9aaa",cursor:"pointer",textDecoration:"underline"}}>← Volver</button>
      </div>
    </div>
  );

  // ── TRABAJADOR: CREAR CONTRASEÑA (primer ingreso) ─────────────────────────
  if(forgotMode) return(
    <div style={{width:"100%",maxWidth:400}}>
      <div style={{textAlign:"center",marginBottom:20}}>
        <div style={{fontSize:28,marginBottom:8}}>🔑</div>
        <div style={{fontFamily:"'Lora',serif",fontSize:18,fontWeight:600,color:"#1a3a4a",marginBottom:6}}>Recuperar Acceso</div>
        <div style={{fontSize:12.5,color:"#6a8a9a"}}>Ingresa tu usuario y establece una nueva contraseña.</div>
      </div>
      {fgOk?(
        <div style={{background:"#f0f9f7",border:"1.5px solid #4a9d8f",borderRadius:10,padding:"14px 16px",textAlign:"center",marginBottom:16}}>
          <div style={{fontSize:22,marginBottom:6}}>✅</div>
          <div style={{fontSize:13.5,color:"#2a6a5a",fontWeight:600}}>{fgOk}</div>
          <button onClick={()=>{setForgotMode(false);setFgOk("");}} style={{marginTop:12,background:"#4a9d8f",color:"#fff",border:"none",borderRadius:8,padding:"9px 20px",fontSize:13,fontWeight:600,cursor:"pointer"}}>
            Ir al Login →
          </button>
        </div>
      ):(
        <>
          <Field label="Usuario"><Inp value={fgUser} onChange={e=>setFgUser(e.target.value)} placeholder="Tu nombre de usuario" autoFocus/></Field>
          <Field label="Nueva Contraseña"><Inp type="password" value={fgPwd} onChange={e=>setFgPwd(e.target.value)} placeholder="Mínimo 4 caracteres"/></Field>
          <Field label="Confirmar Contraseña"><Inp type="password" value={fgPwd2} onChange={e=>setFgPwd2(e.target.value)} placeholder="Repite la contraseña" onKeyDown={e=>e.key==="Enter"&&doForgot()}/></Field>
          {fgErr&&<div style={{color:"#e05050",fontSize:12.5,marginBottom:8}}>⚠ {fgErr}</div>}
          <Btn onClick={doForgot} disabled={fgLoading} size="lg" style={{width:"100%",justifyContent:"center",marginTop:4}}>
            {fgLoading?"Procesando...":"Cambiar Contraseña"}
          </Btn>
        </>
      )}
      <div style={{textAlign:"center",marginTop:14}}>
        <button onClick={()=>setForgotMode(false)} style={{background:"none",border:"none",fontSize:12,color:"#8a9aaa",cursor:"pointer",textDecoration:"underline"}}>← Volver al login</button>
      </div>
    </div>
  );
  if(createMode&&pendingUser) return WRAP(
    <div className="fade-in" style={{background:"rgba(255,255,255,0.97)",borderRadius:22,padding:44,width:"100%",maxWidth:390,boxShadow:"0 32px 100px rgba(0,0,0,0.4)"}}>
      <div style={{textAlign:"center",marginBottom:24}}>
        <Logo size={72} style={{marginBottom:12}}/>
        <div style={{fontSize:22,marginBottom:6}}>🔐</div>
        <div style={{fontFamily:"'Lora',serif",fontSize:18,fontWeight:600,color:"#1a3a4a",marginBottom:6}}>Crear contraseña</div>
        <div style={{fontSize:12.5,color:"#6a8a9a",lineHeight:1.5}}>Hola <strong>{pendingUser.name||pendingUser.username}</strong>, es tu primer ingreso.<br/>Crea una contraseña para tu cuenta.</div>
      </div>
      {createErr&&<div className="pop-in" style={{background:"#fff0f0",border:"1px solid #f5b0b0",borderRadius:10,padding:"10px 14px",fontSize:13,color:"#c03030",marginBottom:14}}>{createErr}</div>}
      <Field label="Nueva contraseña"><Inp type="password" value={np} onChange={e=>setNp(e.target.value)} placeholder="Mínimo 6 caracteres"/></Field>
      {np&&<div style={{marginTop:-10,marginBottom:12,padding:"4px 10px",borderRadius:6,fontSize:11.5,fontWeight:600,
        background:np.length<6?"#fff0f0":np.length<10?"#fffbe6":"#f0faf5",
        color:np.length<6?"#c03030":np.length<10?"#92620a":"#1a6a4a",border:"1px solid",
        borderColor:np.length<6?"#f5b0b0":np.length<10?"#f59e0b44":"#2ea87e44"}}>
        {np.length<6?"⚠️ Muy corta":np.length<10?"● Regular":"● Fuerte"}
      </div>}
      <Field label="Confirmar contraseña"><Inp type="password" value={np2} onChange={e=>setNp2(e.target.value)} placeholder="Repetir contraseña" onKeyDown={e=>e.key==="Enter"&&saveNewPassword()}/></Field>
      <Btn onClick={saveNewPassword} size="lg" style={{width:"100%",justifyContent:"center",marginTop:4}}><Icon name="check" size={15}/>Guardar y Entrar</Btn>
      <div style={{textAlign:"center",marginTop:14}}>
        <button onClick={()=>{setCreateMode(false);setPendingUser(null);setNp("");setNp2("");}} style={{background:"none",border:"none",fontSize:12,color:"#8a9aaa",cursor:"pointer",textDecoration:"underline"}}>← Volver al login</button>
      </div>
    </div>
  );

  // ── TRABAJADOR: LOGIN CON DROPDOWN ────────────────────────────────────────
  return WRAP(
    <div className="fade-in" style={{background:"rgba(255,255,255,0.97)",borderRadius:22,padding:"36px 40px",width:"100%",maxWidth:400,boxShadow:"0 32px 100px rgba(0,0,0,0.4)",position:"relative",zIndex:1}}>
      <div style={{textAlign:"center",marginBottom:28}}>
        <Logo size={80} style={{marginBottom:12}}/>
        <div style={{fontFamily:"'Lora',serif",fontSize:20,fontWeight:500,color:"#1a3a4a"}}>Podología Más Bela</div>
        <div style={{fontSize:10.5,color:"#9aacb8",marginTop:4,letterSpacing:"0.1em",textTransform:"uppercase"}}>Sistema de Gestión v4.0</div>
      </div>
      {err&&<div className="pop-in" style={{background:"#fff0f0",border:"1px solid #f5b0b0",borderRadius:10,padding:"10px 14px",fontSize:13,color:"#c03030",marginBottom:16}}>{err}</div>}

      {/* USUARIO DESPLEGABLE */}
      <div style={{marginBottom:14,position:"relative"}}>
        <label style={{display:"block",fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em",marginBottom:6}}>Usuario</label>
        <div style={{position:"relative"}}>
          <div onClick={()=>setShowDrop(!showDrop)}
            style={{width:"100%",padding:"10px 36px 10px 12px",border:"1.5px solid",borderColor:showDrop?"#4a9d8f":"#d4dde5",borderRadius:10,fontSize:13.5,color:u?"#1a2332":"#9aacb8",background:"#fff",cursor:"pointer",display:"flex",alignItems:"center",gap:10,userSelect:"none",transition:"border-color .15s"}}>
            {u&&userList.find(ul=>ul.username===u)?(()=>{
              const found=userList.find(ul=>ul.username===u);
              return(<>
                <div style={{width:28,height:28,borderRadius:"50%",background:(roleColor[found.role]||"#4a9d8f")+"22",border:"1.5px solid "+(roleColor[found.role]||"#4a9d8f")+"44",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:700,color:roleColor[found.role]||"#4a9d8f",flexShrink:0}}>{(found.name||found.username)[0].toUpperCase()}</div>
                <div style={{flex:1}}>
                  <div style={{fontSize:13,fontWeight:600,color:"#1a2332"}}>{found.name||found.username}</div>
                  <div style={{fontSize:10,color:"#8a9aaa"}}>{found.role}</div>
                </div>
              </>);
            })():<span>Seleccione su usuario...</span>}
            <div style={{position:"absolute",right:12,top:"50%",transform:"translateY(-50%) rotate("+(showDrop?"180":"0")+"deg)",transition:"transform .2s",color:"#8a9aaa",fontSize:12}}>▼</div>
          </div>
          {showDrop&&(
            <div style={{position:"absolute",top:"calc(100% + 4px)",left:0,right:0,background:"#fff",border:"1.5px solid #4a9d8f44",borderRadius:10,boxShadow:"0 8px 24px rgba(0,0,0,0.12)",zIndex:200,overflow:"hidden",maxHeight:220,overflowY:"auto"}}>
              {userList.length===0&&<div style={{padding:"12px 16px",fontSize:12.5,color:"#8a9aaa",textAlign:"center"}}>Cargando usuarios...</div>}
              {userList.map(ul=>(
                <div key={ul.username} onClick={()=>selectUser(ul.username)}
                  style={{padding:"9px 14px",cursor:"pointer",display:"flex",alignItems:"center",gap:10,transition:"background .1s",borderBottom:"1px solid #f0f4f8"}}
                  onMouseOver={e=>e.currentTarget.style.background="#f0faf7"}
                  onMouseOut={e=>e.currentTarget.style.background="transparent"}>
                  <div style={{width:30,height:30,borderRadius:"50%",background:(roleColor[ul.role]||"#4a9d8f")+"18",border:"1.5px solid "+(roleColor[ul.role]||"#4a9d8f")+"33",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:700,color:roleColor[ul.role]||"#4a9d8f",flexShrink:0}}>{(ul.name||ul.username)[0].toUpperCase()}</div>
                  <div style={{flex:1}}>
                    <div style={{fontSize:13,fontWeight:600,color:"#1a2332"}}>{ul.name||ul.username}</div>
                    <div style={{fontSize:10.5,color:"#8a9aaa"}}>{ul.username} · {ul.role}</div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      <Field label="Contraseña"><Inp type="password" value={p} onChange={e=>setP(e.target.value)} placeholder="••••••••" onKeyDown={e=>e.key==="Enter"&&go()}/></Field>
      <Btn onClick={go} disabled={loading} size="lg" style={{width:"100%",justifyContent:"center",marginTop:12}}>
        {loading?<span className="pulse">Verificando...</span>:<><Icon name="arrow" size={15}/>Iniciar Sesión</>}
      </Btn>
      <div style={{textAlign:"center",marginTop:10}}>
        <button onClick={()=>{setForgotMode(true);setFgErr("");setFgOk("");}} style={{background:"none",border:"none",fontSize:12,color:"#4a9d8f",cursor:"pointer",textDecoration:"underline"}}>¿Olvidaste tu contraseña?</button>
      </div>
      <div style={{textAlign:"center",marginTop:6}}>
        <button onClick={()=>setMode(null)} style={{background:"none",border:"none",fontSize:12,color:"#8a9aaa",cursor:"pointer",textDecoration:"underline"}}>← Cambiar modo de acceso</button>
      </div>
    </div>
  );
};

// ─── MÓDULO PROVEEDORES ───────────────────────────────────────────────────────
const SuppliersModule=()=>{
  const[suppliers,setSuppliers]=useState(db.get(SK.suppliers)||[]);
  const[modal,setModal]=useState(false);const[editItem,setEditItem]=useState(null);
  const[search,setSearch]=useState("");
  const blank={name:"",contact:"",phone:"",email:"",address:"",ruc:"",category:"",notes:""};
  const[form,setForm]=useState(blank);
  const[rucLoading,setRucLoading]=useState(false);
  const[rucStatus,setRucStatus]=useState(null); // null | "ok" | "error"

  const consultRUC=async()=>{
    const ruc=form.ruc?.trim();
    if(!ruc||ruc.length<8){alert("Ingrese un RUC/NIT válido (mínimo 8 dígitos)");return}
    setRucLoading(true);setRucStatus(null);
    try{
      // Try SUNAT API via free proxy
      const r=await fetch(`https://api.sunat.cloud/v1/contribuyente/consultaruc?ruc=${ruc}`,{signal:AbortSignal.timeout(5000)});
      if(r.ok){
        const d=await r.json();
        if(d.nombre||d.razonSocial){
          const name=d.razonSocial||d.nombre||"";
          setForm(p=>({...p,name,address:d.direccion||p.address}));
          setRucStatus("ok");
        } else {setRucStatus("error")}
      } else {setRucStatus("error")}
    }catch{
      // No internet or API unavailable - allow manual entry
      setRucStatus("manual");
    }
    setRucLoading(false);
  };

  const save=async()=>{
    if(!form.name){alert("Ingrese el nombre del proveedor");return}
    const local={...form,id:editItem?.id||genId(suppliers)};
    try{
      await saveCrudAndSync('suppliers',local,SK.suppliers,setSuppliers,editItem?undefined:local.id);
      setModal(false);setEditItem(null);setForm(blank);setRucStatus(null);
      alert("✅ Proveedor guardado en la base de datos");
    }catch(e){alert("No se guardó el proveedor en la base de datos: "+e.message);}
  };
  const del=id=>{if(window.confirm("¿Eliminar proveedor?"))removeCrudAndSync('suppliers',id,SK.suppliers,setSuppliers).catch(e=>alert("No se pudo eliminar el proveedor en la base de datos: "+e.message))};
  const openEdit=s=>{setEditItem(s);setForm({...s});setModal(true);setRucStatus(s.ruc?"ok":null)};
  const filtered=suppliers.filter(s=>!search||`${s.name} ${s.contact} ${s.ruc}`.toLowerCase().includes(search.toLowerCase()));

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Proveedores</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>{suppliers.length} proveedores registrados</div>
        </div>
        <Btn onClick={()=>{setEditItem(null);setForm(blank);setRucStatus(null);setModal(true)}}><Icon name="plus" size={14}/>Nuevo Proveedor</Btn>
      </div>
      <Card style={{marginBottom:14,padding:"12px 16px"}}>
        <div style={{position:"relative"}}>
          <div style={{position:"absolute",left:11,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={15}/></div>
          <input value={search} onChange={e=>setSearch(e.target.value)} placeholder="Buscar por nombre, contacto o RUC..." style={{width:"100%",padding:"8px 12px 8px 34px",border:"1.5px solid #d4dde5",borderRadius:9,fontSize:13.5,outline:"none"}}/>
        </div>
      </Card>
      {filtered.length===0&&(
        <Card style={{textAlign:"center",padding:48}}>
          <div style={{fontSize:40,marginBottom:10}}>🚚</div>
          <div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin proveedores registrados</div>
          <Btn onClick={()=>{setEditItem(null);setForm(blank);setRucStatus(null);setModal(true)}}><Icon name="plus" size={13}/>Agregar Proveedor</Btn>
        </Card>
      )}
      {filtered.length>0&&(
        <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(300px,1fr))",gap:14}}>
          {filtered.map(s=>(
            <Card key={s.id} style={{transition:"transform .15s"}} onMouseOver={e=>e.currentTarget.style.transform="translateY(-2px)"} onMouseOut={e=>e.currentTarget.style.transform="none"}>
              <div style={{display:"flex",alignItems:"flex-start",justifyContent:"space-between",marginBottom:10}}>
                <div style={{display:"flex",alignItems:"center",gap:10}}>
                  <div style={{width:42,height:42,borderRadius:10,background:"linear-gradient(135deg,#4a9d8f22,#2563eb18)",border:"2px solid #4a9d8f33",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,flexShrink:0}}>🏭</div>
                  <div>
                    <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{s.name}</div>
                    {s.ruc&&<div style={{fontSize:11,color:"#8a9aaa",fontFamily:"monospace"}}>RUC: {s.ruc}</div>}
                  </div>
                </div>
                {s.category&&<Badge color="teal">{s.category}</Badge>}
              </div>
              <div style={{display:"grid",gap:4,fontSize:12.5,color:"#3a5a6a"}}>
                {s.contact&&<div style={{display:"flex",gap:6}}><span style={{color:"#8a9aaa",width:60,flexShrink:0}}>Contacto:</span><span style={{fontWeight:500}}>{s.contact}</span></div>}
                {s.phone&&<div style={{display:"flex",gap:6}}><span style={{color:"#8a9aaa",width:60,flexShrink:0}}>Teléfono:</span><span>{s.phone}</span></div>}
                {s.email&&<div style={{display:"flex",gap:6}}><span style={{color:"#8a9aaa",width:60,flexShrink:0}}>Email:</span><span style={{wordBreak:"break-all"}}>{s.email}</span></div>}
              </div>
              {s.notes&&<div style={{marginTop:8,fontSize:11.5,color:"#8a9aaa",background:"#f8fafc",borderRadius:6,padding:"6px 10px"}}>{s.notes}</div>}
              <div style={{display:"flex",gap:6,marginTop:12}}>
                <Btn size="sm" variant="ghost" onClick={()=>openEdit(s)}><Icon name="edit" size={11}/>Editar</Btn>
                <Btn size="sm" variant="danger" onClick={()=>del(s.id)}><Icon name="trash" size={11}/></Btn>
              </div>
            </Card>
          ))}
        </div>
      )}
      {modal&&(
        <Modal title={editItem?"Editar Proveedor":"Nuevo Proveedor"} onClose={()=>{setModal(false);setEditItem(null);setRucStatus(null)}} width={540}>
          {/* RUC first */}
          <Field label="RUC / NIT *">
            <div style={{display:"flex",gap:8}}>
              <Inp value={form.ruc||""} onChange={e=>{setForm(p=>({...p,ruc:e.target.value}));setRucStatus(null)}} placeholder="20XXXXXXXXX o NIT" style={{flex:1}}/>
              <Btn onClick={consultRUC} variant={rucStatus==="ok"?"success":"ghost"} style={{flexShrink:0}} disabled={rucLoading}>
                {rucLoading?<span className="pulse">⏳</span>:rucStatus==="ok"?"✅ OK":rucStatus==="error"?"❌ No hallado":"🔍 Consultar SUNAT"}
              </Btn>
            </div>
            {rucStatus==="error"&&<div style={{fontSize:11.5,color:"#e05050",marginTop:4}}>RUC no encontrado en SUNAT. Ingrese el nombre manualmente.</div>}
            {rucStatus==="manual"&&<div style={{fontSize:11.5,color:"#f59223",marginTop:4}}>Sin conexión a SUNAT. Ingrese los datos manualmente.</div>}
          </Field>
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
            <Field label="Nombre / Razón Social *" col="1/-1"><Inp value={form.name||""} onChange={e=>setForm(p=>({...p,name:e.target.value}))}/></Field>
            <Field label="Categoría">
              <Sel value={form.category||""} onChange={e=>setForm(p=>({...p,category:e.target.value}))}>
                <option value="">Seleccionar categoría...</option>
                {(db.get(SK.categories)||DEF_CATEGORIES).map(c=><option key={c.id} value={c.name}>{c.name}</option>)}
                <option value="Otro">Otro</option>
              </Sel>
            </Field>
            <Field label="Contacto Principal"><Inp value={form.contact||""} onChange={e=>setForm(p=>({...p,contact:e.target.value}))}/></Field>
            <Field label="Teléfono"><Inp value={form.phone||""} onChange={e=>setForm(p=>({...p,phone:e.target.value}))} placeholder="+51 999 000 000"/></Field>
            <Field label="Correo Electrónico" col="1/-1"><Inp value={form.email||""} onChange={e=>setForm(p=>({...p,email:e.target.value}))} placeholder="proveedor@empresa.com"/></Field>
            <Field label="Dirección" col="1/-1"><Inp value={form.address||""} onChange={e=>setForm(p=>({...p,address:e.target.value}))}/></Field>
          </div>
          <Field label="Notas"><TA value={form.notes||""} onChange={e=>setForm(p=>({...p,notes:e.target.value}))} placeholder="Condiciones de pago, observaciones..."/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>{setModal(false);setEditItem(null);setRucStatus(null)}}>Cancelar</Btn><Btn onClick={save}><Icon name="check" size={13}/>Guardar Proveedor</Btn></div>
        </Modal>
      )}
    </div>
  );
};

// ─── MÓDULO VENTAS ────────────────────────────────────────────────────────────
// ─── REVISIÓN DE VENTAS ───────────────────────────────────────────────────────
const RevisionVentas=({currentUser})=>{
  const isAdmin=currentUser?.role==="Administrador"||isSA(currentUser);
  const[inv,setInv]=useState((db.get(SK.inventory)||[]).map(p=>({
    ...p,
    code:      p.code||'',
    code_type: p.code_type||'',
    price:     parseFloat(p.price||p.price_sell||0),
    cost:    parseFloat(p.cost||p.price_buy||0),
    stock:   parseInt(p.stock||0),
    minStock:parseInt(p.minStock||p.min_stock||0),
    unit:    p.unit||'unidad',
  })));
  const[, forceRender]=useState(0);
  const rerender=()=>forceRender(n=>n+1);

  // Modal de confirmación de actualización
  const[confirmModal,setConfirmModal]=useState(null);
  // {type:"order", order, items:[{prodId, prodName, source, qtyToDeduct, currentStock}]}
  // {type:"bulk", items:[...], orders:[...]}

  const[filterStatus,setFilterStatus]=useState("all"); // all | cobrado | pendiente
  const[filterSource,setFilterSource]=useState("all"); // all | inventory | catalog
  const[expanded,setExpanded]=useState({});
  const[selectedOrders,setSelectedOrders]=useState({});

  // ── Cargar datos frescos ──────────────────────────────────────────────────
  const allOrders=db.get(SK.salesOrders)||[];
  const allInv=db.get(SK.inventory)||[];
  const allSalProds=db.get(SK.salesProducts)||[];

  // ── Función: detectar si un move ya fue registrado para este order ────────
  const moveExistsForOrder=(product,orderCode,qty)=>{
    const moves=product.moves||[];
    return moves.some(m=>
      m.type==="salida"&&
      m.note&&m.note.includes(orderCode)&&
      parseInt(m.qty)===parseInt(qty)
    );
  };

  // ── Analizar todas las órdenes con productos ───────────────────────────────
  const buildAnalysis=()=>{
    const orders=db.get(SK.salesOrders)||[];
    const curInv=db.get(SK.inventory)||[];
    const curSalProds=db.get(SK.salesProducts)||[];

    return orders
      .filter(o=>o.items&&o.items.some(i=>i._type==="product"))
      .map(o=>{
        const productItems=o.items.filter(i=>i._type==="product");
        const itemDetails=productItems.map(item=>{
          const qty=parseInt(item.qty)||1;

          if(item._source==="inventory"){
            const prod=curInv.find(p=>String(p.id)===String(item._id)||p.name===item.name);
            const alreadyMoved=prod?moveExistsForOrder(prod,o.code,qty):false;
            return{
              _id:item._id,
              name:item.name,
              source:"inventory",
              qty,
              currentStock:prod?(parseInt(prod.stock)||0):null,
              minStock:prod?(parseInt(prod.minStock)||0):null,
              prodFound:!!prod,
              alreadyReconciled:alreadyMoved,
              stockAfter:prod?Math.max(0,(parseInt(prod.stock)||0)-qty):null,
            };
          }else{
            // catalog (salesProducts)
            const prod=curSalProds.find(p=>String(p.id)===String(item._id)||p.name===item.name);
            const alreadyMoved=prod&&prod.moves?moveExistsForOrder(prod,o.code,qty):
              (o.status==="cobrado"&&prod?(
                // Heuristic: si el stock se redujo (less than when created) asumimos que ya fue procesado
                // Marcamos como reconciliado si la orden tiene paidAt y stock parece reducido
                false // Always show catalog items as candidates unless explicitly marked
              ):false);
            return{
              _id:item._id,
              name:item.name,
              source:"catalog",
              qty,
              currentStock:prod?(parseInt(prod.stock)||0):null,
              minStock:prod?(parseInt(prod.minStock)||0):null,
              prodFound:!!prod,
              alreadyReconciled:o._invUpdated===true,
              stockAfter:prod?Math.max(0,(parseInt(prod.stock)||0)-qty):null,
            };
          }
        });

        const pendingItems=itemDetails.filter(i=>!i.alreadyReconciled&&i.prodFound);
        const unresolvedItems=itemDetails.filter(i=>!i.alreadyReconciled&&!i.prodFound);

        return{
          order:o,
          itemDetails,
          pendingItems,
          unresolvedItems,
          allReconciled:pendingItems.length===0&&unresolvedItems.length===0,
          partiallyReconciled:itemDetails.some(i=>i.alreadyReconciled)&&pendingItems.length>0,
        };
      });
  };

  const analysis=buildAnalysis();

  // ── Filtrar ──────────────────────────────────────────────────────────────
  const filtered=analysis.filter(a=>{
    if(filterStatus!=="all"&&a.order.status!==filterStatus)return false;
    if(filterSource!=="all")return a.itemDetails.some(i=>i.source===filterSource);
    return true;
  });

  const pendingCount=analysis.filter(a=>!a.allReconciled).length;
  const reconcCount=analysis.filter(a=>a.allReconciled).length;

  // ── Aplicar actualización de inventario para UNA orden ───────────────────
  const applyReconciliation=(orderAnalysis)=>{
    const{order,pendingItems}=orderAnalysis;
    let curInv=[...( db.get(SK.inventory)||[])];
    let curSalProds=[...(db.get(SK.salesProducts)||[])];

    pendingItems.forEach(item=>{
      const qty=item.qty;
      const note=`Venta ${order.code} (reconciliación ${todayStr()})`;

      if(item.source==="inventory"){
        curInv=curInv.map(p=>{
          if(String(p.id)===String(item._id)||p.name===item.name){
            const ns=Math.max(0,(parseInt(p.stock)||0)-qty);
            return{...p,stock:ns,moves:[...(p.moves||[]),{type:"salida",qty,note,date:todayStr(),after:ns}]};
          }
          return p;
        });
      }else{
        curSalProds=curSalProds.map(p=>{
          if(String(p.id)===String(item._id)||p.name===item.name){
            const ns=Math.max(0,(parseInt(p.stock)||0)-qty);
            return{...p,stock:ns,moves:[...(p.moves||[]),{type:"salida",qty,note,date:todayStr(),after:ns}]};
          }
          return p;
        });
      }
    });

    // Mark order as reconciled
    const allOrders=db.get(SK.salesOrders)||[];
    db.set(SK.salesOrders,allOrders.map(o=>o.id===order.id?{...o,_invUpdated:true,_invUpdatedAt:todayStr()}:o));
    db.set(SK.inventory,curInv);
    db.set(SK.salesProducts,curSalProds);
    const updatedOrder={...order,_invUpdated:true,_invUpdatedAt:todayStr()};
    crudApi.update('sales_orders',order.id,serverPayload('sales_orders',updatedOrder)).catch(()=>{});
    pendingItems.forEach(item=>{
      const sourceList=item.source==="inventory"?curInv:curSalProds;
      const entity=item.source==="inventory"?'inventory':'sales_products';
      const updated=sourceList.find(p=>String(p.id)===String(item._id)||p.name===item.name);
      if(updated)crudApi.update(entity,updated.id,serverPayload(entity,updated)).catch(()=>{});
    });
    setInv(curInv);
    rerender();
  };

  // ── Aplicar actualización masiva ─────────────────────────────────────────
  const applyBulkReconciliation=(selectedIds)=>{
    const targets=analysis.filter(a=>selectedIds.includes(a.order.id)&&!a.allReconciled);
    targets.forEach(applyReconciliation);
    setSelectedOrders({});
    rerender();
  };

  const toggleOrder=(id)=>setSelectedOrders(p=>({...p,[id]:!p[id]}));
  const selectedIds=Object.entries(selectedOrders).filter(([,v])=>v).map(([k])=>parseInt(k));
  const selectedAnalysis=analysis.filter(a=>selectedIds.includes(a.order.id)&&!a.allReconciled);
  const totalPendingInSelected=selectedAnalysis.reduce((s,a)=>s+a.pendingItems.length,0);

  const statusColor={cobrado:"#059669",pendiente:"#f59223",procesando:"#2563eb",cancelado:"#8a9aaa",anulado:"#dc2626"};
  const statusLabel={cobrado:"Cobrado",pendiente:"Pendiente",procesando:"En caja",cancelado:"Cancelado",anulado:"Anulado"};
  const getCurrency=()=>{const c=db.get(SK.company);return c?.currency||"S/"};

  return(
    <div className="fade-in">
      {/* Header */}
      <div style={{display:"flex",alignItems:"center",gap:12,marginBottom:20,padding:"16px 20px",borderRadius:14,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff"}}>
        <div style={{fontSize:28}}>🔍</div>
        <div style={{flex:1}}>
          <div style={{fontWeight:800,fontSize:16}}>Revisión de Ventas e Inventario</div>
          <div style={{fontSize:12,opacity:.7,marginTop:2}}>Verifica que cada venta con productos haya descontado correctamente el stock.</div>
        </div>
        <button onClick={()=>rerender()} style={{background:"rgba(255,255,255,0.1)",border:"1px solid rgba(255,255,255,0.2)",borderRadius:8,padding:"8px 14px",color:"#fff",cursor:"pointer",fontSize:12.5,fontWeight:600,fontFamily:"inherit"}}>
          🔄 Actualizar
        </button>
      </div>

      {/* Stats cards */}
      <div style={{display:"grid",gridTemplateColumns:"repeat(4,1fr)",gap:10,marginBottom:20}}>
        {[
          {label:"Ventas totales",val:analysis.length,color:"#2563eb",icon:"🛒"},
          {label:"Sin reconciliar",val:pendingCount,color:pendingCount>0?"#dc2626":"#059669",icon:pendingCount>0?"⚠️":"✅"},
          {label:"Reconciliadas",val:reconcCount,color:"#059669",icon:"✔️"},
          {label:"Seleccionadas",val:selectedIds.length,color:"#7c3aed",icon:"☑️"},
        ].map(s=>(
          <div key={s.label} style={{background:"#fff",borderRadius:12,padding:"14px 16px",border:"1px solid #e8edf2"}}>
            <div style={{fontSize:18,marginBottom:4}}>{s.icon}</div>
            <div style={{fontSize:24,fontWeight:800,color:s.color}}>{s.val}</div>
            <div style={{fontSize:11,color:"#8a9aaa",textTransform:"uppercase",letterSpacing:"0.05em",marginTop:2}}>{s.label}</div>
          </div>
        ))}
      </div>

      {/* Toolbar */}
      <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:16,flexWrap:"wrap"}}>
        <div style={{display:"flex",gap:6,alignItems:"center"}}>
          <span style={{fontSize:12.5,color:"#5a7a8a",fontWeight:600}}>Estado:</span>
          {["all","cobrado","pendiente","procesando"].map(s=>(
            <button key={s} onClick={()=>setFilterStatus(s)}
              style={{padding:"5px 12px",borderRadius:8,border:`1.5px solid ${filterStatus===s?"#1a2332":"#d4dde5"}`,background:filterStatus===s?"#1a2332":"#fff",color:filterStatus===s?"#fff":"#5a7a8a",fontSize:12,fontWeight:600,cursor:"pointer",fontFamily:"inherit"}}>
              {s==="all"?"Todos":statusLabel[s]||s}
            </button>
          ))}
        </div>
        <div style={{display:"flex",gap:6,alignItems:"center",marginLeft:"auto"}}>
          {isAdmin&&selectedIds.length>0&&(
            <button
              onClick={()=>{
                if(totalPendingInSelected===0){alert("Las ventas seleccionadas ya están reconciliadas.");return;}
                setConfirmModal({type:"bulk",orders:selectedAnalysis,totalItems:totalPendingInSelected,selectedIds});
              }}
              style={{padding:"8px 18px",borderRadius:10,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",fontFamily:"inherit"}}>
              📦 Actualizar inventario ({selectedIds.length} ventas)
            </button>
          )}
        </div>
      </div>

      {/* Lista de órdenes */}
      {filtered.length===0?(
        <Card style={{textAlign:"center",padding:48}}>
          <div style={{fontSize:40,marginBottom:10}}>🎉</div>
          <div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>
            {analysis.length===0?"No hay ventas con productos registradas":"No hay ventas que coincidan con el filtro"}
          </div>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>
            {analysis.length===0?"Las ventas de servicios no generan movimientos de inventario.":"Prueba con otros filtros."}
          </div>
        </Card>
      ):(
        filtered.map(a=>{
          const{order,itemDetails,pendingItems,unresolvedItems,allReconciled}=a;
          const isExp=!!expanded[order.id];
          const isChecked=!!selectedOrders[order.id];

          return(
            <div key={order.id} style={{background:"#fff",borderRadius:12,border:`1.5px solid ${allReconciled?"#059669"+(pendingItems.length>0?"":"33"):pendingItems.length>0?"#dc262633":"#e8edf2"}`,marginBottom:10,overflow:"hidden",transition:"all .2s"}}>
              {/* Order header */}
              <div style={{display:"flex",alignItems:"center",gap:12,padding:"14px 18px",cursor:"pointer",background:allReconciled?"#f0faf7":"pendingItems.length>0"?"#fff5f5":"#fff"}} onClick={()=>setExpanded(p=>({...p,[order.id]:!p[order.id]}))}>
                {isAdmin&&!allReconciled&&(
                  <input type="checkbox" checked={isChecked} onClick={e=>e.stopPropagation()} onChange={()=>toggleOrder(order.id)}
                    style={{width:16,height:16,accentColor:"#1a2332",cursor:"pointer",flexShrink:0}}/>
                )}
                {allReconciled?(
                  <div title="Inventario al día" style={{width:28,height:28,borderRadius:"50%",background:"#f0faf7",border:"2px solid #059669",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,flexShrink:0}}>✅</div>
                ):(
                  <div title="Pendiente de reconciliación" style={{width:28,height:28,borderRadius:"50%",background:"#fff5f5",border:"2px solid #dc2626",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,flexShrink:0}}>⚠️</div>
                )}
                <div style={{flex:1,minWidth:0}}>
                  <div style={{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"}}>
                    <span style={{fontFamily:"monospace",fontWeight:700,color:"#4a9d8f",fontSize:13}}>{order.code}</span>
                    <span style={{padding:"2px 8px",borderRadius:6,fontSize:11,fontWeight:700,background:(statusColor[order.status]||"#8a9aaa")+"22",color:statusColor[order.status]||"#8a9aaa"}}>{statusLabel[order.status]||order.status}</span>
                    {allReconciled&&<span style={{fontSize:11,fontWeight:600,color:"#059669",background:"#f0faf7",padding:"2px 8px",borderRadius:6,border:"1px solid #05996944"}}>✔ Inventario al día</span>}
                    {!allReconciled&&pendingItems.length>0&&<span style={{fontSize:11,fontWeight:600,color:"#dc2626",background:"#fff5f5",padding:"2px 8px",borderRadius:6,border:"1px solid #dc262644"}}>{pendingItems.length} producto(s) sin descontar</span>}
                  </div>
                  <div style={{fontSize:12,color:"#8a9aaa",marginTop:3}}>
                    {order.razonSocial||"Cliente general"} · {fmt(order.date)}{order.time?" — "+order.time+"h":""} · <b style={{color:"#4a9d8f"}}>{order.assignedTo||"—"}</b>
                  </div>
                </div>
                <div style={{textAlign:"right",flexShrink:0}}>
                  <div style={{fontWeight:800,fontSize:16,color:"#059669"}}>{getCurrency()} {parseFloat(order.total||0).toFixed(2)}</div>
                  <div style={{fontSize:11,color:"#8a9aaa"}}>{itemDetails.length} producto(s)</div>
                </div>
                <div style={{color:"#8a9aaa",fontSize:18,flexShrink:0,transition:"transform .2s",transform:isExp?"rotate(180deg)":"none"}}>▾</div>
              </div>

              {/* Expandido: detalle de items */}
              {isExp&&(
                <div style={{borderTop:"1px solid #f0f4f8",padding:"14px 18px",background:"#fafcfd"}}>
                  <div style={{fontWeight:700,fontSize:12.5,color:"#5a7a8a",marginBottom:12,textTransform:"uppercase",letterSpacing:"0.05em"}}>Productos de la venta</div>
                  <div style={{display:"flex",flexDirection:"column",gap:8,marginBottom:14}}>
                    {itemDetails.map((item,idx)=>(
                      <div key={idx} style={{display:"flex",alignItems:"center",gap:12,padding:"10px 14px",borderRadius:10,background:item.alreadyReconciled?"#f0faf7":!item.prodFound?"#fff8e1":item.currentStock!==null&&item.currentStock<item.qty?"#fff5f5":"#fff",border:`1px solid ${item.alreadyReconciled?"#05996933":!item.prodFound?"#fde68a":item.currentStock!==null&&item.currentStock<item.qty?"#dc262633":"#e8edf2"}`}}>
                        <div style={{width:36,height:36,borderRadius:8,background:item.alreadyReconciled?"#059669":"#f4f8fa",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,flexShrink:0}}>
                          {item.alreadyReconciled?"✅":item.source==="inventory"?"📦":"🏷️"}
                        </div>
                        <div style={{flex:1,minWidth:0}}>
                          <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{item.name}</div>
                          <div style={{display:"flex",gap:8,marginTop:3,flexWrap:"wrap"}}>
                            <span style={{fontSize:11.5,color:"#8a9aaa"}}>Vendido: <b style={{color:"#1a2332"}}>×{item.qty}</b></span>
                            <span style={{fontSize:11,padding:"1px 7px",borderRadius:4,background:item.source==="inventory"?"#4a9d8f22":"#7c3aed22",color:item.source==="inventory"?"#2a7a6a":"#5b21b6",fontWeight:600}}>
                              {item.source==="inventory"?"Inventario":"Catálogo"}
                            </span>
                            {item.prodFound?(
                              <span style={{fontSize:11.5,color:item.currentStock<item.qty?"#dc2626":"#5a7a8a"}}>
                                Stock actual: <b style={{color:item.currentStock<item.qty?"#dc2626":"#1a2332"}}>{item.currentStock}</b>
                                {!item.alreadyReconciled&&<span style={{color:"#8a9aaa"}}> → {item.stockAfter} tras descontar</span>}
                              </span>
                            ):(
                              <span style={{fontSize:11.5,color:"#92400e",background:"#fff8e1",padding:"1px 6px",borderRadius:4,border:"1px solid #fde68a",fontWeight:600}}>⚠ Producto no encontrado en inventario</span>
                            )}
                            {item.alreadyReconciled&&<span style={{fontSize:11,color:"#059669",fontWeight:700}}>✔ Ya descontado</span>}
                          </div>
                        </div>
                        {!item.alreadyReconciled&&item.prodFound&&item.currentStock!==null&&item.currentStock<item.qty&&(
                          <div style={{fontSize:11,color:"#dc2626",background:"#fff5f5",padding:"4px 8px",borderRadius:6,border:"1px solid #dc262633",fontWeight:600,flexShrink:0}}>
                            Stock insuficiente
                          </div>
                        )}
                      </div>
                    ))}
                  </div>

                  {/* Botón por orden */}
                  {isAdmin&&!allReconciled&&pendingItems.length>0&&(
                    <div style={{display:"flex",justifyContent:"flex-end"}}>
                      <button
                        onClick={()=>setConfirmModal({type:"order",order,analysis:a,pendingItems})}
                        style={{padding:"9px 20px",borderRadius:10,background:"linear-gradient(135deg,#1a2332,#0f3a2a)",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",fontFamily:"inherit",display:"flex",alignItems:"center",gap:8}}>
                        📦 Actualizar inventario de esta venta
                      </button>
                    </div>
                  )}
                  {allReconciled&&(
                    <div style={{fontSize:12.5,color:"#059669",background:"#f0faf7",borderRadius:8,padding:"8px 14px",display:"flex",alignItems:"center",gap:6,fontWeight:600}}>
                      <span>✅</span> Todos los productos de esta venta están reconciliados con el inventario.
                      {order._invUpdatedAt&&<span style={{fontSize:11,color:"#8a9aaa",fontWeight:400,marginLeft:4}}>(actualizado: {fmt(order._invUpdatedAt)})</span>}
                    </div>
                  )}
                </div>
              )}
            </div>
          );
        })
      )}

      {/* ── Modal de confirmación ─────────────────────────────────── */}
      {confirmModal&&(
        <Modal title="📦 Confirmar actualización de inventario" onClose={()=>setConfirmModal(null)} width={560}>
          <div style={{marginBottom:18}}>
            {confirmModal.type==="order"?(
              <>
                <div style={{fontSize:14,color:"#5a7a8a",marginBottom:14}}>
                  Se descontará del inventario los siguientes productos correspondientes a la venta <strong style={{color:"#4a9d8f"}}>{confirmModal.order.code}</strong>:
                </div>
                <div style={{background:"#f4f8fa",borderRadius:10,padding:"12px 16px",marginBottom:14}}>
                  {confirmModal.pendingItems.map((item,i)=>(
                    <div key={i} style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"8px 0",borderBottom:i<confirmModal.pendingItems.length-1?"1px solid #e8edf2":"none"}}>
                      <div>
                        <div style={{fontWeight:600,fontSize:13.5,color:"#1a2332"}}>{item.name}</div>
                        <div style={{fontSize:11.5,color:"#8a9aaa"}}>Fuente: {item.source==="inventory"?"Inventario":"Catálogo de ventas"}</div>
                      </div>
                      <div style={{textAlign:"right"}}>
                        <div style={{fontSize:13,color:"#1a2332"}}><b style={{color:"#dc2626"}}>−{item.qty}</b> unidades</div>
                        <div style={{fontSize:11.5,color:"#8a9aaa"}}>{item.currentStock} → <b style={{color:item.stockAfter<0?"#dc2626":"#1a2332"}}>{item.stockAfter}</b></div>
                      </div>
                    </div>
                  ))}
                </div>
              </>
            ):(
              <>
                <div style={{fontSize:14,color:"#5a7a8a",marginBottom:14}}>
                  Se actualizará el inventario de <strong style={{color:"#1a2332"}}>{confirmModal.orders.length} venta(s)</strong> seleccionadas, descontando <strong style={{color:"#dc2626"}}>{confirmModal.totalItems} movimiento(s)</strong> de stock.
                </div>
                <div style={{background:"#f4f8fa",borderRadius:10,padding:"12px 16px",marginBottom:14,maxHeight:220,overflowY:"auto"}}>
                  {confirmModal.orders.map((a,i)=>(
                    <div key={i} style={{padding:"6px 0",borderBottom:i<confirmModal.orders.length-1?"1px solid #e8edf2":"none"}}>
                      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center"}}>
                        <span style={{fontFamily:"monospace",fontSize:12.5,color:"#4a9d8f",fontWeight:700}}>{a.order.code}</span>
                        <span style={{fontSize:12,color:"#8a9aaa"}}>{a.pendingItems.length} producto(s)</span>
                      </div>
                      <div style={{fontSize:12,color:"#5a7a8a",marginTop:2}}>{a.pendingItems.map(p=>`${p.name} ×${p.qty}`).join(" · ")}</div>
                    </div>
                  ))}
                </div>
              </>
            )}
            <div style={{background:"#fff3e8",border:"1px solid #f59223",borderRadius:8,padding:"10px 14px",display:"flex",gap:8,alignItems:"flex-start",fontSize:12.5,color:"#92400e",marginBottom:6}}>
              <span style={{flexShrink:0}}>⚠️</span>
              <span>Esta acción <strong>reducirá el stock</strong> en inventario. Se registrará un movimiento de salida por cada producto. La acción es reversible desde el módulo de Inventario.</span>
            </div>
          </div>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end"}}>
            <Btn variant="secondary" onClick={()=>setConfirmModal(null)}>Cancelar</Btn>
            <button
              onClick={()=>{
                if(confirmModal.type==="order")applyReconciliation(confirmModal.analysis);
                else applyBulkReconciliation(confirmModal.selectedIds);
                setConfirmModal(null);
              }}
              style={{padding:"9px 24px",borderRadius:10,background:"linear-gradient(135deg,#059669,#047857)",color:"#fff",border:"none",fontWeight:700,fontSize:13.5,cursor:"pointer",fontFamily:"inherit",display:"flex",alignItems:"center",gap:8}}>
              ✅ Sí, actualizar inventario
            </button>
          </div>
        </Modal>
      )}
    </div>
  );
};

const VentasModule=({currentUser,onPreventaCreated})=>{
  const[tab,setTab]=useState("products");
  const[,setVentasTick]=useState(0);
  const[products,setProducts]=useState(db.get(SK.salesProducts)||[]);
  const[salesSvcs,setSalesSvcs]=useState(db.get(SK.salesServices)||[]);
  const[pModal,setPModal]=useState(false);const[editP,setEditP]=useState(null);
  const[sModal,setSModal]=useState(false);const[editS,setEditS]=useState(null);
  const[ventaModal,setVentaModal]=useState(false);
  const[searchQ,setSearchQ]=useState("");
  const suppliers=db.get(SK.suppliers)||[];
  const categories=db.get(SK.categories)||DEF_CATEGORIES;
  const users=db.get(SK.users)||DEF_USERS;
  const imgRef=useRef();const svcImgRef=useRef();

  const blankP={name:"",code:"",supplier:"",category:"",minStock:"",stock:"",cost:"",price:"",description:"",image:null};
  const blankS={name:"",code:"",category:"",price:"",description:"",image:null};
  const[pF,setPF]=useState(blankP);
  const[sF,setSF]=useState(blankS);

  // Preventa state
  const[ventaForm,setVentaForm]=useState({dniRuc:"",razonSocial:"",assignedTo:"",items:[],notes:"",payMethod:"Efectivo",photos:[],esEventual:false});
  const ventaPhotoRef=useRef();
  const[patientSuggestions,setPatientSuggestions]=useState([]);
  const[showPatientDrop,setShowPatientDrop]=useState(false);
  const allVentaPatients=()=>[...(_cache['patients']||[]),...(db.get(SK.patients)||[])]
    .filter((p,i,arr)=>arr.findIndex(x=>String(x.id||x.dni||"")===String(p.id||p.dni||""))===i);
  const ptName=p=>((p.firstName||p.first_name||'').trim()+' '+(p.lastName||p.last_name||'').trim()).trim();
  const ventaDoc=String(ventaForm.dniRuc||"").trim();
  const dniIncomplete=!ventaForm.esEventual&&ventaDoc.length>0&&ventaDoc.length<8;
  const docInvalid=!ventaForm.esEventual&&ventaDoc.length>0&&![8,11].includes(ventaDoc.length);
  const selectVentaParty=item=>{
    setVentaForm(f=>({...f,dniRuc:item._dni,razonSocial:item._name}));
    setShowPatientDrop(false);
    setPatientSuggestions([]);
  };

  useEffect(()=>{
    if((db.get(SK.patients)||[]).length===0)api.get('patients').catch(()=>{});
  },[]);

  const handleImg=(e,setter)=>{const f=e.target.files[0];if(!f)return;const rd=new FileReader();rd.onload=()=>setter(p=>({...p,image:rd.result}));rd.readAsDataURL(f)};

  const handleVentaPhotos=e=>{
    const files=Array.from(e.target.files);
    Promise.all(files.map(f=>new Promise(r=>{const rd=new FileReader();rd.onload=()=>r({name:f.name,data:rd.result});rd.readAsDataURL(f)}))).then(imgs=>setVentaForm(f=>({...f,photos:[...(f.photos||[]),...imgs]})));
  };

  const saveProduct=async()=>{
    if(!pF.name){alert("Ingrese nombre del producto");return}
    const local={...pF,id:editP?.id||genId(products),stock:parseInt(pF.stock)||0,minStock:parseInt(pF.minStock)||0,cost:parseFloat(pF.cost)||0,price:parseFloat(pF.price)||0};
    try{
      await saveCrudAndSync('sales_products',local,SK.salesProducts,setProducts,editP?undefined:local.id);
      setPModal(false);setEditP(null);setPF(blankP);
      alert("✅ Producto de venta guardado en la base de datos");
    }catch(e){alert("No se guardó el producto en la base de datos: "+e.message);}
  };
  const delP=id=>{if(window.confirm("¿Eliminar producto?"))removeCrudAndSync('sales_products',id,SK.salesProducts,setProducts).catch(e=>alert("No se pudo eliminar el producto en la base de datos: "+e.message))};
  const openEditP=p=>{setEditP(p);setPF({...p});setPModal(true)};

  const saveSvc=async()=>{
    if(!sF.name){alert("Ingrese nombre del servicio");return}
    const local={...sF,id:editS?.id||genId(salesSvcs),price:parseFloat(sF.price)||0};
    try{
      await saveCrudAndSync('sales_services',local,SK.salesServices,setSalesSvcs,editS?undefined:local.id);
      setSModal(false);setEditS(null);setSF(blankS);
      alert("✅ Servicio de venta guardado en la base de datos");
    }catch(e){alert("No se guardó el servicio en la base de datos: "+e.message);}
  };
  const delSvc=id=>{if(window.confirm("¿Eliminar servicio?"))removeCrudAndSync('sales_services',id,SK.salesServices,setSalesSvcs).catch(e=>alert("No se pudo eliminar el servicio en la base de datos: "+e.message))};
  const openEditSvc=s=>{setEditS(s);setSF({...s});setSModal(true)};

  const productCats=categories.filter(c=>c.type==="product"||!c.type);
  const serviceCats=categories.filter(c=>c.type==="service"||!c.type);
  const getCatColor=name=>{const c=categories.find(x=>x.name===name);return c?.color||"#4a9d8f"};

  // All sellable items (products + services + inventory items)
  const allInventory=db.get(SK.inventory)||[];
  const allSellable=[
    ...products.map(p=>({...p,_type:"product",_source:"catalog"})),
    ...salesSvcs.map(s=>({...s,_type:"service",_source:"catalog"})),
    ...allInventory.filter(p=>p.code||p.name).map(p=>({...p,_type:"product",_source:"inventory"}))
  ];
  const searchResults=searchQ.length>1?allSellable.filter(p=>
    `${p.name} ${p.code||""} ${p.category||""}`.toLowerCase().includes(searchQ.toLowerCase())
  ):[];

  const addToVenta=(item)=>{
    setVentaForm(f=>{
      const exists=f.items.find(i=>i._id===item.id&&i._source===item._source);
      if(exists){return{...f,items:f.items.map(i=>i._id===item.id&&i._source===item._source?{...i,qty:i.qty+1}:i)}}
      return{...f,items:[...f.items,{_id:item.id,_source:item._source,_type:item._type,name:item.name,code:item.code||"",price:parseFloat(item.price)||0,qty:1,discountPct:0,discountAmt:""}]};
    });
  };

  const itemGross=i=>(parseFloat(i.price)||0)*(parseInt(i.qty)||1);
  const itemDiscount=i=>{
    const gross=itemGross(i);
    const fixed=parseFloat(i.discountAmt)||0;
    const pct=Math.min(100,Math.max(0,parseFloat(i.discountPct)||0));
    return Math.min(gross,fixed>0?fixed:gross*(pct/100));
  };
  const itemNet=i=>Math.max(0,itemGross(i)-itemDiscount(i));
  const subtotal=ventaForm.items.reduce((s,i)=>s+itemGross(i),0);
  const igv=subtotal*0.18;
  const descuentoAmt=ventaForm.items.reduce((s,i)=>s+itemDiscount(i),0);
  const total=Math.max(0,subtotal-descuentoAmt);

  const generarPreventa=async()=>{
    if(ventaForm.items.length===0){alert("Agregue al menos un producto o servicio");return;}
    // Paciente eventual: solo requiere razón social o nombre (no DNI obligatorio)
    if(!ventaForm.esEventual&&!ventaForm.dniRuc&&!ventaForm.razonSocial){alert("Ingrese DNI o nombre del cliente");return;}
    if(dniIncomplete){alert("DNI incompleto: debe tener exactamente 8 caracteres.");return;}
    if(docInvalid){alert("Documento incompleto o inválido: use 8 caracteres para DNI o 11 para RUC/NIT.");return;}
    if(!ventaForm.assignedTo){alert("Seleccione el personal que hizo la atención o venta.");return;}
    const orders=db.get(SK.salesOrders)||[];
    const ordId=genId(orders);
    const newOrder={
      id:ordId,
      code:`ORD-${String(ordId).padStart(5,"0")}`,
      date:todayStr(),
      time:new Date().toLocaleTimeString("es-PE",{hour:"2-digit",minute:"2-digit",hour12:false}),
      dniRuc:ventaForm.dniRuc||'EVENTUAL',
      dni_ruc:ventaForm.dniRuc||'EVENTUAL',
      razonSocial:ventaForm.razonSocial||(ventaForm.esEventual?'Paciente Eventual':''),
      razon_social:ventaForm.razonSocial||(ventaForm.esEventual?'Paciente Eventual':''),
      esEventual:ventaForm.esEventual||false,
      assignedTo:ventaForm.assignedTo,
      assigned_to:ventaForm.assignedTo,
      items:ventaForm.items.map(i=>({...i,grossTotal:itemGross(i),discount:itemDiscount(i),lineTotal:itemNet(i)})),
      subtotal,
      discount:descuentoAmt,
      igv,total,
      payMethod:ventaForm.payMethod||"Efectivo",
      pay_method:ventaForm.payMethod||"Efectivo",
      photos:ventaForm.photos||[],
      status:"pendiente",
      notes:ventaForm.notes,
      createdBy:currentUser?.name,
      created_by:currentUser?.name
    };
    let created;
    try{
      created=await apiFetch('/crud?entity=sales_orders',{method:'POST',body:JSON.stringify(newOrder)});
      const savedOrder={...newOrder,...created,id:created?.id||newOrder.id};
      db.set(SK.salesOrders,[...orders,savedOrder]);
      if(onPreventaCreated)onPreventaCreated(savedOrder);
    }catch(e){alert("No se guardó la pre-venta en la base de datos: "+e.message);return;}

    // El stock se descuenta al COBRAR en Caja (cobrarOrden), no al generar pre-venta
    // Así se evita doble descuento si la orden se cancela antes de cobrar
    const productoItems=ventaForm.items.filter(i=>i._type==="product");

    setVentaForm({dniRuc:"",razonSocial:"",assignedTo:"",items:[],notes:"",payMethod:"Efectivo",photos:[],esEventual:false});
    setVentaModal(false);
    setPatientSuggestions([]);setShowPatientDrop(false);
    alert("✅ Pre-venta guardada en la base de datos");
  };

  const eliminarPreventaPendiente=async(order)=>{
    if(!confirm("¿Eliminar esta pre-venta pendiente?"))return;
    try{
      await crudApi.remove('sales_orders',order.id);
      const all=db.get(SK.salesOrders)||[];
      db.set(SK.salesOrders,all.filter(x=>String(x.id)!==String(order.id)));
      setVentasTick(t=>t+1);
      alert("✅ Pre-venta eliminada");
    }catch(e){
      alert("No se pudo eliminar la pre-venta en la base de datos: "+e.message);
    }
  };

  const ProductImg=({src,size=80})=>src?<img src={src} alt="" style={{width:size,height:size,objectFit:"contain",borderRadius:10,border:"1px solid #e8edf2"}}/>
    :<div style={{width:size,height:size,borderRadius:10,background:"linear-gradient(135deg,#e8f4f2,#d0eae6)",border:"2px solid #b0d8d4",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",color:"#4a9d8f",fontSize:size>50?28:18}}><div>💊</div>{size>50&&<div style={{fontSize:9,marginTop:4,color:"#8a9aaa",fontWeight:600}}>Sin imagen</div>}</div>;
  const SvcImg=({src,size=80})=>src?<img src={src} alt="" style={{width:size,height:size,objectFit:"contain",borderRadius:10,border:"1px solid #e8edf2"}}/>
    :<div style={{width:size,height:size,borderRadius:10,background:"linear-gradient(135deg,#e8f0fa,#d0dff5)",border:"2px solid #b0c8e8",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",color:"#2563eb",fontSize:size>50?28:18}}><div>🏥</div>{size>50&&<div style={{fontSize:9,marginTop:4,color:"#8a9aaa",fontWeight:600}}>Sin imagen</div>}</div>;

  return(
    <div className="slide-in">
      <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:18,flexWrap:"wrap",gap:8}}>
        <div>
          <h2 style={{fontSize:22,fontWeight:800,color:"#1a2332",letterSpacing:"-0.02em"}}>Ventas</h2>
          <div style={{fontSize:12.5,color:"#8a9aaa"}}>Catálogo de productos y servicios · Pre-ventas → Caja</div>
        </div>
        <div style={{display:"flex",gap:8}}>
          <Btn variant="success" onClick={()=>setVentaModal(true)}><Icon name="shop" size={14}/>Nueva Pre-venta</Btn>
          <Btn onClick={()=>{if(tab==="products"){setEditP(null);setPF(blankP);setPModal(true)}else{setEditS(null);setSF(blankS);setSModal(true)}}}>
            <Icon name="plus" size={14}/>{tab==="products"?"Nuevo Producto":"Nuevo Servicio"}
          </Btn>
        </div>
      </div>

      <Tabs tabs={[
        {id:"products",label:`📦 Productos (${products.length})`},
        {id:"services",label:`🏥 Servicios (${salesSvcs.length})`},
        {id:"orders",label:`🛒 Pre-ventas (${(db.get(SK.salesOrders)||[]).filter(o=>o.status==="pendiente").length})`},
        {id:"revision",label:"🔍 Revisión de Ventas"},
      ]} active={tab} onChange={setTab}/>

      {tab==="products"&&(
        <div className="fade-in">
          {products.length===0&&<Card style={{textAlign:"center",padding:48}}><div style={{fontSize:40,marginBottom:10}}>📦</div><div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin productos registrados</div><Btn onClick={()=>{setEditP(null);setPF(blankP);setPModal(true)}}><Icon name="plus" size={13}/>Agregar</Btn></Card>}
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(280px,1fr))",gap:14}}>
            {products.map(p=>{
              const catColor=getCatColor(p.category);
              const stockOk=!p.minStock||parseInt(p.stock)>=parseInt(p.minStock);
              return(
                <Card key={p.id} style={{borderTop:`3px solid ${catColor}`,transition:"transform .15s"}} onMouseOver={e=>e.currentTarget.style.transform="translateY(-2px)"} onMouseOut={e=>e.currentTarget.style.transform="none"}>
                  <div style={{display:"flex",gap:14,marginBottom:12}}>
                    <div style={{position:"relative",cursor:"pointer"}} onClick={()=>openEditP(p)}>
                      <ProductImg src={p.image} size={74}/>
                      <div style={{position:"absolute",bottom:-4,right:-4,width:18,height:18,background:"#4a9d8f",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",border:"2px solid #fff"}}><Icon name="edit" size={9}/></div>
                    </div>
                    <div style={{flex:1,minWidth:0}}>
                      {p.code&&<div style={{fontSize:10,color:"#8a9aaa",fontFamily:"monospace",marginBottom:2}}>#{p.code}</div>}
                      <div style={{fontWeight:700,fontSize:14,color:"#1a2332",lineHeight:1.3}}>{p.name}</div>
                      {p.category&&<div style={{marginTop:4}}><span style={{display:"inline-block",padding:"2px 8px",borderRadius:20,fontSize:10.5,fontWeight:700,background:catColor+"22",color:catColor}}>{p.category}</span></div>}
                      <div style={{fontSize:20,fontWeight:800,color:catColor,marginTop:4}}>{p.price?`${getCurrency()} ${parseFloat(p.price).toFixed(2)}`:"—"}</div>
                    </div>
                  </div>
                  {!stockOk&&<div style={{background:"#fff3e8",border:"1px solid #f59223",borderRadius:8,padding:"5px 10px",fontSize:11.5,color:"#8a4f00",marginBottom:8}}>⚠️ Stock bajo ({p.minStock})</div>}
                  <div style={{display:"flex",gap:6}}>
                    <Btn size="sm" variant="ghost" onClick={()=>openEditP(p)}><Icon name="edit" size={11}/>Editar</Btn>
                    <Btn size="sm" variant="success" onClick={()=>{addToVenta(p);setVentaModal(true)}}>🛒 Vender</Btn>
                    <Btn size="sm" variant="danger" onClick={()=>delP(p.id)}><Icon name="trash" size={11}/></Btn>
                  </div>
                </Card>
              );
            })}
          </div>
        </div>
      )}

      {tab==="services"&&(
        <div className="fade-in">
          {salesSvcs.length===0&&<Card style={{textAlign:"center",padding:48}}><div style={{fontSize:40,marginBottom:10}}>🏥</div><div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin servicios</div><Btn onClick={()=>{setEditS(null);setSF(blankS);setSModal(true)}}><Icon name="plus" size={13}/>Agregar</Btn></Card>}
          <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(280px,1fr))",gap:14}}>
            {salesSvcs.map(s=>{
              const catColor=getCatColor(s.category);
              return(
                <Card key={s.id} style={{borderTop:`3px solid ${catColor}`,transition:"transform .15s"}} onMouseOver={e=>e.currentTarget.style.transform="translateY(-2px)"} onMouseOut={e=>e.currentTarget.style.transform="none"}>
                  <div style={{display:"flex",gap:14,marginBottom:12}}>
                    <div style={{position:"relative",cursor:"pointer"}} onClick={()=>openEditSvc(s)}>
                      <SvcImg src={s.image} size={74}/>
                      <div style={{position:"absolute",bottom:-4,right:-4,width:18,height:18,background:"#2563eb",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",border:"2px solid #fff"}}><Icon name="edit" size={9}/></div>
                    </div>
                    <div style={{flex:1,minWidth:0}}>
                      {s.code&&<div style={{fontSize:10,color:"#8a9aaa",fontFamily:"monospace",marginBottom:2}}>#{s.code}</div>}
                      <div style={{fontWeight:700,fontSize:14,color:"#1a2332"}}>{s.name}</div>
                      {s.category&&<span style={{display:"inline-block",padding:"2px 8px",borderRadius:20,fontSize:10.5,fontWeight:700,background:catColor+"22",color:catColor}}>{s.category}</span>}
                      <div style={{fontSize:20,fontWeight:800,color:catColor,marginTop:4}}>{s.price?`${getCurrency()} ${parseFloat(s.price).toFixed(2)}`:"—"}</div>
                    </div>
                  </div>
                  <div style={{display:"flex",gap:6}}>
                    <Btn size="sm" variant="ghost" onClick={()=>openEditSvc(s)}><Icon name="edit" size={11}/>Editar</Btn>
                    <Btn size="sm" variant="success" onClick={()=>{addToVenta(s);setVentaModal(true)}}>🛒 Vender</Btn>
                    <Btn size="sm" variant="danger" onClick={()=>delSvc(s.id)}><Icon name="trash" size={11}/></Btn>
                  </div>
                </Card>
              );
            })}
          </div>
        </div>
      )}

      {tab==="orders"&&(
        <div className="fade-in">
          {(()=>{
            const orders=(db.get(SK.salesOrders)||[]).filter(o=>o.status==="pendiente");
            if(orders.length===0)return<Card style={{textAlign:"center",padding:48}}><div style={{fontSize:40,marginBottom:10}}>🛒</div><div style={{fontWeight:700,color:"#3a5a6a",marginBottom:6}}>Sin pre-ventas pendientes</div><Btn onClick={()=>setVentaModal(true)}>Nueva Pre-venta</Btn></Card>;
            return orders.slice().reverse().map(o=>(
              <Card key={o.id} style={{marginBottom:12}}>
                <div style={{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:10}}>
                  <div>
                    <div style={{fontFamily:"monospace",fontWeight:700,color:"#4a9d8f",fontSize:13}}>{o.code}</div>
                    <div style={{fontSize:13,fontWeight:600,color:"#1a2332"}}>{o.razonSocial||"Cliente general"}</div>
                    {o.dniRuc&&<div style={{fontSize:11,color:"#8a9aaa"}}>DNI/RUC: {o.dniRuc}</div>}
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Asignado: <b style={{color:"#4a9d8f"}}>{o.assignedTo||"—"}</b> · {fmt(o.date)}{o.time?" — "+o.time+"h":""}</div>
                  </div>
                  <div style={{textAlign:"right"}}>
                    <div style={{fontSize:22,fontWeight:800,color:"#059669"}}>{currency(o.total)}</div>
                    <Badge color="orange">Pendiente</Badge>
                  </div>
                </div>
                <div style={{fontSize:12,color:"#3a5a6a",marginBottom:8}}>
                  {o.items.map(i=>`${i.name} x${i.qty}`).join(" · ")}
                </div>
                <div style={{display:"flex",gap:6}}>
                  <Btn size="sm" variant="success" onClick={()=>{
                    const all=db.get(SK.salesOrders)||[];
                    db.set(SK.salesOrders,all.map(x=>x.id===o.id?{...x,status:"procesando"}:x));
                    crudApi.update('sales_orders',o.id,{status:"procesando"}).catch(e=>alert("No se guardó el envío a Caja en la base de datos: "+e.message));
                    alert("✅ Orden enviada a Caja & Pagos");
                  }}><Icon name="cash" size={11}/>Enviar a Caja</Btn>
                  <Btn size="sm" variant="danger" onClick={()=>eliminarPreventaPendiente(o)}>Eliminar</Btn>
                </div>
              </Card>
            ));
          })()}
        </div>
      )}

      {tab==="revision"&&<RevisionVentas currentUser={currentUser}/>}

      {/* Modal Preventa */}
      {ventaModal&&(
        <Modal title="Nueva Pre-venta" onClose={()=>{setVentaModal(false);setPatientSuggestions([]);setShowPatientDrop(false);setVentaForm(f=>({...f,photos:[]}));}} width={700}>
          {/* ── Paciente Eventual toggle ── */}
          <div style={{marginBottom:12,display:'flex',alignItems:'center',gap:10,
            background:ventaForm.esEventual?'#fff8e6':'#f8fafc',
            border:`1.5px solid ${ventaForm.esEventual?'#f59223':'#e8edf2'}`,
            borderRadius:10,padding:'10px 14px',cursor:'pointer'}}
            onClick={()=>setVentaForm(f=>({...f,
              esEventual:!f.esEventual,
              dniRuc:!f.esEventual?'':f.dniRuc,
              razonSocial:!f.esEventual?'Paciente Eventual':f.razonSocial==='Paciente Eventual'?'':f.razonSocial
            }))}>
            <div style={{width:22,height:22,borderRadius:6,transition:'all .2s',flexShrink:0,
              background:ventaForm.esEventual?'#f59223':'#e8edf2',
              display:'flex',alignItems:'center',justifyContent:'center'}}>
              {ventaForm.esEventual&&<span style={{color:'#fff',fontSize:14,fontWeight:700}}>✓</span>}
            </div>
            <div>
              <div style={{fontWeight:700,fontSize:13,color:ventaForm.esEventual?'#92620a':'#5a7a8a'}}>
                👤 Paciente Eventual — sin apertura de historia clínica
              </div>
              <div style={{fontSize:11,color:'#8a9aaa'}}>
                Figura en todos los movimientos de cobranza y reportes de caja
              </div>
            </div>
          </div>

          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px",
            opacity:ventaForm.esEventual?0.6:1,pointerEvents:ventaForm.esEventual?'none':'auto'}}>
            <Field label={ventaForm.esEventual?"DNI / RUC (opcional)":"DNI / RUC / NIT"}>
              <div style={{position:"relative"}}>
                <Inp value={ventaForm.dniRuc} onChange={e=>{
                  const val=e.target.value.replace(/[^0-9]/g,'').slice(0,11);
                  setVentaForm(f=>({...f,dniRuc:val}));
                  if(val.length>=8){
                    // 1. Cache local
                    const pts=allVentaPatients();
                    const foundPt=pts.find(p=>String(p.dni||'')===val);
                    if(foundPt&&ptName(foundPt)){setVentaForm(f=>({...f,dniRuc:val,razonSocial:ptName(foundPt)}));return;}
                    const sups=db.get(SK.suppliers)||[];
                    const foundSup=sups.find(s=>String(s.ruc||'')===val);
                    if(foundSup){setVentaForm(f=>({...f,dniRuc:val,razonSocial:foundSup.name||''}));return;}
                    // 2. Servidor (paciente no en caché)
                    apiFetch('/crud?entity=patients&dni='+encodeURIComponent(val))
                      .then(r=>{
                        const rows=Array.isArray(r)?r:(r.data||[]);
                        const hit=rows.find(p=>String(p.dni||'')===val);
                        if(hit){const nm=ptName(hit);if(nm)setVentaForm(f=>({...f,razonSocial:nm}));}
                      }).catch(()=>{});
                  } else if(val.length===0){
                    setVentaForm(f=>({...f,razonSocial:''}));
                  }
                }} placeholder="12345678 / 20xxxxxxxxx" style={{borderColor:dniIncomplete?"#d97706":docInvalid?"#e05050":undefined,paddingRight:(()=>{const v=ventaForm.dniRuc;if(v.length<8)return"12px";const pts=allVentaPatients();const sups=db.get(SK.suppliers)||[];return(pts.find(p=>String(p.dni)===v)||sups.find(s=>String(s.ruc)===v))?"32px":"12px"})()}}/>
                {(()=>{const v=ventaForm.dniRuc;if(v.length<8)return null;const pts=allVentaPatients();const sups=db.get(SK.suppliers)||[];const isPt=pts.find(p=>String(p.dni)===v);const isSup=sups.find(s=>String(s.ruc)===v);if(!isPt&&!isSup)return null;return<div style={{position:"absolute",right:10,top:"50%",transform:"translateY(-50%)",fontSize:13,display:"flex",alignItems:"center",gap:3}}><span title={isPt?"Paciente encontrado":"Empresa encontrada"}>✅</span><span style={{fontSize:10,color:"#4a9d8f",fontWeight:700}}>{isPt?"Paciente":"Empresa"}</span></div>})()}
              </div>
              {dniIncomplete&&<div style={{fontSize:11,color:"#a16207",marginTop:4,fontWeight:600}}>DNI incompleto: debe tener 8 caracteres.</div>}
              {!dniIncomplete&&docInvalid&&<div style={{fontSize:11,color:"#c2410c",marginTop:4,fontWeight:600}}>Documento incompleto: DNI 8 caracteres o RUC/NIT 11.</div>}
            </Field>
            <Field label="Razón Social / Nombre">
              <div style={{position:"relative"}}>
                <Inp value={ventaForm.razonSocial} onChange={e=>{
                  const val=e.target.value;
                  setVentaForm(f=>({...f,razonSocial:val}));
                  if(val.trim().length>=2){
                    const q=val.trim().toLowerCase();
                    const pts=allVentaPatients();
                    const ptMatches=pts.filter(p=>{
                      const fn=p.firstName||p.first_name||'';
                      const ln=p.lastName||p.last_name||'';
                      const dni=String(p.dni||'');
                      const full=(fn+' '+ln).toLowerCase();
                      return full.includes(q)||fn.toLowerCase().includes(q)||ln.toLowerCase().includes(q)||dni.includes(q);
                    }).slice(0,6).map(p=>{
                      const fn=p.firstName||p.first_name||'';
                      const ln=p.lastName||p.last_name||'';
                      const nm=(fn+' '+ln).trim();
                      return{_kind:'patient',id:p.id,label:nm,doc:p.dni?'DNI: '+p.dni:'Sin DNI',sub:p.phone||'',_dni:String(p.dni||''),_name:nm};
                    });
                    const sups=db.get(SK.suppliers)||[];
                    const supMatches=sups.filter(s=>(s.name||"").toLowerCase().includes(q)).slice(0,4).map(s=>({_kind:"supplier",id:"s-"+s.id,label:s.name||"",doc:s.ruc?"RUC: "+s.ruc:"Sin RUC",sub:s.phone||s.contact||"",_dni:String(s.ruc||""),_name:s.name||""}));
                    const all=[...ptMatches,...supMatches];
                    setPatientSuggestions(all);
                    setShowPatientDrop(all.length>0);
                  }else{
                    setPatientSuggestions([]);setShowPatientDrop(false);
                  }
                }} onBlur={()=>{
                  setTimeout(()=>{
                    const q=String(ventaForm.razonSocial||"").trim().toLowerCase();
                    if(q&&!ventaForm.dniRuc){
                      const exact=allVentaPatients().find(p=>ptName(p).toLowerCase()===q&&String(p.dni||"").trim());
                      if(exact)selectVentaParty({_dni:String(exact.dni||""),_name:ptName(exact)});
                    }
                    setShowPatientDrop(false);
                  },200);
                }} onFocus={()=>{if(patientSuggestions.length>0)setShowPatientDrop(true)}} placeholder="Buscar paciente por nombre, apellido, DNI o empresa..."/>
                {showPatientDrop&&(
                  <div style={{position:"absolute",top:"100%",left:0,right:0,zIndex:999,background:"#fff",border:"1.5px solid #4a9d8f",borderRadius:9,boxShadow:"0 6px 24px rgba(74,157,143,.18)",maxHeight:230,overflowY:"auto",marginTop:2}}>
                    <div style={{padding:"5px 12px",fontSize:10,fontWeight:700,color:"#4a9d8f",textTransform:"uppercase",letterSpacing:"0.07em",borderBottom:"1px solid #e8edf2",background:"#f0f9f7",borderRadius:"7px 7px 0 0"}}>Resultados encontrados</div>
                    {patientSuggestions.map(item=>(
                      <div key={item.id} onMouseDown={()=>selectVentaParty(item)} style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"9px 14px",borderBottom:"1px solid #f0f4f8",cursor:"pointer",transition:"background .12s"}} onMouseOver={e=>e.currentTarget.style.background="#f0f8f6"} onMouseOut={e=>e.currentTarget.style.background=""}>
                        <div style={{display:"flex",alignItems:"center",gap:9}}>
                          <div style={{width:28,height:28,borderRadius:"50%",background:item._kind==="supplier"?"#e8f0fa":"#e8f7f4",display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,flexShrink:0}}>{item._kind==="supplier"?"🏢":"👤"}</div>
                          <div>
                            <div style={{fontWeight:600,fontSize:13,color:"#1a2332"}}>{item.label}</div>
                            <div style={{fontSize:11,color:"#8a9aaa"}}>{item.doc}{item.sub?" · "+item.sub:""}</div>
                          </div>
                        </div>
                        <div style={{textAlign:"right",flexShrink:0}}>
                          <div style={{fontSize:10,fontWeight:700,color:item._kind==="supplier"?"#2563eb":"#4a9d8f",background:item._kind==="supplier"?"#eff4ff":"#f0f9f7",padding:"2px 7px",borderRadius:5,marginBottom:2}}>{item._kind==="supplier"?"Empresa":"Paciente"}</div>
                          <div style={{fontSize:10,color:"#4a9d8f",fontWeight:600}}>{item._dni||"—"}</div>
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </Field>
            <Field label="Personal Asignado" col="1/-1">
              <Sel value={ventaForm.assignedTo} onChange={e=>setVentaForm(f=>({...f,assignedTo:e.target.value}))}>
                <option value="">Seleccionar personal...</option>
                {users.filter(u=>u.active).map(u=><option key={u.id} value={u.name}>{u.name} — {u.role}</option>)}
              </Sel>
            </Field>
          </div>
          <Field label="Buscar Producto / Servicio">
            <div style={{position:"relative"}}>
              <div style={{position:"absolute",left:10,top:"50%",transform:"translateY(-50%)",color:"#8a9aaa"}}><Icon name="search" size={14}/></div>
              <input value={searchQ} onChange={e=>setSearchQ(e.target.value)} placeholder="Buscar por nombre o código..." style={{width:"100%",padding:"8px 12px 8px 32px",border:"1.5px solid #4a9d8f",borderRadius:9,fontSize:13,outline:"none"}}/>
            </div>
            {searchResults.length>0&&(
              <div style={{border:"1px solid #e8edf2",borderRadius:9,marginTop:4,maxHeight:200,overflowY:"auto"}}>
                {searchResults.slice(0,10).map(item=>(
                  <div key={`${item._source}-${item.id}`} onClick={()=>addToVenta(item)} style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"9px 14px",borderBottom:"1px solid #f0f4f8",cursor:"pointer",transition:"background .1s"}} onMouseOver={e=>e.currentTarget.style.background="#f0f8f6"} onMouseOut={e=>e.currentTarget.style.background=""}>
                    <div>
                      <div style={{fontWeight:600,fontSize:13}}>{item.name}</div>
                      <div style={{fontSize:11,color:"#8a9aaa"}}>{item.code?`#${item.code} · `:""}{item._source==="inventory"?"Inventario":"Catálogo"} · {item._type==="service"?"Servicio":"Producto"}</div>
                    </div>
                    <div style={{textAlign:"right"}}>
                      <div style={{fontWeight:700,color:"#4a9d8f"}}>{item.price?`${getCurrency()} ${parseFloat(item.price).toFixed(2)}`:"—"}</div>
                      <div style={{fontSize:11,color:"#2ea87e"}}>+ Agregar</div>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </Field>
          {/* Lista de items agregados */}
          {ventaForm.items.length>0&&(
            <div style={{border:"1px solid #e8edf2",borderRadius:10,overflow:"hidden",marginTop:4}}>
              <div style={{background:"#f4f8fa",padding:"8px 14px",fontSize:11,fontWeight:700,color:"#5a7a8a",textTransform:"uppercase",letterSpacing:"0.06em"}}>Productos / Servicios seleccionados</div>
              {ventaForm.items.map((item,idx)=>(
                <div key={idx} style={{display:"flex",alignItems:"center",gap:8,padding:"9px 12px",borderTop:"1px solid #f0f4f8",flexWrap:"wrap"}}>
                  <div style={{flex:1}}>
                    <div style={{fontWeight:600,fontSize:13}}>{item.name}</div>
                    {item.code&&<div style={{fontSize:11,color:"#8a9aaa"}}>#{item.code}</div>}
                    <div style={{fontSize:10,color:item._type==="product"?"#4a9d8f":"#2563eb",fontWeight:700}}>{item._type==="product"?"📦 Producto":"🏥 Servicio"}</div>
                  </div>
                  <div style={{display:"flex",alignItems:"center",gap:8}}>
                    <button onClick={()=>setVentaForm(f=>({...f,items:f.items.map((i,j)=>j===idx?{...i,qty:Math.max(1,i.qty-1)}:i)}))} style={{width:26,height:26,borderRadius:6,border:"1px solid #d4dde5",background:"#fff",cursor:"pointer",fontSize:14,fontWeight:700}}>−</button>
                    <span style={{fontWeight:700,minWidth:24,textAlign:"center"}}>{item.qty}</span>
                    <button onClick={()=>setVentaForm(f=>({...f,items:f.items.map((i,j)=>j===idx?{...i,qty:i.qty+1}:i)}))} style={{width:26,height:26,borderRadius:6,border:"1px solid #d4dde5",background:"#fff",cursor:"pointer",fontSize:14,fontWeight:700}}>+</button>
                  </div>
                  <div style={{display:"flex",alignItems:"center",gap:4,background:"#fffbeb",border:"1px solid #fde68a",borderRadius:8,padding:"4px 6px"}}>
                    <span style={{fontSize:9.5,fontWeight:800,color:"#92400e"}}>DESC.</span>
                    <input type="number" min="0" max="100" value={item.discountPct||""} placeholder="%" title="Descuento porcentual"
                      onChange={e=>setVentaForm(f=>({...f,items:f.items.map((i,j)=>j===idx?{...i,discountPct:e.target.value,discountAmt:""}:i)}))}
                      style={{width:42,padding:"5px 4px",border:"1px solid #f4c96b",borderRadius:6,fontSize:11,textAlign:"center",outline:"none"}}/>
                    <span style={{fontSize:10,color:"#92400e"}}>o</span>
                    <input type="number" min="0" value={item.discountAmt||""} placeholder="S/"
                      title="Descuento en soles"
                      onChange={e=>setVentaForm(f=>({...f,items:f.items.map((i,j)=>j===idx?{...i,discountAmt:e.target.value,discountPct:0}:i)}))}
                      style={{width:58,padding:"5px 4px",border:"1px solid #f4c96b",borderRadius:6,fontSize:11,textAlign:"center",outline:"none"}}/>
                  </div>
                  <div style={{minWidth:86,textAlign:"right"}}>
                    {itemDiscount(item)>0&&<div style={{fontSize:10,color:"#8a9aaa",textDecoration:"line-through"}}>{currency(itemGross(item))}</div>}
                    <div style={{fontWeight:800,color:"#059669"}}>{currency(itemNet(item))}</div>
                  </div>
                  <button onClick={()=>setVentaForm(f=>({...f,items:f.items.filter((_,j)=>j!==idx)}))} style={{background:"none",border:"none",cursor:"pointer",color:"#e05050",fontSize:16,padding:"0 4px"}}>✕</button>
                </div>
              ))}
              <div style={{background:"#f0f9f7",padding:"12px 14px",borderTop:"2px solid #e8edf2"}}>
                <div style={{display:"flex",justifyContent:"space-between",fontSize:12,color:"#5a7a8a",marginBottom:4}}>
                  <span>Subtotal:</span><span style={{fontWeight:700,color:"#1a2332"}}>{currency(subtotal)}</span>
                </div>
                {descuentoAmt>0&&(
                  <div style={{display:"flex",justifyContent:"space-between",fontSize:12,color:"#dc2626",marginBottom:4}}>
                    <span>Descuentos aplicados:</span>
                    <span style={{fontWeight:700}}>− {currency(descuentoAmt)}</span>
                  </div>
                )}
                <div style={{display:"flex",justifyContent:"space-between",fontSize:14,fontWeight:800}}>
                  <span style={{color:"#0f3a2a"}}>TOTAL:</span><span style={{color:"#059669",fontSize:18}}>{currency(total)}</span>
                </div>
              </div>
            </div>
          )}
          {/* ── FIX 4: Método de pago — igual que AttModal ── */}
          <Field label="Método de Pago">
            <div style={{display:"grid",gridTemplateColumns:"repeat(auto-fill,minmax(100px,1fr))",gap:6}}>
              {PAY_METHODS.map(m=>(
                <button key={m} onClick={()=>setVentaForm(f=>({...f,payMethod:m}))} style={{padding:"7px 4px",borderRadius:8,border:`2px solid ${ventaForm.payMethod===m?"#4a9d8f":"#d4dde5"}`,background:ventaForm.payMethod===m?"#4a9d8f18":"#fff",color:ventaForm.payMethod===m?"#4a9d8f":"#5a7a8a",fontWeight:600,fontSize:11.5,cursor:"pointer",textAlign:"center"}}>{m}</button>
              ))}
            </div>
          </Field>
          <Field label="Notas"><TA value={ventaForm.notes} onChange={e=>setVentaForm(f=>({...f,notes:e.target.value}))} placeholder="Observaciones de la venta..." style={{minHeight:55}}/></Field>
          {/* ── FIX 4: Fotos de evidencia — igual que AttModal ── */}
          <Field label="Fotos de Evidencia (opcional)">
            <input ref={ventaPhotoRef} type="file" accept="image/*" multiple onChange={handleVentaPhotos} style={{display:"none"}}/>
            <Btn variant="ghost" size="sm" onClick={()=>ventaPhotoRef.current.click()}><Icon name="photo" size={13}/>Agregar Fotos</Btn>
            {(ventaForm.photos||[]).length>0&&(
              <div style={{display:"flex",gap:6,flexWrap:"wrap",marginTop:8}}>
                {ventaForm.photos.map((ph,i)=>(
                  <div key={i} style={{position:"relative"}}>
                    <img src={ph.data} alt="" style={{width:64,height:64,objectFit:"cover",borderRadius:7,border:"2px solid #d0dce5"}}/>
                    <button onClick={()=>setVentaForm(f=>({...f,photos:f.photos.filter((_,j)=>j!==i)}))} style={{position:"absolute",top:-5,right:-5,background:"#e05050",border:"none",borderRadius:"50%",width:16,height:16,cursor:"pointer",color:"#fff",fontSize:10,display:"flex",alignItems:"center",justifyContent:"center"}}>×</button>
                  </div>
                ))}
              </div>
            )}
          </Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}>
            <Btn variant="secondary" onClick={()=>setVentaModal(false)}>Cancelar</Btn>
            <Btn variant="success" onClick={generarPreventa}><Icon name="cash" size={13}/>Generar Pre-venta → Caja</Btn>
          </div>
        </Modal>
      )}

      {/* Modal Producto */}
      {pModal&&(
        <Modal title={editP?"Editar Producto":"Nuevo Producto"} onClose={()=>{setPModal(false);setEditP(null)}} width={640}>
          <div style={{display:"flex",gap:20,alignItems:"flex-start"}}>
            <div style={{textAlign:"center",flexShrink:0}}>
              <ProductImg src={pF.image} size={100}/>
              <input ref={imgRef} type="file" accept="image/*" onChange={e=>handleImg(e,setPF)} style={{display:"none"}}/>
              <div style={{display:"flex",gap:4,justifyContent:"center",marginTop:8}}>
                <Btn size="xs" variant="ghost" onClick={()=>imgRef.current.click()}><Icon name="image" size={11}/>Imagen</Btn>
                {pF.image&&<Btn size="xs" variant="danger" onClick={()=>setPF(p=>({...p,image:null}))}><Icon name="trash" size={11}/></Btn>}
              </div>
            </div>
            <div style={{flex:1}}>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
                <Field label="Producto *" col="1/-1"><Inp value={pF.name} onChange={e=>setPF(p=>({...p,name:e.target.value}))}/></Field>
                <Field label="Código"><Inp value={pF.code||""} onChange={e=>setPF(p=>({...p,code:e.target.value}))} placeholder="UREA20"/></Field>
                <Field label="Proveedor">
                  <Sel value={pF.supplier||""} onChange={e=>setPF(p=>({...p,supplier:e.target.value}))}>
                    <option value="">Sin proveedor...</option>
                    {suppliers.map(s=><option key={s.id} value={s.name}>{s.name}</option>)}
                  </Sel>
                </Field>
                <Field label="Categoría">
                  <Sel value={pF.category||""} onChange={e=>setPF(p=>({...p,category:e.target.value}))}>
                    <option value="">Seleccionar...</option>
                    {productCats.map(c=><option key={c.id} value={c.name}>{c.name}</option>)}
                  </Sel>
                </Field>
                <Field label="Stock"><Inp type="number" value={pF.stock||""} onChange={e=>setPF(p=>({...p,stock:e.target.value}))} placeholder="0"/></Field>
                <Field label="Costo"><Inp type="number" value={pF.cost||""} onChange={e=>setPF(p=>({...p,cost:e.target.value}))} placeholder="0.00"/></Field>
                <Field label="Precio"><Inp type="number" value={pF.price||""} onChange={e=>setPF(p=>({...p,price:e.target.value}))} placeholder="0.00"/></Field>
              </div>
            </div>
          </div>
          <Field label="Descripción"><TA value={pF.description||""} onChange={e=>setPF(p=>({...p,description:e.target.value}))} style={{minHeight:60}}/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>{setPModal(false);setEditP(null)}}>Cerrar</Btn><Btn onClick={saveProduct}><Icon name="check" size={13}/>Guardar Producto</Btn></div>
        </Modal>
      )}

      {/* Modal Servicio */}
      {sModal&&(
        <Modal title={editS?"Editar Servicio":"Nuevo Servicio"} onClose={()=>{setSModal(false);setEditS(null)}} width={540}>
          <div style={{display:"flex",gap:20,alignItems:"flex-start"}}>
            <div style={{textAlign:"center",flexShrink:0}}>
              <SvcImg src={sF.image} size={100}/>
              <input ref={svcImgRef} type="file" accept="image/*" onChange={e=>handleImg(e,setSF)} style={{display:"none"}}/>
              <div style={{display:"flex",gap:4,justifyContent:"center",marginTop:8}}>
                <Btn size="xs" variant="ghost" onClick={()=>svcImgRef.current.click()}><Icon name="image" size={11}/>Imagen</Btn>
                {sF.image&&<Btn size="xs" variant="danger" onClick={()=>setSF(p=>({...p,image:null}))}><Icon name="trash" size={11}/></Btn>}
              </div>
            </div>
            <div style={{flex:1}}>
              <Field label="Servicio *"><Inp value={sF.name} onChange={e=>setSF(p=>({...p,name:e.target.value}))}/></Field>
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"0 14px"}}>
                <Field label="Código"><Inp value={sF.code||""} onChange={e=>setSF(p=>({...p,code:e.target.value}))} placeholder="QUIR"/></Field>
                <Field label="Categoría">
                  <Sel value={sF.category||""} onChange={e=>setSF(p=>({...p,category:e.target.value}))}>
                    <option value="">Introduzca la categoría...</option>
                    {serviceCats.map(c=><option key={c.id} value={c.name}>{c.name}</option>)}
                  </Sel>
                </Field>
                <Field label="Precio" col="1/-1"><Inp type="number" value={sF.price||""} onChange={e=>setSF(p=>({...p,price:e.target.value}))} placeholder="0.00"/></Field>
              </div>
            </div>
          </div>
          <Field label="Descripción"><TA value={sF.description||""} onChange={e=>setSF(p=>({...p,description:e.target.value}))} style={{minHeight:60}}/></Field>
          <div style={{display:"flex",gap:10,justifyContent:"flex-end",marginTop:14}}><Btn variant="secondary" onClick={()=>{setSModal(false);setEditS(null)}}>Cerrar</Btn><Btn onClick={saveSvc}><Icon name="check" size={13}/>Guardar Servicio</Btn></div>
        </Modal>
      )}
    </div>
  );
};

// ─── APP ──────────────────────────────────────────────────────────────────────
// ─── PATIENT PORTAL (acceso por QR, sin login) ────────────────────────────────

// ─── PORTAL EVOLUCIÓN QR (acceso público con DNI) ────────────────────────────
const PortalEvolucion=()=>{
  const params=new URLSearchParams(window.location.search);
  const pid=params.get('pid')||'';
  const dniParam=params.get('dni')||'';
  const[step,setStep]=useState('dni');
  const[dniInput,setDniInput]=useState('');
  const[error,setError]=useState('');
  const[patient,setPatient]=useState(null);
  const[attendances,setAttendances]=useState([]);
  const[loading,setLoading]=useState(false);

  const buscar=async()=>{
    if(!dniInput.trim()){setError('Ingrese su número de DNI');return;}
    setLoading(true);setError('');
    try{
      var dniClean=dniInput.trim().replace(/\D/g,'');
      if(!dniClean){setError('Ingrese un DNI válido (solo números)');setLoading(false);return;}
      // Endpoint público — sin token de sesión
      var base=window.location.pathname.replace(/\/[^\/]*$/,'/');
      var url=base+'api/portal_evolucion.php?action=buscar_dni&dni='+encodeURIComponent(dniClean);
      var resp=await fetch(url);
      if(resp.status===404){setError('DNI no encontrado. Verifique el número e intente de nuevo.');setLoading(false);return;}
      if(!resp.ok){var err=await resp.json().catch(function(){return{error:'Error del servidor'};});setError(err.error||'Error al buscar');setLoading(false);return;}
      var data=await resp.json();
      if(data.error){setError(data.error);setLoading(false);return;}
      setPatient(data.patient);
      setAttendances(data.attendances||[]);
      setStep('historia');
    }catch(e2){console.error(e2);setError('Error de conexión. Verifique su internet.');}
    setLoading(false);
  };

  const S=(v)=>'S/ '+parseFloat(v||0).toFixed(2);
  const fmt=(d)=>d?d.split('-').reverse().join('/'):'—';

  if(step==='historia'&&patient){
    const p=patient;
    const closedAtts=attendances.filter(a=>a.closed||a.payStatus==='pagado');
    return(
      <div style={{minHeight:'100vh',background:'#eef2f7',fontFamily:"'Segoe UI',Arial,sans-serif"}}>
        <div style={{background:'linear-gradient(135deg,#0f3a2a,#1a4a5a)',padding:'16px 20px',display:'flex',alignItems:'center',justifyContent:'space-between'}}>
          <div>
            <div style={{fontSize:18,fontWeight:800,color:'#5dd4c6'}}>📋 Historia Clínica</div>
            <div style={{fontSize:13,color:'rgba(255,255,255,0.7)',marginTop:2}}>Podología Más Bela — Solo lectura</div>
          </div>
          <button onClick={()=>setStep('dni')} style={{background:'rgba(224,80,80,0.3)',border:'1px solid rgba(224,80,80,0.5)',borderRadius:10,padding:'8px 18px',color:'#ff9999',fontWeight:700,fontSize:13,cursor:'pointer'}}>✕ Cerrar Historia</button>
        </div>
        <div style={{maxWidth:760,margin:'0 auto',padding:'20px 16px'}}>
          {/* Datos del paciente */}
          <div style={{background:'#fff',borderRadius:14,padding:'18px',marginBottom:16,boxShadow:'0 2px 8px rgba(0,0,0,0.06)'}}>
            <div style={{fontWeight:800,fontSize:16,color:'#1a2332',marginBottom:12}}>👤 Datos del Paciente</div>
            <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'8px 20px',fontSize:13}}>
              <div><span style={{color:'#8a9aaa'}}>Nombre:</span> <strong>{(p.firstName||p.first_name||'')+' '+(p.lastName||p.last_name||'')}</strong></div>
              <div><span style={{color:'#8a9aaa'}}>DNI:</span> <strong>{p.dni||'—'}</strong></div>
              <div><span style={{color:'#8a9aaa'}}>Fecha de nacimiento:</span> {fmt(p.dob)}</div>
              <div><span style={{color:'#8a9aaa'}}>Teléfono:</span> {p.phone||'—'}</div>
              <div><span style={{color:'#8a9aaa'}}>Dirección:</span> {p.address||'—'}</div>
              <div><span style={{color:'#8a9aaa'}}>Sexo:</span> {p.sex||'—'}</div>
            </div>
            {(p.pathologies||[]).length>0&&(
              <div style={{marginTop:12}}>
                <div style={{fontSize:12,fontWeight:700,color:'#5a7a8a',marginBottom:6}}>PATOLOGÍAS</div>
                <div style={{display:'flex',flexWrap:'wrap',gap:6}}>
                  {(p.pathologies||[]).map((pt,i)=><span key={i} style={{background:'#4a9d8f18',color:'#2a6a5a',border:'1px solid #4a9d8f33',borderRadius:6,padding:'3px 10px',fontSize:12,fontWeight:600}}>{pt}</span>)}
                </div>
              </div>
            )}
            {(p.antecedentes||p.background)&&(
              <div style={{marginTop:10,fontSize:12,color:'#5a7a8a'}}><strong>Antecedentes:</strong> {p.antecedentes||p.background}</div>
            )}
          </div>
          {/* Historial de atenciones */}
          <div style={{fontWeight:700,fontSize:15,color:'#1a2332',marginBottom:10}}>🩺 Historial de Atenciones ({closedAtts.length})</div>
          {closedAtts.length===0?(
            <div style={{background:'#fff',borderRadius:12,padding:'24px',textAlign:'center',color:'#8a9aaa'}}>Sin atenciones registradas</div>
          ):closedAtts.map((a,i)=>(
            <div key={i} style={{background:'#fff',borderRadius:12,padding:'16px',marginBottom:12,boxShadow:'0 1px 4px rgba(0,0,0,0.06)',borderLeft:'4px solid #4a9d8f'}}>
              <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
                <div style={{fontWeight:700,color:'#4a9d8f',fontSize:13}}>Atención #{i+1} — {fmt(a.date)} {a.time||''}</div>
                <span style={{background:'#dcfce7',color:'#16a34a',borderRadius:6,padding:'2px 10px',fontSize:11,fontWeight:700}}>✓ Pagado</span>
              </div>
              <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:'4px 16px',fontSize:12.5,marginBottom:8}}>
                <div><span style={{color:'#8a9aaa'}}>Servicio:</span> {a.service||'—'}</div>
                <div><span style={{color:'#8a9aaa'}}>Atendido por:</span> {a.attendedBy||a.attended_by||'—'}</div>
                {(a.orderItems||[]).filter(it=>it._type==='product'||it._type==='inventory').length>0&&(
                  <div style={{gridColumn:'1/-1'}}><span style={{color:'#8a9aaa'}}>Medicamentos:</span> {(a.orderItems||[]).filter(it=>it._type==='product'||it._type==='inventory').map(it=>it.name).join(', ')}</div>
                )}
              </div>
              {a.notes&&<div style={{background:'#f0f9f7',border:'1px solid #4a9d8f22',borderRadius:8,padding:'8px 12px',fontSize:12,color:'#1a4a3a',marginBottom:8}}><strong>Indicaciones:</strong><br/>{a.notes}</div>}
              {(a.photos||[]).length>0&&(
                <div style={{display:'flex',flexWrap:'wrap',gap:8,marginTop:6}}>
                  {(a.photos||[]).map((ph,j)=><img key={j} src={ph.data} alt={'foto '+(j+1)} style={{width:90,height:90,objectFit:'cover',borderRadius:8,border:'2px solid #e8edf2'}}/>)}
                </div>
              )}
            </div>
          ))}
          <div style={{textAlign:'center',fontSize:11,color:'#aaa',marginTop:20,paddingBottom:20}}>Podología Más Bela · Historia Clínica de {(p.firstName||p.first_name||'')+' '+(p.lastName||p.last_name||'')} · Generado el {new Date().toLocaleDateString('es-PE')}</div>
        </div>
      </div>
    );
  }

  return(
    <div style={{minHeight:'100vh',background:'linear-gradient(135deg,#0f3a2a,#081828)',display:'flex',alignItems:'center',justifyContent:'center',padding:20}}>
      <div style={{background:'#fff',borderRadius:20,padding:'36px 32px',maxWidth:400,width:'100%',textAlign:'center',boxShadow:'0 24px 64px rgba(0,0,0,0.3)'}}>
        <div style={{fontSize:48,marginBottom:12}}>📋</div>
        <div style={{fontWeight:800,fontSize:20,color:'#1a2332',marginBottom:4}}>Historia Clínica</div>
        <div style={{fontSize:13,color:'#5a7a8a',marginBottom:24}}>Ingrese su DNI para acceder a su evolución de tratamiento</div>
        <input value={dniInput} onChange={e=>setDniInput(e.target.value)} onKeyDown={e=>e.key==='Enter'&&buscar()}
          placeholder="Número de DNI" maxLength={12}
          style={{width:'100%',padding:'12px 14px',border:'2px solid #d4dde5',borderRadius:10,fontSize:15,outline:'none',textAlign:'center',fontFamily:'monospace',letterSpacing:'0.1em',boxSizing:'border-box',marginBottom:8}}/>
        {error&&<div style={{color:'#e05050',fontSize:12.5,marginBottom:8,background:'#fff3f3',border:'1px solid #fecaca',borderRadius:8,padding:'8px 12px'}}>{error}</div>}
        <button onClick={buscar} disabled={loading}
          style={{width:'100%',padding:'12px',background:'linear-gradient(135deg,#4a9d8f,#2a7a6a)',color:'#fff',border:'none',borderRadius:10,fontSize:14,fontWeight:700,cursor:'pointer',marginTop:4}}>
          {loading?'Buscando...':'Acceder a mi Historia Clínica'}
        </button>
        <div style={{marginTop:14,fontSize:11,color:'#aaa'}}>Solo lectura · Sus datos están protegidos</div>
      </div>
    </div>
  );
};


// ─── MÓDULO GASTOS DE REPOSICIÓN ──────────────────────────────────────────────
const GastosReposicionModule=({currentUser})=>{
  const SK_GR='pmb_gastos_reposicion';
  const[gastos,setGastos]=useState([]);
  const[concepto,setConcepto]=useState('');
  const[monto,setMonto]=useState('');
  const[proveedor,setProveedor]=useState('');
  const today=new Date().toLocaleDateString('en-CA',{timeZone:'America/Lima'});
  const now=new Date();
  const cur='S/';
  useEffect(()=>{
    apiFetch('/special?action=expenses&type=reposicion')
      .then(r=>setGastos((r.data||[]).map(x=>({id:x.id,concepto:x.concept,monto:parseFloat(x.amount||0),proveedor:x.supplier||'',fecha:x.date,hora:x.time||'',registradoPor:x.registered_by||''}))))
      .catch(e=>alert('No se pudieron cargar gastos de reposición desde la BD: '+e.message));
  },[]);

  const saveGasto=async()=>{
    if(!concepto.trim()){alert('Ingrese el concepto');return;}
    if(!monto||parseFloat(monto)<=0){alert('Ingrese un monto válido');return;}
    const nuevo={id:Date.now(),concepto:concepto.trim(),monto:parseFloat(monto),proveedor:proveedor.trim(),fecha:today,hora:new Date().toLocaleTimeString('es-PE',{hour:'2-digit',minute:'2-digit'}),registradoPor:currentUser?.name||'SA'};
    try{
      const saved=await apiFetch('/special?action=expenses',{method:'POST',body:JSON.stringify({type:'reposicion',concept:nuevo.concepto,amount:nuevo.monto,supplier:nuevo.proveedor,date:nuevo.fecha,time:nuevo.hora,registered_by:nuevo.registradoPor})});
      const row=saved.row||{};
      setGastos([...gastos,{...nuevo,id:row.id||nuevo.id}]);
      setConcepto('');setMonto('');setProveedor('');
      alert('✅ Gasto de reposición guardado en la base de datos');
    }catch(e){alert('No se guardó el gasto en la base de datos: '+e.message);}
  };
  const del=async(id)=>{if(!window.confirm('¿Eliminar?'))return;try{await apiFetch('/special?action=expenses&id='+id,{method:'DELETE'});setGastos(gastos.filter(g=>g.id!==id));}catch(e){alert('No se eliminó el gasto en la base de datos: '+e.message);}};

  const inRange=(g,range)=>{
    const d=new Date(g.fecha+'T00:00:00');
    if(range==='day')return g.fecha===today;
    if(range==='week'){const w=new Date(now);w.setDate(w.getDate()-6);return d>=w;}
    if(range==='month')return d.getMonth()===now.getMonth()&&d.getFullYear()===now.getFullYear();
    return true;
  };
  const totalDay=gastos.filter(g=>inRange(g,'day')).reduce((s,g)=>s+g.monto,0);
  const totalWeek=gastos.filter(g=>inRange(g,'week')).reduce((s,g)=>s+g.monto,0);
  const totalMonth=gastos.filter(g=>inRange(g,'month')).reduce((s,g)=>s+g.monto,0);

  return(
    <div className="slide-in" style={{display:'flex',gap:20,alignItems:'flex-start'}}>
      <div style={{width:310,flexShrink:0,background:'#fff',borderRadius:14,padding:'16px',boxShadow:'0 2px 8px rgba(0,0,0,0.06)',maxHeight:'80vh',overflowY:'auto'}}>
        <div style={{fontWeight:800,fontSize:14,color:'#1a2332',marginBottom:12}}>📋 Registro de Reposición</div>
        {gastos.length===0?<div style={{textAlign:'center',color:'#8a9aaa',fontSize:12.5,padding:'20px 0'}}>Sin gastos registrados</div>:
        [...gastos].reverse().map(g=>(
          <div key={g.id} style={{borderBottom:'1px solid #f0f4f8',padding:'10px 0',display:'flex',justifyContent:'space-between',alignItems:'flex-start'}}>
            <div>
              <div style={{fontSize:13,fontWeight:600,color:'#1a2332'}}>{g.concepto}</div>
              <div style={{fontSize:11,color:'#8a9aaa'}}>{g.fecha.split('-').reverse().join('/')} {g.hora}{g.proveedor?' · '+g.proveedor:''}</div>
            </div>
            <div style={{display:'flex',alignItems:'center',gap:6,flexShrink:0}}>
              <span style={{fontWeight:800,fontSize:13,color:'#7c3aed'}}>{cur} {g.monto.toFixed(2)}</span>
              <button onClick={()=>del(g.id)} style={{background:'none',border:'none',cursor:'pointer',color:'#e05050',fontSize:14,padding:0}}>✕</button>
            </div>
          </div>
        ))}
      </div>
      <div style={{flex:1}}>
        <h2 style={{fontSize:22,fontWeight:800,color:'#1a2332',letterSpacing:'-0.02em',marginBottom:4}}>Gastos de Reposición</h2>
        <div style={{fontSize:12.5,color:'#8a9aaa',marginBottom:18}}>Compras de reposición de inventario · Administración autorizada</div>
        <div style={{background:'#fff',borderRadius:14,padding:'18px',marginBottom:16,boxShadow:'0 2px 8px rgba(0,0,0,0.06)'}}>
          <div style={{fontWeight:700,fontSize:14,color:'#1a2332',marginBottom:12}}>➕ Nuevo Gasto de Reposición</div>
          <div style={{display:'grid',gridTemplateColumns:'1fr 1fr auto',gap:10,alignItems:'end'}}>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>CONCEPTO / PRODUCTO</div>
              <input value={concepto} onChange={e=>setConcepto(e.target.value)} placeholder="Ej: Resina, alcohol, guantes..."
                style={{width:'100%',padding:'9px 12px',border:'1.5px solid #d4dde5',borderRadius:8,fontSize:13,outline:'none',boxSizing:'border-box'}}/>
            </div>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>PROVEEDOR</div>
              <input value={proveedor} onChange={e=>setProveedor(e.target.value)} placeholder="Proveedor (opcional)"
                style={{width:'100%',padding:'9px 12px',border:'1.5px solid #d4dde5',borderRadius:8,fontSize:13,outline:'none',boxSizing:'border-box'}}/>
            </div>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>MONTO S/.</div>
              <input type="number" min="0" step="0.01" value={monto} onChange={e=>setMonto(e.target.value)} placeholder="0.00"
                style={{width:110,padding:'9px 12px',border:'1.5px solid #d4dde5',borderRadius:8,fontSize:13,outline:'none'}}/>
            </div>
          </div>
          <div style={{marginTop:10,display:'flex',alignItems:'center',gap:16}}>
            <div style={{fontSize:12,color:'#8a9aaa'}}>Fecha: <strong>{today.split('-').reverse().join('/')}</strong> (automática)</div>
            <button onClick={saveGasto} style={{padding:'10px 24px',background:'linear-gradient(135deg,#7c3aed,#4f46e5)',color:'#fff',border:'none',borderRadius:10,fontSize:13,fontWeight:700,cursor:'pointer'}}>Registrar Gasto</button>
          </div>
        </div>
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:12}}>
          {[['Hoy','day',totalDay],['Esta semana','week',totalWeek],['Este mes','month',totalMonth]].map(([label,range,total])=>(
            <div key={range} style={{background:'#fff',borderRadius:12,padding:'14px',boxShadow:'0 2px 8px rgba(0,0,0,0.06)'}}>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',textTransform:'uppercase',marginBottom:6}}>{label}</div>
              <div style={{fontSize:20,fontWeight:900,color:'#7c3aed'}}>{cur} {total.toFixed(2)}</div>
              <div style={{fontSize:11,color:'#8a9aaa',marginTop:4}}>{gastos.filter(g=>inRange(g,range)).length} registros</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

// ─── MÓDULO GASTOS OPERATIVOS ─────────────────────────────────────────────────
const GastosOperativosModule=({currentUser})=>{
  const SK_GASTOS='pmb_gastos_operativos';
  const[gastos,setGastos]=useState([]);
  const[concepto,setConcepto]=useState('');
  const[monto,setMonto]=useState('');
  const today=new Date().toLocaleDateString('en-CA',{timeZone:'America/Lima'});
  const now=new Date();
  useEffect(()=>{
    apiFetch('/special?action=expenses&type=operativo')
      .then(r=>setGastos((r.data||[]).map(x=>({id:x.id,concepto:x.concept,monto:parseFloat(x.amount||0),fecha:x.date,hora:x.time||'',registradoPor:x.registered_by||''}))))
      .catch(e=>alert('No se pudieron cargar gastos operativos desde la BD: '+e.message));
  },[]);

  const saveGasto=async()=>{
    if(!concepto.trim()){alert('Ingrese el concepto del gasto');return;}
    if(!monto||parseFloat(monto)<=0){alert('Ingrese un monto válido');return;}
    const nuevo={id:Date.now(),concepto:concepto.trim(),monto:parseFloat(monto),fecha:today,hora:new Date().toLocaleTimeString('es-PE',{hour:'2-digit',minute:'2-digit'}),registradoPor:currentUser?.name||'SA'};
    try{
      const saved=await apiFetch('/special?action=expenses',{method:'POST',body:JSON.stringify({type:'operativo',concept:nuevo.concepto,amount:nuevo.monto,date:nuevo.fecha,time:nuevo.hora,registered_by:nuevo.registradoPor})});
      const row=saved.row||{};
      setGastos([...gastos,{...nuevo,id:row.id||nuevo.id}]);
      setConcepto('');setMonto('');
      alert('✅ Gasto guardado en la base de datos');
    }catch(e){alert('No se guardó el gasto en la base de datos: '+e.message);}
  };

  const del=async(id)=>{if(!window.confirm('¿Eliminar este gasto?'))return;try{await apiFetch('/special?action=expenses&id='+id,{method:'DELETE'});setGastos(gastos.filter(g=>g.id!==id));}catch(e){alert('No se eliminó el gasto en la base de datos: '+e.message);}};

  const inRange=(g,range)=>{
    const d=new Date(g.fecha+'T00:00:00');
    if(range==='day')return g.fecha===today;
    if(range==='week'){const w=new Date(now);w.setDate(w.getDate()-6);return d>=w;}
    if(range==='month')return d.getMonth()===now.getMonth()&&d.getFullYear()===now.getFullYear();
    return true;
  };

  const totalDay=gastos.filter(g=>inRange(g,'day')).reduce((s,g)=>s+g.monto,0);
  const totalWeek=gastos.filter(g=>inRange(g,'week')).reduce((s,g)=>s+g.monto,0);
  const totalMonth=gastos.filter(g=>inRange(g,'month')).reduce((s,g)=>s+g.monto,0);

  // Recaudación para ratio (attendances)
  const atts=safeJson(localStorage.getItem('pmb_attendances'),[]);
  const recDay=atts.filter(a=>a.date===today&&a.closed).reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const recWeek=atts.filter(a=>{const d=new Date(a.date+'T00:00:00');const w=new Date(now);w.setDate(w.getDate()-6);return d>=w&&a.closed;}).reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const recMonth=atts.filter(a=>{const d=new Date(a.date+'T00:00:00');return d.getMonth()===now.getMonth()&&d.getFullYear()===now.getFullYear()&&a.closed;}).reduce((s,a)=>s+(parseFloat(a.price)||0),0);

  const ratio=(g,r)=>r>0?Math.round((g/r)*100):null;
  const cur='S/';

  return(
    <div className="slide-in" style={{display:'flex',gap:20,alignItems:'flex-start'}}>
      {/* SIDEBAR izquierdo — listado */}
      <div style={{width:310,flexShrink:0,background:'#fff',borderRadius:14,padding:'16px',boxShadow:'0 2px 8px rgba(0,0,0,0.06)',maxHeight:'80vh',overflowY:'auto'}}>
        <div style={{fontWeight:800,fontSize:14,color:'#1a2332',marginBottom:12}}>📋 Registro de Gastos</div>
        {gastos.length===0?<div style={{textAlign:'center',color:'#8a9aaa',fontSize:12.5,padding:'20px 0'}}>Sin gastos registrados</div>:
        [...gastos].reverse().map(g=>(
          <div key={g.id} style={{borderBottom:'1px solid #f0f4f8',padding:'10px 0',display:'flex',justifyContent:'space-between',alignItems:'flex-start'}}>
            <div>
              <div style={{fontSize:13,fontWeight:600,color:'#1a2332'}}>{g.concepto}</div>
              <div style={{fontSize:11,color:'#8a9aaa'}}>{g.fecha.split('-').reverse().join('/')} {g.hora} · {g.registradoPor}</div>
            </div>
            <div style={{display:'flex',alignItems:'center',gap:6,flexShrink:0}}>
              <span style={{fontWeight:800,fontSize:13,color:'#e05050'}}>{cur} {g.monto.toFixed(2)}</span>
              <button onClick={()=>del(g.id)} style={{background:'none',border:'none',cursor:'pointer',color:'#e05050',fontSize:14,padding:0}}>✕</button>
            </div>
          </div>
        ))}
      </div>
      {/* CONTENIDO PRINCIPAL */}
      <div style={{flex:1}}>
        <h2 style={{fontSize:22,fontWeight:800,color:'#1a2332',letterSpacing:'-0.02em',marginBottom:4}}>Gastos Operativos</h2>
        <div style={{fontSize:12.5,color:'#8a9aaa',marginBottom:18}}>Gastos no programados del día · Administración autorizada</div>
        {/* Formulario registro */}
        <div style={{background:'#fff',borderRadius:14,padding:'18px',marginBottom:16,boxShadow:'0 2px 8px rgba(0,0,0,0.06)'}}>
          <div style={{fontWeight:700,fontSize:14,color:'#1a2332',marginBottom:12}}>➕ Nuevo Gasto</div>
          <div style={{display:'grid',gridTemplateColumns:'1fr auto auto',gap:10,alignItems:'end'}}>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>CONCEPTO DE LA COMPRA</div>
              <input value={concepto} onChange={e=>setConcepto(e.target.value)} placeholder="Ej: Compra de insumos, papelería..."
                style={{width:'100%',padding:'9px 12px',border:'1.5px solid #d4dde5',borderRadius:8,fontSize:13,outline:'none',boxSizing:'border-box'}}/>
            </div>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>MONTO S/.</div>
              <input type="number" min="0" step="0.01" value={monto} onChange={e=>setMonto(e.target.value)} placeholder="0.00"
                style={{width:110,padding:'9px 12px',border:'1.5px solid #d4dde5',borderRadius:8,fontSize:13,outline:'none'}}/>
            </div>
            <div>
              <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',marginBottom:4}}>FECHA</div>
              <div style={{padding:'9px 12px',background:'#f4f8fa',borderRadius:8,fontSize:13,color:'#5a7a8a',border:'1.5px solid #e8edf2'}}>{today.split('-').reverse().join('/')}</div>
            </div>
          </div>
          <button onClick={saveGasto} style={{marginTop:12,padding:'10px 24px',background:'linear-gradient(135deg,#4a9d8f,#2a7a6a)',color:'#fff',border:'none',borderRadius:10,fontSize:13,fontWeight:700,cursor:'pointer'}}>Registrar Gasto</button>
        </div>
        {/* Tarjetas resumen */}
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:12,marginBottom:16}}>
          {[['Hoy','day',totalDay,recDay],['Esta semana','week',totalWeek,recWeek],['Este mes','month',totalMonth,recMonth]].map(([label,range,total,rec])=>{
            const pct=ratio(total,rec);
            return(
              <div key={range} style={{background:'#fff',borderRadius:12,padding:'14px',boxShadow:'0 2px 8px rgba(0,0,0,0.06)'}}>
                <div style={{fontSize:11,fontWeight:700,color:'#5a7a8a',textTransform:'uppercase',marginBottom:6}}>{label}</div>
                <div style={{fontSize:20,fontWeight:900,color:'#e05050',marginBottom:4}}>{cur} {total.toFixed(2)}</div>
                <div style={{fontSize:11,color:'#8a9aaa',marginBottom:6}}>Recaudado: {cur} {rec.toFixed(2)}</div>
                {pct!==null?(
                  <>
                    <div style={{display:'flex',justifyContent:'space-between',fontSize:10,marginBottom:3}}>
                      <span style={{color:'#8a9aaa'}}>Impacto en recaudación</span>
                      <span style={{fontWeight:700,color:pct>30?'#e05050':pct>15?'#f59223':'#2ea87e'}}>{pct}%</span>
                    </div>
                    <div style={{background:'#eef2f7',borderRadius:4,height:6,overflow:'hidden'}}>
                      <div style={{width:Math.min(100,pct)+'%',height:'100%',background:pct>30?'#e05050':pct>15?'#f59223':'#2ea87e',borderRadius:4}}/>
                    </div>
                  </>
                ):<div style={{fontSize:10,color:'#8a9aaa'}}>Sin recaudación registrada</div>}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

const PatientPortal=()=>{
  const[step,setStep]=useState("dni"); // dni | found | notfound | form | success
  const[dni,setDni]=useState("");
  const[searching,setSearching]=useState(false);
  const[foundPat,setFoundPat]=useState(null);
  const[saving,setSaving]=useState(false);
  const company=useState(null);
  const[comp,setComp]=useState({name:"Podología Más Bela",logo:null});
  const[form,setForm]=useState({firstName:"",lastName:"",dob:"",dni:"",phone:"",email:"",sex:"",address:""});
  const[formErr,setFormErr]=useState("");

  useEffect(()=>{
    fetch("/api/company").then(r=>r.json()).then(d=>{if(d&&d.name)setComp(d);}).catch(()=>{});
  },[]);

  const buscar=async()=>{
    if(!String(dni||"").trim()){return;}
    setSearching(true);
    try{
      const r=await fetch("/api/patients");
      const list=await r.json();
      const found=list.find(p=>String(p.dni||"")===String(dni||"").trim());
      if(found){setFoundPat(found);setStep("found");}
      else{setForm(f=>({...f,dni:dni.trim()}));setStep("notfound");}
    }catch(e){alert("Error de conexión. Verifique que el sistema esté activo.");}
    setSearching(false);
  };

  const guardar=async()=>{
    if(!form.firstName.trim()||!form.lastName.trim())return setFormErr("Ingrese nombre y apellido");
    if(!form.dob)return setFormErr("Ingrese fecha de nacimiento");
    if(!form.sex)return setFormErr("Seleccione sexo");
    if(!String(form.dni||"").trim())return setFormErr("Ingrese su DNI");
    setFormErr("");setSaving(true);
    try{
      const r=await fetch("/api/patients");
      const list=await r.json();
      if(list.find(p=>String(p.dni||"")===String(form.dni||"").trim())){setFormErr("Este DNI ya está registrado. Consulte en recepción.");setSaving(false);return;}
      const newP={...emptyPt(),...form,dni:String(form.dni||"").trim(),registrationDate:todayStr(),status:"active",patientType:"publico",portalRegistered:true};
      await fetch("/api/patients",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(newP)});
      setStep("success");
    }catch(e){setFormErr("Error al guardar. Intente de nuevo.");}
    setSaving(false);
  };

  const BtnPrimary=({onClick,children,disabled})=>(
    <button onClick={onClick} disabled={disabled} style={{width:"100%",padding:"13px",borderRadius:12,background:disabled?"#c0d4d0":"linear-gradient(135deg,#4a9d8f,#2a7a6a)",color:"#fff",border:"none",fontWeight:700,fontSize:15,cursor:disabled?"not-allowed":"pointer",fontFamily:"'Outfit',sans-serif",transition:"opacity .15s",marginTop:12}}>
      {children}
    </button>
  );

  const InpPortal=({label,children})=>(
    <div style={{marginBottom:14}}>
      <label style={{fontSize:12,fontWeight:700,color:"#5a7a8a",marginBottom:5,display:"block"}}>{label}</label>
      {children}
    </div>
  );

  const inpStyle={width:"100%",padding:"11px 14px",borderRadius:10,border:"1.5px solid #d4e2e8",fontSize:14,fontFamily:"'Outfit',sans-serif",color:"#1a2332",outline:"none",background:"#f8fafc",boxSizing:"border-box"};

  return(
    <div style={{minHeight:"100vh",background:"linear-gradient(135deg,#081828 0%,#0f3a2a 55%,#1a4a5a 100%)",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"flex-start",padding:"28px 16px",fontFamily:"'Outfit',sans-serif"}}>
      <link rel="preconnect" href="https://fonts.googleapis.com"/>
      <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"/>
      {/* Header */}
      <div style={{textAlign:"center",marginBottom:28}}>
        <div style={{width:72,height:72,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 12px",boxShadow:"0 6px 24px rgba(74,157,143,0.4)"}}>
          <span style={{fontSize:32}}>🩺</span>
        </div>
        <div style={{fontFamily:"serif",fontSize:20,color:"#fff",fontWeight:600,marginBottom:4}}>{comp.name}</div>
        <div style={{fontSize:12,color:"rgba(255,255,255,0.45)",letterSpacing:"0.06em",textTransform:"uppercase"}}>Portal de Registro Digital</div>
      </div>

      <div style={{background:"#fff",borderRadius:20,padding:"28px 24px",width:"100%",maxWidth:420,boxShadow:"0 24px 64px rgba(0,0,0,0.35)"}}>

        {step==="dni"&&(
          <>
            <div style={{fontWeight:800,fontSize:18,color:"#1a2332",marginBottom:4}}>Bienvenido/a</div>
            <div style={{fontSize:13,color:"#8a9aaa",marginBottom:22}}>Ingresa tu DNI para verificar si ya estás registrado/a o para crear tu ficha.</div>
            <InpPortal label="📋 Número de DNI / Documento">
              <input style={inpStyle} placeholder="Ej: 12345678" value={dni} onChange={e=>setDni(e.target.value)} onKeyDown={e=>e.key==="Enter"&&buscar()} maxLength={12} inputMode="numeric"/>
            </InpPortal>
            <BtnPrimary onClick={buscar} disabled={searching||!dni.trim()}>
              {searching?"Buscando...":"Verificar DNI →"}
            </BtnPrimary>
          </>
        )}

        {step==="found"&&foundPat&&(
          <>
            <div style={{textAlign:"center",marginBottom:20}}>
              <div style={{width:60,height:60,borderRadius:"50%",background:"linear-gradient(135deg,#059669,#2ea87e)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:26,margin:"0 auto 12px",boxShadow:"0 6px 20px rgba(5,150,105,0.3)"}}>✅</div>
              <div style={{fontWeight:800,fontSize:17,color:"#1a2332"}}>¡Ya estás registrado/a!</div>
            </div>
            <div style={{background:"linear-gradient(135deg,#f0faf7,#e8f5f0)",borderRadius:14,padding:"18px 20px",marginBottom:20}}>
              <div style={{fontSize:13,color:"#5a7a8a",fontWeight:600,marginBottom:3}}>Paciente Verificado</div>
              <div style={{fontWeight:800,fontSize:16,color:"#1a2332"}}>{foundPat.firstName} {foundPat.lastName}</div>
              <div style={{fontSize:12.5,color:"#8a9aaa",marginTop:4}}>DNI: {foundPat.dni} · Ficha #{String(foundPat.id).padStart(6,"0")}</div>
              {foundPat.phone&&<div style={{fontSize:12.5,color:"#8a9aaa"}}>📞 {foundPat.phone}</div>}
            </div>
            <div style={{background:"#fffbeb",border:"1px solid #fde68a",borderRadius:12,padding:"12px 16px",fontSize:12.5,color:"#92400e",marginBottom:16,display:"flex",gap:8,alignItems:"flex-start"}}>
              <span style={{fontSize:16,flexShrink:0}}>💡</span>
              <span>Para modificar tus datos o agendar una cita, por favor dirígete a recepción. El personal te atenderá con tu número de ficha.</span>
            </div>
            <button onClick={()=>{setStep("dni");setDni("");setFoundPat(null);}} style={{width:"100%",padding:"11px",borderRadius:12,background:"#f0f4f8",color:"#5a7a8a",border:"none",fontWeight:600,fontSize:14,cursor:"pointer",fontFamily:"'Outfit',sans-serif"}}>← Volver</button>
          </>
        )}

        {step==="notfound"&&(
          <>
            <div style={{textAlign:"center",marginBottom:20}}>
              <div style={{width:60,height:60,borderRadius:"50%",background:"linear-gradient(135deg,#f59223,#e07d10)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:26,margin:"0 auto 12px"}}>📝</div>
              <div style={{fontWeight:800,fontSize:17,color:"#1a2332"}}>No estás registrado/a</div>
              <div style={{fontSize:13,color:"#8a9aaa",marginTop:4}}>Completa el formulario para crear tu ficha de paciente.</div>
            </div>
            <BtnPrimary onClick={()=>setStep("form")}>Registrarme ahora →</BtnPrimary>
            <button onClick={()=>{setStep("dni");setDni("");}} style={{width:"100%",padding:"10px",borderRadius:12,background:"transparent",color:"#8a9aaa",border:"1px solid #e0e8f0",fontWeight:600,fontSize:13,cursor:"pointer",fontFamily:"'Outfit',sans-serif",marginTop:8}}>← Volver</button>
          </>
        )}

        {step==="form"&&(
          <>
            <div style={{fontWeight:800,fontSize:16,color:"#1a2332",marginBottom:4}}>📋 Nueva Ficha de Paciente</div>
            <div style={{fontSize:12,color:"#8a9aaa",marginBottom:20}}>Completa tus datos básicos. El personal completará el resto en consulta.</div>
            {formErr&&<div style={{background:"#fff0f0",border:"1px solid #fca5a5",borderRadius:10,padding:"10px 14px",fontSize:12.5,color:"#dc2626",marginBottom:14}}>{formErr}</div>}
            <InpPortal label="Nombres *"><input style={inpStyle} placeholder="Ej: María Elena" value={form.firstName} onChange={e=>setForm(f=>({...f,firstName:e.target.value}))}/></InpPortal>
            <InpPortal label="Apellidos *"><input style={inpStyle} placeholder="Ej: García López" value={form.lastName} onChange={e=>setForm(f=>({...f,lastName:e.target.value}))}/></InpPortal>
            <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10}}>
              <InpPortal label="DNI / Documento *"><input style={inpStyle} value={form.dni} onChange={e=>setForm(f=>({...f,dni:e.target.value}))} maxLength={12} inputMode="numeric"/></InpPortal>
              <InpPortal label="Fecha de Nacimiento *"><input style={inpStyle} type="date" value={form.dob} onChange={e=>setForm(f=>({...f,dob:e.target.value}))}/></InpPortal>
            </div>
            <InpPortal label="Sexo *">
              <select style={inpStyle} value={form.sex} onChange={e=>setForm(f=>({...f,sex:e.target.value}))}>
                <option value="">— Seleccionar —</option>
                <option value="F">Femenino</option>
                <option value="M">Masculino</option>
              </select>
            </InpPortal>
            <InpPortal label="Celular / Teléfono"><input style={inpStyle} placeholder="Ej: 987654321" value={form.phone} onChange={e=>setForm(f=>({...f,phone:e.target.value}))} inputMode="tel"/></InpPortal>
            <InpPortal label="Correo electrónico"><input style={inpStyle} type="email" placeholder="ejemplo@correo.com" value={form.email} onChange={e=>setForm(f=>({...f,email:e.target.value}))}/></InpPortal>
            <InpPortal label="Dirección"><input style={inpStyle} placeholder="Dirección de domicilio" value={form.address} onChange={e=>setForm(f=>({...f,address:e.target.value}))}/></InpPortal>
            <BtnPrimary onClick={guardar} disabled={saving}>{saving?"Guardando...":"✅ Crear mi Ficha"}</BtnPrimary>
            <button onClick={()=>setStep("notfound")} style={{width:"100%",padding:"10px",borderRadius:12,background:"transparent",color:"#8a9aaa",border:"1px solid #e0e8f0",fontWeight:600,fontSize:13,cursor:"pointer",fontFamily:"'Outfit',sans-serif",marginTop:8}}>← Volver</button>
          </>
        )}

        {step==="success"&&(
          <>
            <div style={{textAlign:"center",padding:"12px 0"}}>
              <div style={{width:72,height:72,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:32,margin:"0 auto 16px",boxShadow:"0 8px 28px rgba(74,157,143,0.35)"}}>🎉</div>
              <div style={{fontWeight:800,fontSize:19,color:"#1a2332",marginBottom:6}}>¡Ficha creada!</div>
              <div style={{fontSize:13.5,color:"#5a7a8a",marginBottom:22}}>Tu historia clínica ha sido registrada exitosamente. Por favor acércate a recepción para completar tu registro.</div>
              <div style={{background:"linear-gradient(135deg,#f0faf7,#e8f5f0)",borderRadius:14,padding:"16px 20px",marginBottom:20,textAlign:"left"}}>
                <div style={{fontSize:12,fontWeight:700,color:"#2ea87e",marginBottom:4,textTransform:"uppercase",letterSpacing:".05em"}}>✅ Datos registrados</div>
                <div style={{fontWeight:700,fontSize:15,color:"#1a2332"}}>{form.firstName} {form.lastName}</div>
                <div style={{fontSize:12.5,color:"#8a9aaa"}}>DNI: {form.dni} {form.phone&&`· 📞 ${form.phone}`}</div>
              </div>
              <button onClick={()=>{setStep("dni");setDni("");setForm({firstName:"",lastName:"",dob:"",dni:"",phone:"",email:"",sex:"",address:""}); }} style={{width:"100%",padding:"12px",borderRadius:12,background:"#f0f4f8",color:"#5a7a8a",border:"none",fontWeight:600,fontSize:14,cursor:"pointer",fontFamily:"'Outfit',sans-serif"}}>Registrar otro paciente</button>
            </div>
          </>
        )}
      </div>
      <div style={{marginTop:20,fontSize:11,color:"rgba(255,255,255,0.25)",textAlign:"center"}}>PodoCLINIC · Portal Digital de Pacientes</div>
    </div>
  );
};

// ─── QR MODAL ────────────────────────────────────────────────────────────────
const QRModal=({onClose})=>{
  const qrRef=useRef(null);
  const[copied,setCopied]=useState(false);
  const portalUrl=`${window.location.protocol}//${window.location.hostname}:3737/?portal=1`;

  useEffect(()=>{
    if(!qrRef.current)return;
    if(typeof QRCode!=="undefined"){
      qrRef.current.innerHTML="";
      try{
        new QRCode(qrRef.current,{
          text:portalUrl,width:200,height:200,
          colorDark:"#081828",colorLight:"#ffffff",
          correctLevel:QRCode.CorrectLevel.M
        });
      }catch(e){qrRef.current.innerHTML="<div style='color:#8a9aaa;font-size:12px;padding:20px'>No se pudo generar el QR</div>";}
    }else{
      qrRef.current.innerHTML="<div style='color:#5a7a8a;font-size:12px;line-height:1.5;padding:20px;word-break:break-all'>Generador QR no disponible en este navegador.<br/>Use el enlace del portal:<br/><b>"+portalUrl+"</b></div>";
    }
  },[portalUrl]);

  const copy=()=>{navigator.clipboard.writeText(portalUrl).then(()=>{setCopied(true);setTimeout(()=>setCopied(false),2000);});};

  const print=()=>{
    const w=window.open("","_blank","width=600,height=700");
    const comp=db.get("pmb_company")||{name:"Podología Más Bela"};
    const canvas=qrRef.current&&qrRef.current.querySelector("canvas");
    const imgSrc=canvas?canvas.toDataURL("image/png"):"";
    w.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>QR Portal Pacientes</title><style>body{font-family:'Segoe UI',sans-serif;text-align:center;padding:40px;background:#fff;}h1{color:#081828;font-size:22px;margin-bottom:4px;}p{color:#5a7a8a;font-size:13px;margin:4px 0;}img{margin:24px auto;display:block;border:8px solid #f0f4f8;border-radius:12px;}.url{background:#f0f9f7;border:1px solid #4a9d8f44;border-radius:8px;padding:8px 14px;font-size:12px;color:#2a7a6a;font-family:monospace;word-break:break-all;margin:16px auto;max-width:360px;}.footer{margin-top:28px;font-size:11px;color:#aaa;}</style></head><body>
    <h1>🩺 ${comp.name}</h1>
    <p style="font-size:15px;font-weight:700;color:#4a9d8f;margin-top:12px;">Escanea el QR para registrarte como paciente</p>
    <p>Verifica tu DNI o crea tu ficha de historia clínica</p>
    ${imgSrc?`<img src="${imgSrc}" width="200" height="200"/>`:""}
    <div class="url">${portalUrl}</div>
    <p>También puedes ingresar esta dirección en tu navegador desde la red local</p>
    <div class="footer">Portal de Registro Digital · PodoCLINIC</div>
    </body></html>`);
    w.document.close();
    setTimeout(()=>w.print(),600);
  };

  return(
    <>
      <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",zIndex:9998}} onClick={onClose}/>
      <div style={{position:"fixed",top:"50%",left:"50%",transform:"translate(-50%,-50%)",background:"#fff",borderRadius:20,padding:"32px 36px",boxShadow:"0 24px 64px rgba(0,0,0,0.28)",zIndex:9999,minWidth:340,maxWidth:440,width:"90%",textAlign:"center",fontFamily:"'Outfit',sans-serif"}}>
        <div style={{width:56,height:56,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:24,margin:"0 auto 14px",boxShadow:"0 6px 20px rgba(74,157,143,0.3)"}}>📲</div>
        <div style={{fontWeight:800,fontSize:18,color:"#1a2332",marginBottom:4}}>Portal QR de Registro</div>
        <div style={{fontSize:12.5,color:"#8a9aaa",marginBottom:20}}>Muestra este QR a los pacientes para que registren o verifiquen sus datos desde su celular.</div>
        <div style={{display:"inline-block",background:"#f8fafc",borderRadius:16,padding:16,border:"1.5px solid #e0eaf0",marginBottom:16}}>
          <div ref={qrRef}/>
        </div>
        <div style={{display:"flex",alignItems:"center",gap:8,background:"#f0faf7",borderRadius:10,padding:"8px 12px",marginBottom:16,border:"1px solid #4a9d8f33"}}>
          <div style={{flex:1,fontSize:11.5,color:"#2a7a6a",fontFamily:"monospace",wordBreak:"break-all",textAlign:"left"}}>{portalUrl}</div>
          <button onClick={copy} style={{flexShrink:0,padding:"4px 10px",background:copied?"#059669":"#4a9d8f",color:"#fff",border:"none",borderRadius:7,fontSize:11.5,fontWeight:700,cursor:"pointer",fontFamily:"'Outfit',sans-serif",transition:"background .2s"}}>{copied?"✓ Copiado":"Copiar"}</button>
        </div>
        <div style={{display:"flex",gap:10}}>
          <button onClick={print} style={{flex:1,padding:"10px",borderRadius:12,background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",fontFamily:"'Outfit',sans-serif"}}>🖨️ Imprimir QR</button>
          <button onClick={onClose} style={{flex:1,padding:"10px",borderRadius:12,background:"#f0f4f8",color:"#5a7a8a",border:"none",fontWeight:600,fontSize:13,cursor:"pointer",fontFamily:"'Outfit',sans-serif"}}>Cerrar</button>
        </div>
        <div style={{marginTop:14,fontSize:11,color:"#b0bec5",padding:"10px 0",borderTop:"1px solid #f0f4f8"}}>
          💡 El paciente debe estar conectado a la misma red Wi-Fi de la clínica.
        </div>
      </div>
    </>
  );
};

// ─── MOBILE VENTAS RESUMEN (usuario movil) ────────────────────────────────────
const MobileVentasResumen=({user})=>{
  const now=new Date();
  const monthStart=`${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,"0")}-01`;
  const attendances=db.get(SK.attendances)||[];
  const salesOrders=db.get(SK.salesOrders)||[];
  const monthAtt=attendances.filter(a=>a.date>=monthStart&&(a.payStatus==="pagado"||a.closed)&&a.attendedBy===user.name);
  const monthOrders=salesOrders.filter(o=>o.date>=monthStart&&o.status==="cobrado"&&o.assignedTo===user.name);
  const svcAtts=monthAtt.filter(a=>a.type!=="venta"&&!a.orderCode);
  const prodAtts=monthAtt.filter(a=>a.type==="venta"||a.orderCode);
  const svcTotal=svcAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0);
  const prodTotal=prodAtts.reduce((s,a)=>s+(parseFloat(a.price)||0),0)+monthOrders.reduce((s,o)=>s+(o.total||0),0);
  const goals=safeJson(localStorage.getItem('podo_worker_goals'),{});
  const myGoal=goals[user.name]||{svc:0,prod:0};
  const pctSvc=myGoal.svc>0?Math.min(100,Math.round((svcTotal/myGoal.svc)*100)):null;
  const pctProd=myGoal.prod>0?Math.min(100,Math.round((prodTotal/myGoal.prod)*100)):null;
  const S=(v)=>`S/ ${parseFloat(v).toFixed(2)}`;
  return(
    <div style={{padding:"16px 12px"}}>
      <div style={{fontWeight:800,fontSize:18,color:"#1a2332",marginBottom:4}}>👋 Hola, {user.name.split(' ')[0]}</div>
      <div style={{fontSize:12,color:"#8a9aaa",marginBottom:16}}>Resumen de ventas · {new Date().toLocaleDateString('es-PE',{month:'long',year:'numeric'})}</div>
      <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12,marginBottom:16}}>
        <div style={{background:"linear-gradient(135deg,#2563eb,#3b82f6)",borderRadius:14,padding:"16px 14px",color:"#fff",boxShadow:"0 4px 16px #2563eb44"}}>
          <div style={{fontSize:10,fontWeight:700,textTransform:"uppercase",opacity:0.75,marginBottom:6}}>Vta por Servicio</div>
          <div style={{fontSize:22,fontWeight:900,marginBottom:2}}>{S(svcTotal)}</div>
          <div style={{fontSize:11,opacity:0.8}}>{svcAtts.length} atenciones</div>
          {pctSvc!==null&&(
            <div style={{marginTop:10}}>
              <div style={{display:"flex",justifyContent:"space-between",fontSize:9,opacity:0.85,marginBottom:3}}>
                <span>Meta: {S(myGoal.svc)}</span><span>{pctSvc}%</span>
              </div>
              <div style={{background:"rgba(255,255,255,0.25)",borderRadius:4,height:6,overflow:"hidden"}}>
                <div style={{width:`${pctSvc}%`,height:"100%",background:"#fff",borderRadius:4}}/>
              </div>
            </div>
          )}
        </div>
        <div style={{background:"linear-gradient(135deg,#7c3aed,#a855f7)",borderRadius:14,padding:"16px 14px",color:"#fff",boxShadow:"0 4px 16px #7c3aed44"}}>
          <div style={{fontSize:10,fontWeight:700,textTransform:"uppercase",opacity:0.75,marginBottom:6}}>Vta por Producto</div>
          <div style={{fontSize:22,fontWeight:900,marginBottom:2}}>{S(prodTotal)}</div>
          <div style={{fontSize:11,opacity:0.8}}>{prodAtts.length+monthOrders.length} ventas</div>
          {pctProd!==null&&(
            <div style={{marginTop:10}}>
              <div style={{display:"flex",justifyContent:"space-between",fontSize:9,opacity:0.85,marginBottom:3}}>
                <span>Meta: {S(myGoal.prod)}</span><span>{pctProd}%</span>
              </div>
              <div style={{background:"rgba(255,255,255,0.25)",borderRadius:4,height:6,overflow:"hidden"}}>
                <div style={{width:`${pctProd}%`,height:"100%",background:"#fff",borderRadius:4}}/>
              </div>
            </div>
          )}
        </div>
      </div>
      <div style={{background:"#fff",borderRadius:14,padding:"14px",boxShadow:"0 2px 8px rgba(0,0,0,0.06)"}}>
        <div style={{fontWeight:700,fontSize:13,color:"#1a2332",marginBottom:10}}>📊 Total del mes</div>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"8px 0",borderBottom:"1px solid #f0f4f8"}}>
          <span style={{fontSize:12.5,color:"#5a7a8a"}}>Servicios</span>
          <span style={{fontSize:13,fontWeight:700,color:"#2563eb"}}>{S(svcTotal)}</span>
        </div>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"8px 0",borderBottom:"1px solid #f0f4f8"}}>
          <span style={{fontSize:12.5,color:"#5a7a8a"}}>Productos</span>
          <span style={{fontSize:13,fontWeight:700,color:"#7c3aed"}}>{S(prodTotal)}</span>
        </div>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 0 0"}}>
          <span style={{fontSize:13,fontWeight:700,color:"#1a2332"}}>TOTAL</span>
          <span style={{fontSize:16,fontWeight:900,color:"#059669"}}>{S(svcTotal+prodTotal)}</span>
        </div>
      </div>
    </div>
  );
};

// ─── CASHBOX SUMMARY MOBILE ───────────────────────────────────────────────────
const CashboxSummaryMobile=({user})=>{
  const[data,setData]=useState(null);
  const[loading,setLoading]=useState(true);
  const today=new Date().toISOString().slice(0,10);
  const month=today.slice(0,7);
  useEffect(()=>{
    var tok=localStorage.getItem('podo_token')||localStorage.getItem('podo_token')||'';
    var base=window.location.pathname.replace(/\/[^\/]*$/,'/');
    var url=base+'api/special.php?action=cashbox_summary&date='+today+'&t='+Date.now();
    fetch(url,{headers:{'X-Auth-Token':tok,'Cache-Control':'no-cache'}})
      .then(function(r){return r.json();})
      .then(function(d){setData(d);setLoading(false);})
      .catch(function(){setLoading(false);});
  },[]);
  const currency=n=>'S/ '+parseFloat(n||0).toFixed(2);
  if(loading)return <div style={{textAlign:'center',padding:40,color:'#8a9aaa'}}>Cargando resumen...</div>;
  const efectivo=parseFloat(data?.efectivo||data?.cash||0);
  const tarjeta=parseFloat(data?.tarjeta||data?.card||0);
  const yape=parseFloat(data?.yape||0);
  const plin=parseFloat(data?.plin||0);
  const total=efectivo+tarjeta+yape+plin;
  const rows=[
    {label:'💵 Efectivo',val:efectivo,color:'#16a34a'},
    {label:'💳 Tarjeta',val:tarjeta,color:'#2563eb'},
    {label:'📱 Yape',val:yape,color:'#7c3aed'},
    {label:'📱 Plin',val:plin,color:'#0891b2'},
  ];
  return(
    <div>
      <div style={{fontWeight:700,fontSize:15,color:'#1a2332',marginBottom:14}}>📊 Resumen de Caja — Hoy</div>
      <div style={{background:'linear-gradient(135deg,#0f3a2a,#1a4a5a)',borderRadius:14,padding:'18px 20px',marginBottom:14,color:'#fff'}}>
        <div style={{fontSize:11,opacity:0.7,marginBottom:4}}>Total del día</div>
        <div style={{fontSize:28,fontWeight:800,color:'#5dd4c6'}}>{currency(total)}</div>
        <div style={{fontSize:10,opacity:0.6,marginTop:4}}>{today}</div>
      </div>
      {rows.map(r=>(
        <div key={r.label} style={{display:'flex',justifyContent:'space-between',alignItems:'center',background:'#fff',borderRadius:10,padding:'12px 16px',marginBottom:8,boxShadow:'0 1px 4px rgba(0,0,0,0.06)'}}>
          <span style={{fontSize:13,color:'#3a5a6a'}}>{r.label}</span>
          <span style={{fontSize:15,fontWeight:700,color:r.color}}>{currency(r.val)}</span>
        </div>
      ))}
      {data?.servicios!==undefined&&(
        <div style={{marginTop:14}}>
          <div style={{fontWeight:700,fontSize:13,color:'#1a2332',marginBottom:8}}>Desglose por tipo</div>
          <div style={{display:'flex',gap:10}}>
            <div style={{flex:1,background:'#eff6ff',borderRadius:10,padding:'12px 14px',textAlign:'center'}}>
              <div style={{fontSize:10,color:'#6b7280',marginBottom:4}}>Servicios</div>
              <div style={{fontSize:16,fontWeight:700,color:'#2563eb'}}>{currency(data.servicios)}</div>
            </div>
            <div style={{flex:1,background:'#f5f3ff',borderRadius:10,padding:'12px 14px',textAlign:'center'}}>
              <div style={{fontSize:10,color:'#6b7280',marginBottom:4}}>Productos</div>
              <div style={{fontSize:16,fontWeight:700,color:'#7c3aed'}}>{currency(data.productos)}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

// ─── MOBILE APP COMPONENT ─────────────────────────────────────────────────────
const MobileApp=({user,onLogout})=>{
  const[page,setPage]=useState("dashboard");
  const isSA=user.role==="Super Admin";
  const patients=_cache["patients"]||[];
  const mobileLinkPatient=()=>alert("Para vincular esta atención, abra el sistema en vista de escritorio y haga clic en el aviso desde Cortes.");
  // Todos los usuarios móviles ven las mismas secciones
  const mobileNav=[
    {id:"dashboard",label:"Rendimiento",icon:"chart"},
    {id:"cashbox",label:"Caja & Pagos",icon:"cash"},
    {id:"cashbox_summary",label:"Resumen Caja",icon:"trend"},
    ...(isSA?[{id:"reports",label:"Informe",icon:"file"},{id:"admin",label:"Panel",icon:"shield"},{id:"corte",label:"Corte",icon:"scissors"}]:[]),
  ];
  return(
    <div style={{display:"flex",flexDirection:"column",minHeight:"100vh",background:"#eef2f7",maxWidth:430,margin:"0 auto"}}>
      <div style={{background:"linear-gradient(135deg,#0f3a2a,#1a4a5a)",padding:"12px 16px",display:"flex",alignItems:"center",justifyContent:"space-between",position:"sticky",top:0,zIndex:100}}>
        <div style={{display:"flex",alignItems:"center",gap:10}}>
          <Logo size={32}/>
          <div>
            <div style={{fontSize:13,fontWeight:700,color:"#5dd4c6",fontFamily:"'Lora',serif"}}>PodoCLINIC</div>
            <div style={{fontSize:9,color:"rgba(255,255,255,0.4)",textTransform:"uppercase",letterSpacing:"0.08em"}}>v4.0 Mobile</div>
          </div>
        </div>
        <div style={{display:"flex",alignItems:"center",gap:8}}>
          <div style={{fontSize:11,color:"rgba(255,255,255,0.6)"}}>{user.name}</div>
          <button onClick={onLogout} style={{background:"rgba(224,80,80,0.2)",border:"1px solid rgba(224,80,80,0.4)",borderRadius:8,padding:"4px 10px",color:"#ff8888",fontSize:11,cursor:"pointer"}}>↪</button>
        </div>
      </div>
      <div style={{flex:1,overflow:"auto",padding:"16px 12px"}}>
        {page==="dashboard"&&<MobileVentasResumen user={user}/>}
        {page==="cashbox"&&<CashModule patients={patients} currentUser={user}/>}
        {page==="cashbox_summary"&&<CashboxSummaryMobile user={user}/>}
        {page==="reports"&&isSA&&<ReportsModule patients={patients} staffView={true}/>}
        {page==="admin"&&isSA&&<AdminPanel patients={patients} user={user}/>}
        {page==="corte"&&isSA&&<CorteModule patients={patients} currentUser={user} onLinkPatient={mobileLinkPatient}/>}
      </div>
      <div style={{background:"#fff",borderTop:"1px solid #e8edf2",display:"flex",position:"sticky",bottom:0,zIndex:100}}>
        {mobileNav.map(n=>{
          const active=page===n.id;
          return(
            <button key={n.id} onClick={()=>setPage(n.id)} style={{flex:1,padding:"10px 4px",border:"none",background:"transparent",display:"flex",flexDirection:"column",alignItems:"center",gap:3,cursor:"pointer",borderTop:active?"2px solid #4a9d8f":"2px solid transparent",transition:"all .15s"}}>
              <Icon name={n.icon} size={18} color={active?"#4a9d8f":"#8a9aaa"}/>
              <span style={{fontSize:9,fontWeight:active?700:400,color:active?"#4a9d8f":"#8a9aaa",fontFamily:"'Outfit',sans-serif"}}>{n.label}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
};

function App(){
  // ── Portal mode (QR access) ───────────────────────────────────────────────
  const isPortal=new URLSearchParams(window.location.search).get("portal")==="1";
  const isPortalEvolucion=new URLSearchParams(window.location.search).get("portal")==="evolucion";

  const[user,setUser]=useState(null);
  const[page,setPage]=useState("dashboard");
  const[patients,setPatients]=useState(_cache['patients']||[]);
  // Sync patients from reactive store — updates without page refresh
  useEffect(()=>{
    const unsub=_subscribe(SK.patients,(rows)=>{if(Array.isArray(rows))setPatients(rows);});
    const current=_cache['patients']||_cache[SK.patients];
    if(Array.isArray(current))setPatients(current);
    return unsub;
  },[]);
  const[showSupport,setShowSupport]=useState(false);
  const[showQR,setShowQR]=useState(false);
  const[cashArrival,setCashArrival]=useState(null);
  // Mobile detection
  const isMobile=window.innerWidth<=640||/Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
  // Client visit notification
  const[clientAlerts,setClientAlerts]=useState([]);
  useEffect(()=>{
    const pending=safeJson(localStorage.getItem('podo_client_visits'),[]);
    setClientAlerts(pending);
  },[]);
  const dismissAlert=(idx)=>{
    const newAlerts=clientAlerts.filter((_,i)=>i!==idx);
    setClientAlerts(newAlerts);
    localStorage.setItem('podo_client_visits',JSON.stringify(newAlerts));
  };
  const handlePreventaCreated=(order)=>{
    setCashArrival(order);
    sessionStorage.setItem('podo_open_cash_orders','1');
    setTimeout(()=>{
      setCashArrival(null);
      setPage('cashbox');
    },1300);
  };
  const handleLinkPatientFromAttendance=(att)=>{
    const splitName=(fullName)=>{
      const words=String(fullName||"").replace(/^Falta vincular paciente:.*/,"").trim().split(/\s+/).filter(Boolean);
      if(words.length<=1)return{firstName:words[0]||"",lastName:""};
      if(words.length===2)return{firstName:words[0],lastName:words[1]};
      if(words.length===3)return{firstName:words[0],lastName:words.slice(1).join(" ")};
      return{firstName:words.slice(0,2).join(" "),lastName:words.slice(2).join(" ")};
    };
    const rawName=att.patientName||att.patient_name||"";
    const names=splitName(rawName);
    const rawDni=String(att.patientDni||att.patient_dni||att.patientId||att.patient_id||"").trim();
    const dni=/^[0-9A-Za-z]{8}$/.test(rawDni)?rawDni:"";
    sessionStorage.setItem('podo_link_attendance',JSON.stringify(att));
    sessionStorage.setItem('podo_open_new_patient','1');
    sessionStorage.setItem('podo_new_patient_prefill',JSON.stringify({
      firstName:names.firstName,
      lastName:names.lastName,
      dni,
      notes:`Atención pendiente por vincular: ${att.time||""} ${att.service||""}`.trim()
    }));
    setPage('patients');
  };

  // Aceptar visita → navegar a nuevo paciente con datos prellenados
  // Enviar notificación WhatsApp al paciente
  const sendWhatsAppNotification=(phone,name,isNew)=>{
    if(!phone)return;
    // Limpiar número: solo dígitos, agregar código de país Perú (+51) si no lo tiene
    const clean=phone.replace(/[^0-9]/g,'');
    const intl=clean.startsWith('51')&&clean.length===11?clean:
                clean.startsWith('9')&&clean.length===9?'51'+clean:
                clean.length===9?'51'+clean:clean;
    const comp=_cache['company']||{name:'Podología Más Bela'};
    const clinicName=comp.name||'Podología Más Bela';
    const msg=isNew
      ?`Hola ${name} 👋, te escribimos de *${clinicName}*.

Hemos registrado tu visita. Para agilizar tu atención, por favor completa tu historia clínica cuando el personal te lo indique.

¡Gracias por visitarnos! 🦶`
      :`Hola ${name} 👋, te escribimos de *${clinicName}*.

Hemos confirmado tu llegada. Por favor acércate a la recepción, el personal te atenderá en breve.

¡Gracias por elegirnos! 🦶`;
    const url='https://wa.me/'+intl+'?text='+encodeURIComponent(msg);
    window.open(url,'_blank','noopener');
  };

  const acceptClientVisit=(alert,idx)=>{
    // Verificar si el paciente ya existe en BD
    const allPts=_cache['patients']||db.get(SK.patients)||[];
    const existing=allPts.find(p=>String(p.dni||'')===String(alert.dni||''));
    if(existing){
      // Paciente conocido → ir a su ficha
      setPage('patients');
      sessionStorage.setItem('podo_open_patient_id',String(existing.id));
    } else {
      // Paciente nuevo → abrir formulario prellenado
      sessionStorage.setItem('podo_new_patient_prefill',JSON.stringify({
        firstName: alert.name.split(' ')[0]||'',
        lastName:  alert.name.split(' ').slice(1).join(' ')||'',
        dni:       alert.dni||'',
        phone:     alert.phone||'',
      }));
      setPage('patients');
      sessionStorage.setItem('podo_open_new_patient','1');
    }
    // Notificar por WhatsApp si tiene celular
    if(alert.phone){
      sendWhatsAppNotification(alert.phone, alert.name.split(' ')[0]||alert.name, !existing);
    }
    dismissAlert(idx);
  };

  const[loading,setLoading]=useState(true);
  const[loadError,setLoadError]=useState('');
  const[licenseOk,setLicenseOk]=useState(false);
  const[licenseKey,setLicenseKey]=useState("");
  const[licenseError,setLicenseError]=useState("");
  // PHP: dataDir gestionado por MySQL

  const finishExpiredSession=useCallback(()=>{
    _authToken="";
    localStorage.removeItem('podo_token');
    Object.keys(_cache).filter(k=>k!=='pmb_module_perms'&&k!=='pmb_module_locked_off').forEach(k=>delete _cache[k]);
    setUser(null);
    setPatients([]);
    setPage("dashboard");
    setLoadError("La sesión expiró. Inicie sesión nuevamente.");
  },[]);
  const doLogout=useCallback(()=>{
    fetch(API_BASE+"/auth.php?action=logout",{method:"POST",headers:{"X-Auth-Token":_authToken}}).catch(()=>{});
    _authToken="";
    localStorage.removeItem('podo_token');
    Object.keys(localStorage).filter(k=>!['podo_worker_goals','pmb_module_perms','pmb_module_locked_off'].includes(k)).forEach(k=>localStorage.removeItem(k));
    Object.keys(_cache).forEach(k=>delete _cache[k]);
    setUser(null);
    setPatients([]);
    setPage("dashboard");
    setLoadError("");
  },[]);

  useEffect(()=>{
    const onExpired=()=>finishExpiredSession();
    window.addEventListener('podo-auth-expired',onExpired);
    return()=>window.removeEventListener('podo-auth-expired',onExpired);
  },[finishExpiredSession]);

  useEffect(()=>{
    // Check license and load all data from API
    const init=async()=>{
      const fetchWithTimeout=(url,opts={},ms=8000)=>{
        const ctrl=new AbortController();
        const id=setTimeout(()=>ctrl.abort(),ms);
        const heads={'Content-Type':'application/json',...(opts.headers||{})};
        if(_authToken) heads['X-Auth-Token']=_authToken;
        return fetch(url,{...opts,headers:heads,signal:ctrl.signal}).finally(()=>clearTimeout(id));
      };
      // Restore session from localStorage token
      _authToken=localStorage.getItem('podo_token')||'';
      // Limpiar cache de sesion anterior para evitar datos residuales
      Object.keys(_cache).filter(k=>k!=='pmb_module_perms'&&k!=='pmb_module_locked_off').forEach(k=>delete _cache[k]);
      try{
        // Check license
        const lr=await fetchWithTimeout(API_BASE+'/auth.php?action=license_verify&t='+Date.now());
        const ld=await lr.json();
        if(!ld.valid){setLicenseOk(false);setLoading(false);return}
        setLicenseOk(true);
        // PHP: carpeta gestionada por MySQL, no aplica
        // Load all data
        // PHP: cargar datos esenciales; el resto se carga lazy por módulo
        // Solo cargar datos si hay token activo (evita errores "No autenticado")
        // Cargar permisos de módulos (endpoint público, no necesita token)
        try{
          const mpResp=await fetch(API_BASE+'/special.php?action=module_perms');
          const mpData=await mpResp.json();
          if(mpData&&mpData.perms&&Object.keys(mpData.perms).length>0){
            _cache['pmb_module_perms']=mpData.perms;
            _cache[SK.modulePerms]=mpData.perms;
            if(mpData.lockedOff&&Object.keys(mpData.lockedOff).length>0){
              _cache['pmb_module_locked_off']=mpData.lockedOff;
              localStorage.setItem('pmb_module_locked_off',JSON.stringify(mpData.lockedOff));
            }
            localStorage.setItem('pmb_module_perms',JSON.stringify(mpData.perms));
          } else {
            // BD vacía o nueva — restaurar desde localStorage si hay algo guardado
            const lo=safeJson(localStorage.getItem('pmb_module_locked_off'),null);
            const lp=safeJson(localStorage.getItem('pmb_module_perms'),null);
            if(lo)_cache['pmb_module_locked_off']=lo;
            if(lp){_cache['pmb_module_perms']=lp;_cache[SK.modulePerms]=lp;}
          }
        }catch(e){
          // Servidor no disponible — restaurar desde localStorage
          const lo=safeJson(localStorage.getItem('pmb_module_locked_off'),null);
          const lp=safeJson(localStorage.getItem('pmb_module_perms'),null);
          if(lo)_cache['pmb_module_locked_off']=lo;
          if(lp){_cache['pmb_module_perms']=lp;_cache[SK.modulePerms]=lp;}
        }
        // Verificar sesión activa
        if(_authToken){
          try{
            const me=await apiFetch('/auth?action=me');
            if(me.ok&&me.user){
              const criticalKeys=['patients','appointments','users'];
              const optionalKeys=['company','inventory',
                                  'sales_products','sales_services','commission_scheme',
                                  'sales_orders','suppliers','photos','laboratory',
                                  'payments','memberships','cashbox_cuts'];
              try{
                await Promise.all([
                  ...criticalKeys.map(key=>api.get(key,{strict:true})),
                  api.get('services'),
                  api.get('categories'),
                  api.get('commission_scheme'),
                ]);
                const loadedPatients=_cache['patients'];
                setPatients(Array.isArray(loadedPatients)?loadedPatients:[]);
                setUser(me.user);
                setLoadError('');
                warmupKeys(optionalKeys);
              }catch(loadErr){
                console.error('Critical data load failed',loadErr);
                setLoadError(loadErr.message||'No se pudieron cargar los datos del servidor');
              }
            }
          }catch(authErr){finishExpiredSession();}
        }
        const s=_cache['patients'];if(Array.isArray(s))setPatients(s);else{setPatients([]);}
      }catch(e){
        console.error('Init error',e);
        // If connection failed entirely, show license screen so user knows backend is down
        setLicenseOk(false);
      }
      setLoading(false);

      // PHP: persistencia inmediata por operación, sin auto-save
    };
    init();
  },[]);

  const activateLicense=async()=>{
    if(!licenseKey.trim()){setLicenseError("Ingrese una clave de licencia");return}
    try{
      const r=await fetch(API_BASE+'/auth.php?action=license_activate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({key:licenseKey.trim()})});
      const d=await r.json();
      if(d.ok){setLicenseOk(true);setLicenseError("");window.location.reload()}
      else{setLicenseError(d.error||"Clave inválida")}
    }catch(e){setLicenseError("Error al conectar con el servidor")}
  };


  const savePatients=useCallback(p=>{
    if(typeof p==='function'){
      setPatients(prev=>{
        const newVal=p(prev);
        const safe=Array.isArray(newVal)?newVal:prev;
        _cache['patients']=safe;
        api.set('patients',safe);
        return safe;
      });
    } else {
      const safe=Array.isArray(p)?p:[];
      setPatients(safe);
      _cache['patients']=safe;
      api.set('patients',safe);
    }
  },[]);

  if(isPortalEvolucion)return <PortalEvolucion/>;
  if(isPortal)return <PatientPortal/>;

  if(loading)return(
    <div style={{minHeight:"100vh",background:"linear-gradient(135deg,#0f3a2a,#081828)",display:"flex",alignItems:"center",justifyContent:"center",flexDirection:"column",gap:16}}>
      <Logo size={72}/>
      <div style={{color:"#5dd4c6",fontSize:18,fontWeight:700,fontFamily:"'Lora',serif",fontStyle:"italic"}}>PodoCLINIC</div>
      <div style={{color:"rgba(255,255,255,0.4)",fontSize:13}}>Conectando con el servidor...</div>
      <div style={{width:48,height:48,border:"4px solid rgba(93,212,198,0.2)",borderTop:"4px solid #5dd4c6",borderRadius:"50%",animation:"spin 1s linear infinite"}}/>
      <style>{`@keyframes spin{to{transform:rotate(360deg)}}`}</style>
    </div>
  );

  if(!licenseOk)return(
    <div style={{minHeight:"100vh",background:"linear-gradient(135deg,#0f3a2a,#081828)",display:"flex",alignItems:"center",justifyContent:"center"}}>
      <div style={{background:"#fff",borderRadius:20,padding:"40px 48px",maxWidth:420,width:"90%",textAlign:"center",boxShadow:"0 24px 64px rgba(0,0,0,0.3)"}}>
        <Logo size={64}/>
        <div style={{fontFamily:"'Lora',serif",fontSize:22,fontWeight:600,color:"#0f3a2a",margin:"16px 0 4px"}}>PodoCLINIC</div>
        <div style={{fontSize:13,color:"#8a9aaa",marginBottom:24}}>Sistema de Gestión v4.0</div>
        <div style={{background:"#fff3cd",border:"1px solid #ffc107",borderRadius:10,padding:"12px 16px",marginBottom:20,fontSize:13,color:"#856404",textAlign:"left"}}>
          🔑 Se requiere una licencia válida para usar el sistema.<br/>Ingrese su clave de activación.<br/>
          <span style={{fontSize:11.5,color:"#a07000"}}>⚠️ Si el servidor no responde, asegúrese que el backend esté corriendo en el puerto 3737.</span>
        </div>
        <input value={licenseKey} onChange={e=>setLicenseKey(e.target.value.toUpperCase())} onKeyDown={e=>e.key==="Enter"&&activateLicense()} placeholder="XXXX-XXXX-XXXX-XXXX-XXXX" style={{width:"100%",padding:"10px 14px",border:"2px solid #d4dde5",borderRadius:10,fontSize:14,fontFamily:"monospace",letterSpacing:"0.08em",outline:"none",textAlign:"center",marginBottom:8}}/>
        {licenseError&&<div style={{color:"#e05050",fontSize:12.5,marginBottom:8}}>{licenseError}</div>}
        <button onClick={activateLicense} style={{width:"100%",padding:"11px",background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",border:"none",borderRadius:10,fontSize:14,fontWeight:700,cursor:"pointer",marginTop:4}}>Activar Licencia</button>
        <button onClick={()=>window.location.reload()} style={{width:"100%",padding:"9px",background:"#f0f4f8",color:"#5a7a8a",border:"none",borderRadius:10,fontSize:13,fontWeight:600,cursor:"pointer",marginTop:8}}>🔄 Reintentar Conexión</button>
        <div style={{marginTop:16,fontSize:11.5,color:"#8a9aaa"}}>Contacte a su proveedor si no tiene una clave</div>
      </div>
    </div>
  );
  if(!user)return <Login notice={loadError} onLogin={(u,tok,loadedPatients=[])=>{
    _authToken=tok;
    localStorage.setItem("podo_token",tok);
    db.set("pmb_current_user",u);
    const safePatients=Array.isArray(loadedPatients)?loadedPatients:[];
    _cache['patients']=safePatients;
    _cache[SK.patients]=safePatients;
    setPatients(safePatients);
    setUser(u);
    setPage("dashboard");
    setLoadError("");
  }}/>;

  // ── MODO MÓVIL: SuperAdmin en móvil O usuario "movil" en cualquier dispositivo
  const isMobileUser=user&&(user.username==='movil'||user.username==='mobile');
  if((isMobile&&user&&user.role==="Super Admin")||isMobileUser){
    return <MobileApp user={user} onLogout={doLogout}/>;
  }

  const _navSA=user?.role==="Super Admin";
  const _navAdminPrincipal=(
    String(user?.username||'').trim().toLowerCase()==='admin'||
    String(user?.name||'').trim().toLowerCase()==='admin principal'
  );
  const navGroups=[
    {group:null,items:[{id:"dashboard",label:"Inicio",icon:"chart",perm:"dashboard"}]},
    {group:"Gestión Gerencial",groupIcon:"🛡️",saOnly:true,items:[
      {id:"admin",label:"Panel Admin",icon:"shield",perm:"admin"},
      {id:"commissions",label:"Comisiones",icon:"percent",perm:"commissions"},
    ]},
    {group:"Gestión Clínica",groupIcon:"🦷",items:[
      {id:"patients",label:"Pacientes",icon:"users",perm:"patients"},
      {id:"photos",label:"Control de Fotos",icon:"camera",perm:"photos"},
      {id:"laboratory",label:"Laboratorio",icon:"flask",perm:"laboratory"},
    ]},
    {group:"Gestión Comercial",groupIcon:"🛍️",items:[
      {id:"ventas",label:"Ventas",icon:"shop",perm:"ventas"},
      {id:"cashbox",label:"Caja & Pagos",icon:"cash",perm:"cashbox"},
      {id:"corte",label:"Cortes",icon:"scissors",perm:"corte"},
    ]},
    {group:"Gestión Operacional",groupIcon:"📦",items:[
      {id:"suppliers",label:"Proveedores",icon:"truck",perm:"suppliers"},
      {id:"inventory",label:"Inventario",icon:"box",perm:"inventory"},
    ]},
    {group:"Gestión de Ventas",groupIcon:"📅",items:[
      {id:"appointments",label:"Agenda",icon:"calendar",perm:"appointments"},
      {id:"reminders",label:"Recordatorios",icon:"bell",perm:"reminders"},
      {id:"portal",label:"Portal de Citas",icon:"globe",perm:"portal"},
    ]},
    {group:"Gestión de Compras",groupIcon:"🧾",saOnly:true,adminPrincipal:true,items:[
      {id:"gastos_op",label:"Gastos Operativos",icon:"file",perm:"admin"},
      {id:"gastos_rep",label:"Gastos de Reposición",icon:"book",perm:"admin"},
    ]},
    {group:"Reportes de Gestión",groupIcon:"📊",saOnly:true,items:[
      {id:"reports",label:"Informe de Caja",icon:"trend",perm:"reports"},
      {id:"reports_staff",label:"Informe de Personal",icon:"users",perm:"reports"},
    ]},
    {group:"Herramientas",groupIcon:"🔧",items:[
      {id:"library2",label:"Biblioteca",icon:"book",perm:"library"},
      {id:"documents2",label:"Documentos",icon:"file",perm:"documents"},
    ]},
    {group:"Configuración",groupIcon:"⚙️",items:[
      {id:"config",label:"Configuración",icon:"settings",perm:"config"}
    ]},
  ];
  const canUseNavItem=(group,item)=>can(user,item.perm)||(_navAdminPrincipal&&group.adminPrincipal===true);
  const filteredGroups=navGroups
    .map(g=>({...g,items:g.items.filter(n=>canUseNavItem(g,n))}))
    .filter(g=>(!g.saOnly||_navSA||(_navAdminPrincipal&&g.adminPrincipal===true))&&g.items.length>0);
  const allNav=navGroups.flatMap(g=>g.items);
  const nav=allNav.filter(n=>can(user,n.perm));

  const roleColor={"Super Admin":"#7c3aed",Administrador:"#e05050",Podólogo:"#2563eb",Recepcionista:"#2ea87e"};
  const company=db.get(SK.company)||{name:"Podología Más Bela",logo:null};

  const canSeeClientAlerts=user&&(user.role==="Administrador"||user.role==="Recepcionista"||user.role==="Super Admin");

  return(
    <div style={{display:"flex",minHeight:"100vh",background:"#eef2f7"}}>
      {cashArrival&&(
        <div style={{position:"fixed",inset:0,zIndex:12000,background:"rgba(8,24,40,.68)",display:"flex",alignItems:"center",justifyContent:"center",backdropFilter:"blur(3px)"}}>
          <div style={{textAlign:"center",color:"#fff",animation:"cashBoxIn 1.25s ease forwards"}}>
            <div style={{fontSize:62,animation:"moneyDrop .75s cubic-bezier(.2,.8,.2,1) forwards"}}>💵</div>
            <div style={{fontSize:44,marginTop:-8}}>💰</div>
            <div style={{fontSize:22,fontWeight:900,marginTop:10}}>Importe enviado a Caja</div>
            <div style={{fontSize:30,fontWeight:900,color:"#5dd4c6",marginTop:4}}>{currency(cashArrival.total)}</div>
            <div style={{fontSize:12.5,opacity:.8,marginTop:5}}>{cashArrival.code} · Abriendo Caja & Pagos...</div>
          </div>
          <style>{`@keyframes moneyDrop{0%{opacity:0;transform:translateY(-90px) rotate(-12deg) scale(.7)}65%{opacity:1;transform:translateY(8px) rotate(5deg) scale(1.15)}100%{transform:translateY(24px) rotate(0) scale(.65);opacity:.15}}@keyframes cashBoxIn{0%{transform:scale(.92);opacity:0}20%,78%{transform:scale(1);opacity:1}100%{transform:scale(1.04);opacity:0}}`}</style>
        </div>
      )}
      {/* Cliente alerts — solo Admin/Recep/SuperAdmin */}
      {canSeeClientAlerts&&clientAlerts.length>0&&(
        <div style={{position:"fixed",bottom:20,right:20,zIndex:9999,display:"flex",flexDirection:"column",gap:8,maxWidth:320}}>
          {clientAlerts.map((alert,i)=>{
            const allPts=_cache['patients']||db.get(SK.patients)||[];
            const existing=allPts.find(p=>String(p.dni||'')===String(alert.dni||''));
            return(
            <div key={i} className="pop-in" style={{background:"#fff",border:"2px solid #4a9d8f",borderRadius:16,padding:"14px 16px",boxShadow:"0 8px 32px rgba(74,157,143,0.3)",maxWidth:340,width:340}}>
              {/* Header */}
              <div style={{display:"flex",alignItems:"flex-start",gap:10,marginBottom:10}}>
                <div style={{fontSize:24,flexShrink:0}}>🧑‍🦯</div>
                <div style={{flex:1}}>
                  <div style={{fontSize:12,fontWeight:800,color:"#0f3a2a",letterSpacing:"0.04em",textTransform:"uppercase",marginBottom:2}}>
                    Visita de Cliente
                  </div>
                  <div style={{fontSize:14,fontWeight:700,color:"#1a2332"}}>{alert.name}</div>
                  <div style={{fontSize:12,color:"#5a7a8a"}}>DNI: <strong>{alert.dni}</strong></div>
                  {alert.phone&&<div style={{fontSize:11.5,color:"#5a7a8a"}}>📱 {alert.phone}</div>}
                  <div style={{fontSize:10,color:"#8a9aaa",marginTop:2}}>{alert.time}</div>
                </div>
                <button onClick={()=>dismissAlert(i)}
                  style={{background:"none",border:"none",cursor:"pointer",fontSize:16,color:"#8a9aaa",padding:0,lineHeight:1,flexShrink:0}}>✕</button>
              </div>
              {/* Estado del paciente */}
              {existing?(
                <div style={{background:"#f0faf5",border:"1px solid #4a9d8f44",borderRadius:8,padding:"7px 10px",marginBottom:10,fontSize:11.5,color:"#1a6a4a"}}>
                  ✅ Paciente registrado — historia clínica existente
                </div>
              ):(
                <div style={{background:"#fff8e6",border:"1px solid #f5920044",borderRadius:8,padding:"7px 10px",marginBottom:10,fontSize:11.5,color:"#92620a"}}>
                  🆕 Paciente nuevo — sin historia clínica registrada
                </div>
              )}
              {/* Botones de acción */}
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:6,marginBottom:alert.phone?6:0}}>
                <button onClick={()=>acceptClientVisit(alert,i)}
                  style={{padding:"8px 4px",borderRadius:8,border:"none",cursor:"pointer",
                    background:existing?"linear-gradient(135deg,#4a9d8f,#2a7a6a)":"linear-gradient(135deg,#2563eb,#1a50c0)",
                    color:"#fff",fontWeight:700,fontSize:11.5,fontFamily:"'Outfit',sans-serif",
                    lineHeight:1.3,textAlign:"center"}}>
                  {existing?"📋 Ver Ficha":"📝 Llenar Historia"}
                </button>
                <button onClick={()=>dismissAlert(i)}
                  style={{padding:"8px 4px",borderRadius:8,border:"1px solid #d4dde5",cursor:"pointer",
                    background:"#f8fafc",color:"#5a7a8a",fontWeight:600,fontSize:11.5,
                    fontFamily:"'Outfit',sans-serif",lineHeight:1.3,textAlign:"center"}}>
                  ✓ Atendido
                </button>
              </div>
              {/* Botón WhatsApp — solo si tiene celular */}
              {alert.phone&&(
                <button onClick={()=>sendWhatsAppNotification(alert.phone,alert.name.split(' ')[0]||alert.name,!existing)}
                  style={{width:"100%",padding:"8px 4px",borderRadius:8,border:"none",cursor:"pointer",
                    background:"linear-gradient(135deg,#25d366,#128c7e)",
                    color:"#fff",fontWeight:700,fontSize:11.5,fontFamily:"'Outfit',sans-serif",
                    display:"flex",alignItems:"center",justifyContent:"center",gap:6}}>
                  <svg viewBox="0 0 24 24" width="14" height="14" fill="#fff"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
                  Notificar por WhatsApp
                </button>
              )}
            </div>
            );
          })}
        </div>
      )}
      <aside style={{width:230,background:"linear-gradient(180deg,#081828 0%,#0f3a2a 55%,#1a4a5a 100%)",display:"flex",flexDirection:"column",position:"fixed",height:"100vh",zIndex:100,overflowY:"auto"}}>
        <div style={{padding:"20px 16px 16px",borderBottom:"1px solid rgba(255,255,255,0.07)",textAlign:"center"}}>
          {company.logo
            ?<img src={company.logo} alt="logo" style={{width:68,height:68,borderRadius:"50%",objectFit:"cover",marginBottom:8,border:"2px solid #4a9d8f"}}/>
            :<Logo size={68} style={{marginBottom:8}}/>
          }
          <div style={{fontFamily:"'Lora',serif",fontSize:13.5,color:"#fff",fontWeight:500,lineHeight:1.3}}>{company.name||"Podología Más Bela"}</div>
          <div style={{fontSize:9,color:"rgba(255,255,255,0.3)",letterSpacing:"0.1em",textTransform:"uppercase",marginTop:3}}>Sistema v4.0 Web</div>
        </div>
        <nav style={{flex:1,padding:"10px 8px",overflowY:"auto"}}>
          {filteredGroups.map((g,gi)=>(
            <div key={gi}>
              {g.group&&(
                <div style={{padding:"10px 12px 4px",fontSize:9,fontWeight:700,color:"rgba(255,255,255,0.28)",textTransform:"uppercase",letterSpacing:"0.1em",display:"flex",alignItems:"center",gap:5}}>
                  <span style={{fontSize:10}}>{g.groupIcon}</span>{g.group}
                    {g.saOnly&&!g.adminPrincipal&&<span style={{background:"#7c3aed44",color:"#c4b5fd",borderRadius:3,padding:"1px 5px",fontSize:8,fontWeight:800,marginLeft:"auto"}}>SA</span>}
                </div>
              )}
              {g.items.map(n=>{
                const active=page===n.id||(n.id==="reports_staff"&&page==="reports");
                return(
                  <button key={n.id} onClick={()=>setPage(n.id==="reports_staff"?"reports":n.id==="library2"?"library":n.id==="documents2"?"documents":n.id)} style={{display:"flex",alignItems:"center",gap:9,width:"100%",padding:"8px 12px 8px 18px",borderRadius:10,border:"none",background:active?"rgba(93,212,198,0.15)":"transparent",color:active?"#5dd4c6":"rgba(255,255,255,0.52)",cursor:"pointer",fontSize:12,fontWeight:active?700:400,fontFamily:"'Outfit',sans-serif",marginBottom:1,transition:"all .15s",textAlign:"left"}} onMouseOver={e=>{if(!active)e.currentTarget.style.background="rgba(255,255,255,0.05)"}} onMouseOut={e=>{if(!active)e.currentTarget.style.background="transparent"}}>
                    <Icon name={n.icon} size={13}/>{n.label}
                    {active&&<div style={{marginLeft:"auto",width:5,height:5,borderRadius:"50%",background:"#5dd4c6"}}/>}
                  </button>
                );
              })}
              {gi<filteredGroups.length-1&&g.group&&<div style={{height:1,background:"rgba(255,255,255,0.05)",margin:"4px 8px"}}/>}
            </div>
          ))}
        </nav>
        <div style={{padding:"12px 14px",borderTop:"1px solid rgba(255,255,255,0.07)"}}>
          <div style={{display:"flex",alignItems:"center",gap:8,marginBottom:10}}>
            <div style={{width:32,height:32,borderRadius:"50%",background:`${roleColor[user.role]}33`,border:`1.5px solid ${roleColor[user.role]}66`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:13,fontWeight:700,color:roleColor[user.role],flexShrink:0}}>{user.name[0]}</div>
            <div>
              <div style={{fontSize:11,color:"rgba(255,255,255,0.4)"}}>{user.role}</div>
              <div style={{fontSize:12.5,color:"#fff",fontWeight:600,lineHeight:1.2}}>{user.name}</div>
            </div>
          </div>
          <button onClick={doLogout} style={{display:"flex",alignItems:"center",gap:6,background:"rgba(224,80,80,0.12)",border:"1px solid rgba(224,80,80,0.25)",borderRadius:8,padding:"6px 12px",color:"#ff8888",cursor:"pointer",fontSize:12,fontFamily:"'Outfit',sans-serif",width:"100%",justifyContent:"center",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="rgba(224,80,80,0.22)"} onMouseOut={e=>e.currentTarget.style.background="rgba(224,80,80,0.12)"}>
            <Icon name="logout" size={12}/>Cerrar Sesión
          </button>
        </div>
      </aside>
      <main style={{marginLeft:230,flex:1,maxWidth:"calc(100vw - 230px)",overflowX:"hidden",display:"flex",flexDirection:"column"}}>
        <div style={{background:"#fff",borderBottom:"1px solid #e8edf2",padding:"8px 24px",display:"flex",alignItems:"center",justifyContent:"flex-end",gap:8,position:"sticky",top:0,zIndex:50,flexShrink:0}}>
          <span style={{fontSize:12,color:"#8a9aaa",marginRight:"auto"}}>{new Date().toLocaleString("es-PE",{weekday:"short",day:"2-digit",month:"short",year:"numeric"})}</span>
          <button onClick={()=>setShowSupport(true)} title="Soporte técnico" style={{width:32,height:32,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:15,flexShrink:0,boxShadow:"0 2px 8px #4a9d8f44",transition:"transform .15s"}} onMouseOver={e=>e.currentTarget.style.transform="scale(1.1)"} onMouseOut={e=>e.currentTarget.style.transform="scale(1)"}>?</button>
          {showSupport&&<>
            <div style={{position:"fixed",inset:0,background:"rgba(0,0,0,0.35)",zIndex:9998}} onClick={()=>setShowSupport(false)}/>
            <div style={{position:"fixed",top:"50%",left:"50%",transform:"translate(-50%,-50%)",background:"#fff",borderRadius:18,padding:"32px 36px",boxShadow:"0 24px 64px rgba(0,0,0,0.22)",zIndex:9999,minWidth:360,textAlign:"center"}}>
              <div style={{width:64,height:64,borderRadius:"50%",background:"linear-gradient(135deg,#4a9d8f,#2a7a6a)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:28,margin:"0 auto 16px",boxShadow:"0 6px 20px #4a9d8f44"}}>🩺</div>
              <div style={{fontWeight:800,fontSize:18,color:"#1a2332",marginBottom:4}}>Soporte Técnico</div>
              <div style={{fontSize:12,color:"#8a9aaa",marginBottom:22}}>PodoCLINIC v4.0 Desktop</div>
              <div style={{background:"#f4f8fa",borderRadius:12,padding:"18px 20px",marginBottom:16,textAlign:"left"}}>
                <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:12}}>
                  <div style={{width:36,height:36,borderRadius:"50%",background:"#4a9d8f22",display:"flex",alignItems:"center",justifyContent:"center",fontSize:16,flexShrink:0}}>👨‍💻</div>
                  <div>
                    <div style={{fontSize:11,color:"#8a9aaa",textTransform:"uppercase",letterSpacing:".05em"}}>Desarrollado por</div>
                    <div style={{fontWeight:800,fontSize:14,color:"#1a2332"}}>CPC JOHNNY ROJAS PANDURO</div>
                  </div>
                </div>
                <div style={{display:"flex",alignItems:"center",gap:10,marginBottom:10}}>
                  <div style={{width:36,height:36,borderRadius:"50%",background:"#2563eb22",display:"flex",alignItems:"center",justifyContent:"center",fontSize:16,flexShrink:0}}>📧</div>
                  <div>
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Correo electrónico</div>
                    <a href="mailto:johwes04@gmail.com" style={{fontWeight:700,fontSize:13,color:"#2563eb",textDecoration:"none"}}>johwes04@gmail.com</a>
                  </div>
                </div>
                <div style={{display:"flex",alignItems:"center",gap:10}}>
                  <div style={{width:36,height:36,borderRadius:"50%",background:"#25d36622",display:"flex",alignItems:"center",justifyContent:"center",fontSize:16,flexShrink:0}}>📱</div>
                  <div>
                    <div style={{fontSize:11,color:"#8a9aaa"}}>Celular / WhatsApp</div>
                    <div style={{fontWeight:700,fontSize:13,color:"#1a2332"}}>986 634 330</div>
                  </div>
                </div>
              </div>
              <button onClick={()=>setShowSupport(false)} style={{padding:"9px 28px",borderRadius:10,background:"#4a9d8f",color:"#fff",border:"none",fontWeight:700,fontSize:13,cursor:"pointer",width:"100%"}}>Cerrar</button>
            </div>
          </>}
          <button onClick={async()=>{
            const btn=document.querySelector('[data-backup-btn]');
            if(btn){btn.textContent='⏳ Generando...';btn.disabled=true;}
            try{
              const resp=await apiFetch('/special?action=backup');
              const json=JSON.stringify(resp,null,2);
              const blob=new Blob([json],{type:'application/json'});
              const url=URL.createObjectURL(blob);
              const a=document.createElement('a');a.href=url;
              a.download='podoclinic_backup_'+new Date().toLocaleDateString('en-CA',{timeZone:'America/Lima'})+'.json';
              a.click();URL.revokeObjectURL(url);
            }catch(e){alert('Error al generar backup: '+e.message);}
            if(btn){btn.textContent='💾 Backup';btn.disabled=false;}
          }} data-backup-btn="1" style={{display:"flex",alignItems:"center",gap:5,background:"#f0f9f7",border:"1px solid #4a9d8f44",borderRadius:8,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700,color:"#2a7a6a",fontFamily:"'Outfit',sans-serif",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="#e0f2ee"} onMouseOut={e=>e.currentTarget.style.background="#f0f9f7"}>
            💾 Backup
          </button>
          <button onClick={()=>setShowQR(true)} style={{display:"flex",alignItems:"center",gap:5,background:"#f0f4ff",border:"1px solid #6366f144",borderRadius:8,padding:"5px 12px",cursor:"pointer",fontSize:12,fontWeight:700,color:"#4f46e5",fontFamily:"'Outfit',sans-serif",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="#e0e7ff"} onMouseOut={e=>e.currentTarget.style.background="#f0f4ff"} title="Portal QR de registro para pacientes">
            📲 QR Pacientes
          </button>
          {showQR&&<QRModal onClose={()=>setShowQR(false)}/>}
          <div style={{width:1,height:20,background:"#e8edf2"}}/>
          <div style={{display:"flex",alignItems:"center",gap:7,padding:"4px 8px"}}>
            <div style={{width:28,height:28,borderRadius:"50%",background:`${roleColor[user.role]}22`,border:`1.5px solid ${roleColor[user.role]}55`,display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:700,color:roleColor[user.role]}}>{user.name[0]}</div>
            <span style={{fontSize:12,fontWeight:600,color:"#1a2332"}}>{user.name}</span>
            <span style={{fontSize:10.5,color:"#8a9aaa"}}>· {user.role}</span>
          </div>
          <button onClick={doLogout} style={{display:"flex",alignItems:"center",gap:5,background:"rgba(224,80,80,0.08)",border:"1px solid rgba(224,80,80,0.25)",borderRadius:8,padding:"5px 12px",color:"#c03030",cursor:"pointer",fontSize:12,fontWeight:700,fontFamily:"'Outfit',sans-serif",transition:"background .15s"}} onMouseOver={e=>e.currentTarget.style.background="rgba(224,80,80,0.15)"} onMouseOut={e=>e.currentTarget.style.background="rgba(224,80,80,0.08)"}>
            ↪ Cerrar Sesión
          </button>
        </div>
        {loadError&&(
          <div style={{margin:"14px 24px 0",background:"#fff4e5",border:"1px solid #f59e0b",borderRadius:10,padding:"11px 14px",display:"flex",alignItems:"center",gap:12,color:"#8a4b08",fontSize:12.5}}>
            <strong style={{flex:1}}>No se pudieron cargar los datos: {loadError}</strong>
            <button onClick={()=>window.location.reload()} style={{border:"none",borderRadius:7,background:"#f59e0b",color:"#fff",padding:"6px 12px",fontWeight:700,cursor:"pointer"}}>Reintentar</button>
          </div>
        )}
        <div style={{padding:"22px 24px",flex:1}}>
        {page==="dashboard"&&<Dashboard patients={patients} user={user}/>}
        {page==="admin"&&can(user,"admin")&&<AdminPanel patients={patients} user={user}/>}
        {page==="patients"&&<PatientsModule patients={patients} setPatients={savePatients} currentUser={user}/>}
        {page==="appointments"&&<AgendaModule patients={patients} currentUser={user}/>}
        {page==="ventas"&&<VentasModule currentUser={user} onPreventaCreated={handlePreventaCreated}/>}
        {page==="suppliers"&&<SuppliersModule/>}
        {page==="cashbox"&&<CashModule patients={patients} currentUser={user}/>}
        {page==="laboratory"&&<LaboratoryModule patients={patients}/>}
        {page==="photos"&&<PhotosModule patients={patients}/>}
        {page==="inventory"&&<InventoryModule currentUser={user}/>}
        {page==="commissions"&&<CommissionsModule patients={patients} currentUser={user}/>}
        {page==="corte"&&<CorteModule patients={patients} currentUser={user} onLinkPatient={handleLinkPatientFromAttendance}/>}
        {page==="reminders"&&<RemindersModule patients={patients}/>}
        {page==="portal"&&<PortalModule patients={patients}/>}
        {(page==="library"||page==="library2")&&<LibraryModule/>}
        {(page==="documents"||page==="documents2")&&<DocumentsModule/>}
        {page==="gastos_op"&&<GastosOperativosModule currentUser={user}/>}
        {page==="gastos_rep"&&<GastosReposicionModule currentUser={user}/>}
        {(page==="reports"||page==="reports_staff")&&_navSA&&<ReportsModule patients={patients} staffView={page==="reports_staff"}/>}
        {page==="config"&&can(user,"config")&&<ConfigModule currentUser={user}/>}
        </div>
      </main>
    </div>
  );
}

// ─── ERROR BOUNDARY ───────────────────────────────────────────────────────────
class ErrorBoundary extends React.Component{
  constructor(props){super(props);this.state={hasError:false,error:null,info:null};}
  static getDerivedStateFromError(error){return{hasError:true,error};}
  componentDidCatch(error,info){this.setState({info});console.error("PodoCLINIC Error:",error,info);}
  render(){
    if(this.state.hasError){
      return(
        <div style={{minHeight:"100vh",background:"linear-gradient(135deg,#0f3a2a,#081828)",display:"flex",alignItems:"center",justifyContent:"center",padding:24}}>
          <div style={{background:"#fff",borderRadius:20,padding:"40px 48px",maxWidth:520,width:"100%",boxShadow:"0 24px 64px rgba(0,0,0,0.3)",textAlign:"center"}}>
            <div style={{fontSize:56,marginBottom:16}}>⚠️</div>
            <div style={{fontFamily:"'Lora',serif",fontSize:20,fontWeight:600,color:"#1a2332",marginBottom:8}}>Error en la Aplicación</div>
            <div style={{fontSize:13,color:"#8a9aaa",marginBottom:24}}>Se produjo un error inesperado. Por favor recargue la página.</div>
            <div style={{background:"#fff3cd",border:"1px solid #ffc107",borderRadius:10,padding:"12px 16px",marginBottom:24,fontSize:12,color:"#856404",textAlign:"left",fontFamily:"monospace",maxHeight:120,overflowY:"auto",wordBreak:"break-all"}}>
              {this.state.error&&String(this.state.error)}
            </div>
            <button onClick={()=>window.location.reload()} style={{padding:"11px 32px",background:"linear-gradient(135deg,#4a9d8f,#3a8d80)",color:"#fff",border:"none",borderRadius:10,fontSize:14,fontWeight:700,cursor:"pointer"}}>🔄 Recargar</button>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}

ReactDOM.createRoot(document.getElementById("root")).render(<ErrorBoundary><App/></ErrorBoundary>);
</script>
</body>
</html>
