/* Bernard Health SeniorCare V1.2.4 — personal y asistencia refinados */
(function(){
  'use strict';

  const SHIFT_NAMES=['Matutino','Vespertino','Nocturno'];
  const DIETS=['Corriente','Blanda','Blanda hiposódica','Hiposódica','Diabética','Renal','Cardioprotectora','Hipograsa','Hiperproteica','Líquidos claros','Líquidos completos','Licuada','Purés','Astringente','Sin gluten','Sin lactosa','Vegetariana'];
  const TEXTURES=['Normal','Suave / blanda','Picada fina','Triturada','Puré','Licuada','Líquida espesa tipo néctar','Líquida espesa tipo miel','Líquidos claros'];
  const OP_ROLES=['cook','cleaning','maintenance','security'];
  const ROLE_TEXT={cook:'Cocina',cleaning:'Limpieza',maintenance:'Mantenimiento',security:'Seguridad'};
  let selectedCareShift=localStorage.getItem('seniorcare-care-shift')||'Matutino';
  let medicalNotes=JSON.parse(localStorage.getItem('seniorcare-medical-notes')||'{}');
  let operationalTasks=JSON.parse(localStorage.getItem('seniorcare-operational-tasks')||'[]');
  let staffCodeLinks=JSON.parse(localStorage.getItem('seniorcare-staff-code-links')||'{}');

  function saveMedicalNotes(){localStorage.setItem('seniorcare-medical-notes',JSON.stringify(medicalNotes));}
  function saveOperationalTasks(){localStorage.setItem('seniorcare-operational-tasks',JSON.stringify(operationalTasks));}
  function saveStaffCodeLinks(){localStorage.setItem('seniorcare-staff-code-links',JSON.stringify(staffCodeLinks));}
  function e(v){return String(v??'').replace(/[&<>'"]/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#39;','"':'&quot;'}[m]));}
  function today(){return (window.BHSC_LOCAL_DATE?window.BHSC_LOCAL_DATE():new Intl.DateTimeFormat('en-CA',{timeZone:'America/Costa_Rica'}).format(new Date()));}
  function yesterday(){const d=new Date();d.setDate(d.getDate()-1);return window.BHSC_LOCAL_DATE?window.BHSC_LOCAL_DATE(d):new Intl.DateTimeFormat('en-CA',{timeZone:'America/Costa_Rica'}).format(d);}
  function timeLabel(value){return value?new Date(value).toLocaleTimeString('es-CR',{hour:'2-digit',minute:'2-digit'}):'No registrada';}
  function roleLabel(role){return ({admin:'Administración',nurse:'Enfermería',assistant:'Asistente',cook:'Cocina',cleaning:'Limpieza',maintenance:'Mantenimiento',security:'Seguridad'})[role]||role;}
  function staffRoleKey(role){const key=String(role||'').toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').trim();return ({'enfermera':'nurse','enfermeria':'nurse','asistente':'assistant','cocina':'cook','limpieza':'cleaning','mantenimiento':'maintenance','seguridad':'security'})[key]||null;}
  function selfAttendanceId(){return `user:${currentUser?.id||currentUser?.username||currentUser?.name||'usuario'}`;}
  function selfLog(date=today()){return attendanceLog.find(x=>String(x.staffId)===selfAttendanceId()&&x.date===date);}
  function ensureAdminStaff(){
    if(!currentUser)return;
    const exists=staffMembers.some(x=>x.linkedUserId===currentUser.id);
    if(!exists&&currentUser.role==='admin'){
      staffMembers.unshift({id:Date.now(),linkedUserId:currentUser.id,name:currentUser.name,role:'Administración',shift:'Horario administrativo',assignment:'Administración general',status:'Presente'});
      saveStaff();
    }
  }

  function normalizePersonName(value){return String(value||'').toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g,'').replace(/\s+/g,' ').trim();}
  function tryLinkStaffAccounts(){
    let changed=false;
    staffMembers.forEach(staff=>{
      if(staff.linkedUserId)return;
      const role=staffRoleKey(staff.role);
      if(!role)return;
      const match=users.find(u=>normalizePersonName(u.name)===normalizePersonName(staff.name)&&u.role===role);
      if(match){staff.linkedUserId=match.id;changed=true;const key=String(staff.id);if(staffCodeLinks[key]){staffCodeLinks[key].activated=true;staffCodeLinks[key].linkedUserId=match.id;}}
    });
    if(changed){saveStaff();saveStaffCodeLinks();}
  }
  function staffCodeInfo(staff){return staffCodeLinks[String(staff.id)]||null;}

  /* Dietas con catálogos orientativos */
  renderNutrition=function(){
    const role=currentUser?.role||'admin';
    if(!residentScoped || role==='cook'){
      main.innerHTML=pageHeader('NUTRICIÓN','Dietas de residentes','Indicaciones vigentes, texturas y cambios clínicos')+`
      <section class="nutrition-directory">${residents.map(r=>{const p=dietPlans[r.id]||{base:r.diet,current:r.diet,texture:'Normal',observations:'',changes:[]};return `<article class="nutrition-resident-card"><div><strong>${e(r.name)}</strong><span>${e(r.room)}</span></div><div class="diet-main"><b>${e(p.current||p.base||r.diet)}</b><small>Textura: ${e(p.texture||'Normal')}</small><small>${e(p.observations||'Sin observaciones especiales')}</small></div>${['admin','nurse'].includes(role)?`<button class="mini-btn" data-open-nutrition="${r.id}">Abrir plan</button>`:''}</article>`}).join('')}</section>`;
      return;
    }
    const r=selectedResident;
    const p=dietPlans[r.id]||{base:r.diet||'Corriente',current:r.diet||'Corriente',texture:'Normal',restrictions:'',allergies:r.allergy||'',observations:'',changes:[]};
    main.innerHTML=pageHeader('NUTRICIÓN INDIVIDUAL','Plan nutricional',`${r.name} · dieta, textura y observaciones`)+`
    <section class="form-card"><h3>Indicación nutricional base</h3><div class="form-grid">
      <label>Dieta<select id="dietBase">${DIETS.map(x=>`<option ${x===(p.base||r.diet)?'selected':''}>${x}</option>`).join('')}</select></label>
      <label>Textura<select id="dietTexture">${TEXTURES.map(x=>`<option ${x===(p.texture||'Normal')?'selected':''}>${x}</option>`).join('')}</select></label>
      <label>Restricciones<input id="dietRestrictions" value="${e(p.restrictions||'')}" placeholder="Ej. sin azúcar, baja en potasio"></label>
      <label>Alergias / intolerancias<input id="dietAllergies" value="${e(p.allergies||r.allergy||'')}" placeholder="Ej. lactosa, frutos secos"></label>
      <label class="wide">Observaciones para administración, cocina y enfermería<textarea id="dietObservations" rows="4" placeholder="Porciones, asistencia para comer, espesante, suplementos, horarios, vigilancia...">${e(p.observations||'')}</textarea></label>
    </div><div class="form-actions"><button class="primary-btn" id="saveDietPlan">Guardar plan nutricional</button></div></section>
    <section class="form-card"><h3>Cambio temporal por enfermería</h3><div class="form-grid">
      <label>Nueva dieta<select id="dietChangeValue">${DIETS.map(x=>`<option>${x}</option>`).join('')}</select></label>
      <label>Nueva textura<select id="dietChangeTexture">${TEXTURES.map(x=>`<option>${x}</option>`).join('')}</select></label>
      <label>Turno<select id="dietChangeShift">${SHIFT_NAMES.map(s=>`<option>${s}</option>`).join('')}</select></label>
      <label class="wide">Motivo / observación<textarea id="dietChangeReason" rows="3" required></textarea></label>
    </div><div class="form-actions"><button class="primary-btn" id="saveDietChange">Registrar cambio temporal</button></div></section>
    <section class="history-card"><h3>Historial de cambios</h3>${p.changes?.length?p.changes.map(c=>`<div class="history-line"><b>${e(c.value)} · ${e(c.texture||'Textura sin cambio')}</b><span>${e(c.shift)} · ${e(c.author)} · ${fmtDate(c.date)} · ${e(c.reason)}</span></div>`).join(''):empty('No hay cambios de dieta registrados.')}</section>`;
  };

  /* Notas médicas mensuales y PDF */
  function noteList(residentId){if(!medicalNotes[residentId])medicalNotes[residentId]=[];return medicalNotes[residentId];}
  window.renderMedicalNotes=function(){
    const r=selectedResident||residents[0];
    const notes=noteList(r.id).slice().sort((a,b)=>new Date(b.date)-new Date(a.date));
    main.innerHTML=pageHeader('SEGUIMIENTO MÉDICO','Notas médicas',`${r.name} · consultas mensuales y documentos PDF`)+`
    <section class="medical-note-help"><strong>Registro mensual</strong><p>Adjunte el PDF enviado por el médico y escriba un resumen breve. Ese resumen se incorporará automáticamente a la epicrisis y al cierre del expediente.</p></section>
    <form id="medicalNoteForm" class="form-card"><div class="form-grid">
      <label>Fecha de consulta<input type="date" name="date" value="${today()}" required></label>
      <label>Médico tratante<input name="doctor" placeholder="Nombre del médico" required></label>
      <label class="wide">Resumen clínico de la consulta<textarea name="summary" rows="5" placeholder="Diagnósticos, cambios de tratamiento, indicaciones y seguimiento" required></textarea></label>
      <label class="wide">Adjuntar PDF<input type="file" name="pdf" accept="application/pdf"></label>
    </div><div class="form-actions"><button class="primary-btn">Guardar nota médica</button></div></form>
    <section class="history-card"><h3>Historial médico por fecha</h3>${notes.length?notes.map(n=>`<article class="medical-note-card"><div><strong>${new Date(n.date+'T12:00:00').toLocaleDateString('es-CR')} · ${e(n.doctor)}</strong><span>${e(n.summary)}</span><small>${n.filename?`PDF: ${e(n.filename)}`:'Sin PDF adjunto'}</small></div><div class="card-actions">${n.pdfData?`<button class="mini-btn" data-medical-pdf="${n.id}">Abrir PDF</button>`:''}<button class="icon-delete" data-medical-delete="${n.id}">×</button></div></article>`).join(''):empty('No hay notas médicas registradas.')}</section>`;
  };

  /* Planes por turno, sin compartir indicaciones entre turnos */
  function careKeyFinal(id,shift){return `${id}:${shift}`;}
  function careTasksFinal(id,shift){const key=careKeyFinal(id,shift);if(!carePlans[key])carePlans[key]=defaultCareTasks.map((name,i)=>({id:Date.now()+i+Math.random(),name,done:false,shift,completedAt:null,completedBy:null,notes:''}));return carePlans[key];}
  renderCare=function(){
    const role=currentUser?.role||'admin';
    if(role==='admin'&&!residentScoped){
      const pending=residents.flatMap(r=>SHIFT_NAMES.flatMap(shift=>careTasksFinal(r.id,shift).filter(t=>!t.done).map(t=>({...t,resident:r,shift}))));
      const completed=residents.flatMap(r=>SHIFT_NAMES.flatMap(shift=>careTasksFinal(r.id,shift).filter(t=>t.done).map(t=>({...t,resident:r,shift}))));
      main.innerHTML=pageHeader('SEGUIMIENTO OPERATIVO','Cuidados pendientes','Revisión de ejecución; la programación se realiza desde cada residente')+`
      <section class="care-review-summary"><article><span>Pendientes</span><strong>${pending.length}</strong></article><article><span>Completados</span><strong>${completed.length}</strong></article><article><span>Residentes pendientes</span><strong>${new Set(pending.map(x=>x.resident.id)).size}</strong></article></section>
      <div class="care-review-list">${pending.length?pending.map(t=>`<article><div><strong>${e(t.resident.name)}</strong><span>${e(t.shift)} · ${e(t.name)}</span></div><span class="status warn">Pendiente</span><button class="mini-btn" data-open-care-resident="${t.resident.id}" data-care-shift-open="${t.shift}">Revisar</button></article>`).join(''):empty('Todos los cuidados programados están completados.')}</div>
      <section class="history-card"><h3>Cuidados ejecutados recientemente</h3>${completed.slice(0,20).map(t=>`<div class="history-line"><b>${e(t.resident.name)} · ${e(t.name)}</b><span>${e(t.shift)} · ${t.completedAt?fmtDate(t.completedAt):'Completado'} · ${e(t.completedBy||'Sin responsable')}</span></div>`).join('')||empty('No hay cuidados completados.')}</section>`;
      return;
    }
    const r=selectedResident||residents[0], tasks=careTasksFinal(r.id,selectedCareShift), done=tasks.filter(t=>t.done).length;
    main.innerHTML=pageHeader('CUIDADOS DIARIOS','Plan de cuidados',`${role==='admin'?'Programación':'Ejecución'} de ${r.name}`)+`
      <section class="care-resident-strip"><div><strong>${e(r.name)}</strong><span>${e(r.room)} · ${e(r.diet)}</span></div><span class="status ok">${done}/${tasks.length} completadas</span></section>
      <div class="care-controls">${role==='admin'?`<select id="careResidentSelect">${residents.map(x=>`<option value="${x.id}" ${x.id===r.id?'selected':''}>${e(x.name)}</option>`).join('')}</select>`:''}<select id="careShiftSelect">${SHIFT_NAMES.map(s=>`<option ${s===selectedCareShift?'selected':''}>${s}</option>`).join('')}</select>${role==='admin'?'<button class="secondary-btn" id="addCareTask">+ Añadir tarea</button>':''}<button class="primary-btn" id="saveCarePlan">Guardar plan</button></div>
      <p class="shift-isolation-note">Las indicaciones de este turno son independientes de los otros turnos.</p>
      <div class="care-task-grid">${tasks.map(t=>`<article class="care-task-item ${t.done?'done':''}"><label><input type="checkbox" data-final-care-check="${t.id}" ${t.done?'checked':''}><span>${e(t.name)}</span><small>${t.done?`Completada · ${t.completedAt?fmtDate(t.completedAt):''}`:'Pendiente de realizar'}</small></label>${role==='admin'?`<button class="icon-delete" data-final-care-delete="${t.id}">×</button>`:''}</article>`).join('')}</div>`;
  };

  /* Personal y asistencia: administrador solo consulta; cada usuario marca su propia jornada */
  renderStaff=function(){
    ensureAdminStaff();
    const t=today(), y=yesterday();
    const rows=staffMembers.map(m=>{
      const linked=m.linkedUserId?`user:${m.linkedUserId}`:String(m.id);
      const log=window.getAttendanceLogForStaff?window.getAttendanceLogForStaff(m,t):attendanceLog.find(x=>(String(x.staffId)===linked||String(x.staffId)===String(m.id))&&x.date===t);
      const ylog=window.getAttendanceLogForStaff?window.getAttendanceLogForStaff(m,y):attendanceLog.find(x=>(String(x.staffId)===linked||String(x.staffId)===String(m.id))&&x.date===y);
      return {m,log,ylog,roleKey:staffRoleKey(m.role)};
    });
    const entries=rows.filter(x=>x.log?.clockIn).length;
    const exits=rows.filter(x=>x.log?.clockOut).length;
    main.innerHTML=pageHeader('GESTIÓN DE PERSONAL','Personal y asistencia','Control de colaboradores, horarios, marcas y códigos de registro')+`
      <section class="staff-command-card">
        <div class="staff-command-copy">
          <span>CONTROL DE ASISTENCIA</span>
          <h3>Resumen diario del equipo</h3>
          <p>Consulte las entradas y salidas registradas. Desde cada ficha puede generar un código real para que el colaborador cree su acceso.</p>
        </div>
        <div class="staff-command-actions">
          <button class="primary-btn" id="showStaffForm">${svg.plus} Añadir personal</button>
          <button class="secondary-btn" id="exportAttendanceCsv">Excel / CSV</button>
          <button class="secondary-btn" id="printAttendance">Imprimir / PDF</button>
          <button class="secondary-btn" id="shareAttendance">Compartir</button>
        </div>
      </section>
      <section class="staff-kpi-grid">
        <article><span>COLABORADORES</span><strong>${staffMembers.length}</strong><small>Registrados</small></article>
        <article><span>ENTRADAS HOY</span><strong>${entries}</strong><small>Marcadas por el personal</small></article>
        <article><span>SALIDAS HOY</span><strong>${exits}</strong><small>Marcadas por el personal</small></article>
        <article><span>SIN MARCA</span><strong>${Math.max(0,staffMembers.length-entries)}</strong><small>Pendientes de entrada</small></article>
      </section>
      <form id="staffFormFinal" class="form-card hidden"><div class="form-grid"><label>Nombre completo<input name="name" required></label><label>Puesto<select name="role"><option>Enfermera</option><option>Asistente</option><option>Cuidador</option><option>Cocina</option><option>Limpieza</option><option>Mantenimiento</option><option>Seguridad</option><option>Administración</option></select></label><label>Horario<input name="shift" placeholder="06:00–14:00" required></label><label class="wide">Asignación principal<input name="assignment" placeholder="Área, habitaciones o responsabilidades"></label></div><div class="form-actions"><button type="button" class="secondary-btn" id="cancelStaffFinal">Cancelar</button><button class="primary-btn">Guardar colaborador</button></div></form>
      <section class="staff-directory-pro">${rows.map(({m,log,ylog,roleKey})=>{
        const info=staffCodeInfo(m);
        const linkedUser=m.linkedUserId?users.find(u=>u.id===m.linkedUserId):null;
        const activated=!!linkedUser||!!info?.activated;
        const accessText=!roleKey?'Este puesto no utiliza acceso individual.':activated?`Cuenta activada${linkedUser?.username?` · @${e(linkedUser.username)}`:''}. La recuperación de contraseña se realiza por correo.`:info?.code?`Código vigente: ${e(info.code)} · Vence ${fmtDate(info.expires)}`:'Genere un código para que complete su registro.';
        const action=!roleKey?'<span class="status neutral">No requiere código</span>':activated?'<span class="status ok">Cuenta activada</span>':`<button type="button" class="staff-code-btn" data-create-staff-code="${m.id}" data-role="${roleKey}">${info?.code?'Reenviar código':'Crear código'}</button>`;
        return `<article class="staff-profile-card" data-staff-id="${e(m.id)}" data-linked-user-id="${e(m.linkedUserId||'')}">
          <header>
            <div class="avatar">${e(m.name.split(' ').map(x=>x[0]).slice(0,2).join(''))}</div>
            <div class="staff-profile-title"><strong>${e(m.name)}</strong><span>${e(m.role)} · ${e(m.shift||'Sin horario')}</span></div>
            <span class="status ${log?.clockIn?'ok':'warn'}">${log?.clockIn?'Entrada registrada':'Sin entrada'}</span>
          </header>
          <div class="staff-time-grid">
            <div><span>ENTRADA HOY</span><strong>${timeLabel(log?.clockIn)}</strong></div>
            <div><span>SALIDA HOY</span><strong>${timeLabel(log?.clockOut)}</strong></div>
            <div><span>DÍA ANTERIOR</span><strong>${ylog?.clockIn||ylog?.clockOut?`${timeLabel(ylog.clockIn)} / ${timeLabel(ylog.clockOut)}`:'No registró marcas'}</strong></div>
          </div>
          <footer>
            <div><span>ACCESO AL SISTEMA</span><strong>${roleKey?roleLabel(roleKey):'Sin panel individual'}</strong><small>${accessText}</small></div>
            ${action}
          </footer>
        </article>`}).join('')}</section>
      <dialog id="staffCodeDialog" class="staff-code-dialog"></dialog>`;
  };


  /* Tareas para cocina, limpieza, mantenimiento y seguridad */
  window.renderOperationalTasks=function(){
    if(typeof window.renderOperationalTasksGlobal==='function'){window.renderOperationalTasksGlobal();return;}
    const role=currentUser?.role||'maintenance';
    const isAdmin=role==='admin';
    const list=operationalTasks.filter(t=>isAdmin||t.role===role);
    main.innerHTML=pageHeader('OPERACIÓN DEL HOGAR','Tareas operativas',isAdmin?'Asignaciones por puesto':'Tareas asignadas a su puesto')+`
      ${isAdmin?`<form id="operationalTaskForm" class="form-card"><div class="form-grid"><label>Puesto<select name="role"><option value="cook">Cocina</option><option value="cleaning">Limpieza</option><option value="maintenance">Mantenimiento</option><option value="security">Seguridad</option></select></label><label>Fecha límite<input type="datetime-local" name="due"></label><label class="wide">Tarea<input name="title" required></label><label class="wide">Detalle / precaución<textarea name="detail" rows="3"></textarea></label></div><div class="form-actions"><button class="primary-btn">Asignar tarea</button></div></form>`:''}
      <section class="operational-task-list">${list.length?list.map(t=>`<article class="operational-task-card ${t.done?'done':''}"><div><span>${e(ROLE_TEXT[t.role]||t.role)}</span><strong>${e(t.title)}</strong><small>${e(t.detail||'Sin detalle')} · ${t.due?fmtDate(t.due):'Sin fecha límite'}</small></div>${!isAdmin?`<button class="${t.done?'secondary-btn':'primary-btn'}" data-op-task-toggle="${t.id}">${t.done?'Reabrir':'Completar'}</button>`:`<span class="status ${t.done?'ok':'warn'}">${t.done?'Completada':'Pendiente'}</span>`}</article>`).join(''):empty('No hay tareas asignadas.')}</section>`;
  };

  function operationalHome(){
    if(typeof window.renderOperationalGlobalHome==='function'&&window.renderOperationalGlobalHome())return;
    const role=currentUser.role;
    const tasks=operationalTasks.filter(t=>t.role===role&&!t.done);
    main.innerHTML=`<section class="admin-welcome role-welcome"><div><span class="eyebrow">PANEL DE ${e(ROLE_TEXT[role].toUpperCase())}</span><h2>${greeting()}, ${e((currentUser.name||'').split(' ')[0])}</h2><p>Registre su jornada, revise tareas, alertas y reporte incidentes.</p></div><div class="admin-mark">${svg.check}</div></section>
    <section class="operational-metrics">${metric('check','mint','Tareas pendientes',tasks.length,'Asignadas por administración','operationalTasks')}${metric('bell','rose','Alertas',alertsData.filter(a=>a.status==='Nueva').length,'Requieren atención','alerts')}${metric('alert','amber','Incidentes',incidents.filter(i=>i.status!=='Resuelto').length,'Reportes abiertos','incidents')}</section>
    <section class="quick-section"><div class="quick-heading"><h2>Acciones del puesto</h2></div><div class="quick-grid">${quick('check','mint','Mis tareas','Revisar y completar','operationalTasks')}${role==='cook'?quick('food','amber','Dietas','Indicaciones de residentes','nutrition'):''}${quick('alert','rose','Reportar incidente','Registrar una novedad','incidents')}${quick('bell','blue','Alertas','Mensajes importantes','alerts')}</div></section>`;
  }

  function insertSelfClock(){
    document.querySelectorAll('.self-clock-card').forEach(x=>x.remove());
    if(!currentUser||currentUser.role==='supervisor'||OP_ROLES.includes(currentUser.role))return;
    const welcome=main.querySelector('.admin-welcome');if(!welcome)return;
    const log=selfLog();
    welcome.insertAdjacentHTML('afterend',`<section class="self-clock-card final-clock"><div><span>CONTROL DE ASISTENCIA</span><strong>${e(currentUser.name)}</strong><small>${log?.clockIn?`Entrada ${timeLabel(log.clockIn)}`:'Entrada no registrada'}${log?.clockOut?` · Salida ${timeLabel(log.clockOut)}`:''}</small></div><div class="self-clock-actions">${!log?.clockIn?'<button class="clock-btn clock-in" id="selfClockIn">Marcar entrada</button>':!log.clockOut?'<button class="clock-btn clock-out" id="selfClockOut">Marcar salida</button>':'<span class="status ok">Jornada cerrada</span>'}</div></section>`);
  }

  const previousRenderHome=renderHome;
  renderHome=function(){
    if(OP_ROLES.includes(currentUser?.role)) operationalHome(); else previousRenderHome();
    insertSelfClock();
  };

  const previousResidentDetail=renderResidentDetail;
  renderResidentDetail=function(){
    previousResidentDetail();
    const grid=main.querySelector('.module-grid');
    if(grid&&!grid.querySelector('[data-go="medicalNotes"]')) grid.insertAdjacentHTML('beforeend',residentModuleCard('report','blue','Notas médicas','Consultas mensuales y PDF','medicalNotes'));
  };

  const previousMore=renderMore;
  renderMore=function(){
    if(OP_ROLES.includes(currentUser?.role)){
      main.innerHTML=pageHeader('HERRAMIENTAS','Más','Funciones operativas del puesto')+`<div class="module-list"><button data-go="operationalTasks"><span class="quick-icon mint">${svg.check}</span><div><strong>Mis tareas</strong><small>Asignaciones del puesto</small></div><b>›</b></button><button data-go="incidents"><span class="quick-icon rose">${svg.alert}</span><div><strong>Incidentes</strong><small>Reportar una novedad</small></div><b>›</b></button></div>`;
      return;
    }
    previousMore();
    if(currentUser?.role==='admin'){
      const list=main.querySelector('.module-list,.more-grid');
      if(list&&!list.querySelector('[data-go="operationalTasks"]')) list.insertAdjacentHTML('beforeend',`<button class="module-card operational-admin-card" data-go="operationalTasks"><span class="quick-icon mint">${svg.check}</span><div><strong>Operación del hogar</strong><small>Cocina, limpieza, mantenimiento y seguridad</small></div><b>›</b></button>`);
    }
  };

  /* Reportes con notas médicas y epicrisis cronológica */
  function medicalChronology(r){return noteList(r.id).slice().sort((a,b)=>new Date(a.date)-new Date(b.date));}
  function getFacilityLabel(){return currentUser?.organizationName||localStorage.getItem('seniorcare-facility-name')||'Centro residencial';}
  function formatResidentDate(value){if(!value) return 'No registrada'; const d=new Date(value); return Number.isNaN(d.getTime())?e(value):d.toLocaleDateString('es-CR');}
  function buildMedicalReport(r,epicrisis=false){
    const notes=medicalChronology(r), last=getResidentVitals(r.id)[0], rm=meds.filter(m=>m.resident===r.name), ri=incidents.filter(i=>i.resident===r.name), rw=getResidentWounds(r.id), care=SHIFT_NAMES.flatMap(s=>careTasksFinal(r.id,s));
    const chronology=notes.length?notes.map(n=>`<li><strong>${new Date(n.date+'T12:00:00').toLocaleDateString('es-CR')}</strong> · ${e(n.doctor)}: ${e(n.summary)}</li>`).join(''):'<li>Sin consultas médicas mensuales registradas.</li>';
    if(!epicrisis)return `<h2>Resumen de notas médicas</h2><p><strong>Residente:</strong> ${e(r.name)}</p><ul>${chronology}</ul>`;
    const plan=dietPlans[r.id]||{};
    const admissionDate=formatResidentDate(r.admissionDate||r.entryDate||r.admittedAt);
    const dischargeDate=formatResidentDate(r.dischargeDate||r.exitDate||r.dischargedAt);
    const company='Bernard Health SeniorCare';
    const facility=getFacilityLabel();
    const patientSummary=`<div class="epicrisis-patient-strip"><article><span>Residente</span><strong>${e(r.name)}</strong></article><article><span>Habitación</span><strong>${e(r.room||'Sin asignar')}</strong></article><article><span>Edad</span><strong>${e(r.age||'--')} años</strong></article><article><span>Estado</span><strong>${e(r.status||'Sin dato')}</strong></article></div>`;
    return `
      <div class="epicrisis-doc">
        <header class="epicrisis-header">
          <div class="epicrisis-brand">
            <img src="assets/logo.png" alt="Logo Bernard Health SeniorCare">
            <div>
              <h2>${company}</h2>
              <p>${e(facility)}</p>
            </div>
          </div>
          <div class="epicrisis-title">
            <span>DOCUMENTO DE CIERRE CLÍNICO</span>
            <h1>Epicrisis / resumen de egreso</h1>
          </div>
          <div class="epicrisis-dates">
            <article><span>Fecha de ingreso</span><strong>${admissionDate}</strong></article>
            <article><span>Fecha de egreso</span><strong>${dischargeDate}</strong></article>
          </div>
        </header>
        ${patientSummary}
        <section><h3>Diagnósticos y antecedentes</h3><p><strong>Diagnósticos:</strong> ${e(r.dx||'Sin diagnósticos registrados')}</p><p><strong>Alergias:</strong> ${e(r.allergy||'Sin alergias registradas')}</p><p><strong>Dieta y textura:</strong> ${e((plan.current||r.diet||'No registrada'))} · ${e(plan.texture||'Normal')}</p></section>
        <section><h3>Consultas médicas por fecha</h3><ul>${chronology}</ul></section>
        <section><h3>Última condición clínica</h3><p>${last?`PA ${last.sys}/${last.dia}, FC ${last.hr}, temperatura ${last.temp} °C, SpO₂ ${last.spo2}%. ${e(last.obs||'')}`:'Sin signos vitales recientes.'}</p></section>
        <section><h3>Medicamentos vigentes</h3><p>${rm.length?rm.map(m=>`${e(m.drug)} · ${e(medicationScheduleLabel(m))}`).join('; '):'Sin medicamentos registrados.'}</p></section>
        <section><h3>Cuidados, curaciones e incidentes</h3><p>Cuidados completados: ${care.filter(x=>x.done).length}/${care.length||0}. Curaciones registradas: ${rw.length}. Incidentes: ${ri.length}.</p></section>
        <section><h3>Resumen cronológico del expediente</h3><p>Edite esta sección para integrar cambios clínicos, procedimientos, traslados, incidentes y respuesta al tratamiento.</p></section>
        <section><h3>Condición al egreso o cierre</h3><p>Edite la condición clínica final, destino, recomendaciones, pertenencias entregadas y comunicación con la familia.</p></section>
        <section><h3>Firma responsable</h3><p>Nombre: __________________________ Firma: __________________________ Fecha: __________</p></section>
      </div>`;
  }
  const previousReports=renderReports;
  renderReports=function(){
    const reports=[['Reporte diario del hogar','daily'],['Hoja de medicamentos','meds'],['Signos vitales','vitals'],['Cuidados diarios','care'],['Curaciones','wounds'],['Incidentes','incidents'],['Citas y traslados','appointments'],['Asistencia del personal','attendance'],['Epicrisis / resumen de egreso','epicrisis'],['Notas médicas mensuales','medical-summary']];
    main.innerHTML=pageHeader('DOCUMENTACIÓN Y CONTROL','Reportes','Informes autollenados, editables y exportables')+`
    <section class="report-help"><strong>¿Cómo funciona?</strong><p>Seleccione el residente y luego el reporte. El sistema lo llena con la información registrada y usted puede editarlo antes de imprimir o guardar en PDF.</p></section>
    <section class="report-resident-card">
      <div class="report-resident-copy"><span>RESIDENTE SELECCIONADO</span><strong>Elija el expediente para generar el reporte</strong><small>El formato se autocompleta con la información clínica y operativa del residente.</small></div>
      <label class="report-resident-select modern"><span>Residente</span><select id="reportResidentSelect">${residents.map(r=>`<option value="${r.id}" ${selectedResident?.id===r.id?'selected':''}>${e(r.name)}</option>`).join('')}</select></label>
    </section>
    <div class="report-grid report-grid-pro">${reports.map(([name,key],i)=>`<button type="button" ${key==='medical-summary'?'data-medical-summary-report':''} ${key!=='medical-summary'?`data-sc-report="${key}"`:''}><span class="quick-icon ${i%3===0?'lilac':i%3===1?'mint':'amber'}">${svg.report}</span><div><strong>${name}</strong><small>${key==='medical-summary'?'Resumen cronológico · editable · PDF':'Autollenado · editable · PDF'}</small></div><b>›</b></button>`).join('')}</div><section id="reportPreview" class="report-preview hidden"></section>`;
  };


  async function refreshAccessDirectory(){
    const client=window.seniorcareSupabase;
    if(!client||!currentUser?.organizationId)return;
    const [codesResult,profilesResult]=await Promise.all([
      client.from('activation_codes').select('id,code,role,expires_at,used_count,max_uses,active,created_at').eq('organization_id',currentUser.organizationId).order('created_at',{ascending:false}),
      client.from('profiles').select('id,full_name,username,role,active,last_seen_at').eq('organization_id',currentUser.organizationId).order('created_at',{ascending:false})
    ]);
    if(!codesResult.error) accessCodes=(codesResult.data||[]).map(c=>({id:c.id,code:c.code,role:c.role,expires:c.expires_at,used:Number(c.used_count)>=Number(c.max_uses),active:c.active}));
    if(!profilesResult.error) users=(profilesResult.data||[]).map(u=>({id:u.id,name:u.full_name,username:u.username||'',role:u.role==='administrator'?'admin':u.role,active:u.active,lastSeen:u.last_seen_at}));
    tryLinkStaffAccounts();
    if(activeScreen==='usersAccess'){renderUsersAccess();bindActions();}
  }

  renderUsersAccess=function(){
    if(currentUser?.role!=='admin'){main.innerHTML=pageHeader('ACCESO RESTRINGIDO','Sin autorización','Disponible únicamente para administración.');return;}
    const labels={nurse:'Enfermería',assistant:'Asistente',cook:'Cocina',cleaning:'Limpieza',maintenance:'Mantenimiento',security:'Seguridad',admin:'Administrador'};
    const activeCodes=accessCodes.filter(c=>c.active!==false&&!c.used&&new Date(c.expires)>new Date());
    const selectedRole=localStorage.getItem('seniorcare-access-role')||'nurse';
    const roleOptions=[['nurse','Enfermería'],['assistant','Asistente'],['cook','Cocina'],['cleaning','Limpieza'],['maintenance','Mantenimiento'],['security','Seguridad']];
    main.innerHTML=pageHeader('SEGURIDAD Y PERMISOS','Usuarios y accesos','Cree accesos reales para cada panel del hogar')+`
      <section class="access-summary"><article><span>Usuarios activos</span><strong>${users.filter(u=>u.active!==false).length}</strong></article><article><span>Códigos disponibles</span><strong>${activeCodes.length}</strong></article><article><span>Perfiles operativos</span><strong>6</strong></article></section>
      <section class="form-card access-generator access-generator-pro"><h3>Generar código de inscripción</h3><p>Seleccione el perfil. El código sirve únicamente para activar la cuenta una vez y vence en 7 días.</p><form id="realAccessCodeForm"><input type="hidden" name="role" id="accessRoleValue" value="${selectedRole}"><div class="access-role-grid">${roleOptions.map(([value,label])=>`<button type="button" class="access-role-card ${selectedRole===value?'active':''}" data-access-role="${value}"><strong>${label}</strong><small>Crear acceso para ${label.toLowerCase()}</small></button>`).join('')}</div><div class="access-generator-row"><div class="code-validity-note"><strong>Vigencia fija: 7 días</strong><span>Después de activar la cuenta, el código deja de ser necesario.</span></div><button class="primary-btn" type="submit">${svg.plus} Generar código</button></div></form><div id="generatedStaffCode" class="generated-staff-code hidden"></div></section>
      <section class="history-card"><h3>Códigos vigentes</h3><div class="access-code-list">${activeCodes.length?activeCodes.map(c=>`<article class="access-code-card"><div><span>${e(labels[c.role]||c.role)}</span><strong>${e(c.code)}</strong><small>Vence ${fmtDate(c.expires)}</small></div><div class="card-actions"><button class="mini-btn" data-copy-real-code="${e(c.code)}">Copiar</button><button class="icon-delete" data-revoke-real-code="${c.id}">×</button></div></article>`).join(''):empty('No hay códigos vigentes.')}</div></section>
      <section class="history-card"><h3>Usuarios registrados</h3><div class="user-access-list">${users.length?users.map(u=>`<article class="user-access-card"><div class="avatar">${e(u.name.split(' ').map(x=>x[0]).slice(0,2).join(''))}</div><div><strong>${e(u.name)}</strong><span>${e(labels[u.role]||u.role)} · @${e(u.username)}</span><small>${u.active===false?'Acceso desactivado':`Acceso activo${u.lastSeen?` · Último acceso ${fmtDate(u.lastSeen)}`:''}`}</small></div><span class="status ${u.active===false?'warn':'ok'}">${u.active===false?'Bloqueado':'Activo'}</span></article>`).join(''):empty('No hay usuarios registrados.')}</div></section>`;
    setTimeout(()=>refreshAccessDirectory(),0);
  };


  const previousBind=bindActions;
  bindActions=function(){
    previousBind();
    document.querySelectorAll('[data-access-role]').forEach(btn=>btn.addEventListener('click',()=>{document.querySelectorAll('[data-access-role]').forEach(x=>x.classList.remove('active'));btn.classList.add('active');document.getElementById('accessRoleValue').value=btn.dataset.accessRole;localStorage.setItem('seniorcare-access-role',btn.dataset.accessRole);}));
    document.getElementById('realAccessCodeForm')?.addEventListener('submit',async ev=>{ev.preventDefault();ev.stopImmediatePropagation();const fd=new FormData(ev.currentTarget),role=String(fd.get('role')),days=7;const btn=ev.currentTarget.querySelector('button');btn.disabled=true;btn.textContent='Generando...';const client=window.seniorcareSupabase;const {data,error}=window.BHSC_CALL_RPC?await window.BHSC_CALL_RPC(['bh_create_activation_code_v4325','bh_create_activation_code_v4321','administrator_create_staff_code'],{p_org_id:window.currentUser?.organizationId||window.currentUser?.organization_id,p_role:role,p_days:days}):await client.rpc('administrator_create_staff_code',{p_role:role,p_days:days});btn.disabled=false;btn.textContent='Generar código';if(error){showToast(error.message);return;}const row=Array.isArray(data)?data[0]:data,code=row?.code||row?.result?.code;if(!code){showToast('No se recibió el código.');return;}const expires=row?.expires_at||row?.result?.expires_at||new Date(Date.now()+days*86400000).toISOString();accessCodes.unshift({id:row?.id||row?.result?.id||Date.now(),code,role,expires,used:false,active:true});const box=document.getElementById('generatedStaffCode');box.classList.remove('hidden');box.innerHTML=`<span>Código creado</span><strong>${e(code)}</strong><small>Perfil: ${e(labels[role]||role)} · Vigencia: 7 días</small><button type="button" class="mini-btn" id="copyGeneratedStaffCode">Copiar</button>`;document.getElementById('copyGeneratedStaffCode').onclick=async()=>{await navigator.clipboard.writeText(code);showToast('Código copiado.');};setTimeout(()=>refreshAccessDirectory(),300);},true);
    document.querySelectorAll('[data-copy-real-code]').forEach(b=>b.addEventListener('click',async()=>{await navigator.clipboard.writeText(b.dataset.copyRealCode);showToast('Código copiado.');}));
    document.querySelectorAll('[data-revoke-real-code]').forEach(b=>b.addEventListener('click',async()=>{if(!confirm('¿Revocar este código?'))return;const {error}=window.BHSC_CALL_RPC?await window.BHSC_CALL_RPC(['bh_revoke_activation_code_v4321','administrator_revoke_staff_code'],{p_code_id:b.dataset.revokeRealCode}):await window.seniorcareSupabase.rpc('administrator_revoke_staff_code',{p_code_id:b.dataset.revokeRealCode});if(error){showToast(error.message);return;}await refreshAccessDirectory();showToast('Código revocado.');}));

    document.querySelectorAll('[data-open-nutrition]').forEach(b=>b.addEventListener('click',()=>{selectedResident=residents.find(r=>String(r?.resident_key??r?.id??'')===String(b.dataset.openNutrition)||String(r.id)===String(b.dataset.openNutrition))||selectedResident;residentScoped=true;renderNutrition();bindActions();}));
    document.getElementById('saveDietPlan')?.addEventListener('click',()=>{const p=dietPlans[selectedResident.id]||{changes:[]};p.base=document.getElementById('dietBase').value;p.current=p.current||p.base;p.texture=document.getElementById('dietTexture').value;p.restrictions=document.getElementById('dietRestrictions').value.trim();p.allergies=document.getElementById('dietAllergies').value.trim();p.observations=document.getElementById('dietObservations').value.trim();dietPlans[selectedResident.id]=p;selectedResident.diet=p.current||p.base;saveDietPlans();saveResidents();showToast('Plan nutricional guardado.');});
    document.getElementById('saveDietChange')?.addEventListener('click',()=>{const reason=document.getElementById('dietChangeReason').value.trim();if(!reason){showToast('Indique el motivo del cambio.');return;}const p=dietPlans[selectedResident.id]||{base:selectedResident.diet,changes:[]};p.current=document.getElementById('dietChangeValue').value;p.texture=document.getElementById('dietChangeTexture').value;p.changes=p.changes||[];p.changes.unshift({date:new Date().toISOString(),value:p.current,texture:p.texture,reason,shift:document.getElementById('dietChangeShift').value,author:currentUser?.name||'Enfermería'});dietPlans[selectedResident.id]=p;selectedResident.diet=p.current;saveDietPlans();saveResidents();renderNutrition();bindActions();showToast('Cambio de dieta registrado.');});

    document.getElementById('medicalNoteForm')?.addEventListener('submit',ev=>{ev.preventDefault();const fd=new FormData(ev.currentTarget),file=fd.get('pdf');const save=(pdfData='')=>{noteList(selectedResident.id).unshift({id:Date.now(),date:String(fd.get('date')),doctor:String(fd.get('doctor')).trim(),summary:String(fd.get('summary')).trim(),filename:file?.name||'',pdfData});saveMedicalNotes();renderMedicalNotes();bindActions();showToast('Nota médica guardada.');};if(file&&file.size){if(file.size>2500000){showToast('El PDF supera 2.5 MB. Comprímalo antes de subirlo.');return;}const reader=new FileReader();reader.onload=()=>save(String(reader.result));reader.onerror=()=>showToast('No se pudo leer el PDF.');reader.readAsDataURL(file);}else save();});
    document.querySelectorAll('[data-medical-pdf]').forEach(b=>b.addEventListener('click',()=>{const n=noteList(selectedResident.id).find(x=>x.id===Number(b.dataset.medicalPdf));if(n?.pdfData)window.open(n.pdfData,'_blank','noopener');}));
    document.querySelectorAll('[data-medical-delete]').forEach(b=>b.addEventListener('click',()=>{if(!confirm('¿Eliminar esta nota médica?'))return;medicalNotes[selectedResident.id]=noteList(selectedResident.id).filter(x=>x.id!==Number(b.dataset.medicalDelete));saveMedicalNotes();renderMedicalNotes();bindActions();}));

    document.getElementById('careShiftSelect')?.addEventListener('change',ev=>{ev.stopImmediatePropagation();selectedCareShift=ev.target.value;localStorage.setItem('seniorcare-care-shift',selectedCareShift);renderCare();bindActions();},true);
    document.getElementById('careResidentSelect')?.addEventListener('change',ev=>{selectedResident=residents.find(r=>String(r?.resident_key??r?.id??'')===String(ev.target.value)||String(r.id)===String(ev.target.value))||selectedResident;renderCare();bindActions();},true);
    document.querySelectorAll('[data-final-care-check]').forEach(b=>b.addEventListener('change',()=>{const task=careTasksFinal(selectedResident.id,selectedCareShift).find(x=>x.id===Number(b.dataset.finalCareCheck));if(task){task.done=b.checked;task.completedAt=b.checked?new Date().toISOString():null;task.completedBy=b.checked?currentUser.name:null;saveCarePlans();renderCare();bindActions();}}));
    document.querySelectorAll('[data-final-care-delete]').forEach(b=>b.addEventListener('click',()=>{const key=careKeyFinal(selectedResident.id,selectedCareShift);carePlans[key]=careTasksFinal(selectedResident.id,selectedCareShift).filter(x=>x.id!==Number(b.dataset.finalCareDelete));saveCarePlans();renderCare();bindActions();}));
    document.getElementById('addCareTask')?.addEventListener('click',()=>{const name=prompt(`Nueva tarea para turno ${selectedCareShift}:`);if(name?.trim()){careTasksFinal(selectedResident.id,selectedCareShift).push({id:Date.now(),name:name.trim(),done:false,shift:selectedCareShift});saveCarePlans();renderCare();bindActions();}});

    document.querySelectorAll('[data-reactivate-resident]').forEach(b=>b.addEventListener('click',async ev=>{ev.stopImmediatePropagation();const id=String(b.dataset.reactivateResident||'');if(typeof window.BHSC_REACTIVATE_INACTIVE_RESIDENT==='function'){await window.BHSC_REACTIVATE_INACTIVE_RESIDENT(id);return;}const itemKey=r=>String(r?.resident_key??r?.residentData?.resident_key??r?.residentData?.id??r?.id??'');const idx=inactiveResidents.findIndex(r=>itemKey(r)===id);if(idx<0)return;const item=inactiveResidents[idx];if(item.classification==='Fallecido'){showToast('Un expediente por fallecimiento no puede reactivarse.');return;}const stableKey=itemKey(item);const previousStatus=item.previousStatus&&item.previousStatus!=='Inactivo'?item.previousStatus:'Estable';const restored={...(item.residentData||item),id:item.residentData?.id??stableKey,resident_key:item.residentData?.resident_key??stableKey,status:previousStatus,inactiveClassification:'',inactiveReason:''};if(!residents.some(r=>String(r?.resident_key??r?.id??'')===stableKey))residents.push(restored);inactiveResidents.splice(idx,1);saveResidents();localStorage.setItem('seniorcare-inactive-residents',JSON.stringify(inactiveResidents));selectedResident=restored;residentScoped=false;showToast('Residente reactivado y expediente recuperado.');renderInactiveResidents();bindActions();},true));

    document.getElementById('showStaffForm')?.addEventListener('click',()=>document.getElementById('staffFormFinal')?.classList.remove('hidden'));
    document.getElementById('cancelStaffFinal')?.addEventListener('click',()=>document.getElementById('staffFormFinal')?.classList.add('hidden'));
    document.getElementById('staffFormFinal')?.addEventListener('submit',ev=>{ev.preventDefault();const fd=new FormData(ev.currentTarget);staffMembers.push({id:Date.now(),name:String(fd.get('name')).trim(),role:String(fd.get('role')),shift:String(fd.get('shift')).trim(),assignment:String(fd.get('assignment')).trim(),status:'Próximo'});saveStaff();renderStaff();bindActions();showToast('Colaborador agregado.');});
    document.querySelectorAll('[data-create-staff-code]').forEach(btn=>btn.addEventListener('click',()=>{
      const staff=staffMembers.find(x=>String(x.id)===String(btn.dataset.createStaffCode));
      if(!staff)return;
      const dialog=document.getElementById('staffCodeDialog');
      dialog.innerHTML=`<form method="dialog" class="staff-code-modal"><button class="dialog-close" value="cancel" aria-label="Cerrar">×</button><span class="eyebrow">ACCESO DE PERSONAL</span><h3>Crear código para ${e(staff.name)}</h3><p>Este código permitirá que el colaborador active su cuenta una sola vez. Vence automáticamente en 7 días.</p><div class="code-validity-note"><strong>Vigencia fija: 7 días</strong><span>No limita el acceso después de completar el registro.</span></div><div id="staffGeneratedCode" class="generated-code-panel hidden"></div><div class="form-actions"><button class="secondary-btn" value="cancel">Cancelar</button><button class="primary-btn" type="button" id="confirmStaffCode">Generar código</button></div></form>`;
      dialog.showModal();
      document.getElementById('confirmStaffCode').onclick=async()=>{
        const days=7;
        const action=document.getElementById('confirmStaffCode');
        action.disabled=true;action.textContent='Generando...';
        const {data,error}=window.BHSC_CALL_RPC?await window.BHSC_CALL_RPC(['bh_create_staff_code_v4375','bh_create_staff_code_v4325','bh_create_staff_code_v4321','administrator_create_staff_code_v433','administrator_create_staff_code_v3'],{p_staff_key:String(staff.id),p_role:btn.dataset.role,p_days:days}):await window.seniorcareSupabase.rpc('administrator_create_staff_code_v433',{p_staff_key:String(staff.id),p_role:btn.dataset.role,p_days:days});
        action.disabled=false;action.textContent='Generar código';
        if(error){showToast(error.message);return;}
        const row=Array.isArray(data)?data[0]:data,code=row?.code||row?.result?.code;
        if(!code){showToast('Supabase no devolvió el código.');return;}
        const expires=row?.expires_at||row?.result?.expires_at||new Date(Date.now()+days*86400000).toISOString();
        staffCodeLinks[String(staff.id)]={code,role:btn.dataset.role,expires,createdAt:new Date().toISOString(),activated:false};
        saveStaffCodeLinks();
        accessCodes.unshift({id:row?.id||row?.result?.id||Date.now(),code,role:btn.dataset.role,expires,used:false,active:true});
        const box=document.getElementById('staffGeneratedCode');
        box.classList.remove('hidden');
        box.innerHTML=`<span>CÓDIGO DE REGISTRO</span><strong>${e(code)}</strong><small>${e(staff.name)} · ${e(roleLabel(btn.dataset.role))} · Vigencia 7 días</small><button class="secondary-btn" type="button" id="copyStaffGeneratedCode">Copiar código</button><button class="primary-btn" type="button" id="closeStaffCodeAndRefresh">Listo</button>`;
        document.getElementById('copyStaffGeneratedCode').onclick=async()=>{await navigator.clipboard.writeText(code);showToast('Código copiado.');};
        document.getElementById('closeStaffCodeAndRefresh').onclick=()=>{dialog.close();renderStaff();bindActions();};
        action.remove();
        setTimeout(()=>refreshAccessDirectory(),300);
      };
    }));
    document.getElementById('selfClockIn')?.addEventListener('click',()=>{if(selfLog())return;attendanceLog.push({id:Date.now(),staffId:selfAttendanceId(),name:currentUser.name,role:roleLabel(currentUser.role),date:today(),clockIn:new Date().toISOString(),clockOut:null});saveAttendanceLog();renderHome();bindActions();showToast('Entrada registrada.');});
    document.getElementById('selfClockOut')?.addEventListener('click',()=>{const log=selfLog();if(!log||log.clockOut)return;log.clockOut=new Date().toISOString();saveAttendanceLog();renderHome();bindActions();showToast('Salida registrada.');});

    document.getElementById('operationalTaskForm')?.addEventListener('submit',ev=>{ev.preventDefault();const fd=new FormData(ev.currentTarget);operationalTasks.unshift({id:Date.now(),role:String(fd.get('role')),title:String(fd.get('title')).trim(),detail:String(fd.get('detail')).trim(),due:String(fd.get('due')),done:false,created:new Date().toISOString()});saveOperationalTasks();renderOperationalTasks();bindActions();showToast('Tarea asignada.');});
    document.querySelectorAll('[data-op-task-toggle]').forEach(b=>b.addEventListener('click',()=>{const task=operationalTasks.find(x=>x.id===Number(b.dataset.opTaskToggle));if(task){task.done=!task.done;task.completedAt=task.done?new Date().toISOString():null;saveOperationalTasks();renderOperationalTasks();bindActions();}}));

    document.querySelector('[data-medical-summary-report]')?.addEventListener('click',()=>{const value=String(document.getElementById('reportResidentSelect')?.value||'');const r=residents.find(x=>String(x?.resident_key??x?.id??'')===value||String(x.id)===value)||selectedResident;const box=document.getElementById('reportPreview');box.classList.remove('hidden');box.innerHTML=`<div class="report-preview-actions"><button class="secondary-btn" id="closeMedicalReport">Cerrar</button><button class="primary-btn" id="printMedicalReport">Imprimir / PDF</button></div><div class="report-editor" contenteditable="true" id="editableMedicalReport">${buildMedicalReport(r,false)}</div>`;box.scrollIntoView({behavior:'smooth'});document.getElementById('closeMedicalReport').onclick=()=>box.classList.add('hidden');document.getElementById('printMedicalReport').onclick=()=>{const w=window.open('','_blank');w.document.write(`<html><body>${document.getElementById('editableMedicalReport').innerHTML}<script>window.print()<\/script></body></html>`);w.document.close();};});
    document.querySelector('[data-sc-report="epicrisis"]')?.addEventListener('click',ev=>{ev.preventDefault();ev.stopImmediatePropagation();const value=String(document.getElementById('reportResidentSelect')?.value||'');const r=residents.find(x=>String(x?.resident_key??x?.id??'')===value||String(x.id)===value)||selectedResident;const box=document.getElementById('reportPreview');box.classList.remove('hidden');box.innerHTML=`<div class="report-preview-actions"><button class="secondary-btn" id="closeEpicrisisFinal">Cerrar</button><button class="primary-btn" id="printEpicrisisFinal">Imprimir / PDF</button></div><div class="report-editor" contenteditable="true" id="editableEpicrisisFinal">${buildMedicalReport(r,true)}</div>`;box.scrollIntoView({behavior:'smooth'});document.getElementById('closeEpicrisisFinal').onclick=()=>box.classList.add('hidden');document.getElementById('printEpicrisisFinal').onclick=()=>{const w=window.open('','_blank');w.document.write(`<html><body>${document.getElementById('editableEpicrisisFinal').innerHTML}<script>window.print()<\/script></body></html>`);w.document.close();};},true);
  };

  window.renderNutrition=renderNutrition;
  window.renderMedicalNotes=window.renderMedicalNotes;
  window.renderCare=renderCare;
  window.renderStaff=renderStaff;
  window.renderOperationalTasks=window.renderOperationalTasks;
  window.renderHome=renderHome;
  window.renderResidentDetail=renderResidentDetail;
  window.renderMore=renderMore;
  window.renderReports=renderReports;window.renderUsersAccess=renderUsersAccess;
  window.bindActions=bindActions;
})();
