'use strict';const $=s=>document.querySelector(s),$$=s=>[...document.querySelectorAll(s)];const ui={app:$('#app'),engine:$('#engineSummary'),hero:$('#heroTitle'),copy:$('#heroCopy'),master:$('#masterSwitch'),masterLabel:$('#masterLabel'),static:$('#staticRules'),tier:$('#coverageTier'),cosmetic:$('#cosmeticRules'),trusted:$('#trustedCount'),custom:$('#customCount'),version:$('#listVersion'),allowCount:$('#allowCount'),allow:$('#allowlist'),block:$('#blocklist'),form:$('#blockForm'),input:$('#blockInput'),diagnostics:$('#diagnosticGrid'),report:$('#buildReport'),reconcile:$('#reconcileButton'),update:$('#updateButton'),toast:$('#toast')};let state=null,timer=null;void init();
async function init(){bind();animate();await refresh();ui.app.setAttribute('aria-busy','false');}
function bind(){ui.master.addEventListener('click',()=>void mutate({type:'GRAX_SET_ENABLED',enabled:!state.settings.enabled},'Protection state updated.'));for(const t of $$('[data-setting]'))t.addEventListener('click',()=>void toggle(t.dataset.setting));ui.form.addEventListener('submit',e=>{e.preventDefault();void mutate({type:'GRAX_ADD_CUSTOM_BLOCK_DOMAIN',hostname:ui.input.value},'Custom block added.',()=>ui.input.value='');});ui.reconcile.addEventListener('click',()=>void mutate({type:'GRAX_FORCE_RECONCILE'},'Engine reconciled.'));ui.update.addEventListener('click',()=>void mutate({type:'GRAX_CHECK_LIST_UPDATES'},'List freshness check complete.'));addEventListener('hashchange',nav);observeSections();nav();}
async function refresh(){try{state=await send({type:'GRAX_GET_STATE'});render();}catch(e){notify(e.message,true);ui.engine.textContent='Engine unavailable';}}
async function mutate(message,text,after){busy(true);try{await send(message);after?.();await refresh();notify(text);}catch(e){notify(e.message,true);}finally{busy(false);}}
async function toggle(name){const current=['easylist','easyprivacy'].includes(name)?state.settings.lists[name]:state.settings[name],patch=['easylist','easyprivacy'].includes(name)?{lists:{[name]:!current}}:{[name]:!current};await mutate({type:'GRAX_UPDATE_SETTINGS',patch},'Protection layer updated.');}
async function send(message){const r=await chrome.runtime.sendMessage(message);if(!r?.ok)throw new Error(r?.error?.message||'Grax did not respond.');return r.result;}
function render(){const enabled=state.settings.enabled,c=state.runtime?.staticCoverage||state.diagnostics?.staticCoverage||{},cos=state.filterMetadata?.cosmetic||{};ui.master.setAttribute('aria-checked',String(enabled));ui.masterLabel.textContent=enabled?'Active':'Paused';ui.hero.textContent=enabled?'Protection active':'Protection paused';ui.copy.textContent=enabled?'Grax is filtering network requests and cleaning visual ad residue.':'Filtering is paused. Your site policies and preferences remain saved.';ui.engine.textContent=enabled?'Protected':'Paused';ui.static.textContent=compact(c.enabledRuleCount||0);ui.tier.textContent=`${title(c.tier||'unknown')} coverage · ${c.enabledRulesets?.length||state.runtime.enabledRulesets.length} rulesets`;ui.cosmetic.textContent=compact((cos.genericSelectors||0)+(cos.specificSelectors||0));ui.trusted.textContent=state.allowlist.length;ui.custom.textContent=state.customBlocklist.length;ui.allowCount.textContent=state.allowlist.length;ui.version.textContent=state.filterMetadata?.sources?.easylist?.version?`EasyList ${state.filterMetadata.sources.easylist.version}`:'Packaged lists';for(const name of['easylist','easyprivacy','cosmeticFiltering','showBadge','automaticUpdateChecks'])$(`[data-setting="${name}"]`)?.setAttribute('aria-checked',String(['easylist','easyprivacy'].includes(name)?state.settings.lists[name]:state.settings[name]));domains();diagnostics();}
function domains(){list(ui.allow,state.allowlist,'Enable',h=>void mutate({type:'GRAX_SET_SITE_ENABLED',hostname:h,enabled:true},`${h} is protected again.`));list(ui.block,state.customBlocklist,'Remove',h=>void mutate({type:'GRAX_REMOVE_CUSTOM_BLOCK_DOMAIN',hostname:h},`${h} removed.`));}
function list(container,items,action,handler){container.replaceChildren();if(!items.length){const p=document.createElement('p');p.className='empty';p.textContent='No domains configured.';container.append(p);return;}for(const h of items){const row=document.createElement('div');row.className='domain-item';const span=document.createElement('span');span.textContent=h;const b=document.createElement('button');b.type='button';b.textContent=action;b.addEventListener('click',()=>handler(h));row.append(span,b);container.append(row);}}
function diagnostics(){const c=state.runtime?.staticCoverage||{},d=state.runtime?.dynamicCoverage||{},data=[['Network architecture','Compressed dynamic DNR'],['Installed native rules',String(state.runtime.dynamicRuleCount)],['Coverage tier',title(c.tier||'unknown')],['Dynamic capacity',compact(d.limit||30000)],['Last reconciliation',relative(state.diagnostics.lastReconciledAt)],['Last update check',relative(state.diagnostics.lastUpdateCheckAt)]];ui.diagnostics.replaceChildren(...data.map(([k,v])=>{const row=document.createElement('div'),dt=document.createElement('dt'),dd=document.createElement('dd');dt.textContent=k;dd.textContent=v;row.append(dt,dd);return row;}));ui.report.textContent=JSON.stringify({generatedAt:state.filterMetadata?.generatedAt,sources:state.filterMetadata?.sources,cosmetic:state.filterMetadata?.cosmetic,networkCoverage:d},null,2);}
function busy(v){ui.app.setAttribute('aria-busy',String(v));for(const b of $$('button'))b.disabled=v;}function notify(t,e=false){clearTimeout(timer);ui.toast.textContent=t;ui.toast.classList.toggle('error',e);ui.toast.classList.add('show');timer=setTimeout(()=>ui.toast.classList.remove('show'),2600);}function nav(){const h=location.hash||'#overview';for(const a of $$('.nav'))a.classList.toggle('is-active',a.getAttribute('href')===h);}function observeSections(){if(!('IntersectionObserver'in globalThis))return;const observer=new IntersectionObserver(entries=>{const active=entries.filter(entry=>entry.isIntersecting).sort((a,b)=>b.intersectionRatio-a.intersectionRatio)[0];if(!active)return;for(const a of $$('.nav'))a.classList.toggle('is-active',a.getAttribute('href')===`#${active.target.id}`);},{root:$('.canvas-scroll'),rootMargin:'-18% 0px -62% 0px',threshold:[0,.1,.35,.6]});for(const section of $$('.workspace-section'))observer.observe(section);}function animate(){if(!globalThis.gsap||matchMedia('(prefers-reduced-motion: reduce)').matches)return;gsap.from('.sidebar',{x:-18,opacity:0,duration:.72,ease:'power3.out'});gsap.from('.canvas-header',{y:-12,opacity:0,duration:.68,ease:'power3.out'});gsap.from('.canvas-scroll > *',{y:18,opacity:0,duration:.62,stagger:.06,ease:'power3.out',delay:.1});}function compact(v){return new Intl.NumberFormat(undefined,{notation:'compact',maximumFractionDigits:1}).format(v);}function title(v){return String(v).replace(/\b\w/g,c=>c.toUpperCase());}function relative(v){if(!v)return'Never';const s=Math.round((new Date(v)-Date.now())/1000),a=Math.abs(s),[n,u]=a<60?[s,'second']:a<3600?[Math.round(s/60),'minute']:a<86400?[Math.round(s/3600),'hour']:[Math.round(s/86400),'day'];return new Intl.RelativeTimeFormat(undefined,{numeric:'auto'}).format(n,u);}
