/* Mahour Professional 2 — workflow layer; no data schema changes */
(function(){
 const q=s=>document.querySelector(s), esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
 function dashboard2(){const page=q('#page-dashboard');if(!page||q('#m2Hero'))return;const hero=document.createElement('div');hero.id='m2Hero';hero.className='m2-hero';hero.innerHTML='<div class="m2-welcome"><h3>مرکز کار امروز</h3><p>کارهای پرتکرار را بدون رفت‌وآمد بین صفحات انجام دهید. جستجوی سریع بیمار با <span class="m2-kbd">Ctrl + K</span> در تمام صفحات در دسترس است.</p><div id="m2DayStrip" class="m2-day-strip"></div></div><div class="m2-quick"><h3 style="margin-top:0">دسترسی سریع</h3><div class="m2-quick-actions"><button class="btn primary staff-only" onclick="startNewPatient()">پذیرش جدید</button><button class="btn secondary" onclick="showPage(\'patients\')">جستجوی بیمار</button><button class="btn secondary staff-only" onclick="showPage(\'treatment\')">سیکل درمان</button><button class="btn secondary" onclick="showPage(\'future\')">نوبت‌های آینده</button></div></div>';const head=page.querySelector('.page-head');head.insertAdjacentElement('afterend',hero)}
 function updateDashboard2(){const host=q('#m2DayStrip');if(!host||typeof db==='undefined')return;const today=localDate(),rows=db.appointments.filter(a=>a.date===today&&a.status!=='لغو شده'),present=rows.filter(a=>a.attendance==='present').length,pending=rows.filter(a=>(a.attendance||'pending')==='pending').length,next=rows.filter(a=>a.time>=new Date().toTimeString().slice(0,5)).sort((a,b)=>a.time.localeCompare(b.time))[0],free=Math.max(0,(Number(db.capacity)||0)*Math.max(1,Math.ceil(((parseInt(db.workEnd)||22)-(parseInt(db.workStart)||6))))-rows.filter(a=>a.visitType!=='initial').length);host.innerHTML='<div class="m2-mini ok"><small>حاضر امروز</small><b>'+fa(present)+'</b></div><div class="m2-mini '+(pending?'warn':'ok')+'"><small>نیازمند تعیین وضعیت</small><b>'+fa(pending)+'</b></div><div class="m2-mini"><small>نوبت بعدی</small><b>'+(next?esc(next.time):'—')+'</b></div><div class="m2-mini"><small>ظرفیت تقریبی آزاد</small><b>'+fa(free)+'</b></div>'}
 function searchUI(){if(q('#m2GlobalSearch'))return;const el=document.createElement('div');el.id='m2GlobalSearch';el.className='m2-global-search hidden';el.innerHTML='<div class="m2-search-card"><div class="m2-search-head"><input id="m2SearchInput" placeholder="نام بیمار، موبایل یا کد ملی..."><button class="btn secondary" id="m2SearchClose">بستن</button></div><div id="m2SearchResults" class="m2-results"></div></div>';document.body.appendChild(el);q('#m2SearchClose').onclick=closeSearch;q('#m2SearchInput').oninput=renderSearch;el.addEventListener('click',e=>{if(e.target===el)closeSearch()})}
 function openSearch(){q('#m2GlobalSearch').classList.remove('hidden');const i=q('#m2SearchInput');i.value='';renderSearch();setTimeout(()=>i.focus(),0)} function closeSearch(){q('#m2GlobalSearch')?.classList.add('hidden')}
 function renderSearch(){const host=q('#m2SearchResults'),term=q('#m2SearchInput').value.trim();if(typeof db==='undefined')return;const rows=db.patients.filter(p=>!p.archived&&(!term||(p.name+(p.phone||'')+(p.fileNo||'')).includes(term))).slice(0,12);host.innerHTML=rows.length?rows.map(p=>{const future=db.appointments.filter(a=>a.patientId===p.id&&a.date>=localDate()&&a.status!=='لغو شده').sort((a,b)=>(a.date+a.time).localeCompare(b.date+b.time))[0];return '<button class="m2-result" data-pid="'+p.id+'"><span><b>'+esc(p.name)+'</b><small>'+esc(p.phone||'—')+' · کد ملی '+esc(p.fileNo||'—')+'</small></span><small>'+(future?'نوبت بعدی '+esc(fmtDate(future.date))+' '+esc(future.time):'بدون نوبت آینده')+'</small></button>'}).join(''):'<div class="m2-empty">بیماری پیدا نشد.</div>';host.querySelectorAll('[data-pid]').forEach(b=>b.onclick=()=>{closeSearch();showPage('patients');openPatientPlan(Number(b.dataset.pid))})}
 function enhanceProfile(id){const modal=q('#patientPlanModal'),table=q('#patientPlanTable'),p=patient(id);if(!modal||!table||!p)return;modal.querySelector('#m2Profile')?.remove();const ap=db.appointments.filter(a=>a.patientId===id),treat=ap.filter(a=>a.visitType!=='initial'&&a.status!=='لغو شده'),done=treat.filter(a=>a.attendance==='present').length,future=treat.filter(a=>a.date>=localDate()&&a.status!=='لغو شده').sort((a,b)=>(a.date+a.time).localeCompare(b.date+b.time))[0],paid=ap.reduce((s,a)=>s+(Number(a.payment)||0)+(Number(a.prepaidAmount)||0),0);const box=document.createElement('div');box.id='m2Profile';box.className='m2-profile';box.innerHTML='<div><small>بیمار</small><b>'+esc(p.name)+'</b></div><div><small>جلسات انجام‌شده</small><b>'+fa(done)+' از '+fa(treat.length)+'</b></div><div><small>نوبت درمانی بعدی</small><b>'+(future?esc(fmtDate(future.date))+' · '+esc(future.time):'—')+'</b></div><div><small>پرداخت ثبت‌شده</small><b>'+fa(paid)+' تومان</b></div>';table.parentNode.insertBefore(box,table)}
 function init(){dashboard2();searchUI();const oldRender=window.renderDashboard;if(typeof oldRender==='function')window.renderDashboard=function(){oldRender();updateDashboard2()};const oldOpen=window.openPatientPlan;if(typeof oldOpen==='function')window.openPatientPlan=function(id){oldOpen(id);enhanceProfile(id)};document.addEventListener('keydown',e=>{if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='k'){e.preventDefault();openSearch()}if(e.key==='Escape'&&!q('#m2GlobalSearch').classList.contains('hidden'))closeSearch()});updateDashboard2()}
 if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();
})();

/* Professional 2 — Phase 2 */
(function(){
 const q=s=>document.querySelector(s), esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
 const money=n=>fa(Math.max(0,Number(n)||0))+' تومان';
 function addDays(iso,n){const d=new Date(iso+'T12:00:00');d.setDate(d.getDate()+n);return localDate(d)}
 function calendar2(){const page=q('#page-dashboard');if(!page||q('#m2WeekWrap'))return;const panel=page.querySelector('.panel');if(!panel)return;const wrap=document.createElement('div');wrap.id='m2WeekWrap';wrap.className='m2-section';wrap.innerHTML='<div class="m2-section-head"><div><h3>نمای هفتگی کلینیک</h3><small>تصویر سریع از تراکم نوبت‌ها و ساعت‌های روزهای آینده</small></div></div><div id="m2Week" class="m2-week"></div>';panel.parentNode.insertBefore(wrap,panel)}
 function renderWeek(){const host=q('#m2Week');if(!host||typeof db==='undefined')return;const today=localDate();host.innerHTML=Array.from({length:7},(_,i)=>{const date=addDays(today,i),rows=db.appointments.filter(a=>a.date===date&&a.status!=='لغو شده').sort((a,b)=>a.time.localeCompare(b.time)),items=rows.slice(0,4).map(a=>'<div class="m2-appt"><span>'+esc(a.time)+' '+esc((patient(a.patientId)||{}).name||'—')+'</span><span>'+esc(attendanceText(a.attendance||'pending'))+'</span></div>').join('');return '<div class="m2-day '+(i===0?'today':'')+'"><div class="m2-day-head"><b>'+esc(new Date(date+'T12:00:00').toLocaleDateString('fa-IR',{weekday:'long'}))+'</b><small>'+esc(new Date(date+'T12:00:00').toLocaleDateString('fa-IR',{month:'numeric',day:'numeric'}))+'</small></div><div class="m2-muted">'+fa(rows.length)+' نوبت</div>'+items+(rows.length>4?'<div class="m2-more">+'+fa(rows.length-4)+' نوبت دیگر</div>':'')+'</div>'}).join('')}
 function managerInsights(){const page=q('#page-revenue');if(!page||q('#m2ManagerInsights'))return;const cards=page.querySelector('.cards');if(!cards)return;const box=document.createElement('div');box.id='m2ManagerInsights';box.className='m2-insights';cards.insertAdjacentElement('afterend',box)}
 function renderInsights(){const host=q('#m2ManagerInsights');if(!host||typeof db==='undefined'||role!=='manager')return;const today=localDate(),month=today.slice(0,7),active=db.appointments.filter(a=>a.status!=='لغو شده'),monthRows=active.filter(a=>a.date.startsWith(month)),present=monthRows.filter(a=>a.attendance==='present'),absent=monthRows.filter(a=>a.attendance==='absent'),income=present.reduce((s,a)=>s+(Number(a.payment)||0)+(Number(a.prepaidAmount)||0),0),future=active.filter(a=>a.date>=today),pending=future.filter(a=>(a.attendance||'pending')==='pending').length,rate=(present.length+absent.length)?Math.round(present.length*100/(present.length+absent.length)):0;host.innerHTML='<div class="m2-insight ok"><small>درآمد ماه جاری</small><b>'+money(income)+'</b></div><div class="m2-insight"><small>نرخ حضور ماه</small><b>'+fa(rate)+'٪</b></div><div class="m2-insight warn"><small>غیبت ماه</small><b>'+fa(absent.length)+'</b></div><div class="m2-insight"><small>نوبت‌های آینده باز</small><b>'+fa(pending)+'</b></div>'}
 function p360(id){const modal=q('#patientPlanModal'),table=q('#patientPlanTable'),p=patient(id);if(!modal||!table||!p)return;modal.querySelector('#m2P360')?.remove();const all=db.appointments.filter(a=>a.patientId===id&&a.status!=='لغو شده').sort((a,b)=>(b.date+b.time).localeCompare(a.date+a.time)),treat=all.filter(a=>a.visitType!=='initial'),present=treat.filter(a=>a.attendance==='present'),absent=treat.filter(a=>a.attendance==='absent'),future=treat.filter(a=>a.date>=localDate()).sort((a,b)=>(a.date+a.time).localeCompare(b.date+b.time)),paid=all.reduce((s,a)=>s+(Number(a.payment)||0)+(Number(a.prepaidAmount)||0),0),expected=present.reduce((s,a)=>s+(Number(a.estimatedFee)||0),0),balance=Math.max(0,expected-paid);const box=document.createElement('div');box.id='m2P360';box.className='m2-p360';box.innerHTML='<div class="m2-p360-tabs"><button class="active" data-tab="summary">خلاصه</button><button data-tab="timeline">خط زمانی</button><button data-tab="finance">مالی</button></div><div id="m2P360Body" class="m2-p360-body"></div>';table.parentNode.insertBefore(box,table);const render=tab=>{box.querySelectorAll('[data-tab]').forEach(b=>b.classList.toggle('active',b.dataset.tab===tab));const body=box.querySelector('#m2P360Body');if(tab==='summary')body.innerHTML='<div class="m2-money"><div><small>جلسات انجام‌شده</small><b>'+fa(present.length)+'</b></div><div><small>غیبت</small><b>'+fa(absent.length)+'</b></div><div><small>جلسات آینده</small><b>'+fa(future.length)+'</b></div></div>'+(future[0]?'<div class="notice" style="margin-bottom:0">نوبت بعدی: '+esc(fmtDate(future[0].date))+' ساعت '+esc(future[0].time)+'</div>':'<div class="m2-empty-soft">نوبت درمانی آینده‌ای ثبت نشده است.</div>');else if(tab==='finance')body.innerHTML='<div class="m2-money"><div><small>پرداخت ثبت‌شده</small><b>'+money(paid)+'</b></div><div><small>تعرفه جلسات انجام‌شده</small><b>'+money(expected)+'</b></div><div><small>مانده تقریبی</small><b>'+money(balance)+'</b></div></div>';else{const rows=all.slice(0,20);body.innerHTML=rows.length?'<div class="m2-timeline">'+rows.map(a=>'<div class="m2-line"><small>'+esc(new Date(a.date+'T12:00:00').toLocaleDateString('fa-IR'))+' · '+esc(a.time)+'</small><span>جلسه '+fa(a.session||0)+' · '+esc(attendanceText(a.attendance||'pending'))+'</span><b class="'+(a.attendance==='present'?'good':a.attendance==='absent'?'bad':'')+'">'+money((Number(a.payment)||0)+(Number(a.prepaidAmount)||0))+'</b></div>').join('')+'</div>':'<div class="m2-empty-soft">سابقه‌ای وجود ندارد.</div>'}};box.querySelectorAll('[data-tab]').forEach(b=>b.onclick=()=>render(b.dataset.tab));render('summary')}
 function init2(){calendar2();managerInsights();renderWeek();renderInsights();const oldDash=window.renderDashboard;if(typeof oldDash==='function'&&!oldDash.__m2p2){const wrapped=function(){oldDash();renderWeek();renderInsights()};wrapped.__m2p2=true;window.renderDashboard=wrapped}const oldRev=window.renderRevenue;if(typeof oldRev==='function'&&!oldRev.__m2p2){const wrapped=function(){oldRev();renderInsights()};wrapped.__m2p2=true;window.renderRevenue=wrapped}const oldOpen=window.openPatientPlan;if(typeof oldOpen==='function'&&!oldOpen.__m2p2){const wrapped=function(id){oldOpen(id);p360(id)};wrapped.__m2p2=true;window.openPatientPlan=wrapped}}
 if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init2);else init2();
})();
