@wcag-checkr/ci 1.0.0-rc.77 → 1.0.0-rc.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{e as h,a as p,d as w,r as b}from"./service-worker.ts-Ggld571y.js";import{c as g,d as $}from"./crash-reporter-Dc5lvxvY.js";import"./preload-helper-D7HrI6pR.js";import"./diff-DIBMr3fQ.js";import"./forensic-log-VcNR3Xcq.js";import"./state-BIsozXtc.js";import"./ai-usage-log-Dj9Ub_DT.js";const d=g("parallel-tab-flow");async function S(r){const l=performance.now(),o=h(r.matrix),a=Math.max(1,Math.min(r.parallelism??4,8)),s=[];for(let t=0;t<a;t++)s.push([]);o.forEach((t,m)=>{s[m%a].push(t)}),d.info(`parallel-tab audit starting: ${o.length} states across ${a} tabs (~${Math.ceil(o.length/a)} states/tab)`);const e=s.map((t,m)=>t.length===0?Promise.resolve({results:[],failed:!1}):v(r.targetUrl,r.scope,t,m,r.cancel)),i=await Promise.all(e),n=[];let u=0,c=0;for(const t of i)t.failed?c++:u++,n.push(...t.results);return{results:n,parallelDurationMs:performance.now()-l,tabsCompleted:u,tabsFailed:c}}async function v(r,l,o,a,s){let e;const i=[];try{const n=await chrome.tabs.create({url:r,active:!1});if(!n.id)throw new Error("chrome.tabs.create returned no id");if(e=n.id,d.debug(`worker ${a}: opened tab ${e}`),await T(e),s.isCanceled())throw new Error("canceled");const u=await p(e,0);if(!u.ok)throw new Error(`content script unreachable: ${u.reason}`);for(let c=0;c<o.length&&!s.isCanceled();c++){const t=o[c];try{if(!(await w(e,t,l)).success){d.warn(`worker ${a} state ${c+1}/${o.length} drive failed`);continue}const f=await $(e,{type:"AUDIT_REQUEST",selector:l,currentState:t});f.success&&f.result&&i.push({...f.result,violations:f.result.violations})}catch(m){d.debug(`worker ${a} state ${c+1} error`,m)}}try{await b(e,l)}catch{}return{results:i,failed:!1}}catch(n){return d.warn(`worker ${a} failed`,n),{results:i,failed:!0}}finally{if(e!==void 0)try{await chrome.tabs.remove(e)}catch{}}}function T(r,l=3e4){return new Promise((o,a)=>{const s=setTimeout(()=>{chrome.tabs.onUpdated.removeListener(e),a(new Error(`tab ${r} load timed out after ${l}ms`))},l),e=(i,n)=>{i===r&&n.status==="complete"&&(clearTimeout(s),chrome.tabs.onUpdated.removeListener(e),o())};chrome.tabs.onUpdated.addListener(e),chrome.tabs.get(r).then(i=>{i.status==="complete"&&(clearTimeout(s),chrome.tabs.onUpdated.removeListener(e),o())})})}export{S as runParallelTabAudit};
1
+ import{e as h,a as p,d as w,r as b}from"./service-worker.ts-Do4QemTP.js";import{c as g,d as $}from"./crash-reporter-Dc5lvxvY.js";import"./preload-helper-D7HrI6pR.js";import"./diff-DIBMr3fQ.js";import"./forensic-log-VcNR3Xcq.js";import"./state-BIsozXtc.js";import"./ai-usage-log-Dj9Ub_DT.js";const d=g("parallel-tab-flow");async function S(r){const l=performance.now(),o=h(r.matrix),a=Math.max(1,Math.min(r.parallelism??4,8)),s=[];for(let t=0;t<a;t++)s.push([]);o.forEach((t,m)=>{s[m%a].push(t)}),d.info(`parallel-tab audit starting: ${o.length} states across ${a} tabs (~${Math.ceil(o.length/a)} states/tab)`);const e=s.map((t,m)=>t.length===0?Promise.resolve({results:[],failed:!1}):v(r.targetUrl,r.scope,t,m,r.cancel)),i=await Promise.all(e),n=[];let u=0,c=0;for(const t of i)t.failed?c++:u++,n.push(...t.results);return{results:n,parallelDurationMs:performance.now()-l,tabsCompleted:u,tabsFailed:c}}async function v(r,l,o,a,s){let e;const i=[];try{const n=await chrome.tabs.create({url:r,active:!1});if(!n.id)throw new Error("chrome.tabs.create returned no id");if(e=n.id,d.debug(`worker ${a}: opened tab ${e}`),await T(e),s.isCanceled())throw new Error("canceled");const u=await p(e,0);if(!u.ok)throw new Error(`content script unreachable: ${u.reason}`);for(let c=0;c<o.length&&!s.isCanceled();c++){const t=o[c];try{if(!(await w(e,t,l)).success){d.warn(`worker ${a} state ${c+1}/${o.length} drive failed`);continue}const f=await $(e,{type:"AUDIT_REQUEST",selector:l,currentState:t});f.success&&f.result&&i.push({...f.result,violations:f.result.violations})}catch(m){d.debug(`worker ${a} state ${c+1} error`,m)}}try{await b(e,l)}catch{}return{results:i,failed:!1}}catch(n){return d.warn(`worker ${a} failed`,n),{results:i,failed:!0}}finally{if(e!==void 0)try{await chrome.tabs.remove(e)}catch{}}}function T(r,l=3e4){return new Promise((o,a)=>{const s=setTimeout(()=>{chrome.tabs.onUpdated.removeListener(e),a(new Error(`tab ${r} load timed out after ${l}ms`))},l),e=(i,n)=>{i===r&&n.status==="complete"&&(clearTimeout(s),chrome.tabs.onUpdated.removeListener(e),o())};chrome.tabs.onUpdated.addListener(e),chrome.tabs.get(r).then(i=>{i.status==="complete"&&(clearTimeout(s),chrome.tabs.onUpdated.removeListener(e),o())})})}export{S as runParallelTabAudit};
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/parallel-tab-flow-B4su0Nob.js","assets/crash-reporter-Dc5lvxvY.js","assets/preload-helper-D7HrI6pR.js","assets/diff-DIBMr3fQ.js","assets/forensic-log-VcNR3Xcq.js","assets/state-BIsozXtc.js","assets/ai-usage-log-Dj9Ub_DT.js"])))=>i.map(i=>d[i]);
2
- import{_ as Ze}from"./preload-helper-D7HrI6pR.js";import{c as z,o as D,e as M,f as Mn,g as Un,d as q,b as re,i as Nn,h as Pn}from"./crash-reporter-Dc5lvxvY.js";import{m as Ue,d as Ln,T as Dn,a as bt,c as lt,i as Fn}from"./diff-DIBMr3fQ.js";import{x as Gn,y as Wn,p as wt,i as xe,o as le,A as Ee,F as Vn,z as Vt,O as jt,B as zt,R as jn,C as Ht,s as zn,D as Ce,E as Ie,G as Fe,H as Hn,g as Bn,I as qn,n as he,m as Bt,a as Ge,J as Kn,K as Yn}from"./forensic-log-VcNR3Xcq.js";import{s as Me,T as vt,b as et,i as Jn}from"./state-BIsozXtc.js";import{m as ke,D as Xn,s as Qn,h as Zn,b as ea,g as ta,d as na,e as aa}from"./ai-usage-log-Dj9Ub_DT.js";const oa=z("chrome-api"),sa="1.3";class ra{constructor(t){this.target=t}async attach(){await chrome.debugger.attach(this.target,sa)}async detach(){try{await chrome.debugger.detach(this.target)}catch(t){oa.debug("detach soft-failure",t)}}async send(t,n){return chrome.debugger.sendCommand(this.target,t,n)}}function ia(e){const t=e instanceof Error?e.message:String(e);return/Another debugger is already attached|Cannot attach to/i.test(t)}function ca(e){const t=e instanceof Error?e.message:String(e);return ia(e)?Ue("DEBUGGER_BUSY","DevTools is open on this tab. Close it to run the audit.",!0,{raw:t}):Ue("STATE_DRIVE_FAILED",t,!1)}function la(e){const t=(n,o)=>e(n,o);return chrome.debugger.onDetach.addListener(t),()=>chrome.debugger.onDetach.removeListener(t)}const J=z("state-driver"),da=60*1e3,ne=new Map,Ne=new Map,me=new Map,fe=new Map,$e=new Map,ua={default:[],hover:["hover"],focus:["focus"],"focus-visible":["focus","focus-visible"],active:["active"],disabled:[]};async function qt(e){let t=ne.get(e);if(!t){t=new ra({tabId:e});try{await t.attach(),await t.send("Runtime.enable"),await t.send("Page.enable"),await t.send("DOM.enable"),await t.send("DOM.getDocument",{depth:-1,pierce:!0}),await t.send("CSS.enable")}catch(n){try{await t.detach()}catch{}throw n}ne.set(e,t),me.set(e,new Map),pa(e),J.info("attached",{tabId:e})}return fa(e),t}function pa(e){const t=(n,o,s)=>{var c,r;if(n.tabId!==e)return;const i=me.get(e);if(i)if(o==="Runtime.executionContextCreated"){const d=s,l=d==null?void 0:d.context;l&&((c=l.auxData)!=null&&c.isDefault)&&((r=l.auxData)!=null&&r.frameId)&&i.set(l.auxData.frameId,l.id)}else if(o==="Runtime.executionContextDestroyed"){const d=s,l=d==null?void 0:d.executionContextId;if(l!==void 0)for(const[p,h]of i.entries())h===l&&i.delete(p)}else o==="Runtime.executionContextsCleared"&&i.clear()};chrome.debugger.onEvent.addListener(t)}async function ha(e){const t=ne.get(e);if(ne.delete(e),me.delete(e),fe.delete(e),$e.delete(e),t)try{await t.detach()}catch{}}function fa(e){const t=Ne.get(e);t&&clearTimeout(t),Ne.set(e,setTimeout(()=>{dt(e).catch(n=>J.warn("idle detach failed",n))},da))}async function dt(e){const t=ne.get(e);t&&(await t.detach(),ne.delete(e)),me.delete(e),fe.delete(e),$e.delete(e);const n=Ne.get(e);n&&(clearTimeout(n),Ne.delete(e))}function Kt(e){const t=[{id:e.frame.id,url:e.frame.url}];for(const n of e.childFrames??[])t.push(...Kt(n));return t}async function ga(e,t,n){var i;if(!n||n===0)return;const o=me.get(t);if(!o)return;let s;try{s=(i=(await chrome.scripting.executeScript({target:{tabId:t,frameIds:[n]},func:()=>location.href}))[0])==null?void 0:i.result}catch(c){J.debug("frame URL lookup failed",c)}try{const c=await e.send("Page.getFrameTree"),r=Kt(c.frameTree);if(s){const p=r.find(h=>h.url===s);if(p){const h=o.get(p.id);if(h!==void 0)return h}}const d=c.frameTree.frame.id,l=r.find(p=>p.id!==d);return l?o.get(l.id):void 0}catch(c){J.warn("Page.getFrameTree failed",c);return}}async function ma(e,t,n){var c;const o={expression:`document.querySelector(${JSON.stringify(t)})`,objectGroup:"wcag-auditor",returnByValue:!1};n!==void 0&&(o.contextId=n);const i=(c=(await e.send("Runtime.evaluate",o)).result)==null?void 0:c.objectId;if(!i)return null;try{return(await e.send("DOM.requestNode",{objectId:i})).nodeId??null}finally{e.send("Runtime.releaseObject",{objectId:i}).catch(()=>{})}}async function Yt(e){const t=fe.get(e);if(!t)return;const n=ne.get(e);if(n){try{await n.send("CSS.forcePseudoState",{nodeId:t.nodeId,forcedPseudoClasses:[]})}catch(o){J.debug("forcePseudoState clear failed (node may be gone)",o)}fe.delete(e)}}async function tt(e,t,n,o){await chrome.scripting.executeScript({target:ut(e,t),func:(s,i)=>{const c=document.querySelector(s);c&&(i?c.setAttribute("disabled",""):c.removeAttribute("disabled"))},args:[n,o]})}async function Jt(e,t){await chrome.scripting.executeScript({target:ut(e,t),func:()=>{const n=document.activeElement;n&&typeof n.blur=="function"&&n.blur()}})}async function Xt(e,t){await chrome.scripting.executeScript({target:{tabId:e,frameIds:[0]},func:n=>{document.documentElement.setAttribute("dir",n)},args:[t]})}async function ya(e,t,n,o){await chrome.scripting.executeScript({target:ut(e,t),func:(s,i)=>{const c=document.querySelector(s);if(c)for(const[r,d]of Object.entries(i))c.setAttribute(r,d)},args:[n,o]})}function ut(e,t){return t!==void 0&&t!==0?{tabId:e,frameIds:[t]}:{tabId:e}}async function ba(e,t,n,o){const s=await qt(e),i=$e.get(e),c=(i==null?void 0:i.scope)===n&&(i==null?void 0:i.frameId)===o,r=t.ariaVariation?JSON.stringify(t.ariaVariation.attributes):"",d=!c||(i==null?void 0:i.pseudoState)!==t.pseudoState,l=!i||i.theme!==t.theme,p=!i||i.direction!==t.direction,h=!i||i.breakpointId!==t.breakpoint.id,f=!c||(i==null?void 0:i.ariaVariationKey)!==r;if(d&&(await Yt(e),n)){t.pseudoState==="disabled"?await tt(e,o,n,!0):(await tt(e,o,n,!1),await Jt(e,o));const a=ua[t.pseudoState];if(a.length>0){const g=await ga(s,e,o),u=await ma(s,n,g);if(u!==null)try{await s.send("CSS.forcePseudoState",{nodeId:u,forcedPseudoClasses:a}),fe.set(e,{sessionTabId:e,nodeId:u})}catch(w){J.warn(`CSS.forcePseudoState failed for :${t.pseudoState}`,w)}else J.debug(`could not resolve nodeId for ${n} (frameId=${o})`)}}if(l){const a=[{name:"prefers-reduced-motion",value:"reduce"}];t.theme==="dark"?(a.push({name:"prefers-color-scheme",value:"dark"}),a.push({name:"forced-colors",value:"none"})):t.theme==="light"?(a.push({name:"prefers-color-scheme",value:"light"}),a.push({name:"forced-colors",value:"none"})):t.theme==="forced-colors-active"?a.push({name:"forced-colors",value:"active"}):t.theme==="forced-colors-none"&&a.push({name:"forced-colors",value:"none"}),await s.send("Emulation.setEmulatedMedia",{features:a}),await new Promise(g=>setTimeout(g,50))}p&&await Xt(e,t.direction),h&&await s.send("Emulation.setDeviceMetricsOverride",{width:t.breakpoint.width,height:t.breakpoint.height,deviceScaleFactor:t.breakpoint.deviceScaleFactor,mobile:t.breakpoint.mobile}),f&&t.ariaVariation&&n&&await ya(e,o,n,t.ariaVariation.attributes),$e.set(e,{scope:n,frameId:o,pseudoState:t.pseudoState,theme:t.theme,direction:t.direction,breakpointId:t.breakpoint.id,ariaVariationKey:r})}async function wa(e,t,n){const o=ne.get(e);if(o){if(await Yt(e),$e.delete(e),t)try{await tt(e,n,t,!1),await Jt(e,n),await Xt(e,"ltr")}catch(s){J.warn("element-level reset partial failure",s)}try{await o.send("Emulation.setEmulatedMedia",{features:[]}),await o.send("Emulation.clearDeviceMetricsOverride")}catch(s){J.warn("reset partial failure",s)}await dt(e)}}async function nt(e,t,n,o){try{return await ba(e,t,n,o),M({type:"STATE_CHANGED_EVENT",tabId:e,currentState:t}),{type:"STATE_DRIVE_RESPONSE",success:!0,appliedState:t}}catch(s){return J.error("state drive failed",s),await ha(e),{type:"STATE_DRIVE_RESPONSE",success:!1,error:ca(s)}}}async function Qt(e,t,n){await wa(e,t,n)}async function va(e,t={}){try{const n=await qt(e),o={format:"jpeg",quality:t.quality??75};t.fullPage&&(o.captureBeyondViewport=!0);const s=await n.send("Page.captureScreenshot",o);return s!=null&&s.data?`data:image/jpeg;base64,${s.data}`:null}catch(n){return J.debug("Page.captureScreenshot failed",n),null}}function Aa(){var n;const e=[];if(e.push(D("STATE_DRIVE_REQUEST",o=>nt(o.tabId,o.state,o.scope,o.frameId))),e.push(D("STATE_RESET_REQUEST",o=>Qt(o.tabId))),(n=chrome.tabs)!=null&&n.onRemoved){const o=s=>{dt(s).catch(()=>{})};chrome.tabs.onRemoved.addListener(o),e.push(()=>chrome.tabs.onRemoved.removeListener(o))}const t=la((o,s)=>{o.tabId!==void 0&&(ne.delete(o.tabId),me.delete(o.tabId),fe.delete(o.tabId),J.warn("unexpected detach",{tabId:o.tabId,reason:s}))});return e.push(t),J.info("handlers registered"),()=>e.forEach(o=>o())}const Sa="wcag-component-auditor",xa=1;let Be=null;function We(){return Be||(Be=Gn(Sa,xa,{upgrade(e,t){if(t<1){const n=e.createObjectStore("baselines",{keyPath:"componentId"});n.createIndex("byUrl","snapshotMeta.url"),n.createIndex("byDate","lastUpdated");const o=e.createObjectStore("audit-history",{keyPath:"auditId",autoIncrement:!0});o.createIndex("byComponentId","componentId"),o.createIndex("byDate","runDate")}}})),Be}async function pt(e){return(await We()).get("baselines",e)}async function Zt(e){await(await We()).put("baselines",e)}async function Ea(e){await(await We()).delete("baselines",e)}async function ka(){return(await We()).getAll("baselines")}const pe=z("cloud-sync"),At="cloudSyncEnabled",qe="cloudSyncEndpoint",Ke="licenseToken",at="cloudSyncVersionCache";async function ht(){try{const e=await chrome.storage.local.get([At,qe,Ke]),t=e[At]===!0,n=typeof e[qe]=="string"?e[qe]:"",o=typeof e[Ke]=="string"?e[Ke]:"";return!t||!n||!o?null:{endpoint:n.replace(/\/$/,""),token:o,enabled:t}}catch{return null}}async function en(){try{const t=(await chrome.storage.local.get(at))[at];return t&&typeof t=="object"?t:{}}catch{return{}}}async function Pe(e){try{await chrome.storage.local.set({[at]:e})}catch{}}async function $a(e,t,n){const o=await ht();if(!o)return!1;const s=await en(),i=s[e];try{const c=`${o.endpoint}/v1/products/wcagcheckr/baselines/${encodeURIComponent(e)}`,r=await fetch(c,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o.token}`},body:JSON.stringify({snapshot:t,axeVersion:n,expectedVersion:i})});if(r.status===409)return pe.warn(`baseline ${e} version conflict on push`,{expectedVersion:i}),delete s[e],await Pe(s),!1;if(!r.ok)return pe.warn("baseline push failed",{status:r.status}),!1;const d=await r.json();return typeof d.version=="number"&&(s[e]=d.version,await Pe(s)),!0}catch(c){return pe.debug("push network failure (offline?)",c),!1}}async function Ta(e){const t=await ht();if(!t)return!1;try{const n=`${t.endpoint}/v1/products/wcagcheckr/baselines/${encodeURIComponent(e)}`,o=await fetch(n,{method:"DELETE",headers:{Authorization:`Bearer ${t.token}`}});if(o.ok){const s=await en();delete s[e],await Pe(s)}return o.ok}catch(n){return pe.debug("delete network failure",n),!1}}async function Ca(){const e=await ht();if(!e)return[];try{const t=await fetch(`${e.endpoint}/v1/products/wcagcheckr/baselines`,{headers:{Authorization:`Bearer ${e.token}`}});if(!t.ok)return pe.warn("pull failed",{status:t.status}),[];const o=(await t.json()).items??[],s={};for(const i of o)s[i.componentId]=i.version;return await Pe(s),o}catch(t){return pe.debug("pull network failure",t),[]}}const tn=z("baseline-store"),St="componentIdAliases";async function ge(e,t){try{return await t()}catch(n){const o=n instanceof Error?n.message:String(n);throw tn.error(`baseline IDB ${e} failed: ${o}`),new Dn({code:"BASELINE_DB_ERROR",message:`Baseline storage is unavailable (${e}: ${o}).`,recoverable:!1,details:o})}}async function Ve(e){return((await chrome.storage.local.get(St))[St]??{})[e]??e}async function Ia(e){const t=await Ve(e),n=await ge("get",()=>pt(t));return n?{violations:n.violations,snapshotMeta:n.snapshotMeta}:null}async function Ra(e,t,n,o){const s=await Ve(e),i=await ge("get-for-set",()=>pt(s)),c=(i==null?void 0:i.seenOnUrls)??[],r=c.includes(n.url)?c:[...c,n.url];await ge("set",()=>Zt({componentId:s,violations:t,snapshotMeta:n,lastUpdated:new Date().toISOString(),axeVersion:n.axeVersion,announcements:o==null?void 0:o.announcements,focusEvents:o==null?void 0:o.focusEvents,seenOnUrls:r})),$a(s,{violations:t,snapshotMeta:n},n.axeVersion).catch(()=>{})}function Oa(e,t){if(!e||!t||bt(e)===bt(t))return;const n=i=>{var c,r,d,l,p;return(((c=i.pseudoStates)==null?void 0:c.length)??0)*Math.max(1,((r=i.ariaVariations)==null?void 0:r.length)??0)*(((d=i.themes)==null?void 0:d.length)??0)*(((l=i.directions)==null?void 0:l.length)??0)*(((p=i.breakpoints)==null?void 0:p.length)??0)},o=n(e),s=n(t);return`Baseline was captured under a different state-matrix configuration (${o} states) than this run (${s} states). Per-state-instance deltas inflate when the matrix changes — the unique-violation deltas above are still reliable.`}async function nn(e,t,n,o){var l;const s=await Ve(e),i=await Wn(s),c=await ge("compare",()=>pt(s));if(!c){const p=t.filter(f=>i.has(f.matchKey)),h=t.filter(f=>!i.has(f.matchKey));return{new:h,persistent:[],fixed:[],newCount:h.length,persistentCount:0,fixedCount:0,baselineSnapshotMeta:null,comparedAt:new Date().toISOString(),newAnnouncements:n==null?void 0:n.announcements,newFocusEvents:n==null?void 0:n.focusEvents,acknowledged:p,acknowledgedCount:p.length}}const r=Ln(c.violations,t,c.snapshotMeta,{baselineAnnouncements:c.announcements,currentAnnouncements:n==null?void 0:n.announcements,baselineFocusEvents:c.focusEvents,currentFocusEvents:n==null?void 0:n.focusEvents},i),d=Oa((l=c.snapshotMeta)==null?void 0:l.matrixConfig,o);return d&&(r.matrixMismatchWarning=d),r}async function _a(e){const t=await Ve(e);await ge("delete",()=>Ea(t)),Ta(t).catch(()=>{})}async function Ma(){const e=await Ca();for(const t of e)await Zt({componentId:t.componentId,violations:t.snapshot.violations,snapshotMeta:t.snapshot.snapshotMeta,lastUpdated:t.updatedAt,axeVersion:t.axeVersion});return e.length>0&&M({type:"SCORECARD_UPDATED_EVENT"}),e.length}async function Ua(e){let t=await ge("list",()=>ka());return e!=null&&e.url&&(t=t.filter(n=>n.snapshotMeta.url===e.url)),t.map(n=>{const o=(n.focusEvents??[]).filter(l=>l.isFocusReset).length,s=(n.announcements??[]).length,i=n.violations.filter(l=>l.ruleId==="target-size").length,c=n.violations.some(l=>l.ruleId==="color-contrast"&&l.currentState.pseudoState==="hover"),r=n.violations.filter(l=>l.impact==="critical").length,d=n.violations.filter(l=>l.impact==="serious").length;return{componentId:n.componentId,violationCount:n.violations.length,lastUpdated:n.lastUpdated,seenOnUrlsCount:(n.seenOnUrls??[]).length,metrics:{criticalCount:r,seriousCount:d,focusResetCount:o,announcementCount:s,targetSizeFailCount:i,hoverContrastFail:c}}})}function Na(){const e=[];return e.push(D("BASELINE_GET",async t=>({type:"BASELINE_GET_RESPONSE",baseline:await Ia(t.componentId)}))),e.push(D("BASELINE_SET",async t=>{await Ra(t.componentId,t.violations,t.snapshotMeta,{announcements:t.announcements,focusEvents:t.focusEvents}),M({type:"SCORECARD_UPDATED_EVENT"})})),e.push(D("BASELINE_COMPARE",async t=>({type:"BASELINE_COMPARE_RESPONSE",delta:await nn(t.componentId,t.currentViolations,{announcements:t.announcements,focusEvents:t.focusEvents},t.currentMatrix)}))),e.push(D("BASELINE_DELETE",async t=>{await _a(t.componentId),M({type:"SCORECARD_UPDATED_EVENT"})})),e.push(D("BASELINE_LIST",async t=>({type:"BASELINE_LIST_RESPONSE",items:await Ua(t.filter)}))),tn.info("handlers registered"),()=>e.forEach(t=>t())}const ot="tierConfig:cache",Pa=60*60*1e3,La=24*60*60*1e3,Da=7*24*60*60*1e3;async function Fa(){return(await chrome.storage.local.get(ot))[ot]??null}async function Ga(e){await chrome.storage.local.set({[ot]:e})}function Wa(e,t=Date.now()){const n=t-e.fetchedAt;return n<Pa?"fresh":n<La?"stale":n<Da?"grace":"expired"}function Va(e,t){const n={...e},o=u=>{if(typeof u=="number")return u===-1?1/0:u},s=u=>typeof u=="boolean"?u:void 0,i=u=>{if(u==="all"||u==="configurable"||u==="default-only")return u},c=o(t.maxComponents);c!==void 0&&(n.maxComponents=c);const r=o(t.maxBaselines);r!==void 0&&(n.maxBaselines=r);const d=i(t.stateMatrix);d!==void 0&&(n.stateMatrix=d);const l=s(t.storybookAutoIterate);l!==void 0&&(n.storybookAutoIterate=l);const p=s(t.exportJson);p!==void 0&&(n.exportJson=p);const h=s(t.exportSarif);h!==void 0&&(n.exportSarif=h);const f=s(t.exportJunit);f!==void 0&&(n.exportJunit=f);const a=s(t.cloudSync);a!==void 0&&(n.cloudSync=a);const g=s(t.forensicAnchoring);return g!==void 0&&(n.forensicAnchoring=g),n}function ja(e,t){var o;if(e==="trial")return((o=t.trial)==null?void 0:o.features)??null;const n=t.plans.find(s=>s.code===e||s.code.startsWith(e+"-"));return(n==null?void 0:n.features)??null}const st=z("tier-config-client"),za="wcagcheckr",Ha=`https://api.wcagcheckr.com/v1/products/${za}/tier-config`,Ba=1e4,xt="tier-config-refresh",qa=60,Ka=["trial","free","solo","team"];function an(e){const t={};for(const n of Ka){const o=ja(n,e);t[n]=o?Va(vt[n],o):{...vt[n]}}return t}async function Ya(){const e=await Fa();if(!e){Me(null);return}if(Wa(e)==="expired"){st.warn("cached tier-config is expired (>7d); using hardcoded defaults"),Me(null);return}Me(an(e.config))}async function on(){try{const e=await fetch(Ha,{signal:AbortSignal.timeout(Ba),headers:{accept:"application/json"}});if(!e.ok)throw new Error(`http ${e.status}`);const t=await e.json();await Ga({fetchedAt:Date.now(),config:t}),Me(an(t)),st.info("tier-config refreshed from server")}catch(e){st.warn("tier-config refresh failed; keeping prior cache",e)}}function Ja(){chrome.alarms.create(xt,{periodInMinutes:qa}),chrome.alarms.onAlarm.addListener(e=>{e.name===xt&&on()})}const Xa=z("settings-store"),Et=1,kt="__schemaVersion",rt={stateMatrix:et,componentIdAliases:{},ignorePatterns:[]};async function Se(e,t){return(await chrome.storage.local.get(e))[e]??t}async function Qa(){const e=await chrome.storage.local.get();if(e[kt]===Et)return;const t={[kt]:Et};for(const[n,o]of Object.entries(rt))n in e||(t[n]=o);await chrome.storage.local.set(t),Xa.info("defaults ensured")}const Za=["__","inflight:","license:","support:"];function eo(e){return!Za.some(t=>e.startsWith(t))}function to(){const e=[];return e.push(D("SETTINGS_GET",async t=>({type:"SETTINGS_RESPONSE",data:(await chrome.storage.local.get(t.key))[t.key]??rt[t.key]}))),e.push(D("SETTINGS_SET",async t=>{await chrome.storage.local.set({[t.key]:t.value})})),e.push(D("SETTINGS_GET_ALL",async()=>{const t=await chrome.storage.local.get(),n=Object.fromEntries(Object.entries(t).filter(([o])=>eo(o)));return{type:"SETTINGS_RESPONSE",data:{...rt,...n}}})),()=>e.forEach(t=>t())}const no={input:3/1e6,output:15/1e6},ao={input:1/1e6,output:5/1e6},oo="claude-sonnet-4-6",so="https://api.anthropic.com/v1/messages",ro="2023-06-01";function io(e){const t=e.model||oo,n=t.includes("haiku")?ao:no;return{providerId:"anthropic",async judgeAltText({imageUrl:o,alt:s,surroundingContext:i,signal:c}){const r=await Tt(o,c);if(!r)return Ct("Could not fetch image to verify alt text",0,t);const d=mo(s,i),l=await X({apiKey:e.apiKey,model:t,maxTokens:300,signal:c,messages:[{role:"user",content:[{type:"image",source:{type:"base64",media_type:r.mediaType,data:r.data}},{type:"text",text:d}]}]});return te(l,n)},async judgeHeading({headingText:o,sectionContent:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:yo(o,s)}]}]});return te(c,n)},async judgeSensoryLanguage({instructionText:o,signal:s}){const i=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:s,messages:[{role:"user",content:[{type:"text",text:bo(o)}]}]});return te(i,n)},async judgeAriaSemantics({elementHtml:o,computedRole:s,surroundingHtml:i,signal:c}){const r=await X({apiKey:e.apiKey,model:t,maxTokens:350,signal:c,messages:[{role:"user",content:[{type:"text",text:wo(o,s,i)}]}]});return te(r,n)},async judgeImageOfText({imageUrl:o,accessibleName:s,signal:i}){const c=await Tt(o,i);if(!c)return Ct("Could not fetch image to inspect for embedded text",0,t);const r=await X({apiKey:e.apiKey,model:t,maxTokens:300,signal:i,messages:[{role:"user",content:[{type:"image",source:{type:"base64",media_type:c.mediaType,data:c.data}},{type:"text",text:vo(s)}]}]});return te(r,n)},async judgeColorOnlyMeaning({elementHtml:o,contextDescription:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:Ao(o,s)}]}]});return te(c,n)},async judgeGenericLinkText({linkText:o,surroundingText:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:So(o,s)}]}]});return te(c,n)},async judgeWallOfText({blockText:o,structuralChildrenCount:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:xo(o,s)}]}]});return te(c,n)},async judgeLanguageMismatch({declaredLang:o,bodyTextSample:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:Eo(o,s)}]}]});return te(c,n)},async suggestColorFix(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:600,messages:[{role:"user",content:[{type:"text",text:ko(o)}]}]});return To(s,n)},async generateExecutiveSummary(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:800,messages:[{role:"user",content:[{type:"text",text:$o(o)}]}]});return Ro(s,n)},async resolveAxeIncomplete(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:400,signal:o.signal,messages:[{role:"user",content:[{type:"text",text:Co(o)}]}]});return Io(s,n,t)}}}class Te extends Error{constructor(){super("Anthropic API: canceled by caller"),this.name="ExternalAbortError"}}const sn=3e4,$t=3,co=1e4;function lo(e){return e===429||e>=500}function uo(e){return e instanceof Error?e.name==="TimeoutError"||e.name==="AbortError"||e instanceof TypeError:!1}function po(e,t){if(!t)return e;if(typeof AbortSignal.any=="function")return AbortSignal.any([e,t]);const n=new AbortController,o=()=>n.abort();return e.aborted?n.abort():e.addEventListener("abort",o,{once:!0}),t.aborted?n.abort():t.addEventListener("abort",o,{once:!0}),n.signal}async function ho(e){var s,i;const t=AbortSignal.timeout(sn),n=po(t,e.signal);let o;try{o=await fetch(so,{method:"POST",headers:{"x-api-key":e.apiKey,"anthropic-version":ro,"content-type":"application/json","anthropic-dangerous-direct-browser-access":"true"},body:JSON.stringify({model:e.model,max_tokens:e.maxTokens,messages:e.messages}),signal:n})}catch(c){throw(s=e.signal)!=null&&s.aborted?new Te:c}if(!o.ok){const r=((i=(await o.json().catch(()=>({}))).error)==null?void 0:i.message)??`${o.status} ${o.statusText}`,d=new Error(`Anthropic API: ${r}`);throw d.status=o.status,d}return await o.json()}async function X(e){var n;let t=null;for(let o=1;o<=$t;o++){if((n=e.signal)!=null&&n.aborted)throw new Te;try{return await ho(e)}catch(s){if(s instanceof Te)throw s;const i=s.status;if(!(uo(s)||typeof i=="number"&&lo(i))||o===$t)throw s instanceof Error&&(s.name==="TimeoutError"||s.name==="AbortError")?new Error(`Anthropic API: timed out after ${sn/1e3}s on each of ${o} attempt${o===1?"":"s"}`):s;t=s instanceof Error?s:new Error(String(s)),await fo(o*1e3,e.signal)}}throw t??new Error("Anthropic API: all retries failed")}function fo(e,t){return new Promise((n,o)=>{if(t!=null&&t.aborted){o(new Te);return}const s=setTimeout(()=>{t==null||t.removeEventListener("abort",i),n()},e),i=()=>{clearTimeout(s),o(new Te)};t==null||t.addEventListener("abort",i,{once:!0})})}async function Tt(e,t){var i,c;const n=new AbortController,o=setTimeout(()=>n.abort(),co),s=()=>n.abort();t&&(t.aborted?n.abort():t.addEventListener("abort",s,{once:!0}));try{const r=await fetch(e,{signal:n.signal});if(!r.ok)return null;const d=((c=(i=r.headers.get("content-type"))==null?void 0:i.split(";")[0])==null?void 0:c.trim())??"image/png";if(!d.startsWith("image/"))return null;const l=await r.arrayBuffer();let p="";const h=new Uint8Array(l),f=32768;for(let a=0;a<h.length;a+=f)p+=String.fromCharCode(...h.slice(a,a+f));return{data:btoa(p),mediaType:d}}catch{return null}finally{clearTimeout(o),t&&t.removeEventListener("abort",s)}}function te(e,t){var i;const n=((i=e.content.find(c=>c.type==="text"))==null?void 0:i.text)??"",o=go(n),s=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;return{verdict:o.verdict,reasoning:o.reasoning,confidence:o.confidence,costUsd:s,model:e.model}}function go(e){const n=e.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/);if(!n)return{verdict:"uncertain",reasoning:"Model returned no parseable JSON",confidence:0};try{const o=JSON.parse(n[0]),s=o.verdict==="pass"||o.verdict==="fail"?o.verdict:"uncertain",i=(o.reasoning??"").trim().slice(0,600),c=typeof o.confidence=="number"?o.confidence:.5,r=Math.max(0,Math.min(1,c));return{verdict:s,reasoning:i,confidence:r}}catch{return{verdict:"uncertain",reasoning:"Model returned invalid JSON",confidence:0}}}function Ct(e,t,n){return{verdict:"uncertain",reasoning:e,confidence:0,costUsd:t,model:n}}const ae=`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/parallel-tab-flow-DNWptHLU.js","assets/crash-reporter-Dc5lvxvY.js","assets/preload-helper-D7HrI6pR.js","assets/diff-DIBMr3fQ.js","assets/forensic-log-VcNR3Xcq.js","assets/state-BIsozXtc.js","assets/ai-usage-log-Dj9Ub_DT.js"])))=>i.map(i=>d[i]);
2
+ import{_ as et}from"./preload-helper-D7HrI6pR.js";import{c as z,o as D,e as M,f as Mn,g as Un,d as q,b as re,i as Nn,h as Pn}from"./crash-reporter-Dc5lvxvY.js";import{m as Ue,d as Ln,T as Dn,a as wt,c as lt,i as Fn}from"./diff-DIBMr3fQ.js";import{x as Gn,y as Wn,p as vt,i as Ee,o as le,A as ke,F as Vn,z as jt,O as zt,B as Ht,R as jn,C as Bt,s as zn,D as Ce,E as Ie,G as Ge,H as Hn,g as Bn,I as qn,n as fe,m as qt,a as We,J as Kn,K as Yn}from"./forensic-log-VcNR3Xcq.js";import{s as Me,T as At,b as tt,i as Jn}from"./state-BIsozXtc.js";import{m as ge,D as Xn,s as Qn,h as Zn,b as ea,g as ta,d as na,e as aa}from"./ai-usage-log-Dj9Ub_DT.js";const oa=z("chrome-api"),sa="1.3";class ra{constructor(t){this.target=t}async attach(){await chrome.debugger.attach(this.target,sa)}async detach(){try{await chrome.debugger.detach(this.target)}catch(t){oa.debug("detach soft-failure",t)}}async send(t,n){return chrome.debugger.sendCommand(this.target,t,n)}}function ia(e){const t=e instanceof Error?e.message:String(e);return/Another debugger is already attached|Cannot attach to/i.test(t)}function ca(e){const t=e instanceof Error?e.message:String(e);return ia(e)?Ue("DEBUGGER_BUSY","DevTools is open on this tab. Close it to run the audit.",!0,{raw:t}):Ue("STATE_DRIVE_FAILED",t,!1)}function la(e){const t=(n,o)=>e(n,o);return chrome.debugger.onDetach.addListener(t),()=>chrome.debugger.onDetach.removeListener(t)}const J=z("state-driver"),da=60*1e3,ne=new Map,Ne=new Map,be=new Map,me=new Map,$e=new Map,ua={default:[],hover:["hover"],focus:["focus"],"focus-visible":["focus","focus-visible"],active:["active"],disabled:[]};async function Kt(e){let t=ne.get(e);if(!t){t=new ra({tabId:e});try{await t.attach(),await t.send("Runtime.enable"),await t.send("Page.enable"),await t.send("DOM.enable"),await t.send("DOM.getDocument",{depth:-1,pierce:!0}),await t.send("CSS.enable")}catch(n){try{await t.detach()}catch{}throw n}ne.set(e,t),be.set(e,new Map),pa(e),J.info("attached",{tabId:e})}return fa(e),t}function pa(e){const t=(n,o,s)=>{var c,r;if(n.tabId!==e)return;const i=be.get(e);if(i)if(o==="Runtime.executionContextCreated"){const d=s,l=d==null?void 0:d.context;l&&((c=l.auxData)!=null&&c.isDefault)&&((r=l.auxData)!=null&&r.frameId)&&i.set(l.auxData.frameId,l.id)}else if(o==="Runtime.executionContextDestroyed"){const d=s,l=d==null?void 0:d.executionContextId;if(l!==void 0)for(const[p,h]of i.entries())h===l&&i.delete(p)}else o==="Runtime.executionContextsCleared"&&i.clear()};chrome.debugger.onEvent.addListener(t)}async function ha(e){const t=ne.get(e);if(ne.delete(e),be.delete(e),me.delete(e),$e.delete(e),t)try{await t.detach()}catch{}}function fa(e){const t=Ne.get(e);t&&clearTimeout(t),Ne.set(e,setTimeout(()=>{dt(e).catch(n=>J.warn("idle detach failed",n))},da))}async function dt(e){const t=ne.get(e);t&&(await t.detach(),ne.delete(e)),be.delete(e),me.delete(e),$e.delete(e);const n=Ne.get(e);n&&(clearTimeout(n),Ne.delete(e))}function Yt(e){const t=[{id:e.frame.id,url:e.frame.url}];for(const n of e.childFrames??[])t.push(...Yt(n));return t}async function ga(e,t,n){var i;if(!n||n===0)return;const o=be.get(t);if(!o)return;let s;try{s=(i=(await chrome.scripting.executeScript({target:{tabId:t,frameIds:[n]},func:()=>location.href}))[0])==null?void 0:i.result}catch(c){J.debug("frame URL lookup failed",c)}try{const c=await e.send("Page.getFrameTree"),r=Yt(c.frameTree);if(s){const p=r.find(h=>h.url===s);if(p){const h=o.get(p.id);if(h!==void 0)return h}}const d=c.frameTree.frame.id,l=r.find(p=>p.id!==d);return l?o.get(l.id):void 0}catch(c){J.warn("Page.getFrameTree failed",c);return}}async function ma(e,t,n){var c;const o={expression:`document.querySelector(${JSON.stringify(t)})`,objectGroup:"wcag-auditor",returnByValue:!1};n!==void 0&&(o.contextId=n);const i=(c=(await e.send("Runtime.evaluate",o)).result)==null?void 0:c.objectId;if(!i)return null;try{return(await e.send("DOM.requestNode",{objectId:i})).nodeId??null}finally{e.send("Runtime.releaseObject",{objectId:i}).catch(()=>{})}}async function Jt(e){const t=me.get(e);if(!t)return;const n=ne.get(e);if(n){try{await n.send("CSS.forcePseudoState",{nodeId:t.nodeId,forcedPseudoClasses:[]})}catch(o){J.debug("forcePseudoState clear failed (node may be gone)",o)}me.delete(e)}}async function nt(e,t,n,o){await chrome.scripting.executeScript({target:ut(e,t),func:(s,i)=>{const c=document.querySelector(s);c&&(i?c.setAttribute("disabled",""):c.removeAttribute("disabled"))},args:[n,o]})}async function Xt(e,t){await chrome.scripting.executeScript({target:ut(e,t),func:()=>{const n=document.activeElement;n&&typeof n.blur=="function"&&n.blur()}})}async function Qt(e,t){await chrome.scripting.executeScript({target:{tabId:e,frameIds:[0]},func:n=>{document.documentElement.setAttribute("dir",n)},args:[t]})}async function ya(e,t,n,o){await chrome.scripting.executeScript({target:ut(e,t),func:(s,i)=>{const c=document.querySelector(s);if(c)for(const[r,d]of Object.entries(i))c.setAttribute(r,d)},args:[n,o]})}function ut(e,t){return t!==void 0&&t!==0?{tabId:e,frameIds:[t]}:{tabId:e}}async function ba(e,t,n,o){const s=await Kt(e),i=$e.get(e),c=(i==null?void 0:i.scope)===n&&(i==null?void 0:i.frameId)===o,r=t.ariaVariation?JSON.stringify(t.ariaVariation.attributes):"",d=!c||(i==null?void 0:i.pseudoState)!==t.pseudoState,l=!i||i.theme!==t.theme,p=!i||i.direction!==t.direction,h=!i||i.breakpointId!==t.breakpoint.id,f=!c||(i==null?void 0:i.ariaVariationKey)!==r;if(d&&(await Jt(e),n)){t.pseudoState==="disabled"?await nt(e,o,n,!0):(await nt(e,o,n,!1),await Xt(e,o));const a=ua[t.pseudoState];if(a.length>0){const g=await ga(s,e,o),u=await ma(s,n,g);if(u!==null)try{await s.send("CSS.forcePseudoState",{nodeId:u,forcedPseudoClasses:a}),me.set(e,{sessionTabId:e,nodeId:u})}catch(w){J.warn(`CSS.forcePseudoState failed for :${t.pseudoState}`,w)}else J.debug(`could not resolve nodeId for ${n} (frameId=${o})`)}}if(l){const a=[{name:"prefers-reduced-motion",value:"reduce"}];t.theme==="dark"?(a.push({name:"prefers-color-scheme",value:"dark"}),a.push({name:"forced-colors",value:"none"})):t.theme==="light"?(a.push({name:"prefers-color-scheme",value:"light"}),a.push({name:"forced-colors",value:"none"})):t.theme==="forced-colors-active"?a.push({name:"forced-colors",value:"active"}):t.theme==="forced-colors-none"&&a.push({name:"forced-colors",value:"none"}),await s.send("Emulation.setEmulatedMedia",{features:a}),await new Promise(g=>setTimeout(g,50))}p&&await Qt(e,t.direction),h&&await s.send("Emulation.setDeviceMetricsOverride",{width:t.breakpoint.width,height:t.breakpoint.height,deviceScaleFactor:t.breakpoint.deviceScaleFactor,mobile:t.breakpoint.mobile}),f&&t.ariaVariation&&n&&await ya(e,o,n,t.ariaVariation.attributes),$e.set(e,{scope:n,frameId:o,pseudoState:t.pseudoState,theme:t.theme,direction:t.direction,breakpointId:t.breakpoint.id,ariaVariationKey:r})}async function wa(e,t,n){const o=ne.get(e);if(o){if(await Jt(e),$e.delete(e),t)try{await nt(e,n,t,!1),await Xt(e,n),await Qt(e,"ltr")}catch(s){J.warn("element-level reset partial failure",s)}try{await o.send("Emulation.setEmulatedMedia",{features:[]}),await o.send("Emulation.clearDeviceMetricsOverride")}catch(s){J.warn("reset partial failure",s)}await dt(e)}}async function at(e,t,n,o){try{return await ba(e,t,n,o),M({type:"STATE_CHANGED_EVENT",tabId:e,currentState:t}),{type:"STATE_DRIVE_RESPONSE",success:!0,appliedState:t}}catch(s){return J.error("state drive failed",s),await ha(e),{type:"STATE_DRIVE_RESPONSE",success:!1,error:ca(s)}}}async function Zt(e,t,n){await wa(e,t,n)}async function va(e,t={}){try{const n=await Kt(e),o={format:"jpeg",quality:t.quality??75};t.fullPage&&(o.captureBeyondViewport=!0);const s=await n.send("Page.captureScreenshot",o);return s!=null&&s.data?`data:image/jpeg;base64,${s.data}`:null}catch(n){return J.debug("Page.captureScreenshot failed",n),null}}function Aa(){var n;const e=[];if(e.push(D("STATE_DRIVE_REQUEST",o=>at(o.tabId,o.state,o.scope,o.frameId))),e.push(D("STATE_RESET_REQUEST",o=>Zt(o.tabId))),(n=chrome.tabs)!=null&&n.onRemoved){const o=s=>{dt(s).catch(()=>{})};chrome.tabs.onRemoved.addListener(o),e.push(()=>chrome.tabs.onRemoved.removeListener(o))}const t=la((o,s)=>{o.tabId!==void 0&&(ne.delete(o.tabId),be.delete(o.tabId),me.delete(o.tabId),J.warn("unexpected detach",{tabId:o.tabId,reason:s}))});return e.push(t),J.info("handlers registered"),()=>e.forEach(o=>o())}const Sa="wcag-component-auditor",xa=1;let qe=null;function Ve(){return qe||(qe=Gn(Sa,xa,{upgrade(e,t){if(t<1){const n=e.createObjectStore("baselines",{keyPath:"componentId"});n.createIndex("byUrl","snapshotMeta.url"),n.createIndex("byDate","lastUpdated");const o=e.createObjectStore("audit-history",{keyPath:"auditId",autoIncrement:!0});o.createIndex("byComponentId","componentId"),o.createIndex("byDate","runDate")}}})),qe}async function pt(e){return(await Ve()).get("baselines",e)}async function en(e){await(await Ve()).put("baselines",e)}async function Ea(e){await(await Ve()).delete("baselines",e)}async function ka(){return(await Ve()).getAll("baselines")}const pe=z("cloud-sync"),St="cloudSyncEnabled",Ke="cloudSyncEndpoint",Ye="licenseToken",ot="cloudSyncVersionCache";async function ht(){try{const e=await chrome.storage.local.get([St,Ke,Ye]),t=e[St]===!0,n=typeof e[Ke]=="string"?e[Ke]:"",o=typeof e[Ye]=="string"?e[Ye]:"";return!t||!n||!o?null:{endpoint:n.replace(/\/$/,""),token:o,enabled:t}}catch{return null}}async function tn(){try{const t=(await chrome.storage.local.get(ot))[ot];return t&&typeof t=="object"?t:{}}catch{return{}}}async function Pe(e){try{await chrome.storage.local.set({[ot]:e})}catch{}}async function $a(e,t,n){const o=await ht();if(!o)return!1;const s=await tn(),i=s[e];try{const c=`${o.endpoint}/v1/products/wcagcheckr/baselines/${encodeURIComponent(e)}`,r=await fetch(c,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o.token}`},body:JSON.stringify({snapshot:t,axeVersion:n,expectedVersion:i})});if(r.status===409)return pe.warn(`baseline ${e} version conflict on push`,{expectedVersion:i}),delete s[e],await Pe(s),!1;if(!r.ok)return pe.warn("baseline push failed",{status:r.status}),!1;const d=await r.json();return typeof d.version=="number"&&(s[e]=d.version,await Pe(s)),!0}catch(c){return pe.debug("push network failure (offline?)",c),!1}}async function Ta(e){const t=await ht();if(!t)return!1;try{const n=`${t.endpoint}/v1/products/wcagcheckr/baselines/${encodeURIComponent(e)}`,o=await fetch(n,{method:"DELETE",headers:{Authorization:`Bearer ${t.token}`}});if(o.ok){const s=await tn();delete s[e],await Pe(s)}return o.ok}catch(n){return pe.debug("delete network failure",n),!1}}async function Ca(){const e=await ht();if(!e)return[];try{const t=await fetch(`${e.endpoint}/v1/products/wcagcheckr/baselines`,{headers:{Authorization:`Bearer ${e.token}`}});if(!t.ok)return pe.warn("pull failed",{status:t.status}),[];const o=(await t.json()).items??[],s={};for(const i of o)s[i.componentId]=i.version;return await Pe(s),o}catch(t){return pe.debug("pull network failure",t),[]}}const nn=z("baseline-store"),xt="componentIdAliases";async function ye(e,t){try{return await t()}catch(n){const o=n instanceof Error?n.message:String(n);throw nn.error(`baseline IDB ${e} failed: ${o}`),new Dn({code:"BASELINE_DB_ERROR",message:`Baseline storage is unavailable (${e}: ${o}).`,recoverable:!1,details:o})}}async function je(e){return((await chrome.storage.local.get(xt))[xt]??{})[e]??e}async function Ia(e){const t=await je(e),n=await ye("get",()=>pt(t));return n?{violations:n.violations,snapshotMeta:n.snapshotMeta}:null}async function Ra(e,t,n,o){const s=await je(e),i=await ye("get-for-set",()=>pt(s)),c=(i==null?void 0:i.seenOnUrls)??[],r=c.includes(n.url)?c:[...c,n.url];await ye("set",()=>en({componentId:s,violations:t,snapshotMeta:n,lastUpdated:new Date().toISOString(),axeVersion:n.axeVersion,announcements:o==null?void 0:o.announcements,focusEvents:o==null?void 0:o.focusEvents,seenOnUrls:r})),$a(s,{violations:t,snapshotMeta:n},n.axeVersion).catch(()=>{})}function Oa(e,t){if(!e||!t||wt(e)===wt(t))return;const n=i=>{var c,r,d,l,p;return(((c=i.pseudoStates)==null?void 0:c.length)??0)*Math.max(1,((r=i.ariaVariations)==null?void 0:r.length)??0)*(((d=i.themes)==null?void 0:d.length)??0)*(((l=i.directions)==null?void 0:l.length)??0)*(((p=i.breakpoints)==null?void 0:p.length)??0)},o=n(e),s=n(t);return`Baseline was captured under a different state-matrix configuration (${o} states) than this run (${s} states). Per-state-instance deltas inflate when the matrix changes — the unique-violation deltas above are still reliable.`}async function ft(e,t,n,o){var l;const s=await je(e),i=await Wn(s),c=await ye("compare",()=>pt(s));if(!c){const p=t.filter(f=>i.has(f.matchKey)),h=t.filter(f=>!i.has(f.matchKey));return{new:h,persistent:[],fixed:[],newCount:h.length,persistentCount:0,fixedCount:0,baselineSnapshotMeta:null,comparedAt:new Date().toISOString(),newAnnouncements:n==null?void 0:n.announcements,newFocusEvents:n==null?void 0:n.focusEvents,acknowledged:p,acknowledgedCount:p.length}}const r=Ln(c.violations,t,c.snapshotMeta,{baselineAnnouncements:c.announcements,currentAnnouncements:n==null?void 0:n.announcements,baselineFocusEvents:c.focusEvents,currentFocusEvents:n==null?void 0:n.focusEvents},i),d=Oa((l=c.snapshotMeta)==null?void 0:l.matrixConfig,o);return d&&(r.matrixMismatchWarning=d),r}async function _a(e){const t=await je(e);await ye("delete",()=>Ea(t)),Ta(t).catch(()=>{})}async function Ma(){const e=await Ca();for(const t of e)await en({componentId:t.componentId,violations:t.snapshot.violations,snapshotMeta:t.snapshot.snapshotMeta,lastUpdated:t.updatedAt,axeVersion:t.axeVersion});return e.length>0&&M({type:"SCORECARD_UPDATED_EVENT"}),e.length}async function Ua(e){let t=await ye("list",()=>ka());return e!=null&&e.url&&(t=t.filter(n=>n.snapshotMeta.url===e.url)),t.map(n=>{const o=(n.focusEvents??[]).filter(l=>l.isFocusReset).length,s=(n.announcements??[]).length,i=n.violations.filter(l=>l.ruleId==="target-size").length,c=n.violations.some(l=>l.ruleId==="color-contrast"&&l.currentState.pseudoState==="hover"),r=n.violations.filter(l=>l.impact==="critical").length,d=n.violations.filter(l=>l.impact==="serious").length;return{componentId:n.componentId,violationCount:n.violations.length,lastUpdated:n.lastUpdated,seenOnUrlsCount:(n.seenOnUrls??[]).length,metrics:{criticalCount:r,seriousCount:d,focusResetCount:o,announcementCount:s,targetSizeFailCount:i,hoverContrastFail:c}}})}function Na(){const e=[];return e.push(D("BASELINE_GET",async t=>({type:"BASELINE_GET_RESPONSE",baseline:await Ia(t.componentId)}))),e.push(D("BASELINE_SET",async t=>{await Ra(t.componentId,t.violations,t.snapshotMeta,{announcements:t.announcements,focusEvents:t.focusEvents}),M({type:"SCORECARD_UPDATED_EVENT"})})),e.push(D("BASELINE_COMPARE",async t=>({type:"BASELINE_COMPARE_RESPONSE",delta:await ft(t.componentId,t.currentViolations,{announcements:t.announcements,focusEvents:t.focusEvents},t.currentMatrix)}))),e.push(D("BASELINE_DELETE",async t=>{await _a(t.componentId),M({type:"SCORECARD_UPDATED_EVENT"})})),e.push(D("BASELINE_LIST",async t=>({type:"BASELINE_LIST_RESPONSE",items:await Ua(t.filter)}))),nn.info("handlers registered"),()=>e.forEach(t=>t())}const st="tierConfig:cache",Pa=60*60*1e3,La=24*60*60*1e3,Da=7*24*60*60*1e3;async function Fa(){return(await chrome.storage.local.get(st))[st]??null}async function Ga(e){await chrome.storage.local.set({[st]:e})}function Wa(e,t=Date.now()){const n=t-e.fetchedAt;return n<Pa?"fresh":n<La?"stale":n<Da?"grace":"expired"}function Va(e,t){const n={...e},o=u=>{if(typeof u=="number")return u===-1?1/0:u},s=u=>typeof u=="boolean"?u:void 0,i=u=>{if(u==="all"||u==="configurable"||u==="default-only")return u},c=o(t.maxComponents);c!==void 0&&(n.maxComponents=c);const r=o(t.maxBaselines);r!==void 0&&(n.maxBaselines=r);const d=i(t.stateMatrix);d!==void 0&&(n.stateMatrix=d);const l=s(t.storybookAutoIterate);l!==void 0&&(n.storybookAutoIterate=l);const p=s(t.exportJson);p!==void 0&&(n.exportJson=p);const h=s(t.exportSarif);h!==void 0&&(n.exportSarif=h);const f=s(t.exportJunit);f!==void 0&&(n.exportJunit=f);const a=s(t.cloudSync);a!==void 0&&(n.cloudSync=a);const g=s(t.forensicAnchoring);return g!==void 0&&(n.forensicAnchoring=g),n}function ja(e,t){var o;if(e==="trial")return((o=t.trial)==null?void 0:o.features)??null;const n=t.plans.find(s=>s.code===e||s.code.startsWith(e+"-"));return(n==null?void 0:n.features)??null}const rt=z("tier-config-client"),za="wcagcheckr",Ha=`https://api.wcagcheckr.com/v1/products/${za}/tier-config`,Ba=1e4,Et="tier-config-refresh",qa=60,Ka=["trial","free","solo","team"];function an(e){const t={};for(const n of Ka){const o=ja(n,e);t[n]=o?Va(At[n],o):{...At[n]}}return t}async function Ya(){const e=await Fa();if(!e){Me(null);return}if(Wa(e)==="expired"){rt.warn("cached tier-config is expired (>7d); using hardcoded defaults"),Me(null);return}Me(an(e.config))}async function on(){try{const e=await fetch(Ha,{signal:AbortSignal.timeout(Ba),headers:{accept:"application/json"}});if(!e.ok)throw new Error(`http ${e.status}`);const t=await e.json();await Ga({fetchedAt:Date.now(),config:t}),Me(an(t)),rt.info("tier-config refreshed from server")}catch(e){rt.warn("tier-config refresh failed; keeping prior cache",e)}}function Ja(){chrome.alarms.create(Et,{periodInMinutes:qa}),chrome.alarms.onAlarm.addListener(e=>{e.name===Et&&on()})}const Xa=z("settings-store"),kt=1,$t="__schemaVersion",it={stateMatrix:tt,componentIdAliases:{},ignorePatterns:[]};async function he(e,t){return(await chrome.storage.local.get(e))[e]??t}async function Qa(){const e=await chrome.storage.local.get();if(e[$t]===kt)return;const t={[$t]:kt};for(const[n,o]of Object.entries(it))n in e||(t[n]=o);await chrome.storage.local.set(t),Xa.info("defaults ensured")}const Za=["__","inflight:","license:","support:"];function eo(e){return!Za.some(t=>e.startsWith(t))}function to(){const e=[];return e.push(D("SETTINGS_GET",async t=>({type:"SETTINGS_RESPONSE",data:(await chrome.storage.local.get(t.key))[t.key]??it[t.key]}))),e.push(D("SETTINGS_SET",async t=>{await chrome.storage.local.set({[t.key]:t.value})})),e.push(D("SETTINGS_GET_ALL",async()=>{const t=await chrome.storage.local.get(),n=Object.fromEntries(Object.entries(t).filter(([o])=>eo(o)));return{type:"SETTINGS_RESPONSE",data:{...it,...n}}})),()=>e.forEach(t=>t())}const no={input:3/1e6,output:15/1e6},ao={input:1/1e6,output:5/1e6},oo="claude-sonnet-4-6",so="https://api.anthropic.com/v1/messages",ro="2023-06-01";function io(e){const t=e.model||oo,n=t.includes("haiku")?ao:no;return{providerId:"anthropic",async judgeAltText({imageUrl:o,alt:s,surroundingContext:i,signal:c}){const r=await Ct(o,c);if(!r)return It("Could not fetch image to verify alt text",0,t);const d=mo(s,i),l=await X({apiKey:e.apiKey,model:t,maxTokens:300,signal:c,messages:[{role:"user",content:[{type:"image",source:{type:"base64",media_type:r.mediaType,data:r.data}},{type:"text",text:d}]}]});return te(l,n)},async judgeHeading({headingText:o,sectionContent:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:yo(o,s)}]}]});return te(c,n)},async judgeSensoryLanguage({instructionText:o,signal:s}){const i=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:s,messages:[{role:"user",content:[{type:"text",text:bo(o)}]}]});return te(i,n)},async judgeAriaSemantics({elementHtml:o,computedRole:s,surroundingHtml:i,signal:c}){const r=await X({apiKey:e.apiKey,model:t,maxTokens:350,signal:c,messages:[{role:"user",content:[{type:"text",text:wo(o,s,i)}]}]});return te(r,n)},async judgeImageOfText({imageUrl:o,accessibleName:s,signal:i}){const c=await Ct(o,i);if(!c)return It("Could not fetch image to inspect for embedded text",0,t);const r=await X({apiKey:e.apiKey,model:t,maxTokens:300,signal:i,messages:[{role:"user",content:[{type:"image",source:{type:"base64",media_type:c.mediaType,data:c.data}},{type:"text",text:vo(s)}]}]});return te(r,n)},async judgeColorOnlyMeaning({elementHtml:o,contextDescription:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:Ao(o,s)}]}]});return te(c,n)},async judgeGenericLinkText({linkText:o,surroundingText:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:So(o,s)}]}]});return te(c,n)},async judgeWallOfText({blockText:o,structuralChildrenCount:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:xo(o,s)}]}]});return te(c,n)},async judgeLanguageMismatch({declaredLang:o,bodyTextSample:s,signal:i}){const c=await X({apiKey:e.apiKey,model:t,maxTokens:250,signal:i,messages:[{role:"user",content:[{type:"text",text:Eo(o,s)}]}]});return te(c,n)},async suggestColorFix(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:600,messages:[{role:"user",content:[{type:"text",text:ko(o)}]}]});return To(s,n)},async generateExecutiveSummary(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:800,messages:[{role:"user",content:[{type:"text",text:$o(o)}]}]});return Ro(s,n)},async resolveAxeIncomplete(o){const s=await X({apiKey:e.apiKey,model:t,maxTokens:400,signal:o.signal,messages:[{role:"user",content:[{type:"text",text:Co(o)}]}]});return Io(s,n,t)}}}class Te extends Error{constructor(){super("Anthropic API: canceled by caller"),this.name="ExternalAbortError"}}const sn=3e4,Tt=3,co=1e4;function lo(e){return e===429||e>=500}function uo(e){return e instanceof Error?e.name==="TimeoutError"||e.name==="AbortError"||e instanceof TypeError:!1}function po(e,t){if(!t)return e;if(typeof AbortSignal.any=="function")return AbortSignal.any([e,t]);const n=new AbortController,o=()=>n.abort();return e.aborted?n.abort():e.addEventListener("abort",o,{once:!0}),t.aborted?n.abort():t.addEventListener("abort",o,{once:!0}),n.signal}async function ho(e){var s,i;const t=AbortSignal.timeout(sn),n=po(t,e.signal);let o;try{o=await fetch(so,{method:"POST",headers:{"x-api-key":e.apiKey,"anthropic-version":ro,"content-type":"application/json","anthropic-dangerous-direct-browser-access":"true"},body:JSON.stringify({model:e.model,max_tokens:e.maxTokens,messages:e.messages}),signal:n})}catch(c){throw(s=e.signal)!=null&&s.aborted?new Te:c}if(!o.ok){const r=((i=(await o.json().catch(()=>({}))).error)==null?void 0:i.message)??`${o.status} ${o.statusText}`,d=new Error(`Anthropic API: ${r}`);throw d.status=o.status,d}return await o.json()}async function X(e){var n;let t=null;for(let o=1;o<=Tt;o++){if((n=e.signal)!=null&&n.aborted)throw new Te;try{return await ho(e)}catch(s){if(s instanceof Te)throw s;const i=s.status;if(!(uo(s)||typeof i=="number"&&lo(i))||o===Tt)throw s instanceof Error&&(s.name==="TimeoutError"||s.name==="AbortError")?new Error(`Anthropic API: timed out after ${sn/1e3}s on each of ${o} attempt${o===1?"":"s"}`):s;t=s instanceof Error?s:new Error(String(s)),await fo(o*1e3,e.signal)}}throw t??new Error("Anthropic API: all retries failed")}function fo(e,t){return new Promise((n,o)=>{if(t!=null&&t.aborted){o(new Te);return}const s=setTimeout(()=>{t==null||t.removeEventListener("abort",i),n()},e),i=()=>{clearTimeout(s),o(new Te)};t==null||t.addEventListener("abort",i,{once:!0})})}async function Ct(e,t){var i,c;const n=new AbortController,o=setTimeout(()=>n.abort(),co),s=()=>n.abort();t&&(t.aborted?n.abort():t.addEventListener("abort",s,{once:!0}));try{const r=await fetch(e,{signal:n.signal});if(!r.ok)return null;const d=((c=(i=r.headers.get("content-type"))==null?void 0:i.split(";")[0])==null?void 0:c.trim())??"image/png";if(!d.startsWith("image/"))return null;const l=await r.arrayBuffer();let p="";const h=new Uint8Array(l),f=32768;for(let a=0;a<h.length;a+=f)p+=String.fromCharCode(...h.slice(a,a+f));return{data:btoa(p),mediaType:d}}catch{return null}finally{clearTimeout(o),t&&t.removeEventListener("abort",s)}}function te(e,t){var i;const n=((i=e.content.find(c=>c.type==="text"))==null?void 0:i.text)??"",o=go(n),s=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;return{verdict:o.verdict,reasoning:o.reasoning,confidence:o.confidence,costUsd:s,model:e.model}}function go(e){const n=e.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/);if(!n)return{verdict:"uncertain",reasoning:"Model returned no parseable JSON",confidence:0};try{const o=JSON.parse(n[0]),s=o.verdict==="pass"||o.verdict==="fail"?o.verdict:"uncertain",i=(o.reasoning??"").trim().slice(0,600),c=typeof o.confidence=="number"?o.confidence:.5,r=Math.max(0,Math.min(1,c));return{verdict:s,reasoning:i,confidence:r}}catch{return{verdict:"uncertain",reasoning:"Model returned invalid JSON",confidence:0}}}function It(e,t,n){return{verdict:"uncertain",reasoning:e,confidence:0,costUsd:t,model:n}}const ae=`
3
3
  Respond ONLY with a single JSON object — no preamble, no markdown:
4
4
  { "verdict": "pass" | "fail" | "uncertain", "reasoning": "1-3 sentences", "confidence": 0.0-1.0 }
5
5
  `.trim();function mo(e,t){return`You are an accessibility auditor verifying alt text correctness for screen-reader users (WCAG 1.1.1).
@@ -236,7 +236,7 @@ Respond with strict JSON (no markdown fences):
236
236
  {
237
237
  "verdict": "pass" | "fail" | "uncertain",
238
238
  "reasoning": "one or two sentences explaining the determination, citing the contrast ratio for color-contrast"
239
- }`}function Io(e,t,n){var r;const o=((r=e.content.find(d=>d.type==="text"))==null?void 0:r.text)??"",i=o.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/),c=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;if(!i)return{verdict:"uncertain",reasoning:o||"AI returned no parseable response.",costUsd:c,model:e.model||n};try{const d=JSON.parse(i[0]);return{verdict:d.verdict==="pass"||d.verdict==="fail"?d.verdict:"uncertain",reasoning:typeof d.reasoning=="string"&&d.reasoning?d.reasoning:"AI returned no rationale.",costUsd:c,model:e.model||n}}catch{return{verdict:"uncertain",reasoning:o,costUsd:c,model:e.model||n}}}function Ro(e,t){var c;const n=((c=e.content.find(r=>r.type==="text"))==null?void 0:c.text)??"",s=n.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/),i=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;if(!s)return{lead:"",body:n||"Summary generation failed.",closer:"",costUsd:i,model:e.model};try{const r=JSON.parse(s[0]);return{lead:typeof r.lead=="string"?r.lead:"",body:typeof r.body=="string"?r.body:"",closer:typeof r.closer=="string"?r.closer:"",costUsd:i,model:e.model}}catch{return{lead:"",body:n,closer:"",costUsd:i,model:e.model}}}function Q(e){if(!e.enabled)return{ok:!1,reason:"AI augmentation is disabled in settings"};if(!e.apiKey)return{ok:!1,reason:"No API key configured"};switch(e.provider){case"anthropic":return{ok:!0,client:io({apiKey:e.apiKey,model:e.model})};case"openai":return{ok:!1,reason:"OpenAI provider not yet implemented"};case"gemini":return{ok:!1,reason:"Gemini provider not yet implemented"};default:return{ok:!1,reason:`Unknown provider: ${e.provider}`}}}function Z(e){const t={capUsd:Math.max(0,e),spentUsd:0,exceeded:!1};return{state:t,canCharge(){return!t.exceeded&&t.spentUsd<t.capUsd},recordCharge(n){t.spentUsd+=Math.max(0,n),t.spentUsd>=t.capUsd&&(t.exceeded=!0)}}}const Ye=z("ai-compliance-summarizer");async function rn(e,t){if(!t.enabled)return null;const n=Q(t);if(!n.ok)return Ye.debug(`AI client unavailable: ${n.reason}`),null;const o=Z(t.costCapUsd);if(!o.canCharge())return null;try{const s=await n.client.generateExecutiveSummary(e);return o.recordCharge(s.costUsd),!s.lead&&!s.body?(Ye.debug("AI summary returned empty"),null):s}catch(s){return Ye.warn("compliance-summary generation failed",s),null}}async function Oo(){const e=await chrome.storage.local.get("aiConfig");return ke(e.aiConfig)}function _o(){return D("AI_COMPLIANCE_SUMMARY_REQUEST",async e=>{const t=await Oo();if(!t.enabled)return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:null,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:null,unavailableReason:"No AI API key configured."};const n=await rn(e.input,t);return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:n,unavailableReason:n?void 0:"AI summary generation returned no result."}})}const ee="wcag-component-auditor";function ce(){try{return chrome.runtime.getManifest().version}catch{return"0.0.0"}}function oe(e){const t=e[0];return t?t.pageUrl?t.pageUrl:t.scope&&/^https?:\/\//.test(t.scope)?t.scope:t.scope?`(selector: ${t.scope})`:"unknown":"unknown"}function Mo(e,t){return{schemaVersion:1,generatedAt:new Date().toISOString(),tool:{name:ee,version:ce()},results:e,delta:t}}function It(e){return e==="critical"||e==="serious"?"error":e==="moderate"?"warning":"note"}function Uo(e,t){const n=(t?t.new:e.flatMap(r=>r.violations)).filter(r=>!r.needsReview),o=new Set,s=[];for(const r of n)o.has(r.ruleId)||(o.add(r.ruleId),s.push({id:r.ruleId,shortDescription:{text:r.description||r.ruleId},helpUri:r.helpUrl||void 0,defaultConfiguration:{level:It(r.impact)},properties:{tags:[r.wcagCriterion,`wcag-${r.wcagLevel}`]}}));const i=oe(e),c=n.map(r=>({ruleId:r.ruleId,level:It(r.impact),message:{text:`${r.description}`+(r.target.failureSummary?`
239
+ }`}function Io(e,t,n){var r;const o=((r=e.content.find(d=>d.type==="text"))==null?void 0:r.text)??"",i=o.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/),c=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;if(!i)return{verdict:"uncertain",reasoning:o||"AI returned no parseable response.",costUsd:c,model:e.model||n};try{const d=JSON.parse(i[0]);return{verdict:d.verdict==="pass"||d.verdict==="fail"?d.verdict:"uncertain",reasoning:typeof d.reasoning=="string"&&d.reasoning?d.reasoning:"AI returned no rationale.",costUsd:c,model:e.model||n}}catch{return{verdict:"uncertain",reasoning:o,costUsd:c,model:e.model||n}}}function Ro(e,t){var c;const n=((c=e.content.find(r=>r.type==="text"))==null?void 0:c.text)??"",s=n.replace(/```(?:json)?/g,"").trim().match(/\{[\s\S]*\}/),i=e.usage.input_tokens*t.input+e.usage.output_tokens*t.output;if(!s)return{lead:"",body:n||"Summary generation failed.",closer:"",costUsd:i,model:e.model};try{const r=JSON.parse(s[0]);return{lead:typeof r.lead=="string"?r.lead:"",body:typeof r.body=="string"?r.body:"",closer:typeof r.closer=="string"?r.closer:"",costUsd:i,model:e.model}}catch{return{lead:"",body:n,closer:"",costUsd:i,model:e.model}}}function Q(e){if(!e.enabled)return{ok:!1,reason:"AI augmentation is disabled in settings"};if(!e.apiKey)return{ok:!1,reason:"No API key configured"};switch(e.provider){case"anthropic":return{ok:!0,client:io({apiKey:e.apiKey,model:e.model})};case"openai":return{ok:!1,reason:"OpenAI provider not yet implemented"};case"gemini":return{ok:!1,reason:"Gemini provider not yet implemented"};default:return{ok:!1,reason:`Unknown provider: ${e.provider}`}}}function Z(e){const t={capUsd:Math.max(0,e),spentUsd:0,exceeded:!1};return{state:t,canCharge(){return!t.exceeded&&t.spentUsd<t.capUsd},recordCharge(n){t.spentUsd+=Math.max(0,n),t.spentUsd>=t.capUsd&&(t.exceeded=!0)}}}const Je=z("ai-compliance-summarizer");async function rn(e,t){if(!t.enabled)return null;const n=Q(t);if(!n.ok)return Je.debug(`AI client unavailable: ${n.reason}`),null;const o=Z(t.costCapUsd);if(!o.canCharge())return null;try{const s=await n.client.generateExecutiveSummary(e);return o.recordCharge(s.costUsd),!s.lead&&!s.body?(Je.debug("AI summary returned empty"),null):s}catch(s){return Je.warn("compliance-summary generation failed",s),null}}async function Oo(){const e=await chrome.storage.local.get("aiConfig");return ge(e.aiConfig)}function _o(){return D("AI_COMPLIANCE_SUMMARY_REQUEST",async e=>{const t=await Oo();if(!t.enabled)return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:null,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:null,unavailableReason:"No AI API key configured."};const n=await rn(e.input,t);return{type:"AI_COMPLIANCE_SUMMARY_RESPONSE",summary:n,unavailableReason:n?void 0:"AI summary generation returned no result."}})}const ee="wcag-component-auditor";function ce(){try{return chrome.runtime.getManifest().version}catch{return"0.0.0"}}function oe(e){const t=e[0];return t?t.pageUrl?t.pageUrl:t.scope&&/^https?:\/\//.test(t.scope)?t.scope:t.scope?`(selector: ${t.scope})`:"unknown":"unknown"}function Mo(e,t){return{schemaVersion:1,generatedAt:new Date().toISOString(),tool:{name:ee,version:ce()},results:e,delta:t}}function Rt(e){return e==="critical"||e==="serious"?"error":e==="moderate"?"warning":"note"}function Uo(e,t){const n=(t?t.new:e.flatMap(r=>r.violations)).filter(r=>!r.needsReview),o=new Set,s=[];for(const r of n)o.has(r.ruleId)||(o.add(r.ruleId),s.push({id:r.ruleId,shortDescription:{text:r.description||r.ruleId},helpUri:r.helpUrl||void 0,defaultConfiguration:{level:Rt(r.impact)},properties:{tags:[r.wcagCriterion,`wcag-${r.wcagLevel}`]}}));const i=oe(e),c=n.map(r=>({ruleId:r.ruleId,level:Rt(r.impact),message:{text:`${r.description}`+(r.target.failureSummary?`
240
240
 
241
241
  ${r.target.failureSummary}`:"")},locations:[{physicalLocation:{artifactLocation:{uri:i&&/^https?:\/\//.test(i)?`${i}#${r.target.selector}`:r.target.selector?`selector://${r.target.selector}`:"unknown"},region:{snippet:{text:r.target.outerHTML}}},logicalLocations:[{name:r.componentId,kind:"module"}]}],properties:{componentId:r.componentId,wcagCriterion:r.wcagCriterion,wcagLevel:r.wcagLevel,pseudoState:r.currentState.pseudoState,theme:r.currentState.theme,direction:r.currentState.direction,breakpoint:r.currentState.breakpoint.id,detectedAt:r.detectedAt}}));return{$schema:"https://json.schemastore.org/sarif-2.1.0.json",version:"2.1.0",runs:[{tool:{driver:{name:ee,version:ce(),informationUri:"https://wcagcheckr.com",rules:s}},results:c}]}}function cn(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function se(e){return cn(e).replace(/\n/g,"&#10;").replace(/\r/g,"&#13;")}function No(e,t){const n=!!t,o=l=>(n?l.violations.filter(p=>t.new.some(h=>h.matchKey===p.matchKey)):l.violations).filter(p=>!p.needsReview),s=e.reduce((l,p)=>l+Math.max(1,p.violations.length),0),i=e.reduce((l,p)=>l+o(p).length,0),c=e.reduce((l,p)=>l+p.durationMs,0)/1e3,r=[];r.push('<?xml version="1.0" encoding="UTF-8"?>');const d=`${ee} — ${oe(e)}`;r.push(`<testsuites name="${se(d)}" tests="${s}" failures="${i}" time="${c.toFixed(3)}">`);for(const l of e){const p=`${l.state.pseudoState}_${l.state.theme}_${l.state.direction}_${l.state.breakpoint.id}`,h=`${l.componentId}::${p}`,f=o(l),a=Math.max(1,l.violations.length);if(r.push(` <testsuite name="${se(h)}" tests="${a}" failures="${f.length}" time="${(l.durationMs/1e3).toFixed(3)}">`),l.violations.length===0)r.push(` <testcase classname="${se(h)}" name="no-violations" time="${(l.durationMs/1e3).toFixed(3)}" />`);else for(const g of l.violations){const u=f.some(k=>k.matchKey===g.matchKey),w=`classname="${se(h)}" name="${se(g.ruleId)}" time="0"`;if(!u){r.push(` <testcase ${w} />`);continue}const R=`${g.impact} - ${g.description}`,S=`Selector: ${g.target.selector}
242
242
  WCAG: ${g.wcagCriterion} (${g.wcagLevel})
@@ -416,10 +416,10 @@ ${g.target.failureSummary}`:"");r.push(` <testcase ${w}>`),r.push(` <fai
416
416
  Generated by ${ee} v${ce()}. Conformance assessed against all violations detected during the audit (not delta-filtered).
417
417
  </footer>
418
418
  </body>
419
- </html>`}function Do(e){const t=[],n=e.target.outerHTML;if(e.ruleId==="image-alt"||e.ruleId==="input-image-alt"||e.ruleId==="area-alt"||e.ruleId==="svg-img-alt"||e.ruleId==="object-alt"){const o=/\bsrc\s*=\s*"([^"]+)"|\bsrc\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Image source",value:`\`${o[1]??o[2]}\` — if you have vision capability, view this image and propose alt text. Use \`alt=""\` if it's decorative.`});const s=/<title>([^<]+)<\/title>/i.exec(n);s&&t.push({label:"Inline SVG <title>",value:s[1]})}if(e.ruleId==="button-name"||e.ruleId==="empty-button"||e.ruleId==="input-button-name"){const o=/\baria-label\s*=\s*"([^"]+)"/i.exec(n);o&&t.push({label:"Existing aria-label",value:o[1]});const s=/<svg[^>]*>[\s\S]*?<title>([^<]+)<\/title>/i.exec(n);s&&t.push({label:"SVG <title> inside",value:s[1]});const i=/<(?:i|svg|span)[^>]*class\s*=\s*"([^"]*(?:icon|fa-|material-icon)[^"]*)"/i.exec(n);i&&t.push({label:"Icon class hint",value:`\`${i[1]}\` — name suggests intent`})}if(e.ruleId==="link-name"||e.ruleId==="empty-link"){const o=/\bhref\s*=\s*"([^"]+)"|\bhref\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Link href",value:`\`${o[1]??o[2]}\` — destination may suggest the right link text`});const s=/\baria-label\s*=\s*"([^"]+)"/i.exec(n);s&&t.push({label:"Existing aria-label",value:s[1]})}if(e.ruleId==="label"||e.ruleId==="select-name"||e.ruleId==="aria-input-field-name"){const o=/\bname\s*=\s*"([^"]+)"|\bname\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Field name attribute",value:`\`${o[1]??o[2]}\` — often hints at the intended label`});const s=/\bplaceholder\s*=\s*"([^"]+)"|\bplaceholder\s*=\s*'([^']+)'/i.exec(n);s&&t.push({label:"Placeholder text (visible)",value:s[1]??s[2]});const i=/\btype\s*=\s*"([^"]+)"|\btype\s*=\s*'([^']+)'/i.exec(n);i&&t.push({label:"Input type",value:`\`${i[1]??i[2]}\``});const c=/\bautocomplete\s*=\s*"([^"]+)"|\bautocomplete\s*=\s*'([^']+)'/i.exec(n);c&&t.push({label:"Autocomplete",value:c[1]??c[2]})}return t}function Fo(e,t){var i;const n=new Set((t??[]).map(c=>`${c.pageUrl}::${c.ruleId}::${c.selector}`)),o=new Set,s=[];for(const c of e){const r=c.pageUrl??c.scope,d=((i=c.axeRulesEvaluated)==null?void 0:i.incomplete)??[];for(const l of d)for(const p of l.elements??[]){const h=`${r}::${l.ruleId}::${p.selector}`;o.has(h)||n.has(h)||(o.add(h),s.push({pageUrl:r,ruleId:l.ruleId,wcagCriterion:l.wcagCriterion,selector:p.selector,failureSummary:p.failureSummary,styles:p.styles}))}}return s}function Go(e,t,n,o,s,i){var b,$,O,A,v,T,V,j,F,B;const c=new Set(s??[]),r=((b=e[0])==null?void 0:b.componentId)??"unknown",d=oe(e),l=!!(t&&t.baselineSnapshotMeta),p=e.flatMap(m=>m.violations),h=new Map;for(const m of p){const U=m.ruleId.startsWith("ai-")?`${m.ruleId}::${m.target.selector}::${(m.target.outerHTML??"").slice(0,200)}`:xe(m.ruleId,m.target.selector),I=`${m.currentState.pseudoState} · ${m.currentState.theme} · ${m.currentState.direction} · ${m.currentState.breakpoint.id}`,G=h.get(U);if(G){G._states.includes(I)||G._states.push(I),G._instanceSelectors.includes(m.target.selector)||G._instanceSelectors.push(m.target.selector);continue}h.set(U,{...m,_states:[I],_instanceSelectors:[m.target.selector]})}const f=Array.from(h.values()).sort((m,U)=>{const I={critical:0,serious:1,moderate:2,minor:3};return(I[m.impact]??99)-(I[U.impact]??99)}),a=[];a.push("# Accessibility Fix Request"),a.push(""),a.push(`You are a senior accessibility engineer pairing with the user on their codebase. The component below has ${f.length} unique WCAG violation${f.length===1?"":"s"} detected by an automated audit running axe-core ${(($=e[0])==null?void 0:$.axeVersion)??"4.x"} across ${e.length} state combinations (hover, focus, focus-visible, active, disabled × dark / forced-colors / RTL / breakpoints). Your task: locate each violation in the codebase and apply the canonical fix — carefully, atomically, and asking before guessing.`),a.push("");const g=n&&n.length>0?{runs:n,workflows:Ee}:void 0,u=le(p,g,e);if(a.push("## Context"),a.push(""),a.push(`- **Component / scope:** \`${r}\``),a.push(`- **Audited URL:** ${d}`),a.push("- **WCAG target:** WCAG 2.1 AA + WCAG 2.2 AA + best-practice rules"),a.push("- **Source filter:** Full audit — every detected violation"),a.push(`- **Compliance posture:** Grade **${u.letter}** · **${u.risk.toUpperCase()} risk** (${u.totals.critical} critical · ${u.totals.serious} serious · ${u.totals.moderate} moderate · ${u.totals.minor} minor). ${u.risk==="critical"||u.risk==="high"?"Treat as triage priority — these violations represent meaningful lawsuit exposure under ADA Title III, EAA, and EN 301 549.":u.risk==="moderate"?"Should be addressed in the current sprint cycle; not lawsuit-emergency but real exposure.":"Lower exposure; still worth fixing but not blocking other work."}`),u.coverage){const m=u.coverage.untestedCriteria.length;m>0?a.push(`- **WCAG ${u.coverage.targetVersion} ${u.coverage.targetLevel} coverage:** ${u.coverage.evaluated} of ${u.coverage.totalApplicable} criteria evaluated. **Cannot claim ${u.coverage.targetLevel} conformance** until ${m} untested criteria are evaluated via Guided Tests (Pass / Fail / N/A). Untested: ${u.coverage.untestedCriteria.join(", ")}.`):a.push(`- **WCAG ${u.coverage.targetVersion} ${u.coverage.targetLevel} coverage:** ${u.coverage.evaluated} of ${u.coverage.totalApplicable} criteria evaluated. Full coverage — defensible conformance claim possible once all violations below are fixed.`)}l&&t&&a.push(`- **Trend vs your saved baseline:** ${t.newCount} new · ${t.persistentCount} carried over · ${t.fixedCount} resolved. The fix list below is the FULL current violation set, not just the delta.`),a.push(""),a.push("## Before you start (safety)"),a.push(""),a.push("Do these in order before making any code changes:"),a.push(""),a.push("1. **Verify a clean git working tree** (`git status`). If there are uncommitted changes, ask the user whether to commit, stash, or proceed."),a.push("2. **Switch to a feature branch** dedicated to this work — e.g., `a11y/fix-component-name`. Don't commit directly to `main` / `master` / `develop`."),a.push("3. **Plan one commit per fix.** Each violation gets its own atomic commit so any individual change can be reverted without untangling the rest. Commit messages should follow the pattern: `a11y: fix <ruleId> on <selector or component>`."),a.push("4. **Show diffs before applying** when your tooling supports it (Cursor / Copilot Chat agents). Never silently overwrite files."),a.push("5. **Do not bump dependencies** to resolve accessibility issues — fixes should be code changes, not package upgrades."),a.push(""),a.push("## Ask me these questions first"),a.push(""),a.push("Before applying any fix, ask the user the questions below. Don't proceed until you have answers — guessing here produces fixes that don't match the codebase's conventions and will be rejected on review."),a.push(""),a.push("1. **Framework + style approach?** React / Vue / Svelte / Angular / Solid / vanilla — and CSS Modules / Tailwind / styled-components / Emotion / scoped `<style>` / global CSS / design-tokens system. This determines *how* every fix is written."),a.push("2. **Existing design tokens or raw values?** If the codebase uses `var(--color-text-on-surface)` or a `tokens.ts` / `theme.json`, fixes must use tokens — never introduce new hex codes. Where can you read the available tokens?"),a.push('3. **Existing utility classes or component library?** e.g., does `.text-slate-700` or `<Button variant="primary">` already exist? Use what\'s there before inventing new selectors or components.'),a.push("4. **Files or directories that are off-limits?** Generated code, vendored libraries, third-party widgets, lockfiles — confirm what you must NOT touch."),a.push("5. **For color-contrast fixes: prefer adjusting foreground or background?** Brand color preservation is usually a stakeholder call, not a developer call."),a.push("6. **How should I verify fixes are done?** Re-run this auditor (preferred), run the existing test suite, manual screen-reader pass, or all three?"),a.push(""),a.push("## Decision rules (when ambiguity surfaces during fixes)"),a.push(""),a.push('- **Native HTML beats ARIA.** First rule of ARIA: don\'t use ARIA when a native element works. Prefer `<button>` over `<div role="button">`, `<nav>` over `<div role="navigation">`, etc.'),a.push("- **State-specific failures get state-specific fixes.** A `:hover`-only contrast failure goes in the `:hover` rule, not the default selector."),a.push("- **Where multiple valid fixes exist, surface options — don't pick silently.** E.g., adding an accessible name can be done via visible text, `aria-label`, or `aria-labelledby` referencing existing copy. Present the options with tradeoffs and let the user choose."),a.push("- **When the fix would alter visible design** (color shifts, layout changes, content additions), pause and confirm with the user before applying."),a.push(""),a.push("## ⛔ Do not dismiss findings without empirical verification"),a.push(""),a.push('**Default stance: every finding in this report is real and needs a fix.** Your job is to apply fixes, not to triage which ones "probably aren\'t real." That triage already happened — the auditor ran on a real browser, captured real DOM, real `getBoundingClientRect()` coordinates, real WCAG rule failures from axe-core. You are downstream of all that.'),a.push(""),a.push('Some categories (reading-order, tab-order) are explicitly heuristic and DO have legitimate false-positive cases. Those cases are listed inline in each section. **But "this looks like it might be a false positive based on the pattern" is not verification.** Pattern-matching from the report alone is inference, not evidence.'),a.push(""),a.push("**To dismiss any finding as a false positive, you must do all of the following:**"),a.push(""),a.push("1. **Load the deployed page in a real browser** at the viewport listed in the finding's capture-state header (e.g., 1280×800 LTR for the position-based analyses)."),a.push("2. **Inspect the flagged elements directly** — DevTools, real `getBoundingClientRect()` coordinates, real DOM source order."),a.push("3. **Compare your empirical observation to the auditor's claim.** Does the visual layout actually contradict the DOM order, or not?"),a.push("4. **If you conclude false positive, document why** — include the empirical evidence (coordinates, screenshots, DOM excerpt) so the user can audit your reasoning."),a.push(`5. **Even after empirical verification, ASK THE USER before dismissing.** They have context you don't (e.g., "yes that's an intentional skip-link / multi-column layout / RTL-only behavior").`),a.push(""),a.push("**What does NOT count as verification:**"),a.push(""),a.push("- Looking at the CSS file and not seeing `flex-direction: row-reverse` (the layout could be from `order:`, `grid-area`, absolute positioning, or RTL emulation)"),a.push('- Pattern-matching the finding shape ("this looks like a perfect arithmetic flip therefore it must be an RTL artifact")'),a.push(`- Reading the auditor's false-positive list and concluding your case "looks like one of those"`),a.push(`- Deciding it's "probably fine" because the structure looks reasonable on a quick read`),a.push(""),a.push("**If you cannot run a real browser** (e.g., environment doesn't allow headless Chromium), then you cannot verify, which means you cannot dismiss. In that case: surface the finding to the user, propose the fix, and let them decide."),a.push(""),a.push("**Skipping a finding without verification is worse than fixing one that turns out to be a false positive.** Over-fix is reversible (delete the commit). Under-fix is silent — the user thinks they're compliant when they aren't."),a.push(""),a.push("**When you DO verify a finding is a false positive** (per the empirical rules above), the right action is to recommend the user click **dismiss** on that finding in the auditor's Activity tab. The auditor records the dismissal with your reason, suppresses the finding from displayed counts, the Matrix banner, and future AI prompts. **Don't modify code to silence a verified false positive** — that produces brittle workarounds and pollutes the codebase with comments explaining heuristic quirks. Dismissals persist per-URL and survive re-audits cleanly."),a.push(""),a.push("## Content-decision rules (alt text, button labels, link text)"),a.push(""),a.push("Some violations require copy that the audit can't generate. Don't invent copy out of nowhere, but DON'T just punt to the user either — use the capabilities you have:"),a.push(""),a.push('1. **For images missing alt text** (`image-alt`, `input-image-alt`, `area-alt`, `svg-img-alt`): if you have vision capability, **fetch or view the image** at the `src` URL listed in the violation and PROPOSE descriptive alt text based on what the image actually contains. Mark obviously-decorative images (icons inside buttons that already have text labels, dividers, background flourishes) for `alt=""`.'),a.push('2. **For unlabeled buttons / links** (`button-name`, `link-name`, `empty-button`, `empty-link`): look at the surrounding code context — nearby text, the button\'s icon (often a known SVG name like "close" / "search" / "menu"), the route the link points at — and PROPOSE an accessible name. Show your inference reasoning.'),a.push("3. **For unlabeled form fields** (`label`, `select-name`, `aria-input-field-name`): inspect the field's `name`, `placeholder`, `id`, and any nearby visible text in the parent container. PROPOSE a label."),a.push("4. **For ambiguous content** (alt text where you genuinely can't tell what an image shows; labels where there's no surrounding context), ask the user — don't guess."),a.push("5. **Always show your proposed copy before applying** — let the user approve, edit, or reject."),a.push(""),a.push("## Constraints"),a.push(""),a.push("- Don't fix violations that aren't in this list (no scope creep)."),a.push(`- Don't reformat or reorder unrelated code. No "while I'm here" cleanup.`),a.push(`- Match existing code style. Don't invoke Prettier / ESLint to "fix everything" — focus your diff strictly on the violation's element + relevant style rule.`),a.push("- Don't add new dependencies, configs, or build steps."),a.push("- Add inline comments only where the fix's rationale is non-obvious; otherwise skip comments."),a.push("- Preserve existing functionality and visual design wherever possible."),a.push(""),a.push("## How to use this prompt"),a.push(""),a.push("Paste this into Claude / Cursor / Copilot Chat with your codebase open. The AI should:"),a.push('1. **First**: walk through the "Before you start" + "Ask me these questions" sections with the user.'),a.push("2. **Then**: identify the source files containing each violating element (use the selectors + outerHTML below)."),a.push("3. **Then**: for each violation, propose the fix using the recipe + answers gathered, surface ambiguity per the decision rules, and apply only after the user confirms."),a.push("4. **Finally**: produce one atomic commit per fix, with a clear message."),a.push(""),a.push("---"),a.push("");const w=(((O=e[0])==null?void 0:O.readingOrderIssues)??[]).filter(m=>!c.has(`reading-order::${m.selector}`)),R=(A=e[0])==null?void 0:A.positionAnalysisCapturedAt,S=R?`${R.breakpoint.width}×${R.breakpoint.height} (${R.breakpoint.label}), ${R.direction.toUpperCase()}, ${R.theme} theme, ${R.pseudoState} pseudo-state`:"(reference state unavailable — findings reflect last matrix state)";if(w.length>0){a.push("## Reading-order concerns (DOM ≠ visual order)"),a.push(""),a.push(`_Positions captured at: **${S}**. Multi-column layouts, RTL pages, and mobile-stacked sections may have legitimately different reading orders at other viewports — verify each finding against the layout the user actually sees._`),a.push(""),a.push(`Screen readers read the DOM in source order. CSS that visually rearranges things (\`flex-direction: row-reverse\`, \`order:\`, \`grid-area\`, absolute positioning) does NOT reorder what the SR sees. ${w.length} element${w.length===1?" has":"s have"} a notable gap between their DOM position and their visual position:`),a.push(""),a.push("| DOM index | Visual index | Selector | Text |"),a.push("|---|---|---|---|");for(const m of w){const U=m.textSnippet.replace(/\|/g,"\\|").replace(/\n/g," ");a.push(`| ${m.domIndex} | ${m.visualIndex} | \`${m.selector}\` | ${U} |`)}a.push(""),a.push("**How to fix:** match DOM order to intended reading order — reorder the JSX/HTML, NOT the CSS. CSS visual rearrangement is a code smell only because it diverges from DOM order; if the DOM order is what the user should hear, no fix is needed."),a.push(""),a.push("**False-positive cases — these are the ONLY legitimate reasons to skip a flagged element:**"),a.push(""),a.push('1. **Multi-column / newspaper layouts** — DOM order is "column 1 top to bottom, then column 2", which is correct for SR but reads as "out of order" to this analyzer.'),a.push('2. **Skip-links** ("Skip to main content") — visually positioned late but DOM-early on purpose.'),a.push("3. **Caption-first patterns** — captions placed before their image in DOM so SR users get context before the alt text."),a.push("4. **Modal / popover triggers** — the trigger button is DOM-near the modal's portal mount point, which is often `<body>` end."),a.push(""),a.push('**Per the verification rules above (§ "Do not dismiss findings without empirical verification"): even when a finding looks like one of these false-positive cases, you must verify in a real browser before skipping. "Looks like a multi-column layout" is inference, not proof.** Read the DOM. Get real coordinates. Then ask the user. Then skip if confirmed.'),a.push(""),a.push("Surface the candidates above to the user, ask which (if any) are intended, and only reorder the rest. **If in doubt, fix it.** Reordering JSX is reversible; failing a Level A criterion is not."),a.push(""),a.push("---"),a.push("")}const k=(((v=e[0])==null?void 0:v.tabOrderIssues)??[]).filter(m=>!c.has(`tab-order::${m.selector}`));if(k.length>0){const m=k.filter(I=>I.flag==="visual"||I.flag==="both").length,U=k.filter(I=>I.flag==="tabindex"||I.flag==="both").length;a.push("## Tab-order concerns (keyboard focus sequence ≠ visual order) — WCAG 2.4.3 Focus Order (A)"),a.push(""),a.push(`_Positions captured at: **${S}**. Tab-position-vs-visual-position divergence is direction- and breakpoint-sensitive — what looks wrong here may be correct on RTL or mobile (and vice versa). Verify each finding against the layout the user actually sees._`),a.push(""),a.push(`Keyboard users tab through the page in one order; sighted users scan in another. axe-core does not detect this. ${k.length} focusable element${k.length===1?" has":"s have"} a notable divergence. Of these: ${m} ${m===1?"has":"have"} a visual-vs-tab mismatch (focus jumps around the page); ${U} ${U===1?"is":"are"} caused by positive \`tabindex\` reordering DOM source.`),a.push(""),a.push("| Tab pos | Visual pos | DOM pos | Flag | Selector | Text |"),a.push("|---|---|---|---|---|---|");for(const I of k){const G=I.textSnippet.replace(/\|/g,"\\|").replace(/\n/g," ");a.push(`| ${I.tabPosition} | ${I.visualPosition} | ${I.domPosition} | ${I.flag} | \`${I.selector}\` | ${G} |`)}a.push(""),a.push("**How to fix:**"),a.push(""),a.push("- **`flag: visual`** — tab order doesn't match visual layout. Reorder the JSX/HTML so the DOM source order matches the layout order users see. Don't use `tabindex` to \"patch\" this — that creates the next class of bug."),a.push('- **`flag: tabindex`** — a positive `tabindex` value (`tabindex="3"`) is reordering DOM. Remove the positive `tabindex` and rely on DOM source order. Use `tabindex="0"` only to make a non-focusable element focusable; use `tabindex="-1"` only to remove from the tab order.'),a.push("- **`flag: both`** — both conditions present. Fix the DOM order first, then remove the positive `tabindex`."),a.push(""),a.push("**False-positive cases — these are the ONLY legitimate reasons to skip a flagged element:**"),a.push(""),a.push('1. **Skip-links** ("Skip to main content") — visually-late, DOM-early on purpose. Their tab position should be near 1; their visual position is wherever their `:focus` styling places them.'),a.push("2. **Modal triggers + portal-rendered modals** — the trigger button is DOM-near the modal's portal mount point (often `<body>` end), so tab/visual positions can legitimately diverge."),a.push("3. **Dropdown menus / popovers** — a button DOM-far from its portal-rendered menu may produce false positives when the menu is open."),a.push(""),a.push(`**Per the verification rules above (§ "Do not dismiss findings without empirical verification"): even when a finding looks like one of these cases, you must verify in a real browser before skipping. Tabbing through the actual deployed page is empirical evidence; reading the auditor's table and pattern-matching is not.** If in doubt, fix it. Reordering JSX is reversible; failing a Level A criterion is not.`),a.push(""),a.push("Surface candidates to the user; ask which are intended; only fix the rest."),a.push(""),a.push("---"),a.push("")}const E=e.flatMap(m=>m.announcements??[]),x=e.flatMap(m=>m.focusEvents??[]).filter(m=>m.isFocusReset);if(E.length>0||x.length>0){if(a.push("## Runtime behavioral observations"),a.push(""),E.length>0){const m=E.filter(I=>I.politeness==="assertive").length;a.push(`**Live-region announcements** (${E.length} total, ${m} assertive): screen-reader announcements captured during state-driving. WCAG 4.1.3 Status Messages (AA) requires that non-essential changes use polite announcements; only blocking errors warrant assertive. Review:`),a.push("");const U=E.slice(0,8);for(const I of U){const G=I.text.replace(/\|/g,"\\|").replace(/\n/g," ").slice(0,120);a.push(`- \`[${I.politeness}${I.role?`/${I.role}`:""}]\` ${G}`)}E.length>8&&a.push(`- (and ${E.length-8} more)`),a.push(""),a.push("Verify each is appropriate. Common bug: error messages firing as `polite` (SR may not interrupt), or status updates firing as `assertive` (interrupts user mid-sentence)."),a.push("")}if(x.length>0){a.push(`**Focus resets to body** (${x.length} occurrence${x.length===1?"":"s"}): during the audit, focus jumped to \`<body>\` or \`<html>\` unexpectedly. This is almost always a bug — focus should move to a logical landing place (modal, alert, next field), never disappear.`),a.push("");for(const m of x.slice(0,5))a.push(`- \`${m.fromSelector??"(none)"}\` → \`${m.toSelector}\``);x.length>5&&a.push(`- (and ${x.length-5} more)`),a.push(""),a.push("Common cause: an element is removed from the DOM (e.g., modal closes) without `.focus()` being called on a sensible destination."),a.push("")}a.push("---"),a.push("")}const _=((T=e[0])==null?void 0:T.undefinedCustomProperties)??[];if(_.length>0){a.push("## Undefined CSS custom properties (cascade root cause)"),a.push(""),a.push(`${_.length} CSS custom propert${_.length===1?"y is":"ies are"} referenced via \`var(--name)\` but never declared. When a custom property is missing, the browser falls back to the property's initial value (often \`Canvas\` for color slots → resolves to white), which can produce a wave of false contrast failures. **Fix these missing tokens FIRST** — many of the contrast violations below may disappear once the cascade resolves correctly.`),a.push(""),a.push("| Custom property | References | First sample sites |"),a.push("|---|---|---|");for(const m of _){const U=m.sampleSites.map(I=>`\`${I.selector} { ${I.property} }\``).join("; ");a.push(`| \`${m.name}\` | ${m.referenceCount} | ${U} |`)}a.push(""),a.push("Each entry needs a definition in `:root` (or wherever the design-token layer lives). Surface to the user before applying contrast fixes — the missing token may be the root cause."),a.push(""),a.push("---"),a.push("")}if(n&&n.length>0){a.push("## Manual checks already completed (Guided Tests)"),a.push(""),a.push(`The consultant has run ${n.length} Intelligent Guided Test workflow${n.length===1?"":"s"} against this component covering the WCAG criteria automation cannot verify (keyboard navigation, screen-reader experience, focus management, forms, error prevention, etc.). Treat the verdicts below as ground truth — these came from a human running the actual flow.`),a.push(""),a.push("**Manual passes outrank heuristic findings.** When an IGT workflow has passed (e.g. Keyboard 7/7) and the heuristic analyzers below (Tab-order concerns, Reading-order concerns) flag findings on the same WCAG dimension, the manual pass is ground truth. A human ran real keyboard/SR navigation against the deployed page; the heuristic computes visual position from `getBoundingClientRect()` and can produce false positives on sticky / multi-column / grid layouts. **When the IGT and the heuristic disagree on the same WCAG criterion, treat the heuristic findings as suspect first**, run the empirical verification described above, and (if confirmed false positive) recommend dismissal via the Activity tab."),a.push("");const m=Ee;a.push("| Workflow | Status | Notes |"),a.push("|---|---|---|");for(const W of n){const N=m.find(He=>He.id===W.workflowId);if(!N)continue;let H=0,K=0,je=0,ze=0,de=0;for(const He of N.steps){const Ae=W.steps[He.id];if(!Ae){de++;continue}Ae.status==="pass"?H++:Ae.status==="fail"?K++:Ae.status==="skip"?je++:Ae.status==="not-applicable"?ze++:de++}const On=K>0?`❌ ${K} failed`:de>0?`⚠ ${de} unanswered`:`✓ all ${N.steps.length} answered`,Oe=[`${H}p`,`${K}f`];ze>0&&Oe.push(`${ze} N/A`),je>0&&Oe.push(`${je} skip`),de>0&&Oe.push(`${de} unanswered`);const _n=`${Oe.join(" · ")} of ${N.steps.length} steps`;a.push(`| ${N.name} | ${On} | ${_n} |`)}a.push("");const U=[];for(const W of n){const N=m.find(H=>H.id===W.workflowId);if(N)for(const H of N.steps){const K=W.steps[H.id];(K==null?void 0:K.status)==="fail"&&U.push({workflow:N.name,stepTitle:H.question,notes:K.notes})}}if(U.length>0){a.push("**Failed manual checks** (these are real WCAG failures the consultant verified by hand):"),a.push("");for(const W of U)a.push(`- **${W.workflow} → ${W.stepTitle}**${W.notes?`: ${W.notes}`:""}`);a.push(""),a.push("**Address these alongside the automated violations below.** They will not appear in the violations list because no automated rule catches them — but they are still real WCAG failures and must be fixed for compliance."),a.push("")}const I=new Set(n.map(W=>W.workflowId)),G=m.filter(W=>!I.has(W.id));G.length>0&&(a.push(`**Not yet manually verified** (${G.length} workflow${G.length===1?"":"s"}): `+G.map(W=>W.name).join(", ")+". These cover WCAG criteria automation cannot detect; ask the consultant whether to run them before declaring the audit complete."),a.push("")),a.push("---"),a.push("")}if(o&&o.pagesAudited>1){const m=(()=>{try{return new URL(d).origin}catch{return null}})(),U=(()=>{try{return new URL(o.startUrl).origin}catch{return null}})();if(m&&U&&m===U){if(a.push("## Site-wide context (from a recent site crawl)"),a.push(""),a.push(`A recent crawl of ${o.pagesAudited} page${o.pagesAudited===1?"":"s"} on this origin produced grade **${o.siteGrade}** site-wide with **${o.totalUniqueViolations}** unique violations. Use this context for WCAG 3.2.3 (Consistent Navigation) and 3.2.4 (Consistent Identification) which require cross-page comparison.`),a.push(""),o.topViolations.length>0){a.push("**Most-frequent violations across the site** (rules to prioritize because they affect multiple pages):"),a.push("");for(const I of o.topViolations.slice(0,6))a.push(`- \`${I.ruleId}\` — ${I.impact} — found on ${I.urlsAffected} page${I.urlsAffected===1?"":"s"} (${I.totalOccurrences} total instances)`);a.push(""),a.push("Fixing one of these rules in shared components / layouts is leverage — one fix resolves N pages."),a.push("")}a.push("**Manual cross-page checks the AI should walk through:**"),a.push(""),a.push("- **3.2.3 Consistent Navigation** — verify primary nav appears in the same DOM order on every page audited above. Inconsistent ordering between pages is a Level AA failure."),a.push('- **3.2.4 Consistent Identification** — verify components with identical functionality (logo "home" link, search button, menu toggle) have identical accessible names across pages.'),a.push("- **3.2.6 Consistent Help (WCAG 2.2 A)** — verify any help mechanism (chat widget, contact link, FAQ link) appears in the same relative position on every page that has one."),a.push(""),a.push("---"),a.push("")}}a.push("## Violations to fix"),a.push(""),f.forEach((m,U)=>{const I=Vn[m.ruleId],G=m._instanceSelectors.length;if(a.push(`### ${U+1}. \`${m.ruleId}\` — ${m.impact} — WCAG ${m.wcagCriterion} ${m.wcagLevel}${G>1?` (${G} instances)`:""}`),a.push(""),a.push(`**Description:** ${m.description}`),a.push(""),G>1){a.push(`**Affects ${G} spots — fix the rule once, applies to all:**`);for(const H of m._instanceSelectors.slice(0,8))a.push(`- \`${H}\``);m._instanceSelectors.length>8&&a.push(`- (and ${m._instanceSelectors.length-8} more)`)}else a.push(`**Selector:** \`${m.target.selector}\``);a.push(""),a.push(`**Found in state(s):** ${m._states.join(" / ")}`),a.push("");const W=Do(m);if(W.length>0){for(const H of W)a.push(`**${H.label}:** ${H.value}`);a.push("")}m.target.failureSummary&&(a.push(`**Diagnostic:** ${m.target.failureSummary.replace(/\n+/g," ")}`),a.push("")),m.ai&&(a.push(`**🤖 AI-verified finding** (model: ${m.ai.model}, confidence: ${(m.ai.confidence*100).toFixed(0)}%)`),a.push(`> ${m.ai.reasoning}`),a.push(""));const N=m.target.cascadeChain;if(N&&(N.color||N.backgroundColor)){if(a.push("**CSS cascade chain (authored → rendered):**"),N.color){const H=N.color.vars.length>0?` (vars: ${N.color.vars.map(K=>`\`${K}\``).join(", ")})`:"";a.push(`- \`color\`: \`${N.color.authored}\` → \`${N.color.rendered}\`${H}${N.color.ruleSelector?` — set in rule \`${N.color.ruleSelector}\``:""}`)}if(N.backgroundColor){const H=N.backgroundColor.vars.length>0?` (vars: ${N.backgroundColor.vars.map(K=>`\`${K}\``).join(", ")})`:"";a.push(`- \`background-color\`: \`${N.backgroundColor.authored}\` → \`${N.backgroundColor.rendered}\`${H}${N.backgroundColor.ruleSelector?` — set in rule \`${N.backgroundColor.ruleSelector}\``:""}`)}a.push("")}a.push("**Element HTML:**"),a.push("```html"),a.push(m.target.outerHTML),a.push("```"),a.push(""),I?(a.push(`**Recipe:** ${I.summary}`),I.snippet&&(a.push(""),a.push("```"+(I.snippetLang??"")),a.push(I.snippet),a.push("```"))):a.push(`**Recipe:** No curated recipe for this rule — apply the standard WCAG ${m.wcagCriterion} guidance.`),m.helpUrl&&(a.push(""),a.push(`**More info:** ${m.helpUrl}`)),a.push(""),a.push("---"),a.push("")});const L=Fo(e,i);if(L.length>0){a.push("## Items axe couldn't determine — needs human review"),a.push(""),a.push("axe-core ran these rules but couldn't conclude pass/fail (the most common cause is color-contrast on a gradient / image / semi-transparent background). For each element below: if you have vision capability, sample the rendered background and compute the contrast ratio; otherwise ask the user to verify visually."),a.push("");for(const m of L)a.push(`### \`${m.ruleId}\` on \`${m.selector}\``),a.push(""),a.push(`- **WCAG criterion:** ${m.wcagCriterion}`),a.push(`- **Page URL:** ${m.pageUrl}`),m.failureSummary&&a.push(`- **axe diagnostic:** ${m.failureSummary}`),(V=m.styles)!=null&&V.foreground&&a.push(`- **Foreground:** \`${m.styles.foreground}\``),(j=m.styles)!=null&&j.background&&a.push(`- **Background:** \`${m.styles.background}\``),(F=m.styles)!=null&&F.fontSize&&a.push(`- **Font size:** ${m.styles.fontSize}px, weight ${m.styles.fontWeight??"unknown"}`),(B=m.styles)!=null&&B.textSample&&a.push(`- **Text sample:** ${JSON.stringify(m.styles.textSample)}`),a.push(""),a.push("---"),a.push("")}return a.push("## Manual verification checklist — non-automatable WCAG 2.1 / 2.2 AA criteria"),a.push(""),a.push("Automated audits catch ~30–50% of WCAG criteria. The remaining ~50% require human judgment, multi-page comparison, or runtime interaction we cannot script. **After applying the fixes above, walk the user through each item below before declaring the audit complete.** Mark each one passed, failed (and add to the fix queue), or N/A (with reasoning)."),a.push(""),a.push('Items the auditor has already flagged in earlier sections (reading-order, tab-order, behavioral observations, IGT manual checks) are listed below as "ALREADY FLAGGED" — confirm those fixes are in place.'),a.push(""),a.push("### Perceivable"),a.push(""),a.push("- [ ] **1.2.1 Audio-only / Video-only Prerecorded (A)** — every audio-only file has a text transcript; every silent-video file has a text alternative or audio description. Ask the user: does the page have media? If yes, list each `<audio>` / `<video>` and verify the alternative."),a.push('- [ ] **1.2.2 Captions Prerecorded (A)** — every prerecorded video with audio has synchronized captions. If `<video>` elements exist without `<track kind="captions">`, ask the user about caption files.'),a.push("- [ ] **1.2.3 Audio Description / Media Alternative Prerecorded (A)** — prerecorded video has either audio description or a full text alternative."),a.push("- [ ] **1.2.4 Captions Live (AA)** — live audio content (livestream, real-time meeting) has captions. Usually N/A for static sites."),a.push("- [ ] **1.2.5 Audio Description Prerecorded (AA)** — prerecorded video has audio description for visual-only information."),a.push("- [ ] **1.4.2 Audio Control (A)** — if any audio plays automatically for >3 seconds, there is a mechanism to pause / stop / control volume. Test by loading the page; if anything autoplays audibly, fail."),a.push("- [ ] **1.4.4 Resize Text (AA)** — zoom the browser to 200%. All text remains readable; nothing is cut off. No horizontal scrolling within content blocks."),a.push("- [ ] **1.4.5 Images of Text (AA)** — confirm text is rendered as actual text, not as images. Exceptions: logos, brand wordmarks. Walk the user through their hero / heading sections."),a.push("- [ ] **1.4.10 Reflow (AA)** — resize browser to 320px wide × 256px tall. Page is usable; no horizontal scrollbar appears (except for data tables / maps / code)."),a.push("- [ ] **1.4.12 Text Spacing (AA)** — apply user-stylesheet overrides: line-height ≥1.5×; paragraph spacing ≥2×; letter-spacing ≥0.12×; word-spacing ≥0.16×. Layout doesn't break, no clipped/overlapping text."),a.push("- [ ] **1.4.13 Content on Hover or Focus (AA)** — for any tooltip / popover / hover-revealed content: verify it is *dismissible* (Esc closes), *hoverable* (mouse can move into it without it disappearing), and *persistent* (doesn't auto-disappear unless user dismisses)."),a.push(""),a.push("### Operable"),a.push(""),a.push("- [ ] **2.1.2 No Keyboard Trap (A)** — Tab through the entire page from start to finish; verify focus never gets stuck in a region you can't leave with Tab/Shift+Tab/Esc. Common offenders: video players, custom widgets, modals without proper Esc handling."),a.push('- [ ] **2.1.4 Character Key Shortcuts (A)** — if the site implements single-key shortcuts (pressing "j" advances feed, etc.), they must be either turn-off-able OR only active when focus is on a specific control. Ask the user about implemented shortcuts.'),a.push('- [ ] **2.2.1 Timing Adjustable (A)** — if any timeout exists (auto-logout, session expiry, "complete this in X seconds"), user can turn it off, adjust it, or extend it (≥10× the default). Exception: real-time events. Ask the user.'),a.push("- [ ] **2.2.2 Pause, Stop, Hide (A)** — for moving / blinking / scrolling / auto-updating content lasting >5s: there is a mechanism to pause/stop/hide it. Carousels, tickers, animations, autoplaying video — all need controls."),a.push("- [ ] **2.3.1 Three Flashes or Below Threshold (A)** — no content flashes more than 3× per second. Test with anything that pulses, blinks, or has rapid color changes (loading animations, alert flashing). Use https://trace.umd.edu/peat/ for borderline cases."),k.length>0?a.push("- [x] **2.4.3 Focus Order (A)** — ALREADY FLAGGED above (`Tab-order concerns` section). Confirm fixes are in place."):a.push("- [ ] **2.4.3 Focus Order (A)** — auto-detector flagged 0 issues, but spot-check by tabbing through the page: focus visits elements in a logical order (matches visual / semantic flow)."),a.push("- [ ] **2.4.5 Multiple Ways (AA)** — at least two ways to find any page within a set: site search + nav menu, OR menu + sitemap, OR menu + table of contents, etc. Single-page apps may exempt; ask user."),a.push("- [ ] **2.5.1 Pointer Gestures (A)** — any multi-point gesture (pinch-zoom, two-finger swipe) or path-based gesture (signature, drag-along-curve) has a single-pointer alternative. Common offender: maps, signatures, drawing canvases."),a.push("- [ ] **2.5.2 Pointer Cancellation (A)** — actions trigger on the up-event (mouseup / pointerup), NOT the down-event. Pressing then dragging-away cancels. Test by mouse-down on a button → drag off → release: action should not fire."),a.push("- [ ] **2.5.4 Motion Actuation (A)** — features triggered by device motion (shake-to-undo, tilt-to-scroll) can be disabled AND have UI-button alternatives. Usually N/A for desktop sites."),a.push("- [ ] **2.5.7 Dragging Movements (AA, WCAG 2.2)** — any drag-only operation (kanban board, slider) has a non-drag alternative (buttons, click-to-place). Test sliders, drag-and-drop, sortable lists."),a.push(""),a.push("### Understandable"),a.push(""),a.push("- [ ] **3.2.1 On Focus (A)** — focusing any element does NOT trigger a context change (URL change, viewport scroll, modal open, form submit). Tab through every focusable element; verify none cause unexpected behavior."),a.push("- [ ] **3.2.2 On Input (A)** — changing the value of any form control does NOT trigger context change unless the user was warned. Common offender: `<select onChange={navigate}>` — must include adjacent submit button or warn the user."),o&&o.pagesAudited>1?(a.push("- [x] **3.2.3 Consistent Navigation (AA)** — site-crawl context provided above. Walk the user through verifying nav appears in the same order across pages."),a.push("- [x] **3.2.4 Consistent Identification (AA)** — verify components with the same function have the same accessible name across pages (logo home link, search button, menu toggle).")):(a.push("- [ ] **3.2.3 Consistent Navigation (AA)** — REQUIRES MULTI-PAGE COMPARISON. Ask the user for 2-3 representative pages; verify primary nav, footer, and search appear in the same DOM order on each."),a.push('- [ ] **3.2.4 Consistent Identification (AA)** — REQUIRES MULTI-PAGE COMPARISON. Components with identical functionality must have identical accessible names. Compare logo "home" link, search button, menu toggle across pages.')),a.push("- [ ] **3.2.6 Consistent Help (A, WCAG 2.2)** — REQUIRES MULTI-PAGE COMPARISON. If a help mechanism exists (chat, contact link, FAQ), it appears in the same relative order on every page where it appears."),a.push("- [ ] **3.3.4 Error Prevention — Legal, Financial, Data (AA)** — for any form that submits legal commitments (contracts, agreement), financial transactions (payments), or modifies/deletes user data: there is at least ONE of (a) reversibility, (b) error-checking with confirmation, (c) review-and-confirm step before final submit."),a.push("- [ ] **3.3.7 Redundant Entry (A, WCAG 2.2)** — forms in a multi-step process do NOT ask for the same information twice unless essential (re-entering password for confirmation is allowed). Auto-fill or pre-fill where possible."),a.push("- [ ] **3.3.8 Accessible Authentication — Minimum (AA, WCAG 2.2)** — login does not require a cognitive function test (puzzle, riddle, character-recognition) unless an alternative is provided (object recognition + autofill support are allowed; CAPTCHAs that require pattern recognition typically fail)."),a.push(""),a.push("### Robust"),a.push(""),E.length>0||x.length>0?a.push("- [x] **4.1.3 Status Messages (AA)** — runtime observations provided above (`Runtime behavioral observations` section). Confirm announcements use appropriate `aria-live` politeness and focus management is correct."):a.push('- [ ] **4.1.3 Status Messages (AA)** — status updates that don\'t cause a focus change (form-validation errors, "saved" confirmations, search-result counts) must use `role="status"` (polite) or `role="alert"` (assertive). Ask the user to demo their form-error and async-update flows; verify SR announces them.'),a.push(""),a.push("### Manual checks STILL TO DO"),a.push(""),a.push(`Walk the user through each unchecked box above (or batch them by criterion type — "let's test all the keyboard ones together"). For each: either mark passed (and move on), failed (add to the fix queue and resolve), or N/A (briefly justify why this site doesn't require this criterion).`),a.push(""),a.push('**Do not declare the audit complete until every box above is checked.** A site that passes only the automated portion is "axe-clean," not WCAG-compliant.'),a.push(""),a.push("---"),a.push(""),a.push("## When you're done — verification"),a.push(""),a.push("Before reporting completion, do all of the following:"),a.push(""),a.push(`1. **Confirm all ${f.length} violation${f.length===1?"":"s"} above are addressed.** Walk back through the list with the user, ticking each one off.`),a.push("2. **Re-run the auditor** (or whatever method we agreed in question 6 above). Verify zero NEW violations were introduced by the fixes."),a.push(`3. **Walk through the Manual verification checklist above** — every item should be marked passed, failed-and-fixed, or N/A. This is the half of WCAG that automation can't reach; skipping it means "axe-clean," not "compliant."`),a.push("4. **Visual diff** — for design-affecting fixes (color, spacing, layout), confirm the change with the user against the original. Storybook stories and visual regression suites are good checkpoints if the codebase has them."),a.push("5. **Commit log review** — surface the list of commits you produced. Each should be atomic and revertable."),a.push("6. **Report what you couldn't do** explicitly. If any violation required information we don't have (e.g., correct alt text), surface a TODO list for the user rather than guessing."),a.push(""),a.push("## Success criteria"),a.push(""),a.push("- All "+f.length+" violation"+(f.length===1?"":"s")+" above are resolved or explicitly deferred with reason."),a.push('- **Every reading-order and tab-order finding** is either fixed OR documented as a verified false positive (per § "Do not dismiss findings without empirical verification" above). Pattern-matching dismissals do not count.'),a.push('- **Every item in the manual verification checklist** above is marked passed, failed-and-fixed, or N/A-with-reason. (This is what separates "axe-clean" from "WCAG-compliant" — do not skip.)'),a.push("- No new violations introduced."),a.push("- State-specific behavior preserved (`:hover`, `:focus`, dark-mode, RTL, breakpoints)."),a.push("- One atomic commit per fix; clean revertable history."),a.push("- No unrelated code reformatted, no dependencies bumped."),a.push("- Diff is reviewable in under 10 minutes per fix."),a.push(""),a.push(`_Generated by ${ee} v${ce()}._`),a.join(`
420
- `)}const Wo=5;function Vo(e){const t=new Map;let n=0;for(const o of e){if(!o.screenshotDataUrl||o.violations.length===0)continue;const s=`${o.state.pseudoState} · ${o.state.theme} · ${o.state.direction} · ${o.state.breakpoint.id}`,i=s;t.has(i)||t.set(i,{stateLabel:s,screenshotDataUrl:o.screenshotDataUrl,violations:[]});const c=t.get(i);for(const r of o.violations)n++,c.violations.push({...r,_idx:n})}return Array.from(t.values()).sort((o,s)=>s.violations.length-o.violations.length).slice(0,Wo)}const Rt=1280,Ot=800,jo={low:"Low risk",moderate:"Moderate risk",high:"High risk",critical:"Critical risk"},zo={low:"#d1fae5",moderate:"#fef3c7",high:"#fed7aa",critical:"#fecaca"},Ho={low:"#065f46",moderate:"#92400e",high:"#9a3412",critical:"#991b1b"},Bo={A:"#10b981",B:"#84cc16",C:"#eab308",D:"#f97316",F:"#dc2626"},qo={defense:{title:"Accessibility Defense Bundle",documentLabel:"engineering, design, and risk-management",disclaimerHeading:"This document is not a compliance certification.",disclaimerBody:"Automated accessibility audits, including this one, detect a subset (typically 30–50%) of WCAG success criteria. Conformance with the full WCAG specification requires manual evaluation by qualified accessibility professionals, including (but not limited to): keyboard-only operability testing, screen-reader compatibility testing across NVDA / JAWS / VoiceOver, manual review of dynamic content and live regions, and content-quality review for alt text, link text, and labels."},evidence:{title:"Accessibility Compliance Evidence",documentLabel:"documentation and review",disclaimerHeading:"This document is automated audit evidence — not a determination of liability or conformance.",disclaimerBody:"This report documents detected accessibility defects in the audited resource at the date and time of capture. The audit was conducted using axe-core, an industry-standard automated accessibility-rule engine maintained by Deque Systems and used by Microsoft (Accessibility Insights), Google (Lighthouse), IBM, and others. The findings represent objective rule-engine output, not subjective evaluation. Automated audits surface a subset (typically 30–50%) of WCAG success criteria; the absence of a violation in this report is not evidence of conformance, and the presence of a violation is not, by itself, a determination of legal liability."}};function Ko(e,t,n,o,s){return pn(e,t,"evidence",n,o,s)}function Yo(e){return un(e,"letter")}function Jo(e){return un(e,"report")}function Xo(e){var l;const t=e.flatMap(p=>p.violations),n=le(t,void 0,e),o=oe(e),s=new Map;for(const p of t){const h=xe(p.ruleId,p.target.selector);s.has(h)||s.set(h,p)}const i=Array.from(s.values()).sort((p,h)=>{const f={critical:0,serious:1,moderate:2,minor:3};return(f[p.impact]??99)-(f[h.impact]??99)}),c=new Map;for(const p of i){const h=c.get(p.ruleId)??[];h.push(p),c.set(p.ruleId,h)}const r=[];if(r.push("# Help me fix accessibility issues on my website"),r.push(""),r.push("You are an accessibility advisor helping me — a non-technical site owner — understand and fix accessibility issues on my website. I ran an automated audit and got the issues below. I may not have technical knowledge, so please explain things in plain English."),r.push(""),r.push("## What I need from you"),r.push(""),r.push("1. **First, ask me what I use to manage my website.** Common platforms: Squarespace, Wix, Shopify, WordPress (with theme name), Webflow, Framer, custom-built. Your advice will be different for each."),r.push("2. **Then, for each issue below, tell me clearly:**"),r.push(" - Whether **I can fix it myself** in my site editor (changing colors, adding alt text, editing button labels, etc.) — and if so, walk me through where to look in my platform"),r.push(" - Or whether **my developer needs to do this** (code-level fix) — and what to ask them to do"),r.push("3. **Prioritize ruthlessly.** I want to start with the issues that:"),r.push(" - Are most likely to come up in an ADA-related lawsuit (critical-impact items)"),r.push(" - Are easiest for me to fix without involving a developer"),r.push("4. **Don't bury me in jargon.** If you have to use a technical term, explain it in plain English first."),r.push("5. **If something is genuinely beyond a non-technical fix, say so.** Tell me what to ask my developer or website-builder support team."),r.push(""),r.push("## Audit summary"),r.push(""),r.push(`- **Page audited:** ${o}`),r.push(`- **Lawsuit-target risk:** ${jt[n.risk]} — ${zt[n.risk]}`),r.push(`- **Issues found:** ${n.totals.unique} unique problems (${n.totals.critical} critical · ${n.totals.serious} serious · ${n.totals.moderate} moderate · ${n.totals.minor} minor)`),n.coverage&&n.coverage.untestedCriteria.length>0?r.push(`- **WCAG conformance progress:** ${n.coverage.evaluated} of ${n.coverage.totalApplicable} criteria evaluated. Fixing the issues below will clear me of automated lawsuit-targeting tools. To make a formal claim that the site meets WCAG ${n.coverage.targetVersion} ${n.coverage.targetLevel}, ${n.coverage.untestedCriteria.length} more criteria need human review — see the "Guided Tests" workflows in the auditor side panel for these.`):n.coverage&&n.coverage.untestedCriteria.length===0&&r.push(`- **WCAG conformance:** All ${n.coverage.totalApplicable} applicable WCAG ${n.coverage.targetVersion} ${n.coverage.targetLevel} criteria have been evaluated. Fixing the issues below will produce a defensible conformance claim.`),r.push(""),r.push("## The issues, in plain language"),r.push(""),c.size===0)return r.push("No automated issues were detected. Note: automated checks only catch about 30–50% of accessibility problems. Manual testing covers the rest."),r.join(`
421
- `);let d=1;for(const[p,h]of c.entries()){const f=(l=h.find(u=>u.target.opacityContext))==null?void 0:l.target.opacityContext,a=Vt(p,f),g=h[0].impact;r.push(`### ${d}. [${g.toUpperCase()}] ${a.whatsWrong}`),r.push(""),r.push(`**Why this matters.** ${a.whyItMatters}`),r.push(""),r.push(`**Plain-language fix guidance.** ${a.howToFix}`),r.push(""),r.push(`**Where on the page (${h.length} ${h.length===1?"spot":"spots"}):**`);for(const u of h.slice(0,8))r.push(`- \`${u.target.selector}\``);h.length>8&&r.push(`- (and ${h.length-8} more spots)`),r.push(""),r.push(`*Technical reference for your developer:* axe-core rule \`${p}\` — full docs at https://dequeuniversity.com/rules/axe/4.11/${p}`),r.push(""),d++}return r.push("---"),r.push(""),r.push("## How to use this output"),r.push(""),r.push("Walk through this list with me one issue at a time. For each:"),r.push("1. Help me understand the issue with a real example of who it affects."),r.push("2. Tell me clearly if I can fix it myself, and if so, walk me through it for my platform."),r.push("3. If I need a developer, give me a short paragraph I can paste into an email or message to them."),r.push("4. Help me prioritize — I have limited time and want to fix the riskiest things first."),r.push(""),r.push("Start by asking me which platform I use."),r.join(`
422
- `)}function un(e,t){const n=e.flatMap(f=>f.violations),o=le(n,void 0,e),s=oe(e),i=new Date,c=new Map;for(const f of n){const a=xe(f.ruleId,f.target.selector);c.has(a)||c.set(a,f)}const r=Array.from(c.values()).sort((f,a)=>{const g={critical:0,serious:1,moderate:2,minor:3};return(g[f.impact]??99)-(g[a.impact]??99)}),d=new Map;for(const f of r){const a=d.get(f.ruleId)??[];a.push(f),d.set(f.ruleId,a)}const l=Array.from(d.entries()).map(([f,a])=>{var k;const g=(k=a.find(E=>E.target.opacityContext))==null?void 0:k.target.opacityContext,u=Vt(f,g),w=a[0].impact,R=a.slice(0,8).map(E=>`<code>${y(E.target.selector)}</code>`).join(", "),S=a.length>8?` <em>(and ${a.length-8} more)</em>`:"";return`
419
+ </html>`}function Do(e){const t=[],n=e.target.outerHTML;if(e.ruleId==="image-alt"||e.ruleId==="input-image-alt"||e.ruleId==="area-alt"||e.ruleId==="svg-img-alt"||e.ruleId==="object-alt"){const o=/\bsrc\s*=\s*"([^"]+)"|\bsrc\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Image source",value:`\`${o[1]??o[2]}\` — if you have vision capability, view this image and propose alt text. Use \`alt=""\` if it's decorative.`});const s=/<title>([^<]+)<\/title>/i.exec(n);s&&t.push({label:"Inline SVG <title>",value:s[1]})}if(e.ruleId==="button-name"||e.ruleId==="empty-button"||e.ruleId==="input-button-name"){const o=/\baria-label\s*=\s*"([^"]+)"/i.exec(n);o&&t.push({label:"Existing aria-label",value:o[1]});const s=/<svg[^>]*>[\s\S]*?<title>([^<]+)<\/title>/i.exec(n);s&&t.push({label:"SVG <title> inside",value:s[1]});const i=/<(?:i|svg|span)[^>]*class\s*=\s*"([^"]*(?:icon|fa-|material-icon)[^"]*)"/i.exec(n);i&&t.push({label:"Icon class hint",value:`\`${i[1]}\` — name suggests intent`})}if(e.ruleId==="link-name"||e.ruleId==="empty-link"){const o=/\bhref\s*=\s*"([^"]+)"|\bhref\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Link href",value:`\`${o[1]??o[2]}\` — destination may suggest the right link text`});const s=/\baria-label\s*=\s*"([^"]+)"/i.exec(n);s&&t.push({label:"Existing aria-label",value:s[1]})}if(e.ruleId==="label"||e.ruleId==="select-name"||e.ruleId==="aria-input-field-name"){const o=/\bname\s*=\s*"([^"]+)"|\bname\s*=\s*'([^']+)'/i.exec(n);o&&t.push({label:"Field name attribute",value:`\`${o[1]??o[2]}\` — often hints at the intended label`});const s=/\bplaceholder\s*=\s*"([^"]+)"|\bplaceholder\s*=\s*'([^']+)'/i.exec(n);s&&t.push({label:"Placeholder text (visible)",value:s[1]??s[2]});const i=/\btype\s*=\s*"([^"]+)"|\btype\s*=\s*'([^']+)'/i.exec(n);i&&t.push({label:"Input type",value:`\`${i[1]??i[2]}\``});const c=/\bautocomplete\s*=\s*"([^"]+)"|\bautocomplete\s*=\s*'([^']+)'/i.exec(n);c&&t.push({label:"Autocomplete",value:c[1]??c[2]})}return t}function Fo(e,t){var i;const n=new Set((t??[]).map(c=>`${c.pageUrl}::${c.ruleId}::${c.selector}`)),o=new Set,s=[];for(const c of e){const r=c.pageUrl??c.scope,d=((i=c.axeRulesEvaluated)==null?void 0:i.incomplete)??[];for(const l of d)for(const p of l.elements??[]){const h=`${r}::${l.ruleId}::${p.selector}`;o.has(h)||n.has(h)||(o.add(h),s.push({pageUrl:r,ruleId:l.ruleId,wcagCriterion:l.wcagCriterion,selector:p.selector,failureSummary:p.failureSummary,styles:p.styles}))}}return s}function Go(e,t,n,o,s,i){var b,T,O,A,v,C,V,j,F,B;const c=new Set(s??[]),r=((b=e[0])==null?void 0:b.componentId)??"unknown",d=oe(e),l=!!(t&&t.baselineSnapshotMeta),p=e.flatMap(m=>m.violations),h=new Map;for(const m of p){const U=m.ruleId.startsWith("ai-")?`${m.ruleId}::${m.target.selector}::${(m.target.outerHTML??"").slice(0,200)}`:Ee(m.ruleId,m.target.selector),I=`${m.currentState.pseudoState} · ${m.currentState.theme} · ${m.currentState.direction} · ${m.currentState.breakpoint.id}`,G=h.get(U);if(G){G._states.includes(I)||G._states.push(I),G._instanceSelectors.includes(m.target.selector)||G._instanceSelectors.push(m.target.selector);continue}h.set(U,{...m,_states:[I],_instanceSelectors:[m.target.selector]})}const f=Array.from(h.values()).sort((m,U)=>{const I={critical:0,serious:1,moderate:2,minor:3};return(I[m.impact]??99)-(I[U.impact]??99)}),a=[];a.push("# Accessibility Fix Request"),a.push(""),a.push(`You are a senior accessibility engineer pairing with the user on their codebase. The component below has ${f.length} unique WCAG violation${f.length===1?"":"s"} detected by an automated audit running axe-core ${((T=e[0])==null?void 0:T.axeVersion)??"4.x"} across ${e.length} state combinations (hover, focus, focus-visible, active, disabled × dark / forced-colors / RTL / breakpoints). Your task: locate each violation in the codebase and apply the canonical fix — carefully, atomically, and asking before guessing.`),a.push("");const g=n&&n.length>0?{runs:n,workflows:ke}:void 0,u=le(p,g,e);if(a.push("## Context"),a.push(""),a.push(`- **Component / scope:** \`${r}\``),a.push(`- **Audited URL:** ${d}`),a.push("- **WCAG target:** WCAG 2.1 AA + WCAG 2.2 AA + best-practice rules"),a.push("- **Source filter:** Full audit — every detected violation"),a.push(`- **Compliance posture:** Grade **${u.letter}** · **${u.risk.toUpperCase()} risk** (${u.totals.critical} critical · ${u.totals.serious} serious · ${u.totals.moderate} moderate · ${u.totals.minor} minor). ${u.risk==="critical"||u.risk==="high"?"Treat as triage priority — these violations represent meaningful lawsuit exposure under ADA Title III, EAA, and EN 301 549.":u.risk==="moderate"?"Should be addressed in the current sprint cycle; not lawsuit-emergency but real exposure.":"Lower exposure; still worth fixing but not blocking other work."}`),u.coverage){const m=u.coverage.untestedCriteria.length;m>0?a.push(`- **WCAG ${u.coverage.targetVersion} ${u.coverage.targetLevel} coverage:** ${u.coverage.evaluated} of ${u.coverage.totalApplicable} criteria evaluated. **Cannot claim ${u.coverage.targetLevel} conformance** until ${m} untested criteria are evaluated via Guided Tests (Pass / Fail / N/A). Untested: ${u.coverage.untestedCriteria.join(", ")}.`):a.push(`- **WCAG ${u.coverage.targetVersion} ${u.coverage.targetLevel} coverage:** ${u.coverage.evaluated} of ${u.coverage.totalApplicable} criteria evaluated. Full coverage — defensible conformance claim possible once all violations below are fixed.`)}l&&t&&a.push(`- **Trend vs your saved baseline:** ${t.newCount} new · ${t.persistentCount} carried over · ${t.fixedCount} resolved. The fix list below is the FULL current violation set, not just the delta.`),a.push(""),a.push("## Before you start (safety)"),a.push(""),a.push("Do these in order before making any code changes:"),a.push(""),a.push("1. **Verify a clean git working tree** (`git status`). If there are uncommitted changes, ask the user whether to commit, stash, or proceed."),a.push("2. **Switch to a feature branch** dedicated to this work — e.g., `a11y/fix-component-name`. Don't commit directly to `main` / `master` / `develop`."),a.push("3. **Plan one commit per fix.** Each violation gets its own atomic commit so any individual change can be reverted without untangling the rest. Commit messages should follow the pattern: `a11y: fix <ruleId> on <selector or component>`."),a.push("4. **Show diffs before applying** when your tooling supports it (Cursor / Copilot Chat agents). Never silently overwrite files."),a.push("5. **Do not bump dependencies** to resolve accessibility issues — fixes should be code changes, not package upgrades."),a.push(""),a.push("## Ask me these questions first"),a.push(""),a.push("Before applying any fix, ask the user the questions below. Don't proceed until you have answers — guessing here produces fixes that don't match the codebase's conventions and will be rejected on review."),a.push(""),a.push("1. **Framework + style approach?** React / Vue / Svelte / Angular / Solid / vanilla — and CSS Modules / Tailwind / styled-components / Emotion / scoped `<style>` / global CSS / design-tokens system. This determines *how* every fix is written."),a.push("2. **Existing design tokens or raw values?** If the codebase uses `var(--color-text-on-surface)` or a `tokens.ts` / `theme.json`, fixes must use tokens — never introduce new hex codes. Where can you read the available tokens?"),a.push('3. **Existing utility classes or component library?** e.g., does `.text-slate-700` or `<Button variant="primary">` already exist? Use what\'s there before inventing new selectors or components.'),a.push("4. **Files or directories that are off-limits?** Generated code, vendored libraries, third-party widgets, lockfiles — confirm what you must NOT touch."),a.push("5. **For color-contrast fixes: prefer adjusting foreground or background?** Brand color preservation is usually a stakeholder call, not a developer call."),a.push("6. **How should I verify fixes are done?** Re-run this auditor (preferred), run the existing test suite, manual screen-reader pass, or all three?"),a.push(""),a.push("## Decision rules (when ambiguity surfaces during fixes)"),a.push(""),a.push('- **Native HTML beats ARIA.** First rule of ARIA: don\'t use ARIA when a native element works. Prefer `<button>` over `<div role="button">`, `<nav>` over `<div role="navigation">`, etc.'),a.push("- **State-specific failures get state-specific fixes.** A `:hover`-only contrast failure goes in the `:hover` rule, not the default selector."),a.push("- **Where multiple valid fixes exist, surface options — don't pick silently.** E.g., adding an accessible name can be done via visible text, `aria-label`, or `aria-labelledby` referencing existing copy. Present the options with tradeoffs and let the user choose."),a.push("- **When the fix would alter visible design** (color shifts, layout changes, content additions), pause and confirm with the user before applying."),a.push(""),a.push("## ⛔ Do not dismiss findings without empirical verification"),a.push(""),a.push('**Default stance: every finding in this report is real and needs a fix.** Your job is to apply fixes, not to triage which ones "probably aren\'t real." That triage already happened — the auditor ran on a real browser, captured real DOM, real `getBoundingClientRect()` coordinates, real WCAG rule failures from axe-core. You are downstream of all that.'),a.push(""),a.push('Some categories (reading-order, tab-order) are explicitly heuristic and DO have legitimate false-positive cases. Those cases are listed inline in each section. **But "this looks like it might be a false positive based on the pattern" is not verification.** Pattern-matching from the report alone is inference, not evidence.'),a.push(""),a.push("**To dismiss any finding as a false positive, you must do all of the following:**"),a.push(""),a.push("1. **Load the deployed page in a real browser** at the viewport listed in the finding's capture-state header (e.g., 1280×800 LTR for the position-based analyses)."),a.push("2. **Inspect the flagged elements directly** — DevTools, real `getBoundingClientRect()` coordinates, real DOM source order."),a.push("3. **Compare your empirical observation to the auditor's claim.** Does the visual layout actually contradict the DOM order, or not?"),a.push("4. **If you conclude false positive, document why** — include the empirical evidence (coordinates, screenshots, DOM excerpt) so the user can audit your reasoning."),a.push(`5. **Even after empirical verification, ASK THE USER before dismissing.** They have context you don't (e.g., "yes that's an intentional skip-link / multi-column layout / RTL-only behavior").`),a.push(""),a.push("**What does NOT count as verification:**"),a.push(""),a.push("- Looking at the CSS file and not seeing `flex-direction: row-reverse` (the layout could be from `order:`, `grid-area`, absolute positioning, or RTL emulation)"),a.push('- Pattern-matching the finding shape ("this looks like a perfect arithmetic flip therefore it must be an RTL artifact")'),a.push(`- Reading the auditor's false-positive list and concluding your case "looks like one of those"`),a.push(`- Deciding it's "probably fine" because the structure looks reasonable on a quick read`),a.push(""),a.push("**If you cannot run a real browser** (e.g., environment doesn't allow headless Chromium), then you cannot verify, which means you cannot dismiss. In that case: surface the finding to the user, propose the fix, and let them decide."),a.push(""),a.push("**Skipping a finding without verification is worse than fixing one that turns out to be a false positive.** Over-fix is reversible (delete the commit). Under-fix is silent — the user thinks they're compliant when they aren't."),a.push(""),a.push("**When you DO verify a finding is a false positive** (per the empirical rules above), the right action is to recommend the user click **dismiss** on that finding in the auditor's Activity tab. The auditor records the dismissal with your reason, suppresses the finding from displayed counts, the Matrix banner, and future AI prompts. **Don't modify code to silence a verified false positive** — that produces brittle workarounds and pollutes the codebase with comments explaining heuristic quirks. Dismissals persist per-URL and survive re-audits cleanly."),a.push(""),a.push("## Content-decision rules (alt text, button labels, link text)"),a.push(""),a.push("Some violations require copy that the audit can't generate. Don't invent copy out of nowhere, but DON'T just punt to the user either — use the capabilities you have:"),a.push(""),a.push('1. **For images missing alt text** (`image-alt`, `input-image-alt`, `area-alt`, `svg-img-alt`): if you have vision capability, **fetch or view the image** at the `src` URL listed in the violation and PROPOSE descriptive alt text based on what the image actually contains. Mark obviously-decorative images (icons inside buttons that already have text labels, dividers, background flourishes) for `alt=""`.'),a.push('2. **For unlabeled buttons / links** (`button-name`, `link-name`, `empty-button`, `empty-link`): look at the surrounding code context — nearby text, the button\'s icon (often a known SVG name like "close" / "search" / "menu"), the route the link points at — and PROPOSE an accessible name. Show your inference reasoning.'),a.push("3. **For unlabeled form fields** (`label`, `select-name`, `aria-input-field-name`): inspect the field's `name`, `placeholder`, `id`, and any nearby visible text in the parent container. PROPOSE a label."),a.push("4. **For ambiguous content** (alt text where you genuinely can't tell what an image shows; labels where there's no surrounding context), ask the user — don't guess."),a.push("5. **Always show your proposed copy before applying** — let the user approve, edit, or reject."),a.push(""),a.push("## Constraints"),a.push(""),a.push("- Don't fix violations that aren't in this list (no scope creep)."),a.push(`- Don't reformat or reorder unrelated code. No "while I'm here" cleanup.`),a.push(`- Match existing code style. Don't invoke Prettier / ESLint to "fix everything" — focus your diff strictly on the violation's element + relevant style rule.`),a.push("- Don't add new dependencies, configs, or build steps."),a.push("- Add inline comments only where the fix's rationale is non-obvious; otherwise skip comments."),a.push("- Preserve existing functionality and visual design wherever possible."),a.push(""),a.push("## How to use this prompt"),a.push(""),a.push("Paste this into Claude / Cursor / Copilot Chat with your codebase open. The AI should:"),a.push('1. **First**: walk through the "Before you start" + "Ask me these questions" sections with the user.'),a.push("2. **Then**: identify the source files containing each violating element (use the selectors + outerHTML below)."),a.push("3. **Then**: for each violation, propose the fix using the recipe + answers gathered, surface ambiguity per the decision rules, and apply only after the user confirms."),a.push("4. **Finally**: produce one atomic commit per fix, with a clear message."),a.push(""),a.push("---"),a.push("");const w=(((O=e[0])==null?void 0:O.readingOrderIssues)??[]).filter(m=>!c.has(`reading-order::${m.selector}`)),R=(A=e[0])==null?void 0:A.positionAnalysisCapturedAt,S=R?`${R.breakpoint.width}×${R.breakpoint.height} (${R.breakpoint.label}), ${R.direction.toUpperCase()}, ${R.theme} theme, ${R.pseudoState} pseudo-state`:"(reference state unavailable — findings reflect last matrix state)";if(w.length>0){a.push("## Reading-order concerns (DOM ≠ visual order)"),a.push(""),a.push(`_Positions captured at: **${S}**. Multi-column layouts, RTL pages, and mobile-stacked sections may have legitimately different reading orders at other viewports — verify each finding against the layout the user actually sees._`),a.push(""),a.push(`Screen readers read the DOM in source order. CSS that visually rearranges things (\`flex-direction: row-reverse\`, \`order:\`, \`grid-area\`, absolute positioning) does NOT reorder what the SR sees. ${w.length} element${w.length===1?" has":"s have"} a notable gap between their DOM position and their visual position:`),a.push(""),a.push("| DOM index | Visual index | Selector | Text |"),a.push("|---|---|---|---|");for(const m of w){const U=m.textSnippet.replace(/\|/g,"\\|").replace(/\n/g," ");a.push(`| ${m.domIndex} | ${m.visualIndex} | \`${m.selector}\` | ${U} |`)}a.push(""),a.push("**How to fix:** match DOM order to intended reading order — reorder the JSX/HTML, NOT the CSS. CSS visual rearrangement is a code smell only because it diverges from DOM order; if the DOM order is what the user should hear, no fix is needed."),a.push(""),a.push("**False-positive cases — these are the ONLY legitimate reasons to skip a flagged element:**"),a.push(""),a.push('1. **Multi-column / newspaper layouts** — DOM order is "column 1 top to bottom, then column 2", which is correct for SR but reads as "out of order" to this analyzer.'),a.push('2. **Skip-links** ("Skip to main content") — visually positioned late but DOM-early on purpose.'),a.push("3. **Caption-first patterns** — captions placed before their image in DOM so SR users get context before the alt text."),a.push("4. **Modal / popover triggers** — the trigger button is DOM-near the modal's portal mount point, which is often `<body>` end."),a.push(""),a.push('**Per the verification rules above (§ "Do not dismiss findings without empirical verification"): even when a finding looks like one of these false-positive cases, you must verify in a real browser before skipping. "Looks like a multi-column layout" is inference, not proof.** Read the DOM. Get real coordinates. Then ask the user. Then skip if confirmed.'),a.push(""),a.push("Surface the candidates above to the user, ask which (if any) are intended, and only reorder the rest. **If in doubt, fix it.** Reordering JSX is reversible; failing a Level A criterion is not."),a.push(""),a.push("---"),a.push("")}const k=(((v=e[0])==null?void 0:v.tabOrderIssues)??[]).filter(m=>!c.has(`tab-order::${m.selector}`));if(k.length>0){const m=k.filter(I=>I.flag==="visual"||I.flag==="both").length,U=k.filter(I=>I.flag==="tabindex"||I.flag==="both").length;a.push("## Tab-order concerns (keyboard focus sequence ≠ visual order) — WCAG 2.4.3 Focus Order (A)"),a.push(""),a.push(`_Positions captured at: **${S}**. Tab-position-vs-visual-position divergence is direction- and breakpoint-sensitive — what looks wrong here may be correct on RTL or mobile (and vice versa). Verify each finding against the layout the user actually sees._`),a.push(""),a.push(`Keyboard users tab through the page in one order; sighted users scan in another. axe-core does not detect this. ${k.length} focusable element${k.length===1?" has":"s have"} a notable divergence. Of these: ${m} ${m===1?"has":"have"} a visual-vs-tab mismatch (focus jumps around the page); ${U} ${U===1?"is":"are"} caused by positive \`tabindex\` reordering DOM source.`),a.push(""),a.push("| Tab pos | Visual pos | DOM pos | Flag | Selector | Text |"),a.push("|---|---|---|---|---|---|");for(const I of k){const G=I.textSnippet.replace(/\|/g,"\\|").replace(/\n/g," ");a.push(`| ${I.tabPosition} | ${I.visualPosition} | ${I.domPosition} | ${I.flag} | \`${I.selector}\` | ${G} |`)}a.push(""),a.push("**How to fix:**"),a.push(""),a.push("- **`flag: visual`** — tab order doesn't match visual layout. Reorder the JSX/HTML so the DOM source order matches the layout order users see. Don't use `tabindex` to \"patch\" this — that creates the next class of bug."),a.push('- **`flag: tabindex`** — a positive `tabindex` value (`tabindex="3"`) is reordering DOM. Remove the positive `tabindex` and rely on DOM source order. Use `tabindex="0"` only to make a non-focusable element focusable; use `tabindex="-1"` only to remove from the tab order.'),a.push("- **`flag: both`** — both conditions present. Fix the DOM order first, then remove the positive `tabindex`."),a.push(""),a.push("**False-positive cases — these are the ONLY legitimate reasons to skip a flagged element:**"),a.push(""),a.push('1. **Skip-links** ("Skip to main content") — visually-late, DOM-early on purpose. Their tab position should be near 1; their visual position is wherever their `:focus` styling places them.'),a.push("2. **Modal triggers + portal-rendered modals** — the trigger button is DOM-near the modal's portal mount point (often `<body>` end), so tab/visual positions can legitimately diverge."),a.push("3. **Dropdown menus / popovers** — a button DOM-far from its portal-rendered menu may produce false positives when the menu is open."),a.push(""),a.push(`**Per the verification rules above (§ "Do not dismiss findings without empirical verification"): even when a finding looks like one of these cases, you must verify in a real browser before skipping. Tabbing through the actual deployed page is empirical evidence; reading the auditor's table and pattern-matching is not.** If in doubt, fix it. Reordering JSX is reversible; failing a Level A criterion is not.`),a.push(""),a.push("Surface candidates to the user; ask which are intended; only fix the rest."),a.push(""),a.push("---"),a.push("")}const E=e.flatMap(m=>m.announcements??[]),x=e.flatMap(m=>m.focusEvents??[]).filter(m=>m.isFocusReset);if(E.length>0||x.length>0){if(a.push("## Runtime behavioral observations"),a.push(""),E.length>0){const m=E.filter(I=>I.politeness==="assertive").length;a.push(`**Live-region announcements** (${E.length} total, ${m} assertive): screen-reader announcements captured during state-driving. WCAG 4.1.3 Status Messages (AA) requires that non-essential changes use polite announcements; only blocking errors warrant assertive. Review:`),a.push("");const U=E.slice(0,8);for(const I of U){const G=I.text.replace(/\|/g,"\\|").replace(/\n/g," ").slice(0,120);a.push(`- \`[${I.politeness}${I.role?`/${I.role}`:""}]\` ${G}`)}E.length>8&&a.push(`- (and ${E.length-8} more)`),a.push(""),a.push("Verify each is appropriate. Common bug: error messages firing as `polite` (SR may not interrupt), or status updates firing as `assertive` (interrupts user mid-sentence)."),a.push("")}if(x.length>0){a.push(`**Focus resets to body** (${x.length} occurrence${x.length===1?"":"s"}): during the audit, focus jumped to \`<body>\` or \`<html>\` unexpectedly. This is almost always a bug — focus should move to a logical landing place (modal, alert, next field), never disappear.`),a.push("");for(const m of x.slice(0,5))a.push(`- \`${m.fromSelector??"(none)"}\` → \`${m.toSelector}\``);x.length>5&&a.push(`- (and ${x.length-5} more)`),a.push(""),a.push("Common cause: an element is removed from the DOM (e.g., modal closes) without `.focus()` being called on a sensible destination."),a.push("")}a.push("---"),a.push("")}const _=((C=e[0])==null?void 0:C.undefinedCustomProperties)??[];if(_.length>0){a.push("## Undefined CSS custom properties (cascade root cause)"),a.push(""),a.push(`${_.length} CSS custom propert${_.length===1?"y is":"ies are"} referenced via \`var(--name)\` but never declared. When a custom property is missing, the browser falls back to the property's initial value (often \`Canvas\` for color slots → resolves to white), which can produce a wave of false contrast failures. **Fix these missing tokens FIRST** — many of the contrast violations below may disappear once the cascade resolves correctly.`),a.push(""),a.push("| Custom property | References | First sample sites |"),a.push("|---|---|---|");for(const m of _){const U=m.sampleSites.map(I=>`\`${I.selector} { ${I.property} }\``).join("; ");a.push(`| \`${m.name}\` | ${m.referenceCount} | ${U} |`)}a.push(""),a.push("Each entry needs a definition in `:root` (or wherever the design-token layer lives). Surface to the user before applying contrast fixes — the missing token may be the root cause."),a.push(""),a.push("---"),a.push("")}if(n&&n.length>0){a.push("## Manual checks already completed (Guided Tests)"),a.push(""),a.push(`The consultant has run ${n.length} Intelligent Guided Test workflow${n.length===1?"":"s"} against this component covering the WCAG criteria automation cannot verify (keyboard navigation, screen-reader experience, focus management, forms, error prevention, etc.). Treat the verdicts below as ground truth — these came from a human running the actual flow.`),a.push(""),a.push("**Manual passes outrank heuristic findings.** When an IGT workflow has passed (e.g. Keyboard 7/7) and the heuristic analyzers below (Tab-order concerns, Reading-order concerns) flag findings on the same WCAG dimension, the manual pass is ground truth. A human ran real keyboard/SR navigation against the deployed page; the heuristic computes visual position from `getBoundingClientRect()` and can produce false positives on sticky / multi-column / grid layouts. **When the IGT and the heuristic disagree on the same WCAG criterion, treat the heuristic findings as suspect first**, run the empirical verification described above, and (if confirmed false positive) recommend dismissal via the Activity tab."),a.push("");const m=ke;a.push("| Workflow | Status | Notes |"),a.push("|---|---|---|");for(const W of n){const N=m.find(Be=>Be.id===W.workflowId);if(!N)continue;let H=0,K=0,ze=0,He=0,de=0;for(const Be of N.steps){const xe=W.steps[Be.id];if(!xe){de++;continue}xe.status==="pass"?H++:xe.status==="fail"?K++:xe.status==="skip"?ze++:xe.status==="not-applicable"?He++:de++}const On=K>0?`❌ ${K} failed`:de>0?`⚠ ${de} unanswered`:`✓ all ${N.steps.length} answered`,Oe=[`${H}p`,`${K}f`];He>0&&Oe.push(`${He} N/A`),ze>0&&Oe.push(`${ze} skip`),de>0&&Oe.push(`${de} unanswered`);const _n=`${Oe.join(" · ")} of ${N.steps.length} steps`;a.push(`| ${N.name} | ${On} | ${_n} |`)}a.push("");const U=[];for(const W of n){const N=m.find(H=>H.id===W.workflowId);if(N)for(const H of N.steps){const K=W.steps[H.id];(K==null?void 0:K.status)==="fail"&&U.push({workflow:N.name,stepTitle:H.question,notes:K.notes})}}if(U.length>0){a.push("**Failed manual checks** (these are real WCAG failures the consultant verified by hand):"),a.push("");for(const W of U)a.push(`- **${W.workflow} → ${W.stepTitle}**${W.notes?`: ${W.notes}`:""}`);a.push(""),a.push("**Address these alongside the automated violations below.** They will not appear in the violations list because no automated rule catches them — but they are still real WCAG failures and must be fixed for compliance."),a.push("")}const I=new Set(n.map(W=>W.workflowId)),G=m.filter(W=>!I.has(W.id));G.length>0&&(a.push(`**Not yet manually verified** (${G.length} workflow${G.length===1?"":"s"}): `+G.map(W=>W.name).join(", ")+". These cover WCAG criteria automation cannot detect; ask the consultant whether to run them before declaring the audit complete."),a.push("")),a.push("---"),a.push("")}if(o&&o.pagesAudited>1){const m=(()=>{try{return new URL(d).origin}catch{return null}})(),U=(()=>{try{return new URL(o.startUrl).origin}catch{return null}})();if(m&&U&&m===U){if(a.push("## Site-wide context (from a recent site crawl)"),a.push(""),a.push(`A recent crawl of ${o.pagesAudited} page${o.pagesAudited===1?"":"s"} on this origin produced grade **${o.siteGrade}** site-wide with **${o.totalUniqueViolations}** unique violations. Use this context for WCAG 3.2.3 (Consistent Navigation) and 3.2.4 (Consistent Identification) which require cross-page comparison.`),a.push(""),o.topViolations.length>0){a.push("**Most-frequent violations across the site** (rules to prioritize because they affect multiple pages):"),a.push("");for(const I of o.topViolations.slice(0,6))a.push(`- \`${I.ruleId}\` — ${I.impact} — found on ${I.urlsAffected} page${I.urlsAffected===1?"":"s"} (${I.totalOccurrences} total instances)`);a.push(""),a.push("Fixing one of these rules in shared components / layouts is leverage — one fix resolves N pages."),a.push("")}a.push("**Manual cross-page checks the AI should walk through:**"),a.push(""),a.push("- **3.2.3 Consistent Navigation** — verify primary nav appears in the same DOM order on every page audited above. Inconsistent ordering between pages is a Level AA failure."),a.push('- **3.2.4 Consistent Identification** — verify components with identical functionality (logo "home" link, search button, menu toggle) have identical accessible names across pages.'),a.push("- **3.2.6 Consistent Help (WCAG 2.2 A)** — verify any help mechanism (chat widget, contact link, FAQ link) appears in the same relative position on every page that has one."),a.push(""),a.push("---"),a.push("")}}a.push("## Violations to fix"),a.push(""),f.forEach((m,U)=>{const I=Vn[m.ruleId],G=m._instanceSelectors.length;if(a.push(`### ${U+1}. \`${m.ruleId}\` — ${m.impact} — WCAG ${m.wcagCriterion} ${m.wcagLevel}${G>1?` (${G} instances)`:""}`),a.push(""),a.push(`**Description:** ${m.description}`),a.push(""),G>1){a.push(`**Affects ${G} spots — fix the rule once, applies to all:**`);for(const H of m._instanceSelectors.slice(0,8))a.push(`- \`${H}\``);m._instanceSelectors.length>8&&a.push(`- (and ${m._instanceSelectors.length-8} more)`)}else a.push(`**Selector:** \`${m.target.selector}\``);a.push(""),a.push(`**Found in state(s):** ${m._states.join(" / ")}`),a.push("");const W=Do(m);if(W.length>0){for(const H of W)a.push(`**${H.label}:** ${H.value}`);a.push("")}m.target.failureSummary&&(a.push(`**Diagnostic:** ${m.target.failureSummary.replace(/\n+/g," ")}`),a.push("")),m.ai&&(a.push(`**🤖 AI-verified finding** (model: ${m.ai.model}, confidence: ${(m.ai.confidence*100).toFixed(0)}%)`),a.push(`> ${m.ai.reasoning}`),a.push(""));const N=m.target.cascadeChain;if(N&&(N.color||N.backgroundColor)){if(a.push("**CSS cascade chain (authored → rendered):**"),N.color){const H=N.color.vars.length>0?` (vars: ${N.color.vars.map(K=>`\`${K}\``).join(", ")})`:"";a.push(`- \`color\`: \`${N.color.authored}\` → \`${N.color.rendered}\`${H}${N.color.ruleSelector?` — set in rule \`${N.color.ruleSelector}\``:""}`)}if(N.backgroundColor){const H=N.backgroundColor.vars.length>0?` (vars: ${N.backgroundColor.vars.map(K=>`\`${K}\``).join(", ")})`:"";a.push(`- \`background-color\`: \`${N.backgroundColor.authored}\` → \`${N.backgroundColor.rendered}\`${H}${N.backgroundColor.ruleSelector?` — set in rule \`${N.backgroundColor.ruleSelector}\``:""}`)}a.push("")}a.push("**Element HTML:**"),a.push("```html"),a.push(m.target.outerHTML),a.push("```"),a.push(""),I?(a.push(`**Recipe:** ${I.summary}`),I.snippet&&(a.push(""),a.push("```"+(I.snippetLang??"")),a.push(I.snippet),a.push("```"))):a.push(`**Recipe:** No curated recipe for this rule — apply the standard WCAG ${m.wcagCriterion} guidance.`),m.helpUrl&&(a.push(""),a.push(`**More info:** ${m.helpUrl}`)),a.push(""),a.push("---"),a.push("")});const L=Fo(e,i);if(L.length>0){a.push("## Items axe couldn't determine — needs human review"),a.push(""),a.push("axe-core ran these rules but couldn't conclude pass/fail (the most common cause is color-contrast on a gradient / image / semi-transparent background). For each element below: if you have vision capability, sample the rendered background and compute the contrast ratio; otherwise ask the user to verify visually."),a.push("");for(const m of L)a.push(`### \`${m.ruleId}\` on \`${m.selector}\``),a.push(""),a.push(`- **WCAG criterion:** ${m.wcagCriterion}`),a.push(`- **Page URL:** ${m.pageUrl}`),m.failureSummary&&a.push(`- **axe diagnostic:** ${m.failureSummary}`),(V=m.styles)!=null&&V.foreground&&a.push(`- **Foreground:** \`${m.styles.foreground}\``),(j=m.styles)!=null&&j.background&&a.push(`- **Background:** \`${m.styles.background}\``),(F=m.styles)!=null&&F.fontSize&&a.push(`- **Font size:** ${m.styles.fontSize}px, weight ${m.styles.fontWeight??"unknown"}`),(B=m.styles)!=null&&B.textSample&&a.push(`- **Text sample:** ${JSON.stringify(m.styles.textSample)}`),a.push(""),a.push("---"),a.push("")}return a.push("## Manual verification checklist — non-automatable WCAG 2.1 / 2.2 AA criteria"),a.push(""),a.push("Automated audits catch ~30–50% of WCAG criteria. The remaining ~50% require human judgment, multi-page comparison, or runtime interaction we cannot script. **After applying the fixes above, walk the user through each item below before declaring the audit complete.** Mark each one passed, failed (and add to the fix queue), or N/A (with reasoning)."),a.push(""),a.push('Items the auditor has already flagged in earlier sections (reading-order, tab-order, behavioral observations, IGT manual checks) are listed below as "ALREADY FLAGGED" — confirm those fixes are in place.'),a.push(""),a.push("### Perceivable"),a.push(""),a.push("- [ ] **1.2.1 Audio-only / Video-only Prerecorded (A)** — every audio-only file has a text transcript; every silent-video file has a text alternative or audio description. Ask the user: does the page have media? If yes, list each `<audio>` / `<video>` and verify the alternative."),a.push('- [ ] **1.2.2 Captions Prerecorded (A)** — every prerecorded video with audio has synchronized captions. If `<video>` elements exist without `<track kind="captions">`, ask the user about caption files.'),a.push("- [ ] **1.2.3 Audio Description / Media Alternative Prerecorded (A)** — prerecorded video has either audio description or a full text alternative."),a.push("- [ ] **1.2.4 Captions Live (AA)** — live audio content (livestream, real-time meeting) has captions. Usually N/A for static sites."),a.push("- [ ] **1.2.5 Audio Description Prerecorded (AA)** — prerecorded video has audio description for visual-only information."),a.push("- [ ] **1.4.2 Audio Control (A)** — if any audio plays automatically for >3 seconds, there is a mechanism to pause / stop / control volume. Test by loading the page; if anything autoplays audibly, fail."),a.push("- [ ] **1.4.4 Resize Text (AA)** — zoom the browser to 200%. All text remains readable; nothing is cut off. No horizontal scrolling within content blocks."),a.push("- [ ] **1.4.5 Images of Text (AA)** — confirm text is rendered as actual text, not as images. Exceptions: logos, brand wordmarks. Walk the user through their hero / heading sections."),a.push("- [ ] **1.4.10 Reflow (AA)** — resize browser to 320px wide × 256px tall. Page is usable; no horizontal scrollbar appears (except for data tables / maps / code)."),a.push("- [ ] **1.4.12 Text Spacing (AA)** — apply user-stylesheet overrides: line-height ≥1.5×; paragraph spacing ≥2×; letter-spacing ≥0.12×; word-spacing ≥0.16×. Layout doesn't break, no clipped/overlapping text."),a.push("- [ ] **1.4.13 Content on Hover or Focus (AA)** — for any tooltip / popover / hover-revealed content: verify it is *dismissible* (Esc closes), *hoverable* (mouse can move into it without it disappearing), and *persistent* (doesn't auto-disappear unless user dismisses)."),a.push(""),a.push("### Operable"),a.push(""),a.push("- [ ] **2.1.2 No Keyboard Trap (A)** — Tab through the entire page from start to finish; verify focus never gets stuck in a region you can't leave with Tab/Shift+Tab/Esc. Common offenders: video players, custom widgets, modals without proper Esc handling."),a.push('- [ ] **2.1.4 Character Key Shortcuts (A)** — if the site implements single-key shortcuts (pressing "j" advances feed, etc.), they must be either turn-off-able OR only active when focus is on a specific control. Ask the user about implemented shortcuts.'),a.push('- [ ] **2.2.1 Timing Adjustable (A)** — if any timeout exists (auto-logout, session expiry, "complete this in X seconds"), user can turn it off, adjust it, or extend it (≥10× the default). Exception: real-time events. Ask the user.'),a.push("- [ ] **2.2.2 Pause, Stop, Hide (A)** — for moving / blinking / scrolling / auto-updating content lasting >5s: there is a mechanism to pause/stop/hide it. Carousels, tickers, animations, autoplaying video — all need controls."),a.push("- [ ] **2.3.1 Three Flashes or Below Threshold (A)** — no content flashes more than 3× per second. Test with anything that pulses, blinks, or has rapid color changes (loading animations, alert flashing). Use https://trace.umd.edu/peat/ for borderline cases."),k.length>0?a.push("- [x] **2.4.3 Focus Order (A)** — ALREADY FLAGGED above (`Tab-order concerns` section). Confirm fixes are in place."):a.push("- [ ] **2.4.3 Focus Order (A)** — auto-detector flagged 0 issues, but spot-check by tabbing through the page: focus visits elements in a logical order (matches visual / semantic flow)."),a.push("- [ ] **2.4.5 Multiple Ways (AA)** — at least two ways to find any page within a set: site search + nav menu, OR menu + sitemap, OR menu + table of contents, etc. Single-page apps may exempt; ask user."),a.push("- [ ] **2.5.1 Pointer Gestures (A)** — any multi-point gesture (pinch-zoom, two-finger swipe) or path-based gesture (signature, drag-along-curve) has a single-pointer alternative. Common offender: maps, signatures, drawing canvases."),a.push("- [ ] **2.5.2 Pointer Cancellation (A)** — actions trigger on the up-event (mouseup / pointerup), NOT the down-event. Pressing then dragging-away cancels. Test by mouse-down on a button → drag off → release: action should not fire."),a.push("- [ ] **2.5.4 Motion Actuation (A)** — features triggered by device motion (shake-to-undo, tilt-to-scroll) can be disabled AND have UI-button alternatives. Usually N/A for desktop sites."),a.push("- [ ] **2.5.7 Dragging Movements (AA, WCAG 2.2)** — any drag-only operation (kanban board, slider) has a non-drag alternative (buttons, click-to-place). Test sliders, drag-and-drop, sortable lists."),a.push(""),a.push("### Understandable"),a.push(""),a.push("- [ ] **3.2.1 On Focus (A)** — focusing any element does NOT trigger a context change (URL change, viewport scroll, modal open, form submit). Tab through every focusable element; verify none cause unexpected behavior."),a.push("- [ ] **3.2.2 On Input (A)** — changing the value of any form control does NOT trigger context change unless the user was warned. Common offender: `<select onChange={navigate}>` — must include adjacent submit button or warn the user."),o&&o.pagesAudited>1?(a.push("- [x] **3.2.3 Consistent Navigation (AA)** — site-crawl context provided above. Walk the user through verifying nav appears in the same order across pages."),a.push("- [x] **3.2.4 Consistent Identification (AA)** — verify components with the same function have the same accessible name across pages (logo home link, search button, menu toggle).")):(a.push("- [ ] **3.2.3 Consistent Navigation (AA)** — REQUIRES MULTI-PAGE COMPARISON. Ask the user for 2-3 representative pages; verify primary nav, footer, and search appear in the same DOM order on each."),a.push('- [ ] **3.2.4 Consistent Identification (AA)** — REQUIRES MULTI-PAGE COMPARISON. Components with identical functionality must have identical accessible names. Compare logo "home" link, search button, menu toggle across pages.')),a.push("- [ ] **3.2.6 Consistent Help (A, WCAG 2.2)** — REQUIRES MULTI-PAGE COMPARISON. If a help mechanism exists (chat, contact link, FAQ), it appears in the same relative order on every page where it appears."),a.push("- [ ] **3.3.4 Error Prevention — Legal, Financial, Data (AA)** — for any form that submits legal commitments (contracts, agreement), financial transactions (payments), or modifies/deletes user data: there is at least ONE of (a) reversibility, (b) error-checking with confirmation, (c) review-and-confirm step before final submit."),a.push("- [ ] **3.3.7 Redundant Entry (A, WCAG 2.2)** — forms in a multi-step process do NOT ask for the same information twice unless essential (re-entering password for confirmation is allowed). Auto-fill or pre-fill where possible."),a.push("- [ ] **3.3.8 Accessible Authentication — Minimum (AA, WCAG 2.2)** — login does not require a cognitive function test (puzzle, riddle, character-recognition) unless an alternative is provided (object recognition + autofill support are allowed; CAPTCHAs that require pattern recognition typically fail)."),a.push(""),a.push("### Robust"),a.push(""),E.length>0||x.length>0?a.push("- [x] **4.1.3 Status Messages (AA)** — runtime observations provided above (`Runtime behavioral observations` section). Confirm announcements use appropriate `aria-live` politeness and focus management is correct."):a.push('- [ ] **4.1.3 Status Messages (AA)** — status updates that don\'t cause a focus change (form-validation errors, "saved" confirmations, search-result counts) must use `role="status"` (polite) or `role="alert"` (assertive). Ask the user to demo their form-error and async-update flows; verify SR announces them.'),a.push(""),a.push("### Manual checks STILL TO DO"),a.push(""),a.push(`Walk the user through each unchecked box above (or batch them by criterion type — "let's test all the keyboard ones together"). For each: either mark passed (and move on), failed (add to the fix queue and resolve), or N/A (briefly justify why this site doesn't require this criterion).`),a.push(""),a.push('**Do not declare the audit complete until every box above is checked.** A site that passes only the automated portion is "axe-clean," not WCAG-compliant.'),a.push(""),a.push("---"),a.push(""),a.push("## When you're done — verification"),a.push(""),a.push("Before reporting completion, do all of the following:"),a.push(""),a.push(`1. **Confirm all ${f.length} violation${f.length===1?"":"s"} above are addressed.** Walk back through the list with the user, ticking each one off.`),a.push("2. **Re-run the auditor** (or whatever method we agreed in question 6 above). Verify zero NEW violations were introduced by the fixes."),a.push(`3. **Walk through the Manual verification checklist above** — every item should be marked passed, failed-and-fixed, or N/A. This is the half of WCAG that automation can't reach; skipping it means "axe-clean," not "compliant."`),a.push("4. **Visual diff** — for design-affecting fixes (color, spacing, layout), confirm the change with the user against the original. Storybook stories and visual regression suites are good checkpoints if the codebase has them."),a.push("5. **Commit log review** — surface the list of commits you produced. Each should be atomic and revertable."),a.push("6. **Report what you couldn't do** explicitly. If any violation required information we don't have (e.g., correct alt text), surface a TODO list for the user rather than guessing."),a.push(""),a.push("## Success criteria"),a.push(""),a.push("- All "+f.length+" violation"+(f.length===1?"":"s")+" above are resolved or explicitly deferred with reason."),a.push('- **Every reading-order and tab-order finding** is either fixed OR documented as a verified false positive (per § "Do not dismiss findings without empirical verification" above). Pattern-matching dismissals do not count.'),a.push('- **Every item in the manual verification checklist** above is marked passed, failed-and-fixed, or N/A-with-reason. (This is what separates "axe-clean" from "WCAG-compliant" — do not skip.)'),a.push("- No new violations introduced."),a.push("- State-specific behavior preserved (`:hover`, `:focus`, dark-mode, RTL, breakpoints)."),a.push("- One atomic commit per fix; clean revertable history."),a.push("- No unrelated code reformatted, no dependencies bumped."),a.push("- Diff is reviewable in under 10 minutes per fix."),a.push(""),a.push(`_Generated by ${ee} v${ce()}._`),a.join(`
420
+ `)}const Wo=5;function Vo(e){const t=new Map;let n=0;for(const o of e){if(!o.screenshotDataUrl||o.violations.length===0)continue;const s=`${o.state.pseudoState} · ${o.state.theme} · ${o.state.direction} · ${o.state.breakpoint.id}`,i=s;t.has(i)||t.set(i,{stateLabel:s,screenshotDataUrl:o.screenshotDataUrl,violations:[]});const c=t.get(i);for(const r of o.violations)n++,c.violations.push({...r,_idx:n})}return Array.from(t.values()).sort((o,s)=>s.violations.length-o.violations.length).slice(0,Wo)}const Ot=1280,_t=800,jo={low:"Low risk",moderate:"Moderate risk",high:"High risk",critical:"Critical risk"},zo={low:"#d1fae5",moderate:"#fef3c7",high:"#fed7aa",critical:"#fecaca"},Ho={low:"#065f46",moderate:"#92400e",high:"#9a3412",critical:"#991b1b"},Bo={A:"#10b981",B:"#84cc16",C:"#eab308",D:"#f97316",F:"#dc2626"},qo={defense:{title:"Accessibility Defense Bundle",documentLabel:"engineering, design, and risk-management",disclaimerHeading:"This document is not a compliance certification.",disclaimerBody:"Automated accessibility audits, including this one, detect a subset (typically 30–50%) of WCAG success criteria. Conformance with the full WCAG specification requires manual evaluation by qualified accessibility professionals, including (but not limited to): keyboard-only operability testing, screen-reader compatibility testing across NVDA / JAWS / VoiceOver, manual review of dynamic content and live regions, and content-quality review for alt text, link text, and labels."},evidence:{title:"Accessibility Compliance Evidence",documentLabel:"documentation and review",disclaimerHeading:"This document is automated audit evidence — not a determination of liability or conformance.",disclaimerBody:"This report documents detected accessibility defects in the audited resource at the date and time of capture. The audit was conducted using axe-core, an industry-standard automated accessibility-rule engine maintained by Deque Systems and used by Microsoft (Accessibility Insights), Google (Lighthouse), IBM, and others. The findings represent objective rule-engine output, not subjective evaluation. Automated audits surface a subset (typically 30–50%) of WCAG success criteria; the absence of a violation in this report is not evidence of conformance, and the presence of a violation is not, by itself, a determination of legal liability."}};function Ko(e,t,n,o,s){return pn(e,t,"evidence",n,o,s)}function Yo(e){return un(e,"letter")}function Jo(e){return un(e,"report")}function Xo(e){var l;const t=e.flatMap(p=>p.violations),n=le(t,void 0,e),o=oe(e),s=new Map;for(const p of t){const h=Ee(p.ruleId,p.target.selector);s.has(h)||s.set(h,p)}const i=Array.from(s.values()).sort((p,h)=>{const f={critical:0,serious:1,moderate:2,minor:3};return(f[p.impact]??99)-(f[h.impact]??99)}),c=new Map;for(const p of i){const h=c.get(p.ruleId)??[];h.push(p),c.set(p.ruleId,h)}const r=[];if(r.push("# Help me fix accessibility issues on my website"),r.push(""),r.push("You are an accessibility advisor helping me — a non-technical site owner — understand and fix accessibility issues on my website. I ran an automated audit and got the issues below. I may not have technical knowledge, so please explain things in plain English."),r.push(""),r.push("## What I need from you"),r.push(""),r.push("1. **First, ask me what I use to manage my website.** Common platforms: Squarespace, Wix, Shopify, WordPress (with theme name), Webflow, Framer, custom-built. Your advice will be different for each."),r.push("2. **Then, for each issue below, tell me clearly:**"),r.push(" - Whether **I can fix it myself** in my site editor (changing colors, adding alt text, editing button labels, etc.) — and if so, walk me through where to look in my platform"),r.push(" - Or whether **my developer needs to do this** (code-level fix) — and what to ask them to do"),r.push("3. **Prioritize ruthlessly.** I want to start with the issues that:"),r.push(" - Are most likely to come up in an ADA-related lawsuit (critical-impact items)"),r.push(" - Are easiest for me to fix without involving a developer"),r.push("4. **Don't bury me in jargon.** If you have to use a technical term, explain it in plain English first."),r.push("5. **If something is genuinely beyond a non-technical fix, say so.** Tell me what to ask my developer or website-builder support team."),r.push(""),r.push("## Audit summary"),r.push(""),r.push(`- **Page audited:** ${o}`),r.push(`- **Lawsuit-target risk:** ${zt[n.risk]} — ${Ht[n.risk]}`),r.push(`- **Issues found:** ${n.totals.unique} unique problems (${n.totals.critical} critical · ${n.totals.serious} serious · ${n.totals.moderate} moderate · ${n.totals.minor} minor)`),n.coverage&&n.coverage.untestedCriteria.length>0?r.push(`- **WCAG conformance progress:** ${n.coverage.evaluated} of ${n.coverage.totalApplicable} criteria evaluated. Fixing the issues below will clear me of automated lawsuit-targeting tools. To make a formal claim that the site meets WCAG ${n.coverage.targetVersion} ${n.coverage.targetLevel}, ${n.coverage.untestedCriteria.length} more criteria need human review — see the "Guided Tests" workflows in the auditor side panel for these.`):n.coverage&&n.coverage.untestedCriteria.length===0&&r.push(`- **WCAG conformance:** All ${n.coverage.totalApplicable} applicable WCAG ${n.coverage.targetVersion} ${n.coverage.targetLevel} criteria have been evaluated. Fixing the issues below will produce a defensible conformance claim.`),r.push(""),r.push("## The issues, in plain language"),r.push(""),c.size===0)return r.push("No automated issues were detected. Note: automated checks only catch about 30–50% of accessibility problems. Manual testing covers the rest."),r.join(`
421
+ `);let d=1;for(const[p,h]of c.entries()){const f=(l=h.find(u=>u.target.opacityContext))==null?void 0:l.target.opacityContext,a=jt(p,f),g=h[0].impact;r.push(`### ${d}. [${g.toUpperCase()}] ${a.whatsWrong}`),r.push(""),r.push(`**Why this matters.** ${a.whyItMatters}`),r.push(""),r.push(`**Plain-language fix guidance.** ${a.howToFix}`),r.push(""),r.push(`**Where on the page (${h.length} ${h.length===1?"spot":"spots"}):**`);for(const u of h.slice(0,8))r.push(`- \`${u.target.selector}\``);h.length>8&&r.push(`- (and ${h.length-8} more spots)`),r.push(""),r.push(`*Technical reference for your developer:* axe-core rule \`${p}\` — full docs at https://dequeuniversity.com/rules/axe/4.11/${p}`),r.push(""),d++}return r.push("---"),r.push(""),r.push("## How to use this output"),r.push(""),r.push("Walk through this list with me one issue at a time. For each:"),r.push("1. Help me understand the issue with a real example of who it affects."),r.push("2. Tell me clearly if I can fix it myself, and if so, walk me through it for my platform."),r.push("3. If I need a developer, give me a short paragraph I can paste into an email or message to them."),r.push("4. Help me prioritize — I have limited time and want to fix the riskiest things first."),r.push(""),r.push("Start by asking me which platform I use."),r.join(`
422
+ `)}function un(e,t){const n=e.flatMap(f=>f.violations),o=le(n,void 0,e),s=oe(e),i=new Date,c=new Map;for(const f of n){const a=Ee(f.ruleId,f.target.selector);c.has(a)||c.set(a,f)}const r=Array.from(c.values()).sort((f,a)=>{const g={critical:0,serious:1,moderate:2,minor:3};return(g[f.impact]??99)-(g[a.impact]??99)}),d=new Map;for(const f of r){const a=d.get(f.ruleId)??[];a.push(f),d.set(f.ruleId,a)}const l=Array.from(d.entries()).map(([f,a])=>{var k;const g=(k=a.find(E=>E.target.opacityContext))==null?void 0:k.target.opacityContext,u=jt(f,g),w=a[0].impact,R=a.slice(0,8).map(E=>`<code>${y(E.target.selector)}</code>`).join(", "),S=a.length>8?` <em>(and ${a.length-8} more)</em>`:"";return`
423
423
  <section class="rule">
424
424
  <div class="rule-header">
425
425
  <span class="impact impact-${y(w)}">${y(w)}</span>
@@ -473,7 +473,7 @@ ${g.target.failureSummary}`:"");r.push(` <testcase ${w}>`),r.push(` <fai
473
473
  <p>${p}</p>
474
474
 
475
475
  <div class="summary">
476
- <p style="margin: 0;"><strong>${y(jt[o.risk])}.</strong> ${y(zt[o.risk])}</p>
476
+ <p style="margin: 0;"><strong>${y(zt[o.risk])}.</strong> ${y(Ht[o.risk])}</p>
477
477
  <div class="totals">
478
478
  ${o.totals.critical>0?`<span><strong>${o.totals.critical}</strong> critical</span>`:""}
479
479
  ${o.totals.serious>0?`<span><strong>${o.totals.serious}</strong> serious</span>`:""}
@@ -520,7 +520,7 @@ ${t==="letter"?`
520
520
  behaviors, error prevention, consistency).
521
521
  When manual workflows are completed, their results are integrated into both the executive
522
522
  summary's compliance grade and this section's per-criterion findings.
523
- </p>`;const t=new Map(e.map(r=>[r.workflowId,r])),n=Ee.map(r=>Zo(r,t.get(r.id))).filter(r=>r!==null).join("");let o=0,s=0,i=0,c=0;for(const r of Ee){c+=r.steps.length;const d=t.get(r.id);if(d)for(const l of r.steps){const p=d.steps[l.id];p&&(i++,p.status==="fail"&&(l.severity==="required"?o++:s++))}}return`
523
+ </p>`;const t=new Map(e.map(r=>[r.workflowId,r])),n=ke.map(r=>Zo(r,t.get(r.id))).filter(r=>r!==null).join("");let o=0,s=0,i=0,c=0;for(const r of ke){c+=r.steps.length;const d=t.get(r.id);if(d)for(const l of r.steps){const p=d.steps[l.id];p&&(i++,p.status==="fail"&&(l.severity==="required"?o++:s++))}}return`
524
524
  <h2 id="manual">5. Manual assessment results</h2>
525
525
  <p style="font-size: 10pt; color: #475569; margin-bottom: 8pt;">
526
526
  Manual workflows performed by the auditor. ${i} of ${c} steps answered
@@ -549,21 +549,21 @@ ${s>0?`
549
549
  <thead><tr><th style="width: 80pt;">Severity</th><th style="width: 70pt;">WCAG</th><th>Failed check + auditor notes</th></tr></thead>
550
550
  <tbody>${d}</tbody>
551
551
  </table>
552
- `:""}`}function pn(e,t,n="defense",o,s,i){var x,_,L;const c=qo[n],r=((x=e[0])==null?void 0:x.componentId)??"unknown",d=oe(e),l=e.reduce((b,$)=>b+$.durationMs,0),p=e.flatMap(b=>b.violations),h=o&&o.length>0?{runs:o,workflows:Ee}:void 0,f=le(p,h,e),a=new Date,g=new Map;for(const b of p){const $=xe(b.ruleId,b.target.selector),O=`${b.currentState.pseudoState} · ${b.currentState.theme} · ${b.currentState.direction}`,A=g.get($);if(A){A._states.includes(O)||A._states.push(O);continue}g.set($,{...b,_states:[O]})}const u=Array.from(g.values()).sort((b,$)=>{const O={critical:0,serious:1,moderate:2,minor:3};return(O[b.impact]??99)-(O[$.impact]??99)}),w=Vo(e),R=new Map;for(const b of w)for(const $ of b.violations){const O=xe($.ruleId,$.target.selector);R.has(O)||R.set(O,$._idx)}const S=u.map((b,$)=>`
552
+ `:""}`}function pn(e,t,n="defense",o,s,i){var x,_,L;const c=qo[n],r=((x=e[0])==null?void 0:x.componentId)??"unknown",d=oe(e),l=e.reduce((b,T)=>b+T.durationMs,0),p=e.flatMap(b=>b.violations),h=o&&o.length>0?{runs:o,workflows:ke}:void 0,f=le(p,h,e),a=new Date,g=new Map;for(const b of p){const T=Ee(b.ruleId,b.target.selector),O=`${b.currentState.pseudoState} · ${b.currentState.theme} · ${b.currentState.direction}`,A=g.get(T);if(A){A._states.includes(O)||A._states.push(O);continue}g.set(T,{...b,_states:[O]})}const u=Array.from(g.values()).sort((b,T)=>{const O={critical:0,serious:1,moderate:2,minor:3};return(O[b.impact]??99)-(O[T.impact]??99)}),w=Vo(e),R=new Map;for(const b of w)for(const T of b.violations){const O=Ee(T.ruleId,T.target.selector);R.has(O)||R.set(O,T._idx)}const S=u.map((b,T)=>`
553
553
  <tr>
554
- <td>${$+1}</td>
554
+ <td>${T+1}</td>
555
555
  <td><span class="impact impact-${y(b.impact)}">${y(b.impact)}</span></td>
556
556
  <td><code>${y(b.ruleId)}</code></td>
557
557
  <td>${y(b.wcagCriterion)} ${y(b.wcagLevel)}</td>
558
558
  <td>${y(b.description)}</td>
559
559
  <td><code class="sel">${y(b.target.selector)}</code></td>
560
560
  <td>${y(b._states.join(", "))}</td>
561
- </tr>`).join(""),k=new Set(p.map(b=>b.ruleId)),E=new Set(k);for(const b of e){const $=b.axeRulesEvaluated;if($){for(const O of $.passed)E.add(O.ruleId);for(const O of $.inapplicable)E.add(O.ruleId);for(const O of $.incomplete)E.add(O.ruleId)}}const P=ln.map(b=>{const{conformance:$,hits:O}=dn(b,k,E);return`
562
- <tr class="${$==="Supports"?"supports":$==="Partially Supports"?"partial":$==="Not Evaluated"?"not-evaluated":"na"}">
561
+ </tr>`).join(""),k=new Set(p.map(b=>b.ruleId)),E=new Set(k);for(const b of e){const T=b.axeRulesEvaluated;if(T){for(const O of T.passed)E.add(O.ruleId);for(const O of T.inapplicable)E.add(O.ruleId);for(const O of T.incomplete)E.add(O.ruleId)}}const P=ln.map(b=>{const{conformance:T,hits:O}=dn(b,k,E);return`
562
+ <tr class="${T==="Supports"?"supports":T==="Partially Supports"?"partial":T==="Not Evaluated"?"not-evaluated":"na"}">
563
563
  <td><code>${y(b.ref)}</code></td>
564
564
  <td>${y(b.title)} <span class="lvl">(${b.level})</span></td>
565
- <td>${$}</td>
566
- <td>${O.length>0?`Detected violations of: ${O.map(v=>`<code>${y(v)}</code>`).join(", ")}`:$==="Not Applicable"?"Not addressable by automated audit; requires manual review.":"No automated violations detected."}</td>
565
+ <td>${T}</td>
566
+ <td>${O.length>0?`Detected violations of: ${O.map(v=>`<code>${y(v)}</code>`).join(", ")}`:T==="Not Applicable"?"Not addressable by automated audit; requires manual review.":"No automated violations detected."}</td>
567
567
  </tr>`}).join("");return`<!doctype html>
568
568
  <html lang="en">
569
569
  <head>
@@ -670,7 +670,7 @@ ${i&&(i.lead||i.body||i.closer)?`
670
670
 
671
671
  <h3>Per-category breakdown (top-6 lawsuit-magnet categories)</h3>
672
672
  <div class="categories">
673
- ${f.categories.map(b=>{const $=b.status==="pass"?"✓":b.status==="fail"?"✗":"⚠",O=b.status==="pass"?"cat-pass":b.status==="fail"?"cat-fail":"cat-unchecked",A=b.status==="fail"?` (${b.violationCount})`:b.needsManualCheck?" — requires manual review":"";return`<div class="${O}">${$} ${y(b.label)}${y(A)}</div>`}).join("")}
673
+ ${f.categories.map(b=>{const T=b.status==="pass"?"✓":b.status==="fail"?"✗":"⚠",O=b.status==="pass"?"cat-pass":b.status==="fail"?"cat-fail":"cat-unchecked",A=b.status==="fail"?` (${b.violationCount})`:b.needsManualCheck?" — requires manual review":"";return`<div class="${O}">${T} ${y(b.label)}${y(A)}</div>`}).join("")}
674
674
  </div>
675
675
 
676
676
  <h2 id="methodology">2. Methodology &amp; scope</h2>
@@ -702,13 +702,13 @@ ${u.length===0?"<p>No automated violations were detected during this audit.</p>"
702
702
  </table>`}
703
703
 
704
704
  <h2 id="evidence">4. Visual evidence (per-state screenshots)</h2>
705
- ${w.length===0?'<p style="font-size: 10pt; color: #64748b;">No per-state screenshots were captured for this audit (no states had violations, or screenshot capture failed).</p>':`<p class="caption">Top ${w.length} state${w.length===1?"":"s"} by violation count shown below. Red rectangles mark violation locations; numbers correspond to entries in §3.</p>`+w.map(b=>{const $=b.violations.filter(O=>O.target.boundingRect).map(O=>{const A=O.target.boundingRect,v=String(O._idx).length*8+14,T=22;return[`<rect class="violation-mark" x="${A.x}" y="${A.y}" width="${A.w}" height="${A.h}" />`,`<rect class="label-bg" x="${A.x}" y="${Math.max(0,A.y-T)}" width="${v}" height="${T}" rx="2" />`,`<text class="violation-num" x="${A.x+6}" y="${Math.max(0,A.y-T)+16}">${O._idx}</text>`].join("")}).join("");return`
705
+ ${w.length===0?'<p style="font-size: 10pt; color: #64748b;">No per-state screenshots were captured for this audit (no states had violations, or screenshot capture failed).</p>':`<p class="caption">Top ${w.length} state${w.length===1?"":"s"} by violation count shown below. Red rectangles mark violation locations; numbers correspond to entries in §3.</p>`+w.map(b=>{const T=b.violations.filter(O=>O.target.boundingRect).map(O=>{const A=O.target.boundingRect,v=String(O._idx).length*8+14,C=22;return[`<rect class="violation-mark" x="${A.x}" y="${A.y}" width="${A.w}" height="${A.h}" />`,`<rect class="label-bg" x="${A.x}" y="${Math.max(0,A.y-C)}" width="${v}" height="${C}" rx="2" />`,`<text class="violation-num" x="${A.x+6}" y="${Math.max(0,A.y-C)+16}">${O._idx}</text>`].join("")}).join("");return`
706
706
  <div class="evidence-state">
707
707
  <h3>State: ${y(b.stateLabel)} (${b.violations.length} violation${b.violations.length===1?"":"s"})</h3>
708
708
  <div class="evidence-frame">
709
- <svg viewBox="0 0 ${Rt} ${Ot}" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet">
710
- <image href="${b.screenshotDataUrl}" x="0" y="0" width="${Rt}" height="${Ot}" preserveAspectRatio="xMidYMid slice" />
711
- ${$}
709
+ <svg viewBox="0 0 ${Ot} ${_t}" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet">
710
+ <image href="${b.screenshotDataUrl}" x="0" y="0" width="${Ot}" height="${_t}" preserveAspectRatio="xMidYMid slice" />
711
+ ${T}
712
712
  </svg>
713
713
  </div>
714
714
  </div>`}).join("")}
@@ -722,7 +722,7 @@ ${Qo(o)}
722
722
  <tbody>${P}</tbody>
723
723
  </table>
724
724
 
725
- ${(()=>{const b=s!==void 0,$=b?"8":"7",O=b?"9":"8",A=b?`<h2 id="audit-history">7. Audit history</h2>
725
+ ${(()=>{const b=s!==void 0,T=b?"8":"7",O=b?"9":"8",A=b?`<h2 id="audit-history">7. Audit history</h2>
726
726
  <p style="font-size: 10pt; margin-bottom: 8pt;">Chronological record of audits this user has run, with cryptographic hashes of each audit's identifying fields (component, page URL, grade, severity totals, axe version, timestamp, state-matrix size). Hashes are SHA-256 of canonical-JSON serialization, so any tampering with a logged audit's identity is detectable client-side. Entries marked <em>Anchored</em> additionally carry a third-party RFC 3161 trusted timestamp issued by the named TSA — those entries cannot be backdated.</p>
727
727
  ${s&&s.length>0?`<table>
728
728
  <thead>
@@ -738,21 +738,21 @@ ${s&&s.length>0?`<table>
738
738
  <th>Source</th>
739
739
  </tr>
740
740
  </thead>
741
- <tbody>${s.map(T=>`
741
+ <tbody>${s.map(C=>`
742
742
  <tr>
743
- <td style="white-space: nowrap;">${y(T.capturedAt)}</td>
744
- <td><code>${y(T.componentId)}</code></td>
745
- <td style="word-break: break-all;">${y(T.pageUrl)}</td>
746
- <td><strong>${y(T.grade)}</strong></td>
747
- <td>${T.totals.critical}</td>
748
- <td>${T.totals.serious}</td>
749
- <td>${T.statesAudited}</td>
750
- <td><code title="${y(T.hash)}">${y(T.hash.slice(0,12))}…</code></td>
751
- <td>${T.receipt?`RFC 3161 (${y(T.receipt.tsaName)})`:"Local"}</td>
743
+ <td style="white-space: nowrap;">${y(C.capturedAt)}</td>
744
+ <td><code>${y(C.componentId)}</code></td>
745
+ <td style="word-break: break-all;">${y(C.pageUrl)}</td>
746
+ <td><strong>${y(C.grade)}</strong></td>
747
+ <td>${C.totals.critical}</td>
748
+ <td>${C.totals.serious}</td>
749
+ <td>${C.statesAudited}</td>
750
+ <td><code title="${y(C.hash)}">${y(C.hash.slice(0,12))}…</code></td>
751
+ <td>${C.receipt?`RFC 3161 (${y(C.receipt.tsaName)})`:"Local"}</td>
752
752
  </tr>`).join("")}
753
753
  </tbody>
754
754
  </table>`:'<p style="color: #64748b; font-style: italic;">No prior audits recorded — this is the first audit on record for this installation.</p>'}
755
- `:"",v=n==="evidence"?`<h2 id="remediation">${$}. Recommended approach before legal action</h2>
755
+ `:"",v=n==="evidence"?`<h2 id="remediation">${T}. Recommended approach before legal action</h2>
756
756
  <div style="background: #f0f9ff; border: 1px solid #38bdf8; padding: 12pt 16pt; border-radius: 4pt; font-size: 10.5pt;">
757
757
  <p style="margin: 0 0 8pt;"><strong>Most businesses are unaware their digital properties have accessibility defects.</strong> Many will fix them once notified. A good-faith notice-and-cure approach is more likely to resolve the underlying accessibility barrier (which is the actual purpose of disability-rights law) and, where remediation does not occur, strengthens any subsequent legal claim by establishing both notice and a reasonable opportunity to comply.</p>
758
758
  <p style="margin: 0 0 8pt;"><strong>Recommended steps before considering legal action:</strong></p>
@@ -763,7 +763,7 @@ ${s&&s.length>0?`<table>
763
763
  <li><strong>If after the notice period the business has not engaged or remediated</strong>, the documented good-faith notice combined with this evidence bundle materially strengthens an ADA Title III, EAA, EN 301 549, AODA, or analogous claim, depending on jurisdiction.</li>
764
764
  </ol>
765
765
  <p style="margin: 0; font-size: 9.5pt; color: #475569;">This guidance is general and not legal advice. Specific procedural requirements vary by jurisdiction (e.g., some US states require pre-suit notice under "Unruh Act" amendments; others do not). Consult qualified counsel about the procedural posture appropriate for your situation.</p>
766
- </div>`:`<h2 id="remediation">${$}. Remediation plan</h2>
766
+ </div>`:`<h2 id="remediation">${T}. Remediation plan</h2>
767
767
  <p>Each violation in §3 has a documented canonical fix pattern. The remediation workflow we recommend:</p>
768
768
  <ol>
769
769
  <li>Findings are classified by severity. Address critical and serious findings first.</li>
@@ -788,4 +788,4 @@ ${v}
788
788
  </footer>
789
789
 
790
790
  </body>
791
- </html>`}async function es(){const t=(await chrome.storage.local.get("aiConfig")).aiConfig;return{...Xn,...t??{}}}async function _t(e,t,n){const o=await es();if(!o.enabled||!o.apiKey||e.length===0)return null;const s=e.flatMap(d=>d.violations),i=le(s,void 0,e),c=i.categories.filter(d=>d.status==="fail").sort((d,l)=>l.violationCount-d.violationCount).slice(0,3).map(d=>d.label),r=e[0];return rn({framing:t,riskTier:i.risk,grade:i.letter,totals:{critical:i.totals.critical,serious:i.totals.serious,moderate:i.totals.moderate,minor:i.totals.minor,unique:i.totals.unique},riskDrivers:c,pageUrl:(r==null?void 0:r.pageUrl)??(r==null?void 0:r.scope)??"",auditDate:(r==null?void 0:r.startedAt)??new Date().toISOString(),priorAuditCount:n},o)}function ts(){return D("EXPORT_REQUEST",async e=>{if(e.format==="sarif")return{type:"EXPORT_RESPONSE",format:"sarif",content:JSON.stringify(Uo(e.results,e.delta),null,2)};if(e.format==="junit")return{type:"EXPORT_RESPONSE",format:"junit",content:No(e.results,e.delta)};if(e.format==="html-print")return{type:"EXPORT_RESPONSE",format:"html-print",content:Po(e.results,e.delta)};if(e.format==="vpat")return{type:"EXPORT_RESPONSE",format:"vpat",content:Lo(e.results,e.delta)};if(e.format==="ai-prompt")return{type:"EXPORT_RESPONSE",format:"ai-prompt",content:Go(e.results,e.delta,e.manualRuns,e.siteCrawlReport,e.dismissedKeys,e.incompleteResolutions)};if(e.format==="defense-bundle"){const t=await wt(),n=await _t(e.results,"defense",t.length);return{type:"EXPORT_RESPONSE",format:"defense-bundle",content:pn(e.results,e.delta,"defense",e.manualRuns,t,n)}}if(e.format==="evidence-bundle"){const t=await wt(),n=await _t(e.results,"evidence",t.length);return{type:"EXPORT_RESPONSE",format:"evidence-bundle",content:Ko(e.results,e.delta,e.manualRuns,t,n)}}return e.format==="developer-letter"?{type:"EXPORT_RESPONSE",format:"developer-letter",content:Yo(e.results)}:e.format==="owner-report"?{type:"EXPORT_RESPONSE",format:"owner-report",content:Jo(e.results)}:e.format==="ai-prompt-owner"?{type:"EXPORT_RESPONSE",format:"ai-prompt-owner",content:Xo(e.results)}:{type:"EXPORT_RESPONSE",format:"json",content:JSON.stringify(Mo(e.results,e.delta),null,2)}})}const ns=z("support-messenger"),as="https://api.wcagcheckr.com/v1/products/wcagcheckr/support",Je="support:rate-window",os=5,ss=10*60*1e3,rs=2,is="wcagcheckr",Mt="storybook:lastDetected";async function cs(e){if(!e)return;const t=await chrome.runtime.getPlatformInfo(),o=(await chrome.storage.local.get(Mt))[Mt];return{extensionVersion:chrome.runtime.getManifest().version,platform:t,storybookDetected:o!=null&&o.detected?o.version??"detected":"none",licenseTier:await Ht(),logTail:Mn(Un())}}async function ls(e=Date.now()){const n=((await chrome.storage.local.get(Je))[Je]??[]).filter(o=>e-o<ss);return n.length>=os?!1:(n.push(e),await chrome.storage.local.set({[Je]:n}),!0)}async function hn(e,t=0){try{const n=await fetch(as,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(`http ${n.status}`);const o=await n.json();if(!o.success)throw new Error(o.error??"server returned success=false");return{ticketRef:o.ticketRef??""}}catch(n){if(t<rs){const o=(t+1)*1e3;return await new Promise(s=>setTimeout(s,o)),hn(e,t+1)}throw n}}function ds(){return D("SUPPORT_MESSAGE_REQUEST",async e=>{if(!await ls())return{type:"SUPPORT_MESSAGE_RESPONSE",success:!1,error:Ue("NETWORK","Rate limit reached. Try again in 10 minutes.",!0)};try{const t=await cs(e.includeContext);return{type:"SUPPORT_MESSAGE_RESPONSE",success:!0,ticketRef:(await hn({productSlug:is,subject:e.subject,body:e.body,replyEmail:e.replyEmail,context:t,extensionVersion:chrome.runtime.getManifest().version,timestamp:new Date().toISOString()})).ticketRef}}catch(t){ns.error("send failed",t);const n=t instanceof Error?t.message:String(t);return{type:"SUPPORT_MESSAGE_RESPONSE",success:!1,error:Ue("NETWORK",n,!0)}}})}const fn=z("ai-color-suggester");async function us(e,t,n=[]){if(!t.enabled||e.length===0)return{results:[],totalCostUsd:0,capExceeded:!1};const o=Q(t);if(!o.ok)return{results:[],totalCostUsd:0,capExceeded:!1};const s=o.client,i=Z(t.costCapUsd),c=[];for(const r of e){if(!i.canCharge())break;try{const d=await s.suggestColorFix({foreground:r.foreground,background:r.background,fontSize:r.fontSize,fontWeight:r.fontWeight,targetLevel:r.targetLevel,paletteHints:n});i.recordCharge(d.costUsd),d.verdict==="suggested"&&d.candidates.length>0&&c.push({matchKey:r.matchKey,suggestions:d.candidates,reasoning:d.reasoning,costUsd:d.costUsd})}catch(d){fn.warn(`color-fix suggestion failed for ${r.matchKey}`,d)}}return{results:c,totalCostUsd:i.state.spentUsd,capExceeded:i.state.exceeded}}async function ps(){const e=await chrome.storage.local.get("aiConfig");return ke(e.aiConfig)}function hs(){return D("AI_COLOR_SUGGEST_REQUEST",async e=>{const t=await ps();if(!t.enabled)return{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:"No AI API key configured. Add one in Settings → AI augmentation."};try{const{results:n,totalCostUsd:o,capExceeded:s}=await us(e.inputs,t,e.paletteHints);return{type:"AI_COLOR_SUGGEST_RESPONSE",results:n,totalCostUsd:o,capExceeded:s}}catch(n){return fn.warn("color-suggest handler failed",n),{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:n instanceof Error?n.message:String(n)}}})}const gn=z("ai-incomplete-resolver");async function fs(){const e=await chrome.storage.local.get("aiConfig");return ke(e.aiConfig)}async function gs(e){if(!e.aiConfig.enabled||e.elements.length===0)return{resolutions:[],totalCostUsd:0};const t=Q(e.aiConfig);if(!t.ok)return{resolutions:[],totalCostUsd:0};const n=t.client,o=Z(e.aiConfig.costCapUsd),s=[];for(const i of e.elements){if(!o.canCharge())break;try{const c=await n.resolveAxeIncomplete({ruleId:e.ruleId,element:i,pageUrl:e.pageUrl,targetLevel:e.targetLevel});o.recordCharge(c.costUsd),s.push({pageUrl:e.pageUrl,ruleId:e.ruleId,selector:i.selector,verdict:c.verdict,reasoning:c.reasoning,resolvedAt:new Date().toISOString(),costUsd:c.costUsd,wcagCriterion:e.wcagCriterion})}catch(c){gn.warn(`resolveAxeIncomplete failed for ${i.selector}`,c)}}return s.length>0&&await zn(s),{resolutions:s,totalCostUsd:o.state.spentUsd}}function ms(){return D("AI_RESOLVE_INCOMPLETE_REQUEST",async e=>{const t=await fs();if(!t.enabled)return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:"No AI API key configured. Add one in Settings → AI augmentation."};try{const{resolutions:n,totalCostUsd:o}=await gs({ruleId:e.ruleId,pageUrl:e.pageUrl,wcagCriterion:e.wcagCriterion,elements:e.elements,targetLevel:e.targetLevel,aiConfig:t});return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:n,totalCostUsd:o}}catch(n){return gn.warn("ai-incomplete-resolver failed",n),{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:n instanceof Error?n.message:"Unknown error during AI resolution."}}})}const Le={A:0,B:1,C:2,D:3,F:4},Ut={low:0,moderate:1,high:2,critical:3};function ys(e,t){return Le[e]>Le[t]?e:t}function bs(e,t){return Ut[e]>Ut[t]?e:t}function ws(e){const t=[];for(const n of e)for(const o of n.results)for(const s of o.violations)t.push({url:n.url,v:s});return t}function vs(e,t,n,o,s){const i=t.filter(S=>!S.error).length,c=t.filter(S=>!!S.error).length,r=t.map(S=>{if(S.error)return{url:S.url,grade:"F",risk:"critical",uniqueViolations:0,totals:{critical:0,serious:0,moderate:0,minor:0},durationMs:S.durationMs,error:S.error};const k=S.results.flatMap(P=>P.violations),E=le(k);return{url:S.url,grade:E.letter,risk:E.risk,uniqueViolations:E.totals.unique,totals:{critical:E.totals.critical,serious:E.totals.serious,moderate:E.totals.moderate,minor:E.totals.minor},durationMs:S.durationMs}});r.sort((S,k)=>{const E=Le[k.grade]-Le[S.grade];return E!==0?E:k.uniqueViolations-S.uniqueViolations});let d="A",l="low";for(const S of r)d=ys(d,S.grade),l=bs(l,S.risk);const p=ws(t),h=S=>`${S.ruleId}::${S.target.selector}`,f=new Map;for(const{v:S}of p){const k=h(S);f.has(k)||f.set(k,S)}const a=f.size,g={critical:0,serious:0,moderate:0,minor:0};for(const S of f.values())g[S.impact]++;const u=new Map;for(const{url:S,v:k}of p){let E=u.get(k.ruleId);E||(E={ruleId:k.ruleId,description:k.description,impact:k.impact,urls:new Set,totalOccurrences:0},u.set(k.ruleId,E)),E.urls.add(S),E.totalOccurrences++}const w=Array.from(u.values()).map(S=>({ruleId:S.ruleId,description:S.description,impact:S.impact,urlsAffected:S.urls.size,totalOccurrences:S.totalOccurrences,sampleUrls:Array.from(S.urls).slice(0,5)})).sort((S,k)=>k.urlsAffected!==S.urlsAffected?k.urlsAffected-S.urlsAffected:k.totalOccurrences-S.totalOccurrences),R={A:0,B:0,C:0,D:0,F:0};for(const S of r)R[S.grade]++;return{startedAt:n,finishedAt:o,startUrl:e,pagesAudited:i,pagesFailed:c,totalDurationMs:s,siteGrade:d,siteRisk:l,totalUniqueViolations:a,totals:g,topViolations:w,pages:r,pagesByGrade:R}}function As(e){const t=new Map(e.breakpointPresets.map(o=>[o.id,o])),n=[];for(const o of e.breakpoints){const s=t.get(o);if(s)for(const i of e.directions)for(const c of e.themes){const r=e.ariaVariations.length===0?[null]:e.ariaVariations;for(const d of r)for(const l of e.pseudoStates)n.push({pseudoState:l,ariaVariation:d,theme:c,direction:i,breakpoint:s})}}return n}const mn=["color-contrast","color-contrast-enhanced","link-in-text-block"],Ss=["image-alt","input-image-alt","area-alt","svg-img-alt","object-alt","role-img-alt","label","select-name","aria-input-field-name","aria-toggle-field-name","form-field-multiple-labels","autocomplete-valid","label-content-name-mismatch","label-title-only","button-name","input-button-name","link-name","empty-button","empty-heading","empty-link","frame-title","heading-order","page-has-heading-one","landmark-one-main","landmark-no-duplicate-banner","landmark-no-duplicate-contentinfo","landmark-no-duplicate-main","landmark-unique","landmark-banner-is-top-level","landmark-complementary-is-top-level","landmark-contentinfo-is-top-level","landmark-main-is-top-level","region","bypass","empty-table-header","aria-allowed-attr","aria-required-attr","aria-required-children","aria-required-parent","aria-roles","aria-valid-attr-value","aria-valid-attr","aria-hidden-body","aria-hidden-focus","aria-allowed-role","aria-prohibited-attr","presentation-role-conflict","aria-text","aria-deprecated-role","aria-conditional-attr","aria-braille-equivalent","html-has-lang","html-lang-valid","html-xml-lang-mismatch","valid-lang","nested-interactive","tabindex","frame-focusable-content","no-focusable-content","focus-order-semantics","meta-viewport","meta-refresh","duplicate-id","duplicate-id-active","duplicate-id-aria","video-caption","audio-caption","table-fake-caption","scope-attr-valid","th-has-data-cells","td-headers-attr"];{const e=new Set(mn),t=Ss.filter(n=>e.has(n));t.length>0&&console.error("axe-rule-classification: rule(s) classified as BOTH state-dependent and markup-eligible:",t)}const xs=z("ai-alt-text");async function Es(e,t,n={}){var h,f;if(!t.enabled||!t.enabledChecks.altText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const o=Q(t);if(!o.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${o.reason}`]};const s=o.client,i=Z(t.costCapUsd),c=[],r=[],d=Math.max(1,t.maxCandidatesPerCheck??10),l=e.slice(0,d),p=l.length;for(let a=0;a<l.length;a++){const g=l[a];if(!i.canCharge())break;try{if((h=n.signal)!=null&&h.aborted){r.push(`canceled after ${a}/${p} candidates`);break}const u=await s.judgeAltText({imageUrl:g.imageUrl,alt:g.alt,surroundingContext:g.surroundingContext,signal:n.signal});i.recordCharge(u.costUsd),(u.verdict==="fail"||u.verdict==="uncertain"&&u.confidence<.6)&&c.push(await ks(g,u))}catch(u){if(u instanceof Error&&(u.name==="AbortError"||u.name==="ExternalAbortError")){r.push(`canceled after ${a}/${p} candidates`);break}const R=u instanceof Error?u.message:String(u);r.push(`${g.selector}: ${R}`),xs.warn("alt-text judgment failed",u)}(f=n.onProgress)==null||f.call(n,a+1,p)}return{findings:c,totalCostUsd:i.state.spentUsd,capExceeded:i.state.exceeded,errors:r}}async function ks(e,t){const n=t.verdict==="uncertain"?"ai-alt-uncertain":"ai-alt-misleading",o={selector:e.selector,outerHTML:e.outerHTML.slice(0,500),failureSummary:`AI assessment: ${t.reasoning}`,tagName:"IMG",role:null,accessibleName:e.alt,textSnippet:null,attrId:null,attrTestid:null},s=await lt({ruleId:n,componentId:e.componentId,currentState:e.currentState,target:o}),i=t.verdict==="uncertain";return{ruleId:n,wcagCriterion:"1.1.1",wcagLevel:"A",impact:i?"minor":"serious",description:i?"AI couldn't verify whether this alt text is appropriate — flag for human review.":"AI judged the alt text to be misleading, generic, or otherwise inappropriate.",helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html",target:o,componentId:e.componentId,currentState:e.currentState,axeVersion:e.axeVersion,detectedAt:new Date().toISOString(),matchKey:s,ai:{reasoning:t.reasoning,confidence:t.confidence,model:t.model,costUsd:t.costUsd},...i?{needsReview:!0}:{}}}const ye=z("ai-text");function be(e){if(e!=null&&e.aborted){const t=new Error("aborted");throw t.name="AbortError",t}}function we(e){return e instanceof Error&&(e.name==="AbortError"||e.name==="ExternalAbortError"||e.message==="aborted")}async function $s(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.headings)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeHeading({headingText:g.text,sectionContent:g.sectionContent,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await ve("ai-heading-not-descriptive","2.4.6","AA","moderate","AI judged this heading does not describe its section content.",g.selector,g.outerHTML,g.text,u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("heading judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Ts(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.sensory)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeSensoryLanguage({instructionText:g.text,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await ve("ai-sensory-instruction","1.3.3","A","serious","AI flagged this instruction as relying on sensory characteristics (shape, color, location) without a programmatic identifier.",g.selector,g.outerHTML,g.text.slice(0,100),u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("sensory judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Cs(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.aria)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeAriaSemantics({elementHtml:g.outerHTML,computedRole:g.role,surroundingHtml:g.surroundingHtml,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&r.push(await ve("ai-aria-misuse","4.1.2","A","serious",`AI judged role="${g.role}" is being used inappropriately on this element.`,g.selector,g.outerHTML,g.role,u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("aria judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Is(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.genericLinkText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeGenericLinkText({linkText:g.linkText,surroundingText:g.surroundingText,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await ve("ai-generic-link-text","2.4.4","A","serious","AI judged this link's purpose is not clear from its text or surrounding context.",g.selector,g.outerHTML,g.linkText,u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("generic-link judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Rs(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.wallOfText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeWallOfText({blockText:g.blockText,structuralChildrenCount:g.structuralChildrenCount,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await ve("ai-wall-of-text","3.1.5","AAA","moderate","AI flagged this block as a wall of text with insufficient structural breaks (subheadings, lists, paragraphs).",g.selector,g.outerHTML,g.blockText.slice(0,80),u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("wall-of-text judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Os(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.languageMismatch)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{be(o.signal);const u=await i.judgeLanguageMismatch({declaredLang:g.declaredLang,bodyTextSample:g.bodyTextSample,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.7&&r.push(await ve("ai-language-mismatch","3.1.1","A","serious",`AI judged the page's content does not match the declared lang="${g.declaredLang||"(none)"}".`,g.selector,g.outerHTML,g.bodyTextSample.slice(0,80),u,t))}catch(u){if(we(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),ye.warn("language-mismatch judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function ve(e,t,n,o,s,i,c,r,d,l){const p={selector:i,outerHTML:c.slice(0,500),failureSummary:`AI assessment: ${d.reasoning}`,tagName:"AI",role:null,accessibleName:null,textSnippet:r.slice(0,100)||null,attrId:null,attrTestid:null},h=await lt({ruleId:e,componentId:l.componentId,currentState:l.currentState,target:p});return{ruleId:e,wcagCriterion:t,wcagLevel:n,impact:o,description:s,helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/",target:p,componentId:l.componentId,currentState:l.currentState,axeVersion:l.axeVersion,detectedAt:new Date().toISOString(),matchKey:h,ai:{reasoning:d.reasoning,confidence:d.confidence,model:d.model,costUsd:d.costUsd}}}const yn=z("ai-vision");function bn(e){if(e!=null&&e.aborted){const t=new Error("aborted");throw t.name="AbortError",t}}function wn(e){return e instanceof Error&&(e.name==="AbortError"||e.name==="ExternalAbortError"||e.message==="aborted")}async function _s(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.imageOfText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=Math.max(1,n.imageOfTextMaxImages??5),d=[...e].sort((a,g)=>g.pixelArea-a.pixelArea).slice(0,r),l=d.length,p=[],h=[];for(let a=0;a<d.length;a++){const g=d[a];if(!c.canCharge())break;try{bn(o.signal);const u=await i.judgeImageOfText({imageUrl:g.imageUrl,accessibleName:g.accessibleName,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&p.push(await vn("ai-image-of-text","1.4.5","AA","moderate","AI judged this image bakes substantial text into the raster — should be presented as actual HTML text instead.",g.selector,g.outerHTML,g.accessibleName??"",u,t))}catch(u){if(wn(u)){h.push(`canceled after ${a}/${l} candidates`);break}const w=u instanceof Error?u.message:String(u);h.push(`${g.selector}: ${w}`),yn.warn("image-of-text judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,l)}return{findings:p,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:h}}async function Ms(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.colorOnlyMeaning)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[s.reason]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{bn(o.signal);const u=await i.judgeColorOnlyMeaning({elementHtml:g.elementHtml,contextDescription:g.contextDescription,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&r.push(await vn("ai-color-only-meaning","1.4.1","A","serious","AI judged this region conveys information only through color (no text label, icon glyph, or shape difference).",g.selector,g.outerHTML,g.contextDescription,u,t))}catch(u){if(wn(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(w),yn.warn("color-only judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function vn(e,t,n,o,s,i,c,r,d,l){const p={selector:i,outerHTML:c.slice(0,500),failureSummary:`AI assessment: ${d.reasoning}`,tagName:"AI",role:null,accessibleName:null,textSnippet:r.slice(0,100)||null,attrId:null,attrTestid:null},h=await lt({ruleId:e,componentId:l.componentId,currentState:l.currentState,target:p});return{ruleId:e,wcagCriterion:t,wcagLevel:n,impact:o,description:s,helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/",target:p,componentId:l.componentId,currentState:l.currentState,axeVersion:l.axeVersion,detectedAt:new Date().toISOString(),matchKey:h,ai:{reasoning:d.reasoning,confidence:d.confidence,model:d.model,costUsd:d.costUsd}}}const it=z("ensure-content-script"),Us=1500,Ns=300;async function An(e,t){if(await Nt(e,t))return{ok:!0};const n=chrome.runtime.getManifest(),o=[];for(const s of n.content_scripts??[])Array.isArray(s.js)&&o.push(...s.js);if(o.length===0)return it.error("manifest declares no content_scripts"),{ok:!1,reason:"inject-failed",detail:"no content_scripts declared in manifest"};try{const s=t!==void 0?{tabId:e,frameIds:[t]}:{tabId:e,allFrames:!0};await chrome.scripting.executeScript({target:s,files:o})}catch(s){return Ps(s)}return await Ls(Ns),await Nt(e,t)?(it.info("content script injected on demand",{tabId:e,frameId:t}),{ok:!0}):{ok:!1,reason:"unresponsive-after-inject",detail:"content script injected but did not register handlers — likely Content Security Policy on this page is blocking it"}}async function Nt(e,t){try{const n=t!==void 0?{frameId:t}:void 0,o=await Promise.race([chrome.tabs.sendMessage(e,{type:"PING_REQUEST"},n),new Promise((s,i)=>setTimeout(()=>i(new Error("ping timeout")),Us))]);return(o==null?void 0:o.type)==="PING_RESPONSE"}catch{return!1}}function Ps(e){const t=e instanceof Error?e.message:String(e);return/cannot access contents of (?:the page|url)/i.test(t)||/chrome:\/\//i.test(t)||/chrome-extension:\/\//i.test(t)||/devtools:\/\//i.test(t)||/chrome\.google\.com\/webstore/i.test(t)||/the extensions gallery/i.test(t)?{ok:!1,reason:"restricted-url",detail:t}:/no tab with id/i.test(t)||/tab .* was closed/i.test(t)?{ok:!1,reason:"tab-gone",detail:t}:(it.warn("content-script injection failed",e),{ok:!1,reason:"inject-failed",detail:t})}function Ls(e){return new Promise(t=>setTimeout(t,e))}function Sn(e){switch(e.reason){case"restricted-url":return"Chrome blocks extensions on this page (chrome:// pages, the Chrome Web Store, view-source: pages, and a few others). Open a regular https:// page and try again.";case"tab-gone":return"The tab was closed or navigated away while the audit was starting. Click into the tab you want audited and click Scan again.";case"unresponsive-after-inject":return"We loaded our auditor onto the page, but the page's Content Security Policy appears to be blocking it. Some sites (banks, gov, strict CSPs) prevent extensions from running. Try a different page on the same site, or open DevTools → Console to confirm a CSP error.";case"inject-failed":return`Could not load our auditor onto the page. Try a hard refresh (Ctrl+Shift+R) on the page and click Scan again. If it persists, the page may be using an unusual document type or origin restriction.${e.detail?` (Detail: ${e.detail})`:""}`;case"unknown":default:return"Could not establish connection with the page. Hard-refresh (Ctrl+Shift+R) the tab you want audited and try again."}}const Xe=z("forensic-anchor-client"),Ds="https://api.wcagcheckr.com",Fs="wcagcheckr",Gs=15e3;function Ws(e){if(typeof e!="object"||e===null)return!1;const t=e;return t.schemaVersion!==1&&t.schemaVersion!==2||!(typeof t.anchoredAt=="string"&&typeof t.tsaName=="string"&&typeof t.rfc3161TokenBase64=="string"&&t.rfc3161TokenBase64.length>0&&typeof t.serverSignatureBase64=="string"&&t.serverSignatureBase64.length>0&&typeof t.serverKeyFingerprint=="string"&&t.serverKeyFingerprint.length>0)?!1:t.schemaVersion===2?typeof t.prevAuditHash=="string"&&/^[0-9a-f]{64}$/.test(t.prevAuditHash):!0}async function Vs(e,t){const n={auditHash:e.hash,pageUrl:e.pageUrl,capturedAt:e.capturedAt,...t?{licenseId:t}:{}},o=`${Ds}/v1/products/${Fs}/forensic/anchor`;try{const s=await fetch(o,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(Gs)});if(!s.ok)return Xe.warn(`anchor HTTP ${s.status}; entry stays local-only`),null;const i=await s.json();return Ws(i)?i:(Xe.warn("anchor returned malformed receipt; entry stays local-only",i),null)}catch(s){return Xe.warn("anchor request failed; entry stays local-only",s),null}}const Pt="4.11.4";async function js(e){try{return(await chrome.tabs.get(e)).url??""}catch{return""}}const C=z("flows");async function Re(){const e=await Ge();if(!e)throw new Error("no audit target tab found");return e}async function ft(){var n,o,s,i,c;const e=await Se("stateMatrix",et);return((n=e.pseudoStates)==null?void 0:n.length)>0&&((o=e.themes)==null?void 0:o.length)>0&&((s=e.directions)==null?void 0:s.length)>0&&((i=e.breakpoints)==null?void 0:i.length)>0&&((c=e.breakpointPresets)==null?void 0:c.length)>0?e:(C.warn("stored stateMatrix is invalid; using defaults"),et)}async function zs(){const e=await Se("runsPerState",1);return typeof e!="number"||e<1||e>5?1:Math.floor(e)}async function Hs(e,t,n){const o=t.themes.includes("light"),s=t.themes.includes("dark");if(!o||!s)return t;let i=null;try{i=await q(e,{type:"THEME_AWARENESS_REQUEST"},n)}catch{return t}return!i||i.hasUnreadableSheets?t:i.hasDarkModeCss&&!i.hasLightModeCss?(C.info("theme-axis prune: site is dark-only, skipping light pass"),{...t,themes:t.themes.filter(c=>c!=="light")}):i.hasLightModeCss&&!i.hasDarkModeCss?(C.info("theme-axis prune: site is light-only, skipping dark pass"),{...t,themes:t.themes.filter(c=>c!=="dark")}):t}function Bs(e){if(e.length<=1)return e[0]??[];const t=new Map;return e.forEach((n,o)=>{for(const s of n){const i=`${s.ruleId}::${s.target.selector}`,c=t.get(i);c?c.runIndices.add(o):t.set(i,{v:s,runIndices:new Set([o])})}}),Array.from(t.values()).map(({v:n,runIndices:o})=>({...n,flakyAcrossRuns:o.size<e.length}))}async function ie(e,t,n,o){var x,_,L;const s=await Re(),i=await An(s,n);if(!i.ok){M({type:"AUDIT_FAILED_EVENT",error:{code:i.reason==="restricted-url"?"RESTRICTED_URL":"CONTENT_SCRIPT_UNREACHABLE",message:Sn(i),recoverable:i.reason!=="restricted-url"}});return}const c=o??await ft(),r=await Hs(s,c,n),d=As(r),l=await zs(),p=await Qn(`${await js(s)}|${e}|${n??0}`),h=await Zn(r),f=await Se("axeDisabledRules",[]),a=await ea(f);let g=null;try{g=(await q(s,{type:"SCOPE_FINGERPRINT_REQUEST",selector:e},n)).fingerprint}catch(b){C.debug("scope fingerprint failed; skipping cache fast-path",b)}if(g){const b=await ta(p);if(b&&b.fingerprint===g&&b.axeVersion===Pt&&b.matrixConfigHash===h&&b.disabledRulesHash===a){C.info(`audit-cache HIT for ${b.componentId} — skipping matrix iteration`),M({type:"AUDIT_COMPLETE_EVENT",componentId:b.componentId,results:b.results,delta:b.delta}),M({type:"SCORECARD_UPDATED_EVENT"});return}}await Ce({sessionId:Ie(),mode:"single-element",scope:e,startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"}),await re(s,{type:"LIVE_REGIONS_ARM_REQUEST"},n).catch(()=>{}),await re(s,{type:"FOCUS_TRACE_ARM_REQUEST"},n).catch(()=>{}),await q(s,{type:"WARMUP_REQUEST"},n).catch(()=>{});const u=[],w=[];let R="",S,k=!1,E=null,P=null;try{for(let b=0;b<d.length;b++){if(t.isCanceled()){C.info("single audit canceled by user");break}const $=d[b];try{const O=await nt(s,$,e,n);if(!O.success){S=(x=O.error)==null?void 0:x.message,C.warn(`state ${b+1}/${d.length} drive failed`,S);continue}$.breakpoint.id!==E&&(await q(s,{type:"WARMUP_REQUEST"},n).catch(()=>{}),E=$.breakpoint.id);const A=[];let v=null;const T=b===0?void 0:[...mn];for(let V=0;V<l;V++){const j=await q(s,{type:"AUDIT_REQUEST",selector:e,currentState:$,rulesToRun:T},n);j.success&&j.result?(A.push(j.result.violations),v=j.result):j.error&&(S=j.error.message,C.warn(`state ${b+1}/${d.length} run ${V+1} failed`,S))}if(v&&A.length>0){k=!0;const V=Bs(A),j=await va(s,{quality:75})??void 0;let F,B;try{F=(await q(s,{type:"LIVE_REGIONS_DRAIN_REQUEST"},n)).announcements}catch{}try{B=(await q(s,{type:"FOCUS_TRACE_DRAIN_REQUEST"},n)).focusEvents}catch{}if(w.push({...v,violations:V,frameId:n,announcements:F,focusEvents:B,screenshotDataUrl:j}),u.push(...V),R=v.componentId,b===0&&P===null)try{const m=await Se("aiConfig",{}),U=ke(m);U.enabled&&U.apiKey&&R&&(P=ct(s,e,n,U,w,R,t).catch(I=>{C.warn("ai augmentation (parallel) failed",I)}))}catch(m){C.debug("ai augmentation (parallel) gate-read failed",m)}}}catch(O){S=O instanceof Error?O.message:String(O),C.warn(`state ${b+1}/${d.length} threw`,O)}M({type:"AUDIT_PROGRESS_EVENT",current:b+1,total:d.length,currentState:$,componentId:R||void 0}),await Fe({})}if(k&&R){const b={pseudoState:"default",ariaVariation:null,theme:"light",direction:"ltr",breakpoint:{id:"desktop",label:"Desktop",width:1280,height:800,deviceScaleFactor:1,mobile:!1}};try{await nt(s,b,e,n),await new Promise(v=>setTimeout(v,200))}catch(v){C.debug("reference-state drive failed; analyzers will use last matrix state",v)}try{const v=await q(s,{type:"READING_ORDER_REQUEST",selector:e},n);w[0]&&(v.issues.length>0?(w[0].readingOrderIssues=v.issues,w[0].positionAnalysisCapturedAt=b):(_=w[0].axeRulesEvaluated)==null||_.passed.push({ruleId:"wcc-reading-order-clean",wcagCriterion:"1.3.2"}))}catch(v){C.debug("reading-order analysis skipped",v)}try{const v=await q(s,{type:"TAB_ORDER_ANALYZE_REQUEST"},n);w[0]&&(v.issues.length>0?(w[0].tabOrderIssues=v.issues,w[0].positionAnalysisCapturedAt=b):(L=w[0].axeRulesEvaluated)==null||L.passed.push({ruleId:"wcc-tab-order-clean",wcagCriterion:"2.4.3"}))}catch(v){C.debug("tab-order analysis skipped",v)}try{const v=await q(s,{type:"TYPOGRAPHY_ANALYZE_REQUEST",selector:e},n);v.issues.length>0&&w[0]&&(w[0].typographyIssues=v.issues)}catch(v){C.debug("typography analysis skipped",v)}try{const v=await q(s,{type:"CUSTOM_PROPERTY_REQUEST"},n);v.undefined.length>0&&w[0]&&(w[0].undefinedCustomProperties=v.undefined)}catch(v){C.debug("custom-property analysis skipped",v)}try{if(P)await P;else{const v=await Se("aiConfig",{}),T=ke(v);T.enabled&&T.apiKey&&await ct(s,e,n,T,w,R,t)}}catch(v){C.warn("ai augmentation skipped",v)}const $=w.flatMap(v=>v.announcements??[]),O=w.flatMap(v=>v.focusEvents??[]),A=await nn(R,u,{announcements:$,focusEvents:O},c);try{const v=le(u,void 0,w),T=w.reduce((j,F)=>j+F.durationMs,0),V=await Hn(w,v,T);if(V){const j=await Ht();if(Jn(j,"forensicAnchoring"))try{const F=await Bn(),B=await Vs(V,F??void 0);B&&await qn(V.componentId,V.capturedAt,B)}catch(F){C.warn("forensic anchoring failed (entry stays local-only)",F)}}}catch(v){C.warn("forensic log recording failed",v)}if(g)try{await na({lookupKey:p,fingerprint:g,axeVersion:Pt,matrixConfigHash:h,disabledRulesHash:a,results:w,delta:A,componentId:R,cachedAt:Date.now()})}catch(v){C.warn("audit-cache write failed",v)}M({type:"AUDIT_COMPLETE_EVENT",componentId:R,results:w,delta:A})}else M({type:"AUDIT_FAILED_EVENT",error:{code:"AXE_FAILED",message:S?`All audits failed. Last error: ${S}`:"No state produced results. Selector may not exist in the audit target frame.",recoverable:!0}});await he()}catch(b){C.error("single audit failed",b),M({type:"AUDIT_FAILED_EVENT",componentId:R||void 0,error:Fn(b)?b.payload:{code:"UNKNOWN",message:String(b),recoverable:!1}})}finally{await re(s,{type:"LIVE_REGIONS_DISARM_REQUEST"},n).catch(()=>{}),await re(s,{type:"FOCUS_TRACE_DISARM_REQUEST"},n).catch(()=>{}),await Qt(s,e,n)}}async function xn(e){var t;try{const o=(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{var i;const s=window;return{detected:typeof s.__STORYBOOK_PREVIEW__=="object",version:(i=s.__STORYBOOK_PREVIEW__)==null?void 0:i.version}}})).find(s=>{var i;return(i=s.result)==null?void 0:i.detected});if(o)return{detected:!0,version:(t=o.result)==null?void 0:t.version,frameId:o.frameId}}catch(n){C.warn("storybook detection scripting failed",n)}return{detected:!1}}async function En(e){const t=await Re(),n=await Cn(t);if(await chrome.storage.local.set({"storybook:lastDetected":{detected:n.kind==="storybook"&&n.detected,version:n.version,detectedAt:new Date().toISOString()},"playground:lastDetected":{kind:n.kind,detected:n.detected,version:n.version,detectedAt:new Date().toISOString()}}),!n.detected){M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:"No supported component playground detected on this tab. Open a Storybook (iframe.html / storybook-static), Ladle, or Bit page and try again.",recoverable:!0}});return}if(n.kind==="bit"){M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:"Bit detected. Auto-iterate is not yet supported for Bit (compositions are iframe-per-component without a unified listing API). Use the element picker to audit individual compositions one at a time.",recoverable:!0}});return}const o=n.frameId??0,s=n.kind==="storybook"?await Ks(t,o):await Js(t,o);if(!s.length){C.warn(`${n.kind} detected but no stories returned`),M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:`${n.kind==="ladle"?"Ladle":"Storybook"} detected but no stories were returned. Try reloading the page.`,recoverable:!0}});return}await Ce({sessionId:Ie(),mode:"storybook-all",totalStories:s.length,completedStories:[],startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});for(const i of s){if(e.isCanceled()){C.info(`${n.kind} iteration canceled by user`);break}try{if(n.kind==="storybook"){await Ys(t,o,i.id);const r=await re(t,{type:"STORYBOOK_GET_STORY_TARGET_REQUEST",tabId:t},o);await ie(r.selector,e,o)}else await Xs(t,o,i.id),await ie("#ladle-root",e,o)}catch(r){C.warn(`story ${i.id} failed; continuing with next`,r)}const c=await Bt();if((c==null?void 0:c.state)==="interrupted"){C.info("storybook iteration interrupted");break}await Fe({completedStories:[...(c==null?void 0:c.completedStories)??[],i.id]})}M({type:"SCORECARD_UPDATED_EVENT"}),await he()}async function kn(e){const t=await Re();let n=[];try{n=(await chrome.scripting.executeScript({target:{tabId:t,allFrames:!0},func:()=>({url:window.location.href})})).map(s=>{var i;return{frameId:s.frameId,url:((i=s.result)==null?void 0:i.url)??""}}).filter(s=>/^https?:/i.test(s.url))}catch(o){C.warn("multi-frame discovery failed",o)}if(n.length===0){M({type:"AUDIT_FAILED_EVENT",error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:"No auditable frames found on this tab. The page may use only chrome-extension:// or data: frames.",recoverable:!0}});return}await Ce({sessionId:Ie(),mode:"all-frames",totalFrames:n.length,completedFrames:[],startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});for(const o of n){if(e.isCanceled()){C.info("all-frames iteration canceled");break}try{await ie("html",e,o.frameId)}catch(i){C.warn(`frame ${o.frameId} (${o.url.slice(0,80)}) audit failed; continuing`,i)}const s=await Bt();if((s==null?void 0:s.state)==="interrupted"){C.info("all-frames iteration interrupted");break}await Fe({completedFrames:[...(s==null?void 0:s.completedFrames)??[],o.frameId]})}M({type:"SCORECARD_UPDATED_EVENT"}),await he()}async function qs(e){var o;const t=await Ge();let n;if(t!==null)try{n=(await chrome.tabs.get(t)).url}catch(s){C.warn("failed to get target tab url",s)}if(!n){M({type:"AUDIT_FAILED_EVENT",error:{code:"NETWORK",message:"Could not determine target URL for parallel scan.",recoverable:!1}});return}await Ce({sessionId:Ie(),mode:"single-element",scope:"html",startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});try{const s=await ft(),{runParallelTabAudit:i}=await Ze(async()=>{const{runParallelTabAudit:l}=await import("./parallel-tab-flow-B4su0Nob.js");return{runParallelTabAudit:l}},__vite__mapDeps([0,1,2,3,4,5,6])),c=await i({targetUrl:n,scope:"html",matrix:s,parallelism:4,cancel:e});if(C.info(`parallel scan complete: ${c.results.length} results across ${c.tabsCompleted} tabs (${c.tabsFailed} failed) in ${Math.round(c.parallelDurationMs)}ms`),c.results.length===0){M({type:"AUDIT_FAILED_EVENT",error:{code:"NETWORK",message:`All ${c.tabsFailed} worker tabs failed. Falling back to Full Page scan is recommended.`,recoverable:!0}});return}const r=((o=c.results[0])==null?void 0:o.componentId)??"parallel-scan",d={new:[],persistent:[],fixed:[],newCount:0,persistentCount:0,fixedCount:0,baselineSnapshotMeta:null,comparedAt:new Date().toISOString()};M({type:"AUDIT_COMPLETE_EVENT",componentId:r,results:c.results,delta:d}),M({type:"SCORECARD_UPDATED_EVENT"})}catch(s){C.warn("parallel scan failed",s),M({type:"AUDIT_FAILED_EVENT",error:{code:"UNKNOWN",message:s instanceof Error?s.message:String(s),recoverable:!0}})}finally{await he()}}async function Ks(e,t){var n;try{return((n=(await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",func:async()=>{var d,l;const s=window.__STORYBOOK_PREVIEW__;if(!s)return[];const i=s.storyStoreValue??s.storyStore;if(!i)return[];typeof i.cacheAllCSFFiles=="function"&&await i.cacheAllCSFFiles();const c=((d=i.extract)==null?void 0:d.call(i))??((l=i.cachedCSFFiles)==null?void 0:l.call(i));if(!c)return[];const r=[];if(c instanceof Map)for(const[p,h]of c){const f=h;r.push({id:String(p),name:f.name??String(p),kind:f.title??f.kind??""})}else if(typeof c=="object"&&c!==null)for(const[p,h]of Object.entries(c)){const f=h;r.push({id:p,name:f.name??p,kind:f.title??f.kind??""})}return r}}))[0])==null?void 0:n.result)??[]}catch(o){return C.warn("listStoriesViaMainWorld failed",o),[]}}async function Ys(e,t,n){try{await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",args:[n,3e3],func:async(o,s)=>{const i=new URL(window.location.href);i.searchParams.set("id",o),i.searchParams.set("viewMode","story"),window.location.href!==i.href&&(window.history.pushState({},"",i.href),window.dispatchEvent(new PopStateEvent("popstate"))),await new Promise(c=>{const r=setTimeout(()=>c(),s),d=()=>{clearTimeout(r),c()};window.addEventListener("storyrendered",d,{once:!0})})}})}catch(o){C.warn(`navigateToStoryViaMainWorld(${n}) failed`,o)}}async function $n(e){var t;try{const o=(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{const s=document.getElementById("ladle-root")!==null,i=document.title==="Ladle",c=!!document.querySelector('link[href*="ladle.css"]');return{detected:s&&(i||c),version:void 0}}})).find(s=>{var i;return(i=s.result)==null?void 0:i.detected});if(o)return{detected:!0,version:(t=o.result)==null?void 0:t.version,frameId:o.frameId}}catch(n){C.warn("ladle detection scripting failed",n)}return{detected:!1}}async function Js(e,t){var n;try{return((n=(await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",func:async()=>{try{const s=await fetch(new URL("/meta.json",window.location.href).href,{credentials:"same-origin"});if(!s.ok)return[];const c=(await s.json()).stories??{};return Object.entries(c).map(([r,d])=>({id:r,name:d.name??r,kind:(d.levels??[]).join(" / ")}))}catch{return[]}}}))[0])==null?void 0:n.result)??[]}catch(o){return C.warn("listLadleStoriesViaMainWorld failed",o),[]}}async function Xs(e,t,n){try{await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",args:[n,3e3],func:async(o,s)=>{const i=new URL(window.location.href);i.searchParams.set("story",o),window.location.href!==i.href&&(window.history.pushState({},"",i.href),window.dispatchEvent(new PopStateEvent("popstate"))),await new Promise(c=>setTimeout(c,Math.min(s,500)))}})}catch(o){C.warn(`navigateToLadleStoryViaMainWorld(${n}) failed`,o)}}async function Tn(e){try{return(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{const n=window.location.href;return/bit\.dev|bit-dev|bitsrc|\/~aspect|\/composition/i.test(n)}})).some(n=>n.result===!0)}catch{return!1}}async function Cn(e){const t=await xn(e);if(t.detected)return{kind:"storybook",...t};const n=await $n(e);return n.detected?{kind:"ladle",...n}:await Tn(e)?{kind:"bit",detected:!0}:{kind:null,detected:!1}}const Qs=200,Zs=6e4;function Lt(e,t){try{return new URL(e).origin===new URL(t).origin}catch{return!1}}function er(e,t){try{const n=new URL(e,t);return n.hash="",n.toString()}catch{return null}}async function tr(e,t,n){await chrome.tabs.update(e,{url:t}),await new Promise((o,s)=>{const i=setTimeout(()=>{chrome.tabs.onUpdated.removeListener(c),s(new Error(`navigation timeout (${n}ms): ${t}`))},n);function c(r,d){r===e&&d.status==="complete"&&(clearTimeout(i),chrome.tabs.onUpdated.removeListener(c),o())}chrome.tabs.onUpdated.addListener(c)}),await new Promise(o=>setTimeout(o,400))}async function nr(e){var t;try{return((t=(await chrome.scripting.executeScript({target:{tabId:e},func:()=>Array.from(document.querySelectorAll("a[href]")).map(o=>o.getAttribute("href")).filter(o=>typeof o=="string"&&!o.startsWith("javascript:"))}))[0])==null?void 0:t.result)??[]}catch(n){return C.debug("link discovery failed",n),[]}}async function In(e,t,n){var f;const o=await Re(),s=Math.min(t.maxPages??25,Qs),i=t.includeRegex?Dt(t.includeRegex):null,c=t.excludeRegex?Dt(t.excludeRegex):null,r=new Date().toISOString(),d=Date.now(),l=[e],p=new Set,h=[];await Ce({sessionId:Ie(),mode:"storybook-all",scope:e,startedAt:r,lastProgressAt:new Date().toISOString(),state:"running"});try{for(;l.length>0&&p.size<s;){if(n.isCanceled()){C.info("site crawl canceled by user");break}const w=l.shift();if(!w||p.has(w)||!Lt(w,e)||i&&!i.test(w)||c&&c.test(w))continue;p.add(w);const R=p.size,S=Date.now();M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"auditing"});try{await tr(o,w,Zs);const k=await An(o,0);if(!k.ok)throw new Error(Sn(k));await q(o,{type:"WARMUP_REQUEST"},0).catch(()=>{});const E=await q(o,{type:"AUDIT_REQUEST",selector:"html",currentState:{pseudoState:"default",ariaVariation:null,theme:"light",direction:"ltr",breakpoint:{id:"desktop",label:"Desktop",width:1280,height:800,deviceScaleFactor:1,mobile:!1}}},0),P=Date.now()-S;if(E.success&&E.result)h.push({url:w,results:[E.result],delta:null,componentId:E.result.componentId,durationMs:P}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"completed",violations:E.result.violations.length});else{const _=((f=E.error)==null?void 0:f.message)??"audit returned no result";h.push({url:w,results:[],delta:null,componentId:w,durationMs:P,error:_}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"failed",error:_})}const x=await nr(o);for(const _ of x){const L=er(_,w);L&&Lt(L,e)&&!p.has(L)&&!l.includes(L)&&l.push(L)}}catch(k){const E=Date.now()-S,P=k instanceof Error?k.message:String(k);h.push({url:w,results:[],delta:null,componentId:w,durationMs:E,error:P}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"failed",error:P})}await Fe({})}const a=new Date().toISOString(),g=Date.now()-d,u=vs(e,h,r,a,g);M({type:"SITE_CRAWL_COMPLETE_EVENT",report:u}),await he()}catch(a){C.error("site crawl failed",a),M({type:"SITE_CRAWL_FAILED_EVENT",error:{code:"UNKNOWN",message:String(a),recoverable:!1}}),await he()}}function Dt(e){try{return new RegExp(e)}catch{return null}}const Qe=5*6e4,Ft=9e4,Gt={altText:"Verifying alt text…",headings:"Judging heading quality…",sensory:"Scanning for sensory-only instructions…",aria:"Reviewing ARIA semantics…",imageOfText:"Detecting baked-in text in images…",colorOnlyMeaning:"Checking for color-only meaning…",genericLinkText:"Reviewing link clarity…",wallOfText:"Detecting walls of text…",languageMismatch:"Verifying page language…"};async function ct(e,t,n,o,s,i,c){let r;try{r=await q(e,{type:"AI_CANDIDATES_REQUEST",selector:t},n)}catch(A){C.debug("ai candidates fetch failed",A);return}const d=s[0];if(!d)return;const l={componentId:i,currentState:d.state,axeVersion:d.axeVersion},p={at:new Date().toISOString(),componentId:i,pageUrl:d.pageUrl??t,enabledChecks:o.enabledChecks,candidateCounts:{images:r.images.length,headings:r.headings.length,instructions:r.instructions.length,ariaElements:r.ariaElements.length,links:r.links.length,longTextBlocks:r.longTextBlocks.length,colorOnlyRegions:r.colorOnlyRegions.length,languageInfo:r.languageInfo?"present":"null"}};C.info("ai augmentation gate snapshot",JSON.stringify(p));try{await chrome.storage.local.set({aiDiagnosticLatest:p})}catch(A){C.warn("failed to persist ai diagnostic to storage.local",A)}try{const A=JSON.stringify(p,null,2),v=`data:application/json;charset=utf-8,${encodeURIComponent(A)}`,T=p.at.replace(/[:.]/g,"-"),V=await chrome.downloads.download({url:v,filename:`wcagcheckr-ai-diag-${T}.json`,saveAs:!1,conflictAction:"uniquify"});C.info(`ai diagnostic download started (id=${V})`)}catch(A){C.warn("failed to write ai diagnostic to Downloads (storage.local copy is still available under aiDiagnosticLatest)",A)}const h=[];if(o.enabledChecks.altText&&h.push({key:"altText",run:A=>{const v=r.images.map(T=>({imageUrl:T.imageUrl,alt:T.alt,selector:T.selector,outerHTML:T.outerHTML,surroundingContext:T.surroundingContext,...l}));return Es(v,o,A)}}),o.enabledChecks.headings&&h.push({key:"headings",run:A=>$s(r.headings,l,o,A)}),o.enabledChecks.sensory&&h.push({key:"sensory",run:A=>Ts(r.instructions,l,o,A)}),o.enabledChecks.aria&&h.push({key:"aria",run:A=>Cs(r.ariaElements,l,o,A)}),o.enabledChecks.imageOfText&&h.push({key:"imageOfText",run:A=>{const v=r.images.map(T=>({imageUrl:T.imageUrl,accessibleName:T.alt||void 0,selector:T.selector,outerHTML:T.outerHTML,pixelArea:T.pixelArea}));return _s(v,l,o,A)}}),o.enabledChecks.colorOnlyMeaning&&h.push({key:"colorOnlyMeaning",run:A=>Ms(r.colorOnlyRegions,l,o,A)}),o.enabledChecks.genericLinkText&&h.push({key:"genericLinkText",run:A=>Is(r.links,l,o,A)}),o.enabledChecks.wallOfText&&h.push({key:"wallOfText",run:A=>Rs(r.longTextBlocks,l,o,A)}),o.enabledChecks.languageMismatch){const A=r.languageInfo;h.push({key:"languageMismatch",run:v=>Os(A?[A]:[],l,o,v)})}if(h.length===0)return;let f=0,a=0,g=!1;const u={};let w=0,R=0,S=0;const k=[];let E=!1,P=!1;function x(A,v){if(u[A]=(u[A]??0)+v.totalCostUsd,f+=v.totalCostUsd,a+=v.findings.length,g=g||v.capExceeded,w++,v.errors.length>0){S++;for(const T of v.errors)k.includes(T)||k.push(T)}else R++;C.info(`ai ${A}: ${v.findings.length} findings, $${v.totalCostUsd.toFixed(4)}, errs=${v.errors.length}`),v.capExceeded&&C.warn(`ai cost cap exceeded after $${v.totalCostUsd.toFixed(4)} during ${A}`)}const _=(async()=>{for(let A=0;A<h.length;A++){if(c!=null&&c.isCanceled()){P=!0;break}const v=h[A];M({type:"AI_AUGMENTATION_PROGRESS_EVENT",componentId:i,currentCheck:v.key,currentCheckLabel:Gt[v.key],current:A+1,total:h.length});const T=new AbortController,V=setTimeout(()=>T.abort(),Ft),j=c?setInterval(()=>{c.isCanceled()&&T.abort()},500):null;let F;try{F=await v.run({signal:T.signal,onProgress:(B,m)=>{m>0&&M({type:"AI_AUGMENTATION_PROGRESS_EVENT",componentId:i,currentCheck:v.key,currentCheckLabel:Gt[v.key],current:A+1,total:h.length,candidatesDone:B,candidatesTotal:m})}}),T.signal.aborted&&(c!=null&&c.isCanceled())?F.errors=[...F.errors,`${v.key} canceled by user`]:T.signal.aborted}catch(B){const m=B instanceof Error?B.message:String(B),U=T.signal.aborted,I=U&&(c!=null&&c.isCanceled())?`${v.key} canceled by user`:U?`${v.key} hit per-check ${Ft/1e3}s cap — analyzer aborted`:`${v.key} threw: ${m}`;F={findings:[],totalCostUsd:0,capExceeded:!1,errors:[I]}}finally{clearTimeout(V),j&&clearInterval(j)}F.findings.length>0&&(d.violations=[...d.violations,...F.findings]),x(v.key,F)}})(),L=new Promise(A=>{setTimeout(()=>A("timeout"),Qe)});await Promise.race([_.then(()=>"done"),L])==="timeout"&&(E=!0,C.warn(`ai augmentation hit global ${Qe/1e3}s timeout after ${w}/${h.length} checks`));let $;if(S>0||E||P){E?$=`AI augmentation timed out after ${Qe/1e3}s`:P?$="AI augmentation canceled":$=k[0]??"AI analyzer error";const A=R===0?"total":"partial";M({type:"AI_AUGMENTATION_FAILED_EVENT",componentId:i,severity:A,reason:$,checksAttempted:w,checksSucceeded:R,checksErrored:S,errorDetails:E||P?[$,...k.slice(0,4)]:k.slice(0,5)}),C.warn(`ai augmentation ${A} failure: ${S}/${w} checks errored — ${$}`)}(f>0||a>0||$)&&await aa({at:new Date().toISOString(),pageUrl:d.pageUrl??t,componentId:i,totalCostUsd:f,byCheck:u,findingsCount:a,capExceeded:g,failureReason:$})}const ar=Object.freeze(Object.defineProperty({__proto__:null,detectBit:Tn,detectLadleAcrossFrames:$n,detectPlayground:Cn,detectStorybookAcrossFrames:xn,getActiveTabId:Re,getMatrixSettings:ft,runAiAugmentation:ct,runAllFramesAudit:kn,runParallelScan:qs,runSingleElementAudit:ie,runSiteCrawl:In,runStorybookAllAudit:En},Symbol.toStringTag,{value:"Module"})),Y=z("service-worker");Nn("service-worker");Qa();var _e,Wt;(Wt=(_e=chrome.sidePanel)==null?void 0:_e.setPanelBehavior)==null||Wt.call(_e,{openPanelOnActionClick:!0}).catch(e=>Y.warn("setPanelBehavior failed",e));Aa();Na();Kn();Ma().catch(e=>Y.warn("initial cloud pull failed",e));(async()=>(await Ya(),on()))();Ja();to();ts();ds();hs();_o();ms();self.addEventListener("unhandledrejection",e=>{const t=e.reason;Pn(t instanceof Error?t:new Error(String(t)))});let De=!1;chrome.runtime.onConnect.addListener(e=>{if(e.name==="audit-keepalive"){Y.debug("keepalive connected"),e.onDisconnect.addListener(async()=>{Y.debug("keepalive disconnected"),await Yn()});return}if(e.name==="sidepanel-tracker"){De=!0,Y.debug("chrome.sidePanel opened"),e.onDisconnect.addListener(async()=>{De=!1,Y.debug("chrome.sidePanel closed — restoring in-page overlay"),await mt()});return}});let gt=!1;const ue={isCanceled:()=>gt};async function Rn(){const e=await Ge();if(e)try{await re(e,{type:"SIDEBAR_HIDE_REQUEST"})}catch(t){Y.warn("sidebar hide failed",t)}}async function mt(){const e=await Ge();if(e)try{await re(e,{type:"SIDEBAR_SHOW_REQUEST"})}catch(t){Y.warn("sidebar show failed",t)}}D("START_AUDIT",async e=>{gt=!1,await Rn();let t;if(e.mode==="single-element"){if(!e.scope)throw new Error("START_AUDIT single-element requires scope");t=ie(e.scope,ue,e.frameId,e.matrixOverride)}else if(e.mode==="full-page")t=ie("html",ue,0,e.matrixOverride);else if(e.mode==="quick-scan"){const{QUICK_SCAN_MATRIX_SETTINGS:n}=await Ze(async()=>{const{QUICK_SCAN_MATRIX_SETTINGS:o}=await import("./state-BIsozXtc.js").then(s=>s.e);return{QUICK_SCAN_MATRIX_SETTINGS:o}},__vite__mapDeps([5,1]));t=ie(e.scope??"html",ue,e.frameId??0,n)}else if(e.mode==="all-frames")t=kn(ue);else if(e.mode==="parallel-scan"){const{runParallelScan:n}=await Ze(async()=>{const{runParallelScan:o}=await Promise.resolve().then(()=>ar);return{runParallelScan:o}},void 0);t=n(ue)}else t=En(ue);t.catch(n=>{Y.error("audit failed",n);const o=n instanceof Error?n.message:String(n),s=/no audit target tab/i.test(o);M({type:"AUDIT_FAILED_EVENT",error:{code:s?"RESTRICTED_URL":"UNKNOWN",message:s?"No audit target tab found. Open a regular http(s) page (not chrome:// or about:blank) and try again.":`Audit failed: ${o}`,recoverable:!0}})}).finally(()=>{De||mt()})});D("CANCEL_AUDIT",async()=>{gt=!0,Y.info("cancel requested")});let yt=!1;const or={isCanceled:()=>yt};D("START_SITE_CRAWL",async e=>{yt=!1,await Rn(),In(e.startUrl,{maxPages:e.maxPages,includeRegex:e.includeRegex,excludeRegex:e.excludeRegex},or).catch(t=>Y.error("site crawl failed",t)).finally(()=>{De||mt()})});D("CANCEL_SITE_CRAWL",async()=>{yt=!0,Y.info("site crawl cancel requested")});D("OPEN_SETTINGS",()=>{chrome.runtime.openOptionsPage()});Y.info("service worker ready");export{An as a,nt as d,As as e,Qt as r};
791
+ </html>`}async function es(){const t=(await chrome.storage.local.get("aiConfig")).aiConfig;return{...Xn,...t??{}}}async function Mt(e,t,n){const o=await es();if(!o.enabled||!o.apiKey||e.length===0)return null;const s=e.flatMap(d=>d.violations),i=le(s,void 0,e),c=i.categories.filter(d=>d.status==="fail").sort((d,l)=>l.violationCount-d.violationCount).slice(0,3).map(d=>d.label),r=e[0];return rn({framing:t,riskTier:i.risk,grade:i.letter,totals:{critical:i.totals.critical,serious:i.totals.serious,moderate:i.totals.moderate,minor:i.totals.minor,unique:i.totals.unique},riskDrivers:c,pageUrl:(r==null?void 0:r.pageUrl)??(r==null?void 0:r.scope)??"",auditDate:(r==null?void 0:r.startedAt)??new Date().toISOString(),priorAuditCount:n},o)}function ts(){return D("EXPORT_REQUEST",async e=>{if(e.format==="sarif")return{type:"EXPORT_RESPONSE",format:"sarif",content:JSON.stringify(Uo(e.results,e.delta),null,2)};if(e.format==="junit")return{type:"EXPORT_RESPONSE",format:"junit",content:No(e.results,e.delta)};if(e.format==="html-print")return{type:"EXPORT_RESPONSE",format:"html-print",content:Po(e.results,e.delta)};if(e.format==="vpat")return{type:"EXPORT_RESPONSE",format:"vpat",content:Lo(e.results,e.delta)};if(e.format==="ai-prompt")return{type:"EXPORT_RESPONSE",format:"ai-prompt",content:Go(e.results,e.delta,e.manualRuns,e.siteCrawlReport,e.dismissedKeys,e.incompleteResolutions)};if(e.format==="defense-bundle"){const t=await vt(),n=await Mt(e.results,"defense",t.length);return{type:"EXPORT_RESPONSE",format:"defense-bundle",content:pn(e.results,e.delta,"defense",e.manualRuns,t,n)}}if(e.format==="evidence-bundle"){const t=await vt(),n=await Mt(e.results,"evidence",t.length);return{type:"EXPORT_RESPONSE",format:"evidence-bundle",content:Ko(e.results,e.delta,e.manualRuns,t,n)}}return e.format==="developer-letter"?{type:"EXPORT_RESPONSE",format:"developer-letter",content:Yo(e.results)}:e.format==="owner-report"?{type:"EXPORT_RESPONSE",format:"owner-report",content:Jo(e.results)}:e.format==="ai-prompt-owner"?{type:"EXPORT_RESPONSE",format:"ai-prompt-owner",content:Xo(e.results)}:{type:"EXPORT_RESPONSE",format:"json",content:JSON.stringify(Mo(e.results,e.delta),null,2)}})}const ns=z("support-messenger"),as="https://api.wcagcheckr.com/v1/products/wcagcheckr/support",Xe="support:rate-window",os=5,ss=10*60*1e3,rs=2,is="wcagcheckr",Ut="storybook:lastDetected";async function cs(e){if(!e)return;const t=await chrome.runtime.getPlatformInfo(),o=(await chrome.storage.local.get(Ut))[Ut];return{extensionVersion:chrome.runtime.getManifest().version,platform:t,storybookDetected:o!=null&&o.detected?o.version??"detected":"none",licenseTier:await Bt(),logTail:Mn(Un())}}async function ls(e=Date.now()){const n=((await chrome.storage.local.get(Xe))[Xe]??[]).filter(o=>e-o<ss);return n.length>=os?!1:(n.push(e),await chrome.storage.local.set({[Xe]:n}),!0)}async function hn(e,t=0){try{const n=await fetch(as,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw new Error(`http ${n.status}`);const o=await n.json();if(!o.success)throw new Error(o.error??"server returned success=false");return{ticketRef:o.ticketRef??""}}catch(n){if(t<rs){const o=(t+1)*1e3;return await new Promise(s=>setTimeout(s,o)),hn(e,t+1)}throw n}}function ds(){return D("SUPPORT_MESSAGE_REQUEST",async e=>{if(!await ls())return{type:"SUPPORT_MESSAGE_RESPONSE",success:!1,error:Ue("NETWORK","Rate limit reached. Try again in 10 minutes.",!0)};try{const t=await cs(e.includeContext);return{type:"SUPPORT_MESSAGE_RESPONSE",success:!0,ticketRef:(await hn({productSlug:is,subject:e.subject,body:e.body,replyEmail:e.replyEmail,context:t,extensionVersion:chrome.runtime.getManifest().version,timestamp:new Date().toISOString()})).ticketRef}}catch(t){ns.error("send failed",t);const n=t instanceof Error?t.message:String(t);return{type:"SUPPORT_MESSAGE_RESPONSE",success:!1,error:Ue("NETWORK",n,!0)}}})}const fn=z("ai-color-suggester");async function us(e,t,n=[]){if(!t.enabled||e.length===0)return{results:[],totalCostUsd:0,capExceeded:!1};const o=Q(t);if(!o.ok)return{results:[],totalCostUsd:0,capExceeded:!1};const s=o.client,i=Z(t.costCapUsd),c=[];for(const r of e){if(!i.canCharge())break;try{const d=await s.suggestColorFix({foreground:r.foreground,background:r.background,fontSize:r.fontSize,fontWeight:r.fontWeight,targetLevel:r.targetLevel,paletteHints:n});i.recordCharge(d.costUsd),d.verdict==="suggested"&&d.candidates.length>0&&c.push({matchKey:r.matchKey,suggestions:d.candidates,reasoning:d.reasoning,costUsd:d.costUsd})}catch(d){fn.warn(`color-fix suggestion failed for ${r.matchKey}`,d)}}return{results:c,totalCostUsd:i.state.spentUsd,capExceeded:i.state.exceeded}}async function ps(){const e=await chrome.storage.local.get("aiConfig");return ge(e.aiConfig)}function hs(){return D("AI_COLOR_SUGGEST_REQUEST",async e=>{const t=await ps();if(!t.enabled)return{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:"No AI API key configured. Add one in Settings → AI augmentation."};try{const{results:n,totalCostUsd:o,capExceeded:s}=await us(e.inputs,t,e.paletteHints);return{type:"AI_COLOR_SUGGEST_RESPONSE",results:n,totalCostUsd:o,capExceeded:s}}catch(n){return fn.warn("color-suggest handler failed",n),{type:"AI_COLOR_SUGGEST_RESPONSE",results:[],totalCostUsd:0,capExceeded:!1,unavailableReason:n instanceof Error?n.message:String(n)}}})}const gn=z("ai-incomplete-resolver");async function fs(){const e=await chrome.storage.local.get("aiConfig");return ge(e.aiConfig)}async function gs(e){if(!e.aiConfig.enabled||e.elements.length===0)return{resolutions:[],totalCostUsd:0};const t=Q(e.aiConfig);if(!t.ok)return{resolutions:[],totalCostUsd:0};const n=t.client,o=Z(e.aiConfig.costCapUsd),s=[];for(const i of e.elements){if(!o.canCharge())break;try{const c=await n.resolveAxeIncomplete({ruleId:e.ruleId,element:i,pageUrl:e.pageUrl,targetLevel:e.targetLevel});o.recordCharge(c.costUsd),s.push({pageUrl:e.pageUrl,ruleId:e.ruleId,selector:i.selector,verdict:c.verdict,reasoning:c.reasoning,resolvedAt:new Date().toISOString(),costUsd:c.costUsd,wcagCriterion:e.wcagCriterion})}catch(c){gn.warn(`resolveAxeIncomplete failed for ${i.selector}`,c)}}return s.length>0&&await zn(s),{resolutions:s,totalCostUsd:o.state.spentUsd}}function ms(){return D("AI_RESOLVE_INCOMPLETE_REQUEST",async e=>{const t=await fs();if(!t.enabled)return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:"AI augmentation is disabled in Settings → AI augmentation."};if(!t.apiKey)return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:"No AI API key configured. Add one in Settings → AI augmentation."};try{const{resolutions:n,totalCostUsd:o}=await gs({ruleId:e.ruleId,pageUrl:e.pageUrl,wcagCriterion:e.wcagCriterion,elements:e.elements,targetLevel:e.targetLevel,aiConfig:t});return{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:n,totalCostUsd:o}}catch(n){return gn.warn("ai-incomplete-resolver failed",n),{type:"AI_RESOLVE_INCOMPLETE_RESPONSE",resolutions:[],totalCostUsd:0,unavailableReason:n instanceof Error?n.message:"Unknown error during AI resolution."}}})}const Le={A:0,B:1,C:2,D:3,F:4},Nt={low:0,moderate:1,high:2,critical:3};function ys(e,t){return Le[e]>Le[t]?e:t}function bs(e,t){return Nt[e]>Nt[t]?e:t}function ws(e){const t=[];for(const n of e)for(const o of n.results)for(const s of o.violations)t.push({url:n.url,v:s});return t}function vs(e,t,n,o,s){const i=t.filter(S=>!S.error).length,c=t.filter(S=>!!S.error).length,r=t.map(S=>{if(S.error)return{url:S.url,grade:"F",risk:"critical",uniqueViolations:0,totals:{critical:0,serious:0,moderate:0,minor:0},durationMs:S.durationMs,error:S.error};const k=S.results.flatMap(P=>P.violations),E=le(k);return{url:S.url,grade:E.letter,risk:E.risk,uniqueViolations:E.totals.unique,totals:{critical:E.totals.critical,serious:E.totals.serious,moderate:E.totals.moderate,minor:E.totals.minor},durationMs:S.durationMs}});r.sort((S,k)=>{const E=Le[k.grade]-Le[S.grade];return E!==0?E:k.uniqueViolations-S.uniqueViolations});let d="A",l="low";for(const S of r)d=ys(d,S.grade),l=bs(l,S.risk);const p=ws(t),h=S=>`${S.ruleId}::${S.target.selector}`,f=new Map;for(const{v:S}of p){const k=h(S);f.has(k)||f.set(k,S)}const a=f.size,g={critical:0,serious:0,moderate:0,minor:0};for(const S of f.values())g[S.impact]++;const u=new Map;for(const{url:S,v:k}of p){let E=u.get(k.ruleId);E||(E={ruleId:k.ruleId,description:k.description,impact:k.impact,urls:new Set,totalOccurrences:0},u.set(k.ruleId,E)),E.urls.add(S),E.totalOccurrences++}const w=Array.from(u.values()).map(S=>({ruleId:S.ruleId,description:S.description,impact:S.impact,urlsAffected:S.urls.size,totalOccurrences:S.totalOccurrences,sampleUrls:Array.from(S.urls).slice(0,5)})).sort((S,k)=>k.urlsAffected!==S.urlsAffected?k.urlsAffected-S.urlsAffected:k.totalOccurrences-S.totalOccurrences),R={A:0,B:0,C:0,D:0,F:0};for(const S of r)R[S.grade]++;return{startedAt:n,finishedAt:o,startUrl:e,pagesAudited:i,pagesFailed:c,totalDurationMs:s,siteGrade:d,siteRisk:l,totalUniqueViolations:a,totals:g,topViolations:w,pages:r,pagesByGrade:R}}function As(e){const t=new Map(e.breakpointPresets.map(o=>[o.id,o])),n=[];for(const o of e.breakpoints){const s=t.get(o);if(s)for(const i of e.directions)for(const c of e.themes){const r=e.ariaVariations.length===0?[null]:e.ariaVariations;for(const d of r)for(const l of e.pseudoStates)n.push({pseudoState:l,ariaVariation:d,theme:c,direction:i,breakpoint:s})}}return n}const mn=["color-contrast","color-contrast-enhanced","link-in-text-block"],Ss=["image-alt","input-image-alt","area-alt","svg-img-alt","object-alt","role-img-alt","label","select-name","aria-input-field-name","aria-toggle-field-name","form-field-multiple-labels","autocomplete-valid","label-content-name-mismatch","label-title-only","button-name","input-button-name","link-name","empty-button","empty-heading","empty-link","frame-title","heading-order","page-has-heading-one","landmark-one-main","landmark-no-duplicate-banner","landmark-no-duplicate-contentinfo","landmark-no-duplicate-main","landmark-unique","landmark-banner-is-top-level","landmark-complementary-is-top-level","landmark-contentinfo-is-top-level","landmark-main-is-top-level","region","bypass","empty-table-header","aria-allowed-attr","aria-required-attr","aria-required-children","aria-required-parent","aria-roles","aria-valid-attr-value","aria-valid-attr","aria-hidden-body","aria-hidden-focus","aria-allowed-role","aria-prohibited-attr","presentation-role-conflict","aria-text","aria-deprecated-role","aria-conditional-attr","aria-braille-equivalent","html-has-lang","html-lang-valid","html-xml-lang-mismatch","valid-lang","nested-interactive","tabindex","frame-focusable-content","no-focusable-content","focus-order-semantics","meta-viewport","meta-refresh","duplicate-id","duplicate-id-active","duplicate-id-aria","video-caption","audio-caption","table-fake-caption","scope-attr-valid","th-has-data-cells","td-headers-attr"];{const e=new Set(mn),t=Ss.filter(n=>e.has(n));t.length>0&&console.error("axe-rule-classification: rule(s) classified as BOTH state-dependent and markup-eligible:",t)}const xs=z("ai-alt-text");async function Es(e,t,n={}){var h,f;if(!t.enabled||!t.enabledChecks.altText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const o=Q(t);if(!o.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${o.reason}`]};const s=o.client,i=Z(t.costCapUsd),c=[],r=[],d=Math.max(1,t.maxCandidatesPerCheck??10),l=e.slice(0,d),p=l.length;for(let a=0;a<l.length;a++){const g=l[a];if(!i.canCharge())break;try{if((h=n.signal)!=null&&h.aborted){r.push(`canceled after ${a}/${p} candidates`);break}const u=await s.judgeAltText({imageUrl:g.imageUrl,alt:g.alt,surroundingContext:g.surroundingContext,signal:n.signal});i.recordCharge(u.costUsd),(u.verdict==="fail"||u.verdict==="uncertain"&&u.confidence<.6)&&c.push(await ks(g,u))}catch(u){if(u instanceof Error&&(u.name==="AbortError"||u.name==="ExternalAbortError")){r.push(`canceled after ${a}/${p} candidates`);break}const R=u instanceof Error?u.message:String(u);r.push(`${g.selector}: ${R}`),xs.warn("alt-text judgment failed",u)}(f=n.onProgress)==null||f.call(n,a+1,p)}return{findings:c,totalCostUsd:i.state.spentUsd,capExceeded:i.state.exceeded,errors:r}}async function ks(e,t){const n=t.verdict==="uncertain"?"ai-alt-uncertain":"ai-alt-misleading",o={selector:e.selector,outerHTML:e.outerHTML.slice(0,500),failureSummary:`AI assessment: ${t.reasoning}`,tagName:"IMG",role:null,accessibleName:e.alt,textSnippet:null,attrId:null,attrTestid:null},s=await lt({ruleId:n,componentId:e.componentId,currentState:e.currentState,target:o}),i=t.verdict==="uncertain";return{ruleId:n,wcagCriterion:"1.1.1",wcagLevel:"A",impact:i?"minor":"serious",description:i?"AI couldn't verify whether this alt text is appropriate — flag for human review.":"AI judged the alt text to be misleading, generic, or otherwise inappropriate.",helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/non-text-content.html",target:o,componentId:e.componentId,currentState:e.currentState,axeVersion:e.axeVersion,detectedAt:new Date().toISOString(),matchKey:s,ai:{reasoning:t.reasoning,confidence:t.confidence,model:t.model,costUsd:t.costUsd},...i?{needsReview:!0}:{}}}const we=z("ai-text");function ve(e){if(e!=null&&e.aborted){const t=new Error("aborted");throw t.name="AbortError",t}}function Ae(e){return e instanceof Error&&(e.name==="AbortError"||e.name==="ExternalAbortError"||e.message==="aborted")}async function $s(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.headings)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeHeading({headingText:g.text,sectionContent:g.sectionContent,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await Se("ai-heading-not-descriptive","2.4.6","AA","moderate","AI judged this heading does not describe its section content.",g.selector,g.outerHTML,g.text,u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("heading judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Ts(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.sensory)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeSensoryLanguage({instructionText:g.text,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await Se("ai-sensory-instruction","1.3.3","A","serious","AI flagged this instruction as relying on sensory characteristics (shape, color, location) without a programmatic identifier.",g.selector,g.outerHTML,g.text.slice(0,100),u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("sensory judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Cs(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.aria)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeAriaSemantics({elementHtml:g.outerHTML,computedRole:g.role,surroundingHtml:g.surroundingHtml,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&r.push(await Se("ai-aria-misuse","4.1.2","A","serious",`AI judged role="${g.role}" is being used inappropriately on this element.`,g.selector,g.outerHTML,g.role,u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("aria judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Is(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.genericLinkText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeGenericLinkText({linkText:g.linkText,surroundingText:g.surroundingText,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await Se("ai-generic-link-text","2.4.4","A","serious","AI judged this link's purpose is not clear from its text or surrounding context.",g.selector,g.outerHTML,g.linkText,u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("generic-link judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Rs(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.wallOfText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeWallOfText({blockText:g.blockText,structuralChildrenCount:g.structuralChildrenCount,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.6&&r.push(await Se("ai-wall-of-text","3.1.5","AAA","moderate","AI flagged this block as a wall of text with insufficient structural breaks (subheadings, lists, paragraphs).",g.selector,g.outerHTML,g.blockText.slice(0,80),u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("wall-of-text judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Os(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.languageMismatch)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{ve(o.signal);const u=await i.judgeLanguageMismatch({declaredLang:g.declaredLang,bodyTextSample:g.bodyTextSample,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.7&&r.push(await Se("ai-language-mismatch","3.1.1","A","serious",`AI judged the page's content does not match the declared lang="${g.declaredLang||"(none)"}".`,g.selector,g.outerHTML,g.bodyTextSample.slice(0,80),u,t))}catch(u){if(Ae(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(`${g.selector}: ${w}`),we.warn("language-mismatch judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function Se(e,t,n,o,s,i,c,r,d,l){const p={selector:i,outerHTML:c.slice(0,500),failureSummary:`AI assessment: ${d.reasoning}`,tagName:"AI",role:null,accessibleName:null,textSnippet:r.slice(0,100)||null,attrId:null,attrTestid:null},h=await lt({ruleId:e,componentId:l.componentId,currentState:l.currentState,target:p});return{ruleId:e,wcagCriterion:t,wcagLevel:n,impact:o,description:s,helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/",target:p,componentId:l.componentId,currentState:l.currentState,axeVersion:l.axeVersion,detectedAt:new Date().toISOString(),matchKey:h,ai:{reasoning:d.reasoning,confidence:d.confidence,model:d.model,costUsd:d.costUsd}}}const yn=z("ai-vision");function bn(e){if(e!=null&&e.aborted){const t=new Error("aborted");throw t.name="AbortError",t}}function wn(e){return e instanceof Error&&(e.name==="AbortError"||e.name==="ExternalAbortError"||e.message==="aborted")}async function _s(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.imageOfText)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[`AI client unavailable: ${s.reason}`]};const i=s.client,c=Z(n.costCapUsd),r=Math.max(1,n.imageOfTextMaxImages??5),d=[...e].sort((a,g)=>g.pixelArea-a.pixelArea).slice(0,r),l=d.length,p=[],h=[];for(let a=0;a<d.length;a++){const g=d[a];if(!c.canCharge())break;try{bn(o.signal);const u=await i.judgeImageOfText({imageUrl:g.imageUrl,accessibleName:g.accessibleName,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&p.push(await vn("ai-image-of-text","1.4.5","AA","moderate","AI judged this image bakes substantial text into the raster — should be presented as actual HTML text instead.",g.selector,g.outerHTML,g.accessibleName??"",u,t))}catch(u){if(wn(u)){h.push(`canceled after ${a}/${l} candidates`);break}const w=u instanceof Error?u.message:String(u);h.push(`${g.selector}: ${w}`),yn.warn("image-of-text judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,l)}return{findings:p,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:h}}async function Ms(e,t,n,o={}){var f;if(!n.enabled||!n.enabledChecks.colorOnlyMeaning)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[]};const s=Q(n);if(!s.ok)return{findings:[],totalCostUsd:0,capExceeded:!1,errors:[s.reason]};const i=s.client,c=Z(n.costCapUsd),r=[],d=[],l=Math.max(1,n.maxCandidatesPerCheck??10),p=e.slice(0,l),h=p.length;for(let a=0;a<p.length;a++){const g=p[a];if(!c.canCharge())break;try{bn(o.signal);const u=await i.judgeColorOnlyMeaning({elementHtml:g.elementHtml,contextDescription:g.contextDescription,signal:o.signal});c.recordCharge(u.costUsd),u.verdict==="fail"&&u.confidence>=.65&&r.push(await vn("ai-color-only-meaning","1.4.1","A","serious","AI judged this region conveys information only through color (no text label, icon glyph, or shape difference).",g.selector,g.outerHTML,g.contextDescription,u,t))}catch(u){if(wn(u)){d.push(`canceled after ${a}/${h} candidates`);break}const w=u instanceof Error?u.message:String(u);d.push(w),yn.warn("color-only judgment failed",u)}(f=o.onProgress)==null||f.call(o,a+1,h)}return{findings:r,totalCostUsd:c.state.spentUsd,capExceeded:c.state.exceeded,errors:d}}async function vn(e,t,n,o,s,i,c,r,d,l){const p={selector:i,outerHTML:c.slice(0,500),failureSummary:`AI assessment: ${d.reasoning}`,tagName:"AI",role:null,accessibleName:null,textSnippet:r.slice(0,100)||null,attrId:null,attrTestid:null},h=await lt({ruleId:e,componentId:l.componentId,currentState:l.currentState,target:p});return{ruleId:e,wcagCriterion:t,wcagLevel:n,impact:o,description:s,helpUrl:"https://www.w3.org/WAI/WCAG21/Understanding/",target:p,componentId:l.componentId,currentState:l.currentState,axeVersion:l.axeVersion,detectedAt:new Date().toISOString(),matchKey:h,ai:{reasoning:d.reasoning,confidence:d.confidence,model:d.model,costUsd:d.costUsd}}}const ct=z("ensure-content-script"),Us=1500,Ns=300;async function An(e,t){if(await Pt(e,t))return{ok:!0};const n=chrome.runtime.getManifest(),o=[];for(const s of n.content_scripts??[])Array.isArray(s.js)&&o.push(...s.js);if(o.length===0)return ct.error("manifest declares no content_scripts"),{ok:!1,reason:"inject-failed",detail:"no content_scripts declared in manifest"};try{const s=t!==void 0?{tabId:e,frameIds:[t]}:{tabId:e,allFrames:!0};await chrome.scripting.executeScript({target:s,files:o})}catch(s){return Ps(s)}return await Ls(Ns),await Pt(e,t)?(ct.info("content script injected on demand",{tabId:e,frameId:t}),{ok:!0}):{ok:!1,reason:"unresponsive-after-inject",detail:"content script injected but did not register handlers — likely Content Security Policy on this page is blocking it"}}async function Pt(e,t){try{const n=t!==void 0?{frameId:t}:void 0,o=await Promise.race([chrome.tabs.sendMessage(e,{type:"PING_REQUEST"},n),new Promise((s,i)=>setTimeout(()=>i(new Error("ping timeout")),Us))]);return(o==null?void 0:o.type)==="PING_RESPONSE"}catch{return!1}}function Ps(e){const t=e instanceof Error?e.message:String(e);return/cannot access contents of (?:the page|url)/i.test(t)||/chrome:\/\//i.test(t)||/chrome-extension:\/\//i.test(t)||/devtools:\/\//i.test(t)||/chrome\.google\.com\/webstore/i.test(t)||/the extensions gallery/i.test(t)?{ok:!1,reason:"restricted-url",detail:t}:/no tab with id/i.test(t)||/tab .* was closed/i.test(t)?{ok:!1,reason:"tab-gone",detail:t}:(ct.warn("content-script injection failed",e),{ok:!1,reason:"inject-failed",detail:t})}function Ls(e){return new Promise(t=>setTimeout(t,e))}function Sn(e){switch(e.reason){case"restricted-url":return"Chrome blocks extensions on this page (chrome:// pages, the Chrome Web Store, view-source: pages, and a few others). Open a regular https:// page and try again.";case"tab-gone":return"The tab was closed or navigated away while the audit was starting. Click into the tab you want audited and click Scan again.";case"unresponsive-after-inject":return"We loaded our auditor onto the page, but the page's Content Security Policy appears to be blocking it. Some sites (banks, gov, strict CSPs) prevent extensions from running. Try a different page on the same site, or open DevTools → Console to confirm a CSP error.";case"inject-failed":return`Could not load our auditor onto the page. Try a hard refresh (Ctrl+Shift+R) on the page and click Scan again. If it persists, the page may be using an unusual document type or origin restriction.${e.detail?` (Detail: ${e.detail})`:""}`;case"unknown":default:return"Could not establish connection with the page. Hard-refresh (Ctrl+Shift+R) the tab you want audited and try again."}}const Qe=z("forensic-anchor-client"),Ds="https://api.wcagcheckr.com",Fs="wcagcheckr",Gs=15e3;function Ws(e){if(typeof e!="object"||e===null)return!1;const t=e;return t.schemaVersion!==1&&t.schemaVersion!==2||!(typeof t.anchoredAt=="string"&&typeof t.tsaName=="string"&&typeof t.rfc3161TokenBase64=="string"&&t.rfc3161TokenBase64.length>0&&typeof t.serverSignatureBase64=="string"&&t.serverSignatureBase64.length>0&&typeof t.serverKeyFingerprint=="string"&&t.serverKeyFingerprint.length>0)?!1:t.schemaVersion===2?typeof t.prevAuditHash=="string"&&/^[0-9a-f]{64}$/.test(t.prevAuditHash):!0}async function Vs(e,t){const n={auditHash:e.hash,pageUrl:e.pageUrl,capturedAt:e.capturedAt,...t?{licenseId:t}:{}},o=`${Ds}/v1/products/${Fs}/forensic/anchor`;try{const s=await fetch(o,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(Gs)});if(!s.ok)return Qe.warn(`anchor HTTP ${s.status}; entry stays local-only`),null;const i=await s.json();return Ws(i)?i:(Qe.warn("anchor returned malformed receipt; entry stays local-only",i),null)}catch(s){return Qe.warn("anchor request failed; entry stays local-only",s),null}}const Lt="4.11.4";async function js(e){try{return(await chrome.tabs.get(e)).url??""}catch{return""}}const $=z("flows");async function Re(){const e=await We();if(!e)throw new Error("no audit target tab found");return e}async function gt(){var n,o,s,i,c;const e=await he("stateMatrix",tt);return((n=e.pseudoStates)==null?void 0:n.length)>0&&((o=e.themes)==null?void 0:o.length)>0&&((s=e.directions)==null?void 0:s.length)>0&&((i=e.breakpoints)==null?void 0:i.length)>0&&((c=e.breakpointPresets)==null?void 0:c.length)>0?e:($.warn("stored stateMatrix is invalid; using defaults"),tt)}async function zs(){const e=await he("runsPerState",1);return typeof e!="number"||e<1||e>5?1:Math.floor(e)}async function Hs(e,t,n){const o=t.themes.includes("light"),s=t.themes.includes("dark");if(!o||!s)return t;let i=null;try{i=await q(e,{type:"THEME_AWARENESS_REQUEST"},n)}catch{return t}return!i||i.hasUnreadableSheets?t:i.hasDarkModeCss&&!i.hasLightModeCss?($.info("theme-axis prune: site is dark-only, skipping light pass"),{...t,themes:t.themes.filter(c=>c!=="light")}):i.hasLightModeCss&&!i.hasDarkModeCss?($.info("theme-axis prune: site is light-only, skipping dark pass"),{...t,themes:t.themes.filter(c=>c!=="dark")}):t}function Bs(e){if(e.length<=1)return e[0]??[];const t=new Map;return e.forEach((n,o)=>{for(const s of n){const i=`${s.ruleId}::${s.target.selector}`,c=t.get(i);c?c.runIndices.add(o):t.set(i,{v:s,runIndices:new Set([o])})}}),Array.from(t.values()).map(({v:n,runIndices:o})=>({...n,flakyAcrossRuns:o.size<e.length}))}async function ie(e,t,n,o){var x,_,L;const s=await Re(),i=await An(s,n);if(!i.ok){M({type:"AUDIT_FAILED_EVENT",error:{code:i.reason==="restricted-url"?"RESTRICTED_URL":"CONTENT_SCRIPT_UNREACHABLE",message:Sn(i),recoverable:i.reason!=="restricted-url"}});return}const c=o??await gt(),r=await Hs(s,c,n),d=As(r),l=await zs(),p=await Qn(`${await js(s)}|${e}|${n??0}`),h=await Zn(r),f=await he("axeDisabledRules",[]),a=await ea(f);let g=null;try{g=(await q(s,{type:"SCOPE_FINGERPRINT_REQUEST",selector:e},n)).fingerprint}catch(b){$.debug("scope fingerprint failed; skipping cache fast-path",b)}if(g){const b=await ta(p);if(b&&b.fingerprint===g&&b.axeVersion===Lt&&b.matrixConfigHash===h&&b.disabledRulesHash===a){$.info(`audit-cache HIT for ${b.componentId} — skipping matrix iteration`),M({type:"AUDIT_COMPLETE_EVENT",componentId:b.componentId,results:b.results,delta:b.delta}),M({type:"SCORECARD_UPDATED_EVENT"});return}}await Ce({sessionId:Ie(),mode:"single-element",scope:e,startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"}),await re(s,{type:"LIVE_REGIONS_ARM_REQUEST"},n).catch(()=>{}),await re(s,{type:"FOCUS_TRACE_ARM_REQUEST"},n).catch(()=>{}),await q(s,{type:"WARMUP_REQUEST"},n).catch(()=>{});const u=[],w=[];let R="",S,k=!1,E=null,P=null;try{for(let b=0;b<d.length;b++){if(t.isCanceled()){$.info("single audit canceled by user");break}const T=d[b];try{const O=await at(s,T,e,n);if(!O.success){S=(x=O.error)==null?void 0:x.message,$.warn(`state ${b+1}/${d.length} drive failed`,S);continue}T.breakpoint.id!==E&&(await q(s,{type:"WARMUP_REQUEST"},n).catch(()=>{}),E=T.breakpoint.id);const A=[];let v=null;const C=b===0?void 0:[...mn];for(let V=0;V<l;V++){const j=await q(s,{type:"AUDIT_REQUEST",selector:e,currentState:T,rulesToRun:C},n);j.success&&j.result?(A.push(j.result.violations),v=j.result):j.error&&(S=j.error.message,$.warn(`state ${b+1}/${d.length} run ${V+1} failed`,S))}if(v&&A.length>0){k=!0;const V=Bs(A),j=await va(s,{quality:75})??void 0;let F,B;try{F=(await q(s,{type:"LIVE_REGIONS_DRAIN_REQUEST"},n)).announcements}catch{}try{B=(await q(s,{type:"FOCUS_TRACE_DRAIN_REQUEST"},n)).focusEvents}catch{}if(w.push({...v,violations:V,frameId:n,announcements:F,focusEvents:B,screenshotDataUrl:j}),u.push(...V),R=v.componentId,b===0&&P===null)try{const m=await he("aiConfig",{}),U=ge(m);U.enabled&&U.apiKey&&R&&(P=De(s,e,n,U,w,R,t).catch(I=>{$.warn("ai augmentation (parallel) failed",I)}))}catch(m){$.debug("ai augmentation (parallel) gate-read failed",m)}}}catch(O){S=O instanceof Error?O.message:String(O),$.warn(`state ${b+1}/${d.length} threw`,O)}M({type:"AUDIT_PROGRESS_EVENT",current:b+1,total:d.length,currentState:T,componentId:R||void 0}),await Ge({})}if(k&&R){const b={pseudoState:"default",ariaVariation:null,theme:"light",direction:"ltr",breakpoint:{id:"desktop",label:"Desktop",width:1280,height:800,deviceScaleFactor:1,mobile:!1}};try{await at(s,b,e,n),await new Promise(v=>setTimeout(v,200))}catch(v){$.debug("reference-state drive failed; analyzers will use last matrix state",v)}try{const v=await q(s,{type:"READING_ORDER_REQUEST",selector:e},n);w[0]&&(v.issues.length>0?(w[0].readingOrderIssues=v.issues,w[0].positionAnalysisCapturedAt=b):(_=w[0].axeRulesEvaluated)==null||_.passed.push({ruleId:"wcc-reading-order-clean",wcagCriterion:"1.3.2"}))}catch(v){$.debug("reading-order analysis skipped",v)}try{const v=await q(s,{type:"TAB_ORDER_ANALYZE_REQUEST"},n);w[0]&&(v.issues.length>0?(w[0].tabOrderIssues=v.issues,w[0].positionAnalysisCapturedAt=b):(L=w[0].axeRulesEvaluated)==null||L.passed.push({ruleId:"wcc-tab-order-clean",wcagCriterion:"2.4.3"}))}catch(v){$.debug("tab-order analysis skipped",v)}try{const v=await q(s,{type:"TYPOGRAPHY_ANALYZE_REQUEST",selector:e},n);v.issues.length>0&&w[0]&&(w[0].typographyIssues=v.issues)}catch(v){$.debug("typography analysis skipped",v)}try{const v=await q(s,{type:"CUSTOM_PROPERTY_REQUEST"},n);v.undefined.length>0&&w[0]&&(w[0].undefinedCustomProperties=v.undefined)}catch(v){$.debug("custom-property analysis skipped",v)}try{if(P)await P;else{const v=await he("aiConfig",{}),C=ge(v);C.enabled&&C.apiKey&&await De(s,e,n,C,w,R,t)}}catch(v){$.warn("ai augmentation skipped",v)}const T=w.flatMap(v=>v.announcements??[]),O=w.flatMap(v=>v.focusEvents??[]),A=await ft(R,u,{announcements:T,focusEvents:O},c);try{const v=le(u,void 0,w),C=w.reduce((j,F)=>j+F.durationMs,0),V=await Hn(w,v,C);if(V){const j=await Bt();if(Jn(j,"forensicAnchoring"))try{const F=await Bn(),B=await Vs(V,F??void 0);B&&await qn(V.componentId,V.capturedAt,B)}catch(F){$.warn("forensic anchoring failed (entry stays local-only)",F)}}}catch(v){$.warn("forensic log recording failed",v)}if(g)try{await na({lookupKey:p,fingerprint:g,axeVersion:Lt,matrixConfigHash:h,disabledRulesHash:a,results:w,delta:A,componentId:R,cachedAt:Date.now()})}catch(v){$.warn("audit-cache write failed",v)}M({type:"AUDIT_COMPLETE_EVENT",componentId:R,results:w,delta:A})}else M({type:"AUDIT_FAILED_EVENT",error:{code:"AXE_FAILED",message:S?`All audits failed. Last error: ${S}`:"No state produced results. Selector may not exist in the audit target frame.",recoverable:!0}});await fe()}catch(b){$.error("single audit failed",b),M({type:"AUDIT_FAILED_EVENT",componentId:R||void 0,error:Fn(b)?b.payload:{code:"UNKNOWN",message:String(b),recoverable:!1}})}finally{await re(s,{type:"LIVE_REGIONS_DISARM_REQUEST"},n).catch(()=>{}),await re(s,{type:"FOCUS_TRACE_DISARM_REQUEST"},n).catch(()=>{}),await Zt(s,e,n)}}async function xn(e){var t;try{const o=(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{var i;const s=window;return{detected:typeof s.__STORYBOOK_PREVIEW__=="object",version:(i=s.__STORYBOOK_PREVIEW__)==null?void 0:i.version}}})).find(s=>{var i;return(i=s.result)==null?void 0:i.detected});if(o)return{detected:!0,version:(t=o.result)==null?void 0:t.version,frameId:o.frameId}}catch(n){$.warn("storybook detection scripting failed",n)}return{detected:!1}}async function En(e){const t=await Re(),n=await Cn(t);if(await chrome.storage.local.set({"storybook:lastDetected":{detected:n.kind==="storybook"&&n.detected,version:n.version,detectedAt:new Date().toISOString()},"playground:lastDetected":{kind:n.kind,detected:n.detected,version:n.version,detectedAt:new Date().toISOString()}}),!n.detected){M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:"No supported component playground detected on this tab. Open a Storybook (iframe.html / storybook-static), Ladle, or Bit page and try again.",recoverable:!0}});return}if(n.kind==="bit"){M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:"Bit detected. Auto-iterate is not yet supported for Bit (compositions are iframe-per-component without a unified listing API). Use the element picker to audit individual compositions one at a time.",recoverable:!0}});return}const o=n.frameId??0,s=n.kind==="storybook"?await Ks(t,o):await Js(t,o);if(!s.length){$.warn(`${n.kind} detected but no stories returned`),M({type:"AUDIT_FAILED_EVENT",error:{code:"STORYBOOK_NOT_DETECTED",message:`${n.kind==="ladle"?"Ladle":"Storybook"} detected but no stories were returned. Try reloading the page.`,recoverable:!0}});return}await Ce({sessionId:Ie(),mode:"storybook-all",totalStories:s.length,completedStories:[],startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});for(const i of s){if(e.isCanceled()){$.info(`${n.kind} iteration canceled by user`);break}try{if(n.kind==="storybook"){await Ys(t,o,i.id);const r=await re(t,{type:"STORYBOOK_GET_STORY_TARGET_REQUEST",tabId:t},o);await ie(r.selector,e,o)}else await Xs(t,o,i.id),await ie("#ladle-root",e,o)}catch(r){$.warn(`story ${i.id} failed; continuing with next`,r)}const c=await qt();if((c==null?void 0:c.state)==="interrupted"){$.info("storybook iteration interrupted");break}await Ge({completedStories:[...(c==null?void 0:c.completedStories)??[],i.id]})}M({type:"SCORECARD_UPDATED_EVENT"}),await fe()}async function kn(e){const t=await Re();let n=[];try{n=(await chrome.scripting.executeScript({target:{tabId:t,allFrames:!0},func:()=>({url:window.location.href})})).map(s=>{var i;return{frameId:s.frameId,url:((i=s.result)==null?void 0:i.url)??""}}).filter(s=>/^https?:/i.test(s.url))}catch(o){$.warn("multi-frame discovery failed",o)}if(n.length===0){M({type:"AUDIT_FAILED_EVENT",error:{code:"CONTENT_SCRIPT_UNREACHABLE",message:"No auditable frames found on this tab. The page may use only chrome-extension:// or data: frames.",recoverable:!0}});return}await Ce({sessionId:Ie(),mode:"all-frames",totalFrames:n.length,completedFrames:[],startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});for(const o of n){if(e.isCanceled()){$.info("all-frames iteration canceled");break}try{await ie("html",e,o.frameId)}catch(i){$.warn(`frame ${o.frameId} (${o.url.slice(0,80)}) audit failed; continuing`,i)}const s=await qt();if((s==null?void 0:s.state)==="interrupted"){$.info("all-frames iteration interrupted");break}await Ge({completedFrames:[...(s==null?void 0:s.completedFrames)??[],o.frameId]})}M({type:"SCORECARD_UPDATED_EVENT"}),await fe()}async function qs(e){var o;const t=await We();let n;if(t!==null)try{n=(await chrome.tabs.get(t)).url}catch(s){$.warn("failed to get target tab url",s)}if(!n){M({type:"AUDIT_FAILED_EVENT",error:{code:"NETWORK",message:"Could not determine target URL for parallel scan.",recoverable:!1}});return}await Ce({sessionId:Ie(),mode:"single-element",scope:"html",startedAt:new Date().toISOString(),lastProgressAt:new Date().toISOString(),state:"running"});try{const s=await gt(),{runParallelTabAudit:i}=await et(async()=>{const{runParallelTabAudit:p}=await import("./parallel-tab-flow-DNWptHLU.js");return{runParallelTabAudit:p}},__vite__mapDeps([0,1,2,3,4,5,6])),c=await i({targetUrl:n,scope:"html",matrix:s,parallelism:4,cancel:e});if($.info(`parallel scan complete: ${c.results.length} results across ${c.tabsCompleted} tabs (${c.tabsFailed} failed) in ${Math.round(c.parallelDurationMs)}ms`),c.results.length===0){M({type:"AUDIT_FAILED_EVENT",error:{code:"NETWORK",message:`All ${c.tabsFailed} worker tabs failed. Falling back to Full Page scan is recommended.`,recoverable:!0}});return}const r=((o=c.results[0])==null?void 0:o.componentId)??"parallel-scan";if(t!==null)try{const p=await he("aiConfig",{}),h=ge(p);h.enabled&&h.apiKey&&await De(t,"html",void 0,h,c.results,r,e)}catch(p){$.warn("parallel scan: ai augmentation skipped",p)}const d=c.results.flatMap(p=>p.violations);let l;try{l=await ft(r,d)}catch(p){$.warn("parallel scan: baseline compare failed",p),l={new:[],persistent:[],fixed:[],newCount:0,persistentCount:0,fixedCount:0,baselineSnapshotMeta:null,comparedAt:new Date().toISOString()}}M({type:"AUDIT_COMPLETE_EVENT",componentId:r,results:c.results,delta:l}),M({type:"SCORECARD_UPDATED_EVENT"})}catch(s){$.warn("parallel scan failed",s),M({type:"AUDIT_FAILED_EVENT",error:{code:"UNKNOWN",message:s instanceof Error?s.message:String(s),recoverable:!0}})}finally{await fe()}}async function Ks(e,t){var n;try{return((n=(await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",func:async()=>{var d,l;const s=window.__STORYBOOK_PREVIEW__;if(!s)return[];const i=s.storyStoreValue??s.storyStore;if(!i)return[];typeof i.cacheAllCSFFiles=="function"&&await i.cacheAllCSFFiles();const c=((d=i.extract)==null?void 0:d.call(i))??((l=i.cachedCSFFiles)==null?void 0:l.call(i));if(!c)return[];const r=[];if(c instanceof Map)for(const[p,h]of c){const f=h;r.push({id:String(p),name:f.name??String(p),kind:f.title??f.kind??""})}else if(typeof c=="object"&&c!==null)for(const[p,h]of Object.entries(c)){const f=h;r.push({id:p,name:f.name??p,kind:f.title??f.kind??""})}return r}}))[0])==null?void 0:n.result)??[]}catch(o){return $.warn("listStoriesViaMainWorld failed",o),[]}}async function Ys(e,t,n){try{await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",args:[n,3e3],func:async(o,s)=>{const i=new URL(window.location.href);i.searchParams.set("id",o),i.searchParams.set("viewMode","story"),window.location.href!==i.href&&(window.history.pushState({},"",i.href),window.dispatchEvent(new PopStateEvent("popstate"))),await new Promise(c=>{const r=setTimeout(()=>c(),s),d=()=>{clearTimeout(r),c()};window.addEventListener("storyrendered",d,{once:!0})})}})}catch(o){$.warn(`navigateToStoryViaMainWorld(${n}) failed`,o)}}async function $n(e){var t;try{const o=(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{const s=document.getElementById("ladle-root")!==null,i=document.title==="Ladle",c=!!document.querySelector('link[href*="ladle.css"]');return{detected:s&&(i||c),version:void 0}}})).find(s=>{var i;return(i=s.result)==null?void 0:i.detected});if(o)return{detected:!0,version:(t=o.result)==null?void 0:t.version,frameId:o.frameId}}catch(n){$.warn("ladle detection scripting failed",n)}return{detected:!1}}async function Js(e,t){var n;try{return((n=(await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",func:async()=>{try{const s=await fetch(new URL("/meta.json",window.location.href).href,{credentials:"same-origin"});if(!s.ok)return[];const c=(await s.json()).stories??{};return Object.entries(c).map(([r,d])=>({id:r,name:d.name??r,kind:(d.levels??[]).join(" / ")}))}catch{return[]}}}))[0])==null?void 0:n.result)??[]}catch(o){return $.warn("listLadleStoriesViaMainWorld failed",o),[]}}async function Xs(e,t,n){try{await chrome.scripting.executeScript({target:{tabId:e,frameIds:[t]},world:"MAIN",args:[n,3e3],func:async(o,s)=>{const i=new URL(window.location.href);i.searchParams.set("story",o),window.location.href!==i.href&&(window.history.pushState({},"",i.href),window.dispatchEvent(new PopStateEvent("popstate"))),await new Promise(c=>setTimeout(c,Math.min(s,500)))}})}catch(o){$.warn(`navigateToLadleStoryViaMainWorld(${n}) failed`,o)}}async function Tn(e){try{return(await chrome.scripting.executeScript({target:{tabId:e,allFrames:!0},world:"MAIN",func:()=>{const n=window.location.href;return/bit\.dev|bit-dev|bitsrc|\/~aspect|\/composition/i.test(n)}})).some(n=>n.result===!0)}catch{return!1}}async function Cn(e){const t=await xn(e);if(t.detected)return{kind:"storybook",...t};const n=await $n(e);return n.detected?{kind:"ladle",...n}:await Tn(e)?{kind:"bit",detected:!0}:{kind:null,detected:!1}}const Qs=200,Zs=6e4;function Dt(e,t){try{return new URL(e).origin===new URL(t).origin}catch{return!1}}function er(e,t){try{const n=new URL(e,t);return n.hash="",n.toString()}catch{return null}}async function tr(e,t,n){await chrome.tabs.update(e,{url:t}),await new Promise((o,s)=>{const i=setTimeout(()=>{chrome.tabs.onUpdated.removeListener(c),s(new Error(`navigation timeout (${n}ms): ${t}`))},n);function c(r,d){r===e&&d.status==="complete"&&(clearTimeout(i),chrome.tabs.onUpdated.removeListener(c),o())}chrome.tabs.onUpdated.addListener(c)}),await new Promise(o=>setTimeout(o,400))}async function nr(e){var t;try{return((t=(await chrome.scripting.executeScript({target:{tabId:e},func:()=>Array.from(document.querySelectorAll("a[href]")).map(o=>o.getAttribute("href")).filter(o=>typeof o=="string"&&!o.startsWith("javascript:"))}))[0])==null?void 0:t.result)??[]}catch(n){return $.debug("link discovery failed",n),[]}}async function In(e,t,n){var f;const o=await Re(),s=Math.min(t.maxPages??25,Qs),i=t.includeRegex?Ft(t.includeRegex):null,c=t.excludeRegex?Ft(t.excludeRegex):null,r=new Date().toISOString(),d=Date.now(),l=[e],p=new Set,h=[];await Ce({sessionId:Ie(),mode:"storybook-all",scope:e,startedAt:r,lastProgressAt:new Date().toISOString(),state:"running"});try{for(;l.length>0&&p.size<s;){if(n.isCanceled()){$.info("site crawl canceled by user");break}const w=l.shift();if(!w||p.has(w)||!Dt(w,e)||i&&!i.test(w)||c&&c.test(w))continue;p.add(w);const R=p.size,S=Date.now();M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"auditing"});try{await tr(o,w,Zs);const k=await An(o,0);if(!k.ok)throw new Error(Sn(k));await q(o,{type:"WARMUP_REQUEST"},0).catch(()=>{});const E=await q(o,{type:"AUDIT_REQUEST",selector:"html",currentState:{pseudoState:"default",ariaVariation:null,theme:"light",direction:"ltr",breakpoint:{id:"desktop",label:"Desktop",width:1280,height:800,deviceScaleFactor:1,mobile:!1}}},0),P=Date.now()-S;if(E.success&&E.result)h.push({url:w,results:[E.result],delta:null,componentId:E.result.componentId,durationMs:P}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"completed",violations:E.result.violations.length});else{const _=((f=E.error)==null?void 0:f.message)??"audit returned no result";h.push({url:w,results:[],delta:null,componentId:w,durationMs:P,error:_}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"failed",error:_})}const x=await nr(o);for(const _ of x){const L=er(_,w);L&&Dt(L,e)&&!p.has(L)&&!l.includes(L)&&l.push(L)}}catch(k){const E=Date.now()-S,P=k instanceof Error?k.message:String(k);h.push({url:w,results:[],delta:null,componentId:w,durationMs:E,error:P}),M({type:"SITE_CRAWL_PROGRESS_EVENT",current:R,total:Math.min(s,p.size+l.length),url:w,status:"failed",error:P})}await Ge({})}const a=new Date().toISOString(),g=Date.now()-d,u=vs(e,h,r,a,g);M({type:"SITE_CRAWL_COMPLETE_EVENT",report:u}),await fe()}catch(a){$.error("site crawl failed",a),M({type:"SITE_CRAWL_FAILED_EVENT",error:{code:"UNKNOWN",message:String(a),recoverable:!1}}),await fe()}}function Ft(e){try{return new RegExp(e)}catch{return null}}const Ze=5*6e4,Gt=9e4,Wt={altText:"Verifying alt text…",headings:"Judging heading quality…",sensory:"Scanning for sensory-only instructions…",aria:"Reviewing ARIA semantics…",imageOfText:"Detecting baked-in text in images…",colorOnlyMeaning:"Checking for color-only meaning…",genericLinkText:"Reviewing link clarity…",wallOfText:"Detecting walls of text…",languageMismatch:"Verifying page language…"};async function De(e,t,n,o,s,i,c){let r;try{r=await q(e,{type:"AI_CANDIDATES_REQUEST",selector:t},n)}catch(A){$.debug("ai candidates fetch failed",A);return}const d=s[0];if(!d)return;const l={componentId:i,currentState:d.state,axeVersion:d.axeVersion},p={at:new Date().toISOString(),componentId:i,pageUrl:d.pageUrl??t,enabledChecks:o.enabledChecks,candidateCounts:{images:r.images.length,headings:r.headings.length,instructions:r.instructions.length,ariaElements:r.ariaElements.length,links:r.links.length,longTextBlocks:r.longTextBlocks.length,colorOnlyRegions:r.colorOnlyRegions.length,languageInfo:r.languageInfo?"present":"null"}};$.info("ai augmentation gate snapshot",JSON.stringify(p));try{await chrome.storage.local.set({aiDiagnosticLatest:p})}catch(A){$.warn("failed to persist ai diagnostic to storage.local",A)}try{const A=JSON.stringify(p,null,2),v=`data:application/json;charset=utf-8,${encodeURIComponent(A)}`,C=p.at.replace(/[:.]/g,"-"),V=await chrome.downloads.download({url:v,filename:`wcagcheckr-ai-diag-${C}.json`,saveAs:!1,conflictAction:"uniquify"});$.info(`ai diagnostic download started (id=${V})`)}catch(A){$.warn("failed to write ai diagnostic to Downloads (storage.local copy is still available under aiDiagnosticLatest)",A)}const h=[];if(o.enabledChecks.altText&&h.push({key:"altText",run:A=>{const v=r.images.map(C=>({imageUrl:C.imageUrl,alt:C.alt,selector:C.selector,outerHTML:C.outerHTML,surroundingContext:C.surroundingContext,...l}));return Es(v,o,A)}}),o.enabledChecks.headings&&h.push({key:"headings",run:A=>$s(r.headings,l,o,A)}),o.enabledChecks.sensory&&h.push({key:"sensory",run:A=>Ts(r.instructions,l,o,A)}),o.enabledChecks.aria&&h.push({key:"aria",run:A=>Cs(r.ariaElements,l,o,A)}),o.enabledChecks.imageOfText&&h.push({key:"imageOfText",run:A=>{const v=r.images.map(C=>({imageUrl:C.imageUrl,accessibleName:C.alt||void 0,selector:C.selector,outerHTML:C.outerHTML,pixelArea:C.pixelArea}));return _s(v,l,o,A)}}),o.enabledChecks.colorOnlyMeaning&&h.push({key:"colorOnlyMeaning",run:A=>Ms(r.colorOnlyRegions,l,o,A)}),o.enabledChecks.genericLinkText&&h.push({key:"genericLinkText",run:A=>Is(r.links,l,o,A)}),o.enabledChecks.wallOfText&&h.push({key:"wallOfText",run:A=>Rs(r.longTextBlocks,l,o,A)}),o.enabledChecks.languageMismatch){const A=r.languageInfo;h.push({key:"languageMismatch",run:v=>Os(A?[A]:[],l,o,v)})}if(h.length===0)return;let f=0,a=0,g=!1;const u={};let w=0,R=0,S=0;const k=[];let E=!1,P=!1;function x(A,v){if(u[A]=(u[A]??0)+v.totalCostUsd,f+=v.totalCostUsd,a+=v.findings.length,g=g||v.capExceeded,w++,v.errors.length>0){S++;for(const C of v.errors)k.includes(C)||k.push(C)}else R++;$.info(`ai ${A}: ${v.findings.length} findings, $${v.totalCostUsd.toFixed(4)}, errs=${v.errors.length}`),v.capExceeded&&$.warn(`ai cost cap exceeded after $${v.totalCostUsd.toFixed(4)} during ${A}`)}const _=(async()=>{for(let A=0;A<h.length;A++){if(c!=null&&c.isCanceled()){P=!0;break}const v=h[A];M({type:"AI_AUGMENTATION_PROGRESS_EVENT",componentId:i,currentCheck:v.key,currentCheckLabel:Wt[v.key],current:A+1,total:h.length});const C=new AbortController,V=setTimeout(()=>C.abort(),Gt),j=c?setInterval(()=>{c.isCanceled()&&C.abort()},500):null;let F;try{F=await v.run({signal:C.signal,onProgress:(B,m)=>{m>0&&M({type:"AI_AUGMENTATION_PROGRESS_EVENT",componentId:i,currentCheck:v.key,currentCheckLabel:Wt[v.key],current:A+1,total:h.length,candidatesDone:B,candidatesTotal:m})}}),C.signal.aborted&&(c!=null&&c.isCanceled())?F.errors=[...F.errors,`${v.key} canceled by user`]:C.signal.aborted}catch(B){const m=B instanceof Error?B.message:String(B),U=C.signal.aborted,I=U&&(c!=null&&c.isCanceled())?`${v.key} canceled by user`:U?`${v.key} hit per-check ${Gt/1e3}s cap — analyzer aborted`:`${v.key} threw: ${m}`;F={findings:[],totalCostUsd:0,capExceeded:!1,errors:[I]}}finally{clearTimeout(V),j&&clearInterval(j)}F.findings.length>0&&(d.violations=[...d.violations,...F.findings]),x(v.key,F)}})(),L=new Promise(A=>{setTimeout(()=>A("timeout"),Ze)});await Promise.race([_.then(()=>"done"),L])==="timeout"&&(E=!0,$.warn(`ai augmentation hit global ${Ze/1e3}s timeout after ${w}/${h.length} checks`));let T;if(S>0||E||P){E?T=`AI augmentation timed out after ${Ze/1e3}s`:P?T="AI augmentation canceled":T=k[0]??"AI analyzer error";const A=R===0?"total":"partial";M({type:"AI_AUGMENTATION_FAILED_EVENT",componentId:i,severity:A,reason:T,checksAttempted:w,checksSucceeded:R,checksErrored:S,errorDetails:E||P?[T,...k.slice(0,4)]:k.slice(0,5)}),$.warn(`ai augmentation ${A} failure: ${S}/${w} checks errored — ${T}`)}(f>0||a>0||T)&&await aa({at:new Date().toISOString(),pageUrl:d.pageUrl??t,componentId:i,totalCostUsd:f,byCheck:u,findingsCount:a,capExceeded:g,failureReason:T})}const ar=Object.freeze(Object.defineProperty({__proto__:null,detectBit:Tn,detectLadleAcrossFrames:$n,detectPlayground:Cn,detectStorybookAcrossFrames:xn,getActiveTabId:Re,getMatrixSettings:gt,runAiAugmentation:De,runAllFramesAudit:kn,runParallelScan:qs,runSingleElementAudit:ie,runSiteCrawl:In,runStorybookAllAudit:En},Symbol.toStringTag,{value:"Module"})),Y=z("service-worker");Nn("service-worker");Qa();var _e,Vt;(Vt=(_e=chrome.sidePanel)==null?void 0:_e.setPanelBehavior)==null||Vt.call(_e,{openPanelOnActionClick:!0}).catch(e=>Y.warn("setPanelBehavior failed",e));Aa();Na();Kn();Ma().catch(e=>Y.warn("initial cloud pull failed",e));(async()=>(await Ya(),on()))();Ja();to();ts();ds();hs();_o();ms();self.addEventListener("unhandledrejection",e=>{const t=e.reason;Pn(t instanceof Error?t:new Error(String(t)))});let Fe=!1;chrome.runtime.onConnect.addListener(e=>{if(e.name==="audit-keepalive"){Y.debug("keepalive connected"),e.onDisconnect.addListener(async()=>{Y.debug("keepalive disconnected"),await Yn()});return}if(e.name==="sidepanel-tracker"){Fe=!0,Y.debug("chrome.sidePanel opened"),e.onDisconnect.addListener(async()=>{Fe=!1,Y.debug("chrome.sidePanel closed — restoring in-page overlay"),await yt()});return}});let mt=!1;const ue={isCanceled:()=>mt};async function Rn(){const e=await We();if(e)try{await re(e,{type:"SIDEBAR_HIDE_REQUEST"})}catch(t){Y.warn("sidebar hide failed",t)}}async function yt(){const e=await We();if(e)try{await re(e,{type:"SIDEBAR_SHOW_REQUEST"})}catch(t){Y.warn("sidebar show failed",t)}}D("START_AUDIT",async e=>{mt=!1,await Rn();let t;if(e.mode==="single-element"){if(!e.scope)throw new Error("START_AUDIT single-element requires scope");t=ie(e.scope,ue,e.frameId,e.matrixOverride)}else if(e.mode==="full-page")t=ie("html",ue,0,e.matrixOverride);else if(e.mode==="quick-scan"){const{QUICK_SCAN_MATRIX_SETTINGS:n}=await et(async()=>{const{QUICK_SCAN_MATRIX_SETTINGS:o}=await import("./state-BIsozXtc.js").then(s=>s.e);return{QUICK_SCAN_MATRIX_SETTINGS:o}},__vite__mapDeps([5,1]));t=ie(e.scope??"html",ue,e.frameId??0,n)}else if(e.mode==="all-frames")t=kn(ue);else if(e.mode==="parallel-scan"){const{runParallelScan:n}=await et(async()=>{const{runParallelScan:o}=await Promise.resolve().then(()=>ar);return{runParallelScan:o}},void 0);t=n(ue)}else t=En(ue);t.catch(n=>{Y.error("audit failed",n);const o=n instanceof Error?n.message:String(n),s=/no audit target tab/i.test(o);M({type:"AUDIT_FAILED_EVENT",error:{code:s?"RESTRICTED_URL":"UNKNOWN",message:s?"No audit target tab found. Open a regular http(s) page (not chrome:// or about:blank) and try again.":`Audit failed: ${o}`,recoverable:!0}})}).finally(()=>{Fe||yt()})});D("CANCEL_AUDIT",async()=>{mt=!0,Y.info("cancel requested")});let bt=!1;const or={isCanceled:()=>bt};D("START_SITE_CRAWL",async e=>{bt=!1,await Rn(),In(e.startUrl,{maxPages:e.maxPages,includeRegex:e.includeRegex,excludeRegex:e.excludeRegex},or).catch(t=>Y.error("site crawl failed",t)).finally(()=>{Fe||yt()})});D("CANCEL_SITE_CRAWL",async()=>{bt=!0,Y.info("site crawl cancel requested")});D("OPEN_SETTINGS",()=>{chrome.runtime.openOptionsPage()});Y.info("service worker ready");export{An as a,at as d,As as e,Zt as r};
@@ -2,8 +2,8 @@
2
2
  "manifest_version": 3,
3
3
  "name": "wcagcheckr",
4
4
  "description": "Audit components across hover, focus, dark mode, forced colors, RTL — every state your users actually encounter. Per-component baselines surface only NEW violations.",
5
- "version": "1.0.0.77",
6
- "version_name": "1.0.0-rc.77",
5
+ "version": "1.0.0.78",
6
+ "version_name": "1.0.0-rc.78",
7
7
  "author": "Locustware",
8
8
  "homepage_url": "https://wcagcheckr.com",
9
9
  "icons": {
@@ -1 +1 @@
1
- import './assets/service-worker.ts-Ggld571y.js';
1
+ import './assets/service-worker.ts-Do4QemTP.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcag-checkr/ci",
3
- "version": "1.0.0-rc.77",
3
+ "version": "1.0.0-rc.78",
4
4
  "private": false,
5
5
  "description": "Headless wcagcheckr accessibility audit runner for CI/CD pipelines. Drives the wcagcheckr Chrome extension via Playwright, runs full-page audits across the state matrix (108 combinations: hover, focus, dark mode, RTL, breakpoints), outputs JSON / SARIF / JUnit, exits with severity-aware codes.",
6
6
  "license": "UNLICENSED",