@wcag-checkr/ci 1.0.0-rc.31 → 1.0.0-rc.310

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.
Files changed (104) hide show
  1. package/dist/assets/ErrorBoundary-C-kswn4E.js +594 -0
  2. package/dist/assets/ai-usage-log-BX3L6bKl.js +1 -0
  3. package/dist/assets/content-script.ts-FuMy_sE5.js +217 -0
  4. package/dist/assets/{content-script.ts-loader-Dfu1UEfD.js → content-script.ts-loader-CBHeu186.js} +1 -1
  5. package/dist/assets/copy-ai-fixer-prompt-DQYkHOv3.js +19 -0
  6. package/dist/assets/{crash-reporter-Dc5lvxvY.js → crash-reporter-Bu2p8K-p.js} +1 -1
  7. package/dist/assets/design-system-audit-DpxJrxnb.js +1 -0
  8. package/dist/assets/devtools-panel-DFQvqKKj.js +1 -0
  9. package/dist/assets/diff-DA41zYPc.js +1 -0
  10. package/dist/assets/dom-criterion-analyzers-DoUaJV5C.js +8 -0
  11. package/dist/assets/fraunces-latin-400-normal-6IfK1voy.woff2 +0 -0
  12. package/dist/assets/fraunces-latin-400-normal-NUPT2cO8.woff +0 -0
  13. package/dist/assets/fraunces-latin-500-normal-BTR4KCeb.woff +0 -0
  14. package/dist/assets/fraunces-latin-500-normal-DnGCNyPD.woff2 +0 -0
  15. package/dist/assets/fraunces-latin-600-normal-BFCDtZfi.woff2 +0 -0
  16. package/dist/assets/fraunces-latin-600-normal-DL5QCzvS.woff +0 -0
  17. package/dist/assets/fraunces-latin-ext-400-normal-D8gbi3Gu.woff2 +0 -0
  18. package/dist/assets/fraunces-latin-ext-400-normal-UihxqfOe.woff +0 -0
  19. package/dist/assets/fraunces-latin-ext-500-normal-BMcFk1Xs.woff +0 -0
  20. package/dist/assets/fraunces-latin-ext-500-normal-Z5DV8IzT.woff2 +0 -0
  21. package/dist/assets/fraunces-latin-ext-600-normal-B0Dy4lqi.woff +0 -0
  22. package/dist/assets/fraunces-latin-ext-600-normal-BtzmzP0X.woff2 +0 -0
  23. package/dist/assets/fraunces-vietnamese-400-normal-B65MOf9T.woff +0 -0
  24. package/dist/assets/fraunces-vietnamese-400-normal-CvGt0Ybw.woff2 +0 -0
  25. package/dist/assets/fraunces-vietnamese-500-normal-B-KbxExq.woff +0 -0
  26. package/dist/assets/fraunces-vietnamese-500-normal-GOH_-EGq.woff2 +0 -0
  27. package/dist/assets/fraunces-vietnamese-600-normal-BjlAJixd.woff2 +0 -0
  28. package/dist/assets/fraunces-vietnamese-600-normal-DlAl5EAR.woff +0 -0
  29. package/dist/assets/geist-sans-latin-400-normal-BOaIZNA2.woff +0 -0
  30. package/dist/assets/geist-sans-latin-400-normal-gapTbOY8.woff2 +0 -0
  31. package/dist/assets/geist-sans-latin-500-normal-CN2lyvyL.woff +0 -0
  32. package/dist/assets/geist-sans-latin-500-normal-uokXdC-Q.woff2 +0 -0
  33. package/dist/assets/geist-sans-latin-600-normal-CA1yjETN.woff +0 -0
  34. package/dist/assets/geist-sans-latin-600-normal-DFOURf8L.woff2 +0 -0
  35. package/dist/assets/geist-sans-latin-700-normal-BmN9tIp5.woff2 +0 -0
  36. package/dist/assets/geist-sans-latin-700-normal-CjScfYeH.woff +0 -0
  37. package/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  38. package/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  39. package/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  40. package/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  41. package/dist/assets/jetbrains-mono-cyrillic-600-normal-8K4wrrwR.woff +0 -0
  42. package/dist/assets/jetbrains-mono-cyrillic-600-normal-EVf6-Yzo.woff2 +0 -0
  43. package/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  44. package/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  45. package/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  46. package/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  47. package/dist/assets/jetbrains-mono-greek-600-normal-H7WoG9Et.woff2 +0 -0
  48. package/dist/assets/jetbrains-mono-greek-600-normal-mc2nkWzM.woff +0 -0
  49. package/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  50. package/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  51. package/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  52. package/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  53. package/dist/assets/jetbrains-mono-latin-600-normal-BfsvjouI.woff +0 -0
  54. package/dist/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
  55. package/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  56. package/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  57. package/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  58. package/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  59. package/dist/assets/jetbrains-mono-latin-ext-600-normal-BfB_LPfz.woff2 +0 -0
  60. package/dist/assets/jetbrains-mono-latin-ext-600-normal-DObL3zCW.woff +0 -0
  61. package/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  62. package/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  63. package/dist/assets/jetbrains-mono-vietnamese-600-normal-OWROknRo.woff +0 -0
  64. package/dist/assets/options-BPhjrbGI.js +6 -0
  65. package/dist/assets/parallel-tab-flow-Xk9RSjay.js +1 -0
  66. package/dist/assets/scheduled-audit-runner-DyKpb3zg.js +2167 -0
  67. package/dist/assets/service-worker.ts-CMkltOzu.js +2 -0
  68. package/dist/assets/side-panel-Ctm2yXeo.css +1 -0
  69. package/dist/assets/side-panel-f_X4NOJt.js +4 -0
  70. package/dist/assets/site-report-renderer-DNgytqhZ.js +189 -0
  71. package/dist/assets/{styles-C4Kq0zOO.js → styles-Cn731SYD.js} +13 -13
  72. package/dist/assets/styles-d5msFsnl.css +1 -0
  73. package/dist/assets/zip-encoder-CtULHXx_.js +1 -0
  74. package/dist/axe.min.js +12 -0
  75. package/dist/devtools/panel.html +9 -8
  76. package/dist/manifest.json +11 -8
  77. package/dist/options/options.html +5 -6
  78. package/dist/service-worker-loader.js +1 -1
  79. package/dist/side-panel/App.tsx +129 -5
  80. package/dist/side-panel/audit-launcher.ts +21 -1
  81. package/dist/side-panel/azure-devops-issue.test.ts +68 -0
  82. package/dist/side-panel/azure-devops-issue.ts +89 -0
  83. package/dist/side-panel/gitlab-issue.test.ts +53 -0
  84. package/dist/side-panel/gitlab-issue.ts +78 -0
  85. package/dist/side-panel/main.tsx +39 -2
  86. package/dist/side-panel/side-panel.html +11 -8
  87. package/dist/side-panel/store.ts +149 -13
  88. package/dist/side-panel/styles.css +39 -0
  89. package/dist/side-panel/wire-messaging.ts +146 -9
  90. package/package.json +1 -1
  91. package/wcagcheckr-ci.mjs +193 -32
  92. package/dist/assets/ErrorBoundary-BLcMSVSr.js +0 -524
  93. package/dist/assets/ai-usage-log-Dj9Ub_DT.js +0 -1
  94. package/dist/assets/content-script.ts-CwcUMq3e.js +0 -181
  95. package/dist/assets/devtools-panel-DQ3Bbomf.js +0 -1
  96. package/dist/assets/diff-D4sCAdXf.js +0 -1
  97. package/dist/assets/forensic-log-B1UCXZ23.js +0 -129
  98. package/dist/assets/options-BG2i5vFf.js +0 -6
  99. package/dist/assets/preload-helper-D7HrI6pR.js +0 -1
  100. package/dist/assets/service-worker.ts-CO86CV_p.js +0 -715
  101. package/dist/assets/side-panel-XSB07vDa.js +0 -1
  102. package/dist/assets/site-report-renderer-CyHkM6hB.js +0 -147
  103. package/dist/assets/state-PELIq3oj.js +0 -1
  104. package/dist/assets/styles-Cevp58mS.css +0 -1
@@ -5,7 +5,7 @@
5
5
  (async () => {
6
6
  const { onExecute } = await import(
7
7
  /* @vite-ignore */
8
- chrome.runtime.getURL("assets/content-script.ts-CwcUMq3e.js")
8
+ chrome.runtime.getURL("assets/content-script.ts-FuMy_sE5.js")
9
9
  );
10
10
  onExecute?.({ perf: { injectTime, loadTime: performance.now() - injectTime } });
11
11
  })().catch(console.error);
@@ -0,0 +1,19 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ErrorBoundary-C-kswn4E.js","assets/styles-Cn731SYD.js","assets/_commonjsHelpers-Cpj98o6Y.js","assets/crash-reporter-Bu2p8K-p.js","assets/ai-usage-log-BX3L6bKl.js","assets/styles-d5msFsnl.css","assets/scheduled-audit-runner-DyKpb3zg.js","assets/diff-DA41zYPc.js","assets/design-system-audit-DpxJrxnb.js"])))=>i.map(i=>d[i]);
2
+ import{_ as l}from"./diff-DA41zYPc.js";import{a as v}from"./crash-reporter-Bu2p8K-p.js";async function C(e){var b,w,y,g;if(e.results.length===0)return;let d;if(e.componentId){const o=await chrome.storage.local.get("igtRuns"),a=((o==null?void 0:o.igtRuns)??{})[e.componentId]??{};d=Object.values(a)}let p,u;const i=((b=e.results[0])==null?void 0:b.pageUrl)??((w=e.results[0])==null?void 0:w.scope)??"";if(i){const{getDismissalsForUrl:o}=await l(async()=>{const{getDismissalsForUrl:t}=await import("./ErrorBoundary-C-kswn4E.js").then(n=>n.f);return{getDismissalsForUrl:t}},__vite__mapDeps([0,1,2,3,4,5,6,7,8])),r=await o(i);p=Object.keys(r);const{getResolutionsForPage:a}=await l(async()=>{const{getResolutionsForPage:t}=await import("./scheduled-audit-runner-DyKpb3zg.js").then(n=>n.aS);return{getResolutionsForPage:t}},__vite__mapDeps([6,7,3,4])),c=await a(i),x=new Set;for(const t of e.results)for(const n of((y=t.axeRulesEvaluated)==null?void 0:y.incomplete)??[])for(const _ of n.elements??[])x.add(`${n.ruleId}::${_.selector}`);u=c.filter(t=>x.has(`${t.ruleId}::${t.selector}`))}let m;if(e.componentId){const{loadAcknowledgedKeysForComponent:o}=await l(async()=>{const{loadAcknowledgedKeysForComponent:a}=await import("./scheduled-audit-runner-DyKpb3zg.js").then(c=>c.aR);return{loadAcknowledgedKeysForComponent:a}},__vite__mapDeps([6,7,3,4])),r=await o(e.componentId);m=r.size>0?Array.from(r):void 0}const f=await v({type:"EXPORT_REQUEST",format:"ai-prompt",results:e.results,delta:e.delta??void 0,manualRuns:d,siteCrawlReport:e.siteCrawlReport??void 0,dismissedKeys:p,incompleteResolutions:u,acknowledgedKeys:m});try{await navigator.clipboard.writeText(f.content)}catch{}const h=`<!doctype html><html><head><meta charset="utf-8"><title>AI fix prompt</title>
3
+ <style>body{font:14px/1.5 ui-monospace,Menlo,monospace;max-width:920px;margin:24px auto;padding:0 16px;color:#0f172a;}
4
+ .banner{background:#ecfdf5;border:1px solid #6ee7b7;padding:12px 14px;border-radius:6px;margin-bottom:16px;font-family:system-ui;}
5
+ pre{white-space:pre-wrap;word-break:break-word;background:#f8fafc;border:1px solid #e2e8f0;padding:14px;border-radius:6px;font-size:13px;}
6
+ button{font:13px system-ui;padding:6px 12px;border:1px solid #cbd5e1;border-radius:4px;background:white;cursor:pointer;}
7
+ button:hover{background:#f1f5f9;}</style></head>
8
+ <body>
9
+ <div class="banner">
10
+ <strong>Already copied to your clipboard.</strong> Paste it into Claude, Cursor, Copilot Chat, or any LLM with codebase access.
11
+ <button id="copy" style="margin-left:12px;">Copy again</button>
12
+ </div>
13
+ <pre id="content">${f.content.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</pre>
14
+ <script>
15
+ document.getElementById('copy').addEventListener('click', () => {
16
+ navigator.clipboard.writeText(document.getElementById('content').textContent || '');
17
+ });
18
+ <\/script>
19
+ </body></html>`,R=new Blob([h],{type:"text/html"}),s=URL.createObjectURL(R);typeof chrome<"u"&&((g=chrome.tabs)!=null&&g.create)?chrome.tabs.create({url:s,active:!0}).catch(()=>{window.open(s,"_blank","noopener,noreferrer")}):window.open(s,"_blank","noopener,noreferrer"),setTimeout(()=>URL.revokeObjectURL(s),6e4)}export{C as copyAiFixerPrompt};
@@ -1,4 +1,4 @@
1
1
  const u=[];function M(e){u.push(e),u.length>50&&u.shift()}function S(){return[...u]}const l={debug:0,info:1,warn:2,error:3,silent:4};let $="info";function y(e){return{debug:(n,...r)=>f("debug",e,n,r),info:(n,...r)=>f("info",e,n,r),warn:(n,...r)=>f("warn",e,n,r),error:(n,...r)=>f("error",e,n,r)}}function f(e,n,r,t){if(M(b(e,n,r,t)),l[e]<l[$])return;const o=`[${n}]`,s=e==="error"?console.error:e==="warn"?console.warn:console.log;t.length>0?s(o,r,...t):s(o,r)}function b(e,n,r,t){const o=new Date().toISOString(),s=t.length>0?` ${t.map(O).join(" ")}`:"";return`${o} ${e.toUpperCase()} [${n}] ${r}${s}`}function O(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}const _=y("messaging");function j(e){return chrome.runtime.sendMessage(e)}function q(e,n,r){const t=r!==void 0?{frameId:r}:void 0;return chrome.tabs.sendMessage(e,n,t)}async function C(e){const n=await chrome.runtime.sendMessage(e);if(!d(n))throw new Error(`messaging.request: response was not a Message (sent ${e.type}, got ${typeof n})`);return n}const h=45e3;async function U(e,n,r){const t=r!==void 0?{frameId:r}:void 0,o=await Promise.race([chrome.tabs.sendMessage(e,n,t),new Promise((s,a)=>setTimeout(()=>a(new Error(`messaging.requestFromTab: ${n.type} timed out after ${h/1e3}s`)),h))]);if(!d(o))throw new Error(`messaging.requestFromTab: response was not a Message (sent ${n.type}, got ${typeof o})`);return o}function x(e,n){const r=(t,o,s)=>{if(!d(t)||t.type!==e)return!1;let a;try{a=n(t,o)}catch(c){return p(e,c),s(void 0),!1}return a instanceof Promise?(a.then(c=>s(c??void 0)).catch(c=>{p(e,c),s(void 0)}),!0):(s(a??void 0),!1)};return chrome.runtime.onMessage.addListener(r),()=>chrome.runtime.onMessage.removeListener(r)}function D(e){chrome.runtime.sendMessage(e).catch(()=>{})}function d(e){return typeof e=="object"&&e!==null&&typeof e.type=="string"}function p(e,n){_.error(`handler for ${e} failed`,n)}const I=/https?:\/\/[^\s)]+/g,N=/[\w.+-]+@[\w-]+\.[\w.-]+/g,R=/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;function k(e){return e.replace(I,"[URL]").replace(N,"[EMAIL]").replace(R,"[TOKEN]")}function L(e){return e.map(k)}const A=y("crash-reporter"),F="https://api.wcagcheckr.com/v1/products/wcagcheckr/crash",g="crashReporting:enabled",w=10;let T="unknown",m=!1;const i=new Set;function G(e){m||(m=!0,T=e,typeof window<"u"&&(window.addEventListener("error",n=>{E(n.error??new Error(n.message))}),window.addEventListener("unhandledrejection",n=>{const r=n.reason,t=r instanceof Error?r:new Error(String(r));E(t)})))}async function E(e){if(!await P())return;const n=v(e);if(i.has(n))return;if(i.add(n),i.size>w){const t=[...i].slice(-w);i.clear(),t.forEach(o=>i.add(o))}const r={productSlug:"wcagcheckr",context:T,fingerprint:n,message:e.message,stack:X(e.stack??""),extensionVersion:chrome.runtime.getManifest().version,occurredAt:new Date().toISOString(),logTail:L(S())};try{await fetch(F,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})}catch(t){A.warn("crash report failed to send",t)}}async function P(){try{return(await chrome.storage.local.get(g))[g]===!0}catch{return!1}}async function K(e){await chrome.storage.local.set({[g]:e})}function v(e){var r;const n=((r=(e.stack??"").split(`
2
2
  `)[1])==null?void 0:r.trim())??"";return`${e.name}:${e.message}::${n}`.slice(0,200)}function X(e){return L(e.split(`
3
3
  `)).join(`
4
- `)}export{g as O,K as a,q as b,y as c,U as d,D as e,L as f,S as g,E as h,G as i,x as o,C as r,j as s};
4
+ `)}export{g as O,C as a,K as b,y as c,q as d,D as e,L as f,S as g,E as h,G as i,x as o,U as r,j as s};
@@ -0,0 +1 @@
1
+ const d=/^\s*(?:#[0-9a-f]{3,8}\s*$|(?:rgba?|hsla?|color|oklch|oklab|hwb|lab|lch)\(|currentColor\s*$|transparent\s*$|[a-z]+\s*$)/i;function k(o){return o?d.test(o.trim()):!1}function C(o,s){const t=new Map;for(const e of o)t.set(e.name,{token:e,usageCount:0,violationMatchKeys:[]});for(const e of s)for(const n of e.referencedTokens){const r=t.get(n);r&&(r.usageCount+=1,e.violationMatchKey&&(r.violationMatchKeys.includes(e.violationMatchKey)||r.violationMatchKeys.push(e.violationMatchKey)))}return Array.from(t.values()).sort((e,n)=>e.violationMatchKeys.length!==n.violationMatchKeys.length?n.violationMatchKeys.length-e.violationMatchKeys.length:e.usageCount!==n.usageCount?n.usageCount-e.usageCount:e.token.name.localeCompare(n.token.name))}function T(o){let s=0,t=0,e=0,n=0;for(const r of o)r.token.isColor&&s++,r.usageCount>0?t++:e++,r.violationMatchKeys.length>0&&n++;return{totalTokens:o.length,colorTokens:s,usedTokens:t,unusedTokens:e,violatingTokens:n}}const p=/var\(\s*(--[a-zA-Z0-9_-]+)\s*[,)]/g;function v(o){if(o.id)return`#${o.id}`;const s=[];let t=o;for(;t&&s.length<4;){let e=t.tagName.toLowerCase();t.classList.length>0&&(e+="."+Array.from(t.classList).slice(0,2).join(".")),s.unshift(e),t=t.parentElement}return s.join(" > ")}function M(o=document){var r,m;const s=[],t=new Set;for(const l of Array.from(o.styleSheets??[])){let c=null;try{c=l.cssRules}catch{continue}if(c)for(const a of Array.from(c)){if(a.type!==1)continue;const u=a,f=u.selectorText??"",h=u.style;for(let y=0;y<h.length;y++){const i=h.item(y);if(!i.startsWith("--")||t.has(i))continue;t.add(i);const g=h.getPropertyValue(i).trim();s.push({name:i,value:g,declaredOn:f,isColor:k(g)})}}}const e=Array.from(o.querySelectorAll("*")).slice(0,500),n=[];for(const l of e){if(!((r=o.defaultView)==null?void 0:r.getComputedStyle(l)))continue;const a=new Set;if((m=l.style)!=null&&m.cssText){const u=l.style.cssText;let f;for(;(f=p.exec(u))!==null;)a.add(f[1])}a.size>0&&n.push({selector:v(l),referencedTokens:Array.from(a)})}return{tokens:s,references:n}}export{M as a,T as s,C as t};
@@ -0,0 +1 @@
1
+ import"./modulepreload-polyfill-B5Qt9EMX.js";import{c as t,j as o,R as e}from"./styles-Cn731SYD.js";import{E as i,A as s}from"./ErrorBoundary-C-kswn4E.js";import{i as m}from"./crash-reporter-Bu2p8K-p.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./ai-usage-log-BX3L6bKl.js";import"./scheduled-audit-runner-DyKpb3zg.js";import"./diff-DA41zYPc.js";import"./design-system-audit-DpxJrxnb.js";m("devtools-panel");const r=document.getElementById("root");if(!r)throw new Error("devtools panel: #root not found");t(r).render(o.jsx(e.StrictMode,{children:o.jsx(i,{children:o.jsx(s,{})})}));
@@ -0,0 +1 @@
1
+ var $=Object.defineProperty;var K=(e,t,n)=>t in e?$(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var g=(e,t,n)=>K(e,typeof t!="symbol"?t+"":t,n);const A="modulepreload",k=function(e){return"/"+e},S={},C=function(t,n,o){let u=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const c=document.querySelector("meta[property=csp-nonce]"),s=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));u=Promise.allSettled(n.map(i=>{if(i=k(i),i in S)return;S[i]=!0;const l=i.endsWith(".css"),m=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${i}"]${m}`))return;const a=document.createElement("link");if(a.rel=l?"stylesheet":A,l||(a.as="script"),a.crossOrigin="",a.href=i,s&&a.setAttribute("nonce",s),document.head.appendChild(a),l)return new Promise((d,y)=>{a.addEventListener("load",d),a.addEventListener("error",()=>y(new Error(`Unable to preload CSS for ${i}`)))})}))}function f(c){const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=c,window.dispatchEvent(s),!s.defaultPrevented)throw c}return u.then(c=>{for(const s of c||[])s.status==="rejected"&&f(s.reason);return t().catch(f)})};function T(e,t,n=!1,o){return{code:e,message:t,recoverable:n,details:o}}class b extends Error{constructor(n){super(n.message);g(this,"payload");this.name="TypedError",this.payload=n}}function O(e){return e instanceof b}async function P(e){const t=p(e.currentState),n=[e.target.tagName,e.target.role??"",e.target.accessibleName??"",e.target.textSnippet??"",e.target.attrId??"",e.target.attrTestid??""].join("|");return j(`${e.ruleId}|${e.componentId}|${t}|${n}`)}function F(e,t,n,o,u){const f=new Map(e.map(r=>[r.matchKey,r])),c=new Map(t.map(r=>[r.matchKey,r])),s=u??new Set,i=t.filter(r=>!f.has(r.matchKey)&&!s.has(r.matchKey)),l=t.filter(r=>f.has(r.matchKey)&&!s.has(r.matchKey)),m=e.filter(r=>!c.has(r.matchKey)&&!s.has(r.matchKey)),a=t.filter(r=>s.has(r.matchKey));let d,y;if(o){if(o.currentAnnouncements){const r=new Set((o.baselineAnnouncements??[]).map(w));d=o.currentAnnouncements.filter(h=>!r.has(w(h)))}if(o.currentFocusEvents){const r=new Set((o.baselineFocusEvents??[]).map(E));y=o.currentFocusEvents.filter(h=>!r.has(E(h)))}}return{new:i,persistent:l,fixed:m,newCount:i.length,persistentCount:l.length,fixedCount:m.length,baselineSnapshotMeta:n,comparedAt:new Date().toISOString(),newAnnouncements:d,newFocusEvents:y,acknowledged:a,acknowledgedCount:a.length}}function w(e){return`${e.selector}::${e.text}::${e.politeness}`}function E(e){return`${e.toSelector}::${e.isFocusReset}`}function p(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return"["+e.map(p).join(",")+"]";const t=e;return"{"+Object.keys(t).sort().map(u=>`${JSON.stringify(u)}:${p(t[u])}`).join(",")+"}"}async function j(e){const t=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-1",t);return Array.from(new Uint8Array(n)).map(o=>o.toString(16).padStart(2,"0")).join("")}export{b as T,C as _,p as a,P as c,F as d,O as i,T as m};
@@ -0,0 +1,8 @@
1
+ const I=/\b(cookie|cookies|consent|gdpr|privacy|tracker|analytics|preference)s?\b/i,$=/\b(accept|agree|allow|got it|ok|okay|continue|confirm|accept all|allow all)\b/i,L=/\b(reject|decline|deny|no thanks|cancel|disagree|reject all|deny all)\b/i,y="https://www.w3.org/WAI/WCAG21/Understanding/";function x(t){let e=0;const a=window.getComputedStyle(t),r=a.position;if(r!=="fixed"&&r!=="sticky")return 0;const n=parseInt(a.zIndex,10);Number.isFinite(n)&&n>=100&&(e+=2),Number.isFinite(n)&&n>=1e3&&(e+=1);const o=(t.textContent??"").slice(0,2e3);I.test(o)&&(e+=3),$.test(o)&&(e+=1),L.test(o)&&(e+=1);const s=t.getBoundingClientRect();return s.width>=100&&s.height>=40&&(e+=1),a.display==="none"||a.visibility==="hidden"||t.getAttribute("aria-hidden")==="true"?0:e}function E(t=document){const e=[],a=t.querySelectorAll('[class*="cookie" i], [class*="consent" i], [id*="cookie" i], [id*="consent" i], dialog[open], div[role="dialog"], div[role="alertdialog"]');for(const o of a){const s=x(o);s>0&&e.push({el:o,score:s})}const r=t.querySelectorAll("body *");for(const o of r){if(e.some(u=>u.el===o))continue;const s=window.getComputedStyle(o);if(s.position!=="fixed"&&s.position!=="sticky")continue;const i=(o.textContent??"").slice(0,2e3);if(!I.test(i))continue;const l=x(o);l>0&&e.push({el:o,score:l})}if(e.length===0)return null;e.sort((o,s)=>s.score-o.score);const n=e[0];return n.score>=5?n.el:null}function v(t){var n,o,s,i;const e=(n=t.getAttribute("aria-label"))==null?void 0:n.trim();if(e)return e;const a=t.getAttribute("aria-labelledby");if(a){const l=(o=t.ownerDocument)==null?void 0:o.getElementById(a),u=(s=l==null?void 0:l.textContent)==null?void 0:s.trim();if(u)return u}const r=(i=t.getAttribute("title"))==null?void 0:i.trim();return r||(t.textContent??"").trim()}function R(t){const e=t.tagName;if(e==="BUTTON"||e==="A"||e==="INPUT"||e==="SELECT"||e==="TEXTAREA")return!0;const a=t.getAttribute("role");if(a==="button"||a==="link"||a==="checkbox"||a==="radio"||a==="switch")return!0;const r=t.getAttribute("tabindex");return r!==null&&parseInt(r,10)>=0}function T(t){const e=[],a=Array.from(t.querySelectorAll('button, a, input, select, textarea, [role="button"], [role="link"], [role="checkbox"], [tabindex]'));for(const i of a){if(!R(i)||i.type==="hidden")continue;const l=v(i);(!l||l.length<2)&&e.push({ruleId:"cookie-banner-button-name",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"serious",description:"Cookie banner: interactive element has no accessible name. Screen-reader users cannot tell what this button does (accept, reject, manage preferences, etc.).",helpUrl:`${y}name-role-value`,element:i,failureSummary:'Add an aria-label, visible text content, or aria-labelledby to label this control. "Accept all cookies" / "Reject all cookies" / "Manage preferences" are the conventional labels.'})}a.some(i=>{const l=v(i);return $.test(l)})||e.push({ruleId:"cookie-banner-no-accept",wcagCriterion:"3.2.4",wcagLevel:"AA",impact:"moderate",description:'Cookie banner: no clearly-labeled "accept" control found. Users (especially with cognitive disabilities or screen-reader users skimming labels) need a consistent, recognizable label.',helpUrl:`${y}consistent-identification`,element:t,failureSummary:'Add a button with text or aria-label containing "Accept" / "Allow" / "Agree" so the consent action is identifiable from the label alone.'}),a.some(i=>{const l=v(i);return L.test(l)})||e.push({ruleId:"cookie-banner-no-reject",wcagCriterion:"3.2.4",wcagLevel:"AA",impact:"serious",description:'Cookie banner: no clearly-labeled "reject all" control found. GDPR Art. 7 requires consent withdrawal to be as easy as consent giving; for accessibility this also means the reject control must be discoverable from its label, not buried in a "manage preferences" sub-flow.',helpUrl:`${y}consistent-identification`,element:t,failureSummary:'Add a button with text or aria-label containing "Reject" / "Decline" / "Reject all" alongside the accept control at the same hierarchy level.'});const o=t.getAttribute("role");t.tagName==="DIALOG"||o==="dialog"||o==="alertdialog"||e.push({ruleId:"cookie-banner-no-dialog-role",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"moderate",description:"Cookie banner: no dialog semantics. Screen-reader users will not be alerted that an interrupting modal is on-screen; keyboard users do not get the standard Escape-to-dismiss affordance.",helpUrl:`${y}info-and-relationships`,element:t,failureSummary:'Use <dialog open> or role="dialog" / role="alertdialog" plus aria-labelledby pointing to the banner heading. With the dialog role, screen readers announce "dialog: <name>" when the banner mounts.'});for(const i of a){const l=i.getAttribute("tabindex");l&&parseInt(l,10)<0&&e.push({ruleId:"cookie-banner-unreachable-control",wcagCriterion:"2.1.1",wcagLevel:"A",impact:"critical",description:"Cookie banner: interactive control has tabindex < 0 so keyboard users cannot reach it. If this is the accept/reject button, consent cannot be given without a mouse.",helpUrl:`${y}keyboard`,element:i,failureSummary:'Remove the negative tabindex, or replace with tabindex="0" so the control participates in the keyboard tab order.'})}return e}function U(t=document){const e=E(t);return e?T(e):[]}const h="https://www.w3.org/WAI/ARIA/apg/patterns/";function W(t){var n,o,s,i;const e=(n=t.getAttribute("aria-label"))==null?void 0:n.trim();if(e)return e;const a=t.getAttribute("aria-labelledby");if(a){const l=(o=t.ownerDocument)==null?void 0:o.getElementById(a),u=(s=l==null?void 0:l.textContent)==null?void 0:s.trim();if(u)return u}const r=(i=t.getAttribute("title"))==null?void 0:i.trim();return r||""}function P(t=document){const e=[],a=Array.from(t.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog[open]'));for(const r of a){const n=r.getAttribute("role")??(r.tagName==="DIALOG"?"dialog":"");W(r)||e.push({ruleId:"aria-pattern-dialog-no-name",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"serious",description:`${n} has no accessible name. Screen readers will announce "dialog" with no label, leaving the user unable to identify what's open.`,helpUrl:`${h}dialog-modal/`,element:r,failureSummary:'Add aria-labelledby pointing to the dialog heading, or aria-label with a short title (e.g. aria-labelledby="dlg-title" + <h2 id="dlg-title">Confirm deletion</h2>).'});const o=r.getAttribute("aria-modal");!(r.tagName==="DIALOG")&&o!=="true"&&o!=="false"&&e.push({ruleId:"aria-pattern-dialog-no-modal-attr",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"moderate",description:`${n} has no aria-modal attribute. If this dialog blocks the rest of the page, set aria-modal="true" so assistive technology can mute the background. If it's non-modal, set aria-modal="false" explicitly.`,helpUrl:`${h}dialog-modal/`,element:r,failureSummary:'Set aria-modal="true" on modal dialogs (most common). Native <dialog open> handles this automatically; custom div-based dialogs need the attribute.'})}return e}function N(t=document){const e=[],a=Array.from(t.querySelectorAll('[role="tablist"]'));for(const r of a){const n=Array.from(r.querySelectorAll('[role="tab"]'));if(n.length===0){e.push({ruleId:"aria-pattern-tablist-no-tabs",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"serious",description:'role="tablist" contains no role="tab" descendants. Screen readers announce a tab interface but provide nothing to navigate.',helpUrl:`${h}tabs/`,element:r,failureSummary:'Every tablist must directly contain role="tab" elements as children. Restructure the markup so the tabs are descendants of the tablist.'});continue}const o=n.filter(s=>s.getAttribute("aria-selected")==="true").length;o===0?e.push({ruleId:"aria-pattern-tabs-no-selected",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"serious",description:'No tab in this tablist has aria-selected="true". Screen-reader users hear all tabs as inactive, with no indication which panel is currently shown.',helpUrl:`${h}tabs/`,element:r,failureSummary:'Exactly one tab must have aria-selected="true" at any time. Update the active tab when the user picks a new one.'}):o>1&&e.push({ruleId:"aria-pattern-tabs-multiple-selected",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"serious",description:`${o} tabs have aria-selected="true" at once. Only one tab in a tablist may be selected at a time.`,helpUrl:`${h}tabs/`,element:r,failureSummary:"Clear aria-selected on all other tabs when one is activated. Use the keyboard-handler that updates aria-selected to also clear the previously-active tab."});for(const s of n){const i=s.getAttribute("aria-controls");if(!i){e.push({ruleId:"aria-pattern-tab-no-controls",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"moderate",description:'role="tab" has no aria-controls pointing to its tabpanel. Programmatic relationship between tab and panel is missing.',helpUrl:`${h}tabs/`,element:s,failureSummary:'Set aria-controls to the id of the corresponding tabpanel: <button role="tab" aria-controls="panel-1">Tab 1</button> + <div role="tabpanel" id="panel-1">…</div>'});continue}const l=t.getElementById(i);l?l.getAttribute("role")!=="tabpanel"&&e.push({ruleId:"aria-pattern-tab-wrong-target-role",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"moderate",description:`role="tab" aria-controls target has role="${l.getAttribute("role")??"(none)"}" instead of role="tabpanel".`,helpUrl:`${h}tabs/`,element:s,failureSummary:'The element a tab controls must have role="tabpanel".'}):e.push({ruleId:"aria-pattern-tab-broken-controls",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"serious",description:`role="tab" aria-controls="${i}" points to an id that doesn't exist on the page.`,helpUrl:`${h}tabs/`,element:s,failureSummary:`Add an element with id="${i}" + role="tabpanel" containing the tab's content, or fix the aria-controls value to match an existing panel.`})}}return e}function z(t=document){const e=[],a=Array.from(t.querySelectorAll('[role="combobox"]'));for(const r of a){const n=r.getAttribute("aria-expanded");n===null?e.push({ruleId:"aria-pattern-combobox-no-expanded",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"serious",description:`role="combobox" has no aria-expanded attribute. Screen-reader users can't tell whether the popup is open.`,helpUrl:`${h}combobox/`,element:r,failureSummary:'Set aria-expanded="false" when the popup is closed (default) and aria-expanded="true" when open. Toggle on user interaction.'}):n!=="true"&&n!=="false"&&e.push({ruleId:"aria-pattern-combobox-invalid-expanded",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"moderate",description:`role="combobox" aria-expanded="${n}" is not a valid value. Must be "true" or "false".`,helpUrl:`${h}combobox/`,element:r,failureSummary:'Use aria-expanded="true" or aria-expanded="false" (lowercase, exact match).'});const o=r.getAttribute("aria-controls")||r.getAttribute("aria-owns");if(!o)e.push({ruleId:"aria-pattern-combobox-no-popup",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"serious",description:'role="combobox" has no aria-controls (or aria-owns) pointing to the popup container.',helpUrl:`${h}combobox/`,element:r,failureSummary:"Set aria-controls to the id of the listbox / tree / grid / dialog that opens. The popup container needs the corresponding role."});else{const s=t.getElementById(o);if(!s)e.push({ruleId:"aria-pattern-combobox-broken-popup",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"serious",description:`role="combobox" aria-controls="${o}" points to an id that doesn't exist.`,helpUrl:`${h}combobox/`,element:r,failureSummary:`Add the popup element with id="${o}" and the appropriate role (listbox, tree, grid, or dialog).`});else{const i=s.getAttribute("role");(!i||!new Set(["listbox","tree","grid","dialog"]).has(i))&&e.push({ruleId:"aria-pattern-combobox-wrong-popup-role",wcagCriterion:"1.3.1",wcagLevel:"A",impact:"moderate",description:`role="combobox" popup target has role="${i??"(none)"}". Must be listbox, tree, grid, or dialog per APG.`,helpUrl:`${h}combobox/`,element:r,failureSummary:'Set role="listbox" on the popup container (most common). Use tree / grid / dialog only when the popup is structured that way.'})}}if(n==="true"){const s=r.getAttribute("aria-activedescendant");s&&!t.getElementById(s)&&e.push({ruleId:"aria-pattern-combobox-broken-activedescendant",wcagCriterion:"4.1.2",wcagLevel:"A",impact:"moderate",description:`role="combobox" aria-activedescendant="${s}" references an id that doesn't exist.`,helpUrl:`${h}combobox/`,element:r,failureSummary:"Update aria-activedescendant to the id of the currently-highlighted option, or remove it and rely on DOM focus."})}}return e}function O(t=document){return[...P(t),...N(t),...z(t)]}const S="https://www.w3.org/WAI/WCAG21/Understanding/non-text-content";function G(t){const e=t.getAttribute("href")??"";return!!(/\.pdf(\?|#|$)/i.test(e)||t.getAttribute("type")==="application/pdf")}function F(t){const e=(t.textContent??"").toLowerCase();return!!(/\bpdf\b/.test(e)||/\(pdf/i.test(t.getAttribute("aria-label")??"")||t.querySelector('[aria-label*="PDF" i], [aria-label*="pdf" i], [title*="PDF" i]'))}function D(t=document){const e=[],a=Array.from(t.querySelectorAll("a[href]"));for(const r of a){if(!G(r))continue;const n=r.getAttribute("href")??"";e.push({ruleId:"pdf-needs-cli-audit",wcagCriterion:"1.1.1",wcagLevel:"A",impact:"moderate",description:`Linked PDF at ${n}. PDF accessibility cannot be verified from a browser audit — run \`wcagcheckr-ci pdf ${n}\` (or pass the local file path) to check tagging, language, title, and structure tree.`,helpUrl:S,element:r,failureSummary:"PDFs are a separate accessibility document type with their own structural requirements (PDF/UA-1, WCAG via EN 301 549 §10). The wcagcheckr CLI runs a metadata audit on the PDF binary; see PDF column in the deposition packet for the result."}),F(r)||e.push({ruleId:"pdf-link-no-format-hint",wcagCriterion:"2.4.4",wcagLevel:"A",impact:"serious",description:`Link points to a PDF but the visible label gives no "(PDF)" hint. Screen-reader users hear the link text and won't know the activation will download a document.`,helpUrl:S,element:r,failureSummary:'Add "(PDF)" to the link text, or use an aria-label that includes "PDF" / "PDF document". Bonus: include the file size — "Annual report (PDF, 2.4 MB)".'})}return e}const c="https://www.w3.org/WAI/WCAG21/Understanding/";function H(t=document){const e=[],a=t.querySelectorAll('meta[http-equiv="refresh" i]');for(const n of Array.from(a)){const o=n.getAttribute("content")??"",s=parseInt(o.split(";")[0]??"",10);Number.isFinite(s)&&s>0&&e.push({ruleId:"wcc-meta-refresh",wcagCriterion:"2.2.1",wcagLevel:"A",impact:"serious",description:`Page uses <meta http-equiv="refresh"> to auto-refresh after ${s}s. WCAG 2.2.1 requires that users can turn off, adjust, or extend any time limit. Auto-refresh without user control fails this criterion.`,helpUrl:`${c}timing-adjustable.html`,element:n,failureSummary:`Auto-refresh interval: ${s}s. No user control mechanism on the page.`})}const r=t.querySelectorAll("script:not([src])");for(const n of Array.from(r)){const o=n.textContent??"";o.length===0||!/\b(setTimeout|setInterval)\s*\(/.test(o)||!/\b(innerHTML|textContent|replaceChildren|window\.location|document\.location|location\.href|location\.replace)\b/.test(o)||e.push({ruleId:"wcc-timer-mutates-content",wcagCriterion:"2.2.1",wcagLevel:"A",impact:"moderate",description:"Inline script uses setTimeout/setInterval to mutate page content. WCAG 2.2.1 requires that users can turn off, adjust, or extend any time-limited content change. Verify a pause / extend / disable mechanism exists in the UI.",helpUrl:`${c}timing-adjustable.html`,element:n,failureSummary:"Script combines timer + DOM mutation. Without a user control to pause/extend/disable, fails 2.2.1."})}return e}function M(t=document){var e,a;try{const r=t.styleSheets;for(let n=0;n<r.length;n++){const o=r[n];if(!o)continue;let s=null;try{s=o.cssRules}catch{continue}if(s)for(let i=0;i<s.length;i++){const l=s[i];if(l&&l.constructor&&l.constructor.name==="CSSMediaRule"){const u=l,p=u.conditionText??((e=u.media)==null?void 0:e.mediaText)??"";if(!/prefers-reduced-motion\s*:\s*reduce/i.test(p))continue;for(let d=0;d<u.cssRules.length;d++){const m=u.cssRules[d];if(m&&m.constructor&&m.constructor.name==="CSSStyleRule"){const f=((a=m.style)==null?void 0:a.cssText)??"";if(/animation|transition/i.test(f))return!0}}}}}}catch{}return!1}function _(t=document){const e=[],a=M(t),r=t.querySelectorAll("marquee, blink");for(const i of Array.from(r))e.push({ruleId:"wcc-marquee-blink",wcagCriterion:"2.2.2",wcagLevel:"A",impact:"serious",description:`<${i.tagName.toLowerCase()}> creates continuous motion with no built-in pause control. WCAG 2.2.2 requires a way to pause, stop, or hide auto-moving content.`,helpUrl:`${c}pause-stop-hide.html`,element:i,failureSummary:`Deprecated <${i.tagName.toLowerCase()}> element auto-animates without pause control.`});const n=t.querySelectorAll("video[autoplay]");for(const i of Array.from(n))!i.hasAttribute("controls")&&!i.muted&&e.push({ruleId:"wcc-autoplay-no-controls",wcagCriterion:"2.2.2",wcagLevel:"A",impact:"serious",description:"<video autoplay> without controls attribute (or muted) creates moving content the user cannot pause. WCAG 2.2.2 requires a pause / stop / hide mechanism.",helpUrl:`${c}pause-stop-hide.html`,element:i,failureSummary:"Autoplay video lacks user-accessible pause control."});const o=t.querySelectorAll("*");let s=0;for(const i of Array.from(o)){if(s>1500)break;s++;const l=window.getComputedStyle(i);if(l.animationName==="none"||!l.animationName)continue;const u=l.animationDuration.split(",").map(d=>parseFloat(d)),p=l.animationIterationCount.split(",").map(d=>d.trim());for(let d=0;d<u.length;d++){const m=u[d]??0,b=(p[d]??"1")==="infinite";b&&m>0&&m<.34&&e.push({ruleId:"wcc-flash-risk",wcagCriterion:"2.3.1",wcagLevel:"A",impact:"critical",description:`Element animates with duration ${m.toFixed(2)}s on infinite repeat — that's > 3 cycles/sec, which can trigger photosensitive seizures. WCAG 2.3.1 prohibits content that flashes more than 3 times per second unless the flashing area is below threshold.`,helpUrl:`${c}three-flashes-or-below-threshold.html`,element:i,failureSummary:`Infinite CSS animation @ ${m.toFixed(2)}s/cycle = ${(1/m).toFixed(1)} flashes/sec.`}),b&&m>=5&&!a&&e.push({ruleId:"wcc-long-infinite-animation",wcagCriterion:"2.2.2",wcagLevel:"A",impact:"moderate",description:`Element runs an infinite CSS animation (${m.toFixed(1)}s/cycle). WCAG 2.2.2 requires a way to pause, stop, or hide animation longer than 5 seconds. The canonical mitigation is a \`@media (prefers-reduced-motion: reduce)\` block that disables or shortens the animation — the wcagcheckr rule detects this automatically and stops firing once present. Alternative: a visible pause button.`,helpUrl:`${c}pause-stop-hide.html`,element:i,failureSummary:`Infinite animation @ ${m.toFixed(1)}s/cycle. Confirm user can pause.`})}}return e}function B(t=document){const e=[],a=new Set,r=t.querySelectorAll("[ontouchstart], [ontouchmove], [ongesturestart], [ongesturechange]");for(const o of Array.from(r)){const s=k(o);a.has(s)||(a.add(s),e.push({ruleId:"wcc-gesture-no-alternative",wcagCriterion:"2.5.1",wcagLevel:"A",impact:"serious",description:"Element handles multi-point or path-based gestures (touch/gesture events). WCAG 2.5.1 requires that all functionality operable with a path-based or multi-point gesture is ALSO operable with a single-pointer activation. Verify a button / link / single-tap alternative exists.",helpUrl:`${c}pointer-gestures.html`,element:o,failureSummary:"Touch/gesture handler on this element. Confirm single-pointer alternative."}))}const n=t.querySelectorAll('[draggable="true"], [ondragstart]');for(const o of Array.from(n)){const s=k(o);a.has(s)||(a.add(s),e.push({ruleId:"wcc-drag-no-alternative",wcagCriterion:"2.5.7",wcagLevel:"AA",impact:"serious",description:'Element uses HTML5 drag-and-drop (`draggable="true"` or `ondragstart`). WCAG 2.5.7 requires that any function achieved via a dragging movement is ALSO operable by a single-pointer action (click, button, arrow keys). Confirm an alternative exists.',helpUrl:`${c}dragging-movements.html`,element:o,failureSummary:"Drag-and-drop interaction. Confirm non-drag alternative for keyboard / touch users."}))}return e}function j(t=document){const e=[],a=t.querySelectorAll("video");for(const n of Array.from(a)){const o=Array.from(n.querySelectorAll("track")),s=o.some(l=>(l.kind??"").toLowerCase()==="captions"||(l.kind??"").toLowerCase()==="subtitles"),i=o.some(l=>(l.kind??"").toLowerCase()==="descriptions");s||e.push({ruleId:"wcc-video-no-captions",wcagCriterion:"1.2.2",wcagLevel:"A",impact:"serious",description:'<video> element without `<track kind="captions">` (or `subtitles`). WCAG 1.2.2 requires captions for all prerecorded audio content in synchronized media. If this video has no audio, mark this finding as not-applicable.',helpUrl:`${c}captions-prerecorded.html`,element:n,failureSummary:'No <track kind="captions"> child. Captions required unless video is silent.'}),i||(e.push({ruleId:"wcc-video-no-descriptions",wcagCriterion:"1.2.5",wcagLevel:"AA",impact:"moderate",description:'<video> element without `<track kind="descriptions">`. WCAG 1.2.5 (AA) requires audio description of important visual content in prerecorded video. If all video content is conveyed by the audio track alone, mark this finding as not-applicable.',helpUrl:`${c}audio-description-prerecorded.html`,element:n,failureSummary:'No <track kind="descriptions"> child. Audio description required when visuals carry info not in audio.'}),e.push({ruleId:"wcc-video-no-audio-desc-or-alt",wcagCriterion:"1.2.3",wcagLevel:"A",impact:"serious",description:'<video> element with no audio description track AND no obvious text-alternative link nearby. WCAG 1.2.3 (A) requires EITHER audio description OR a full text alternative for prerecorded video content. Add a <track kind="descriptions"> OR link a transcript/synopsis adjacent to the video.',helpUrl:`${c}audio-description-or-media-alternative-prerecorded.html`,element:n,failureSummary:'No <track kind="descriptions"> and no detectable text alternative. Need at least one.'}))}const r=t.querySelectorAll("audio");for(const n of Array.from(r))e.push({ruleId:"wcc-audio-needs-transcript",wcagCriterion:"1.2.1",wcagLevel:"A",impact:"moderate",description:"<audio> element present. WCAG 1.2.1 requires a text alternative (transcript) for prerecorded audio-only content. Confirm a transcript is linked nearby.",helpUrl:`${c}audio-only-and-video-only-prerecorded.html`,element:n,failureSummary:"Audio element detected. Verify nearby transcript link."});return e}function V(t=document){const e=[],a=/\b(window\.location|document\.location|location\.href|location\.replace|window\.open|\.submit\s*\()/,r=t.querySelectorAll("[onfocus]");for(const o of Array.from(r)){const s=o.getAttribute("onfocus")??"";a.test(s)&&e.push({ruleId:"wcc-onfocus-context-change",wcagCriterion:"3.2.1",wcagLevel:"A",impact:"serious",description:"Element's `onfocus` handler causes a context change (navigation, submit, popup). WCAG 3.2.1 forbids context changes triggered solely by focus — they disorient keyboard and screen-reader users who land on the element while scanning.",helpUrl:`${c}on-focus.html`,element:o,failureSummary:"Focus handler navigates / submits / opens window. Move trigger to explicit click/keypress."})}const n=t.querySelectorAll("select[onchange], input[onchange], textarea[onchange]");for(const o of Array.from(n)){const s=o.getAttribute("onchange")??"";a.test(s)&&e.push({ruleId:"wcc-oninput-context-change",wcagCriterion:"3.2.2",wcagLevel:"A",impact:"serious",description:"Form control's `onchange` handler causes a context change without explicit user request. WCAG 3.2.2 requires that changing a setting in a form control does NOT automatically navigate or submit — the user must explicitly confirm via a button.",helpUrl:`${c}on-input.html`,element:o,failureSummary:"Change handler navigates / submits. Replace with a separate submit button."})}return e}function K(t=document){const e=[],a=[".g-recaptcha","[data-sitekey]",".h-captcha",".cf-turnstile",".frc-captcha",'iframe[src*="recaptcha"]','iframe[src*="hcaptcha"]','iframe[src*="turnstile"]'].join(", "),r=t.querySelectorAll(a),n=new Set;for(const o of Array.from(r)){if(n.has(o))continue;n.add(o);const s=o.closest("form"),i=((s==null?void 0:s.textContent)??"").toLowerCase(),l=/audio captcha|alternative|sign in with|continue with|use email|magic link/.test(i);e.push({ruleId:"wcc-cognitive-auth-challenge",wcagCriterion:"3.3.8",wcagLevel:"AA",impact:l?"moderate":"serious",description:l?"CAPTCHA / cognitive-function challenge detected. An alternative authentication mechanism appears available — verify it actually bypasses the CAPTCHA. WCAG 3.3.8 requires that the alternative not also require a cognitive function test.":'CAPTCHA / cognitive-function challenge detected with no apparent alternative. WCAG 3.3.8 requires an alternative authentication mechanism that does NOT depend on a cognitive function test (recognizing distorted text, solving puzzles, identifying objects in images, etc.). Add a "Sign in with [SSO]" or magic-link option.',helpUrl:`${c}accessible-authentication-minimum.html`,element:o,failureSummary:l?"CAPTCHA detected; alternative may exist — verify it skips the cognitive challenge.":"CAPTCHA detected without an alternative authentication path."})}return e}function X(t=document){const e=[],a=t.querySelectorAll('meta[name="viewport" i]');for(const n of Array.from(a)){const o=n.getAttribute("content")??"";(/user-scalable\s*=\s*(no|0)\b/i.test(o)||/maximum-scale\s*=\s*1(\.0+)?\b/i.test(o))&&e.push({ruleId:"wcc-viewport-locks-zoom",wcagCriterion:"1.4.4",wcagLevel:"AA",impact:"serious",description:'<meta name="viewport"> disables user zoom (`user-scalable=no` or `maximum-scale=1`). WCAG 1.4.4 requires that users can scale text up to 200% without loss of content or functionality. Remove the zoom-disabling tokens.',helpUrl:`${c}resize-text.html`,element:n,failureSummary:"Viewport meta disables zoom. Remove user-scalable=no and maximum-scale<2."})}let r=0;for(const n of Array.from(t.styleSheets)){if(r>40)break;r++;try{const o=n.cssRules;if(!o)continue;for(const s of Array.from(o)){if(!(s instanceof CSSMediaRule))continue;const i=s.media.mediaText.toLowerCase(),l=/\(\s*orientation\s*:\s*portrait\s*\)/.test(i),u=/\(\s*orientation\s*:\s*landscape\s*\)/.test(i);if(!(!l&&!u)){for(const p of Array.from(s.cssRules))if(p instanceof CSSStyleRule&&/display\s*:\s*none/i.test(p.style.cssText)){e.push({ruleId:"wcc-orientation-locked-content",wcagCriterion:"1.3.4",wcagLevel:"AA",impact:"serious",description:`Stylesheet hides content via "display: none" inside an @media (orientation: ${l?"portrait":"landscape"}) block. WCAG 1.3.4 requires content not be restricted to a single display orientation unless that orientation is essential. Provide content in both orientations or document the essential-orientation exception.`,helpUrl:`${c}orientation.html`,element:t.documentElement,failureSummary:`Orientation-locked display:none on selector "${p.selectorText}".`});break}}}}catch{}}return e}function Y(t=document){const e=[];let a=0;const r=t.querySelectorAll("[title]");for(const n of Array.from(r)){if(a>200)break;a++;const o=n.getAttribute("title");!o||o.trim().length<8||n.hasAttribute("aria-describedby")||n.tagName==="A"&&(n.textContent??"").includes(o)||e.push({ruleId:"wcc-title-tooltip-no-persistence",wcagCriterion:"1.4.13",wcagLevel:"AA",impact:"moderate",description:'Element uses the `title` attribute for a tooltip-style description. Browser title tooltips auto-dismiss when the pointer moves, violating WCAG 1.4.13\'s "hoverable" and "persistent" requirements (content triggered on hover must remain visible until the user dismisses it). Use a proper aria-describedby pattern with a hoverable, dismissible tooltip element.',helpUrl:`${c}content-on-hover-or-focus.html`,element:n,failureSummary:"title-attribute tooltip is not dismissible / hoverable."})}return e}function Z(t=document){const e=[],a=typeof window<"u"?window.location.pathname:"/";if(a==="/"||a===""||/\/(search|results)\b/.test(a))return e;const r=t.querySelector('nav, [role="navigation"]')!==null,n=t.querySelector('input[type="search"], [role="search"]')!==null||Array.from(t.querySelectorAll('input[type="text"]')).some(l=>/search/i.test(l.name)||/search/i.test(l.placeholder??"")),o=t.querySelector('a[href*="sitemap" i]')!==null,s=Array.from(t.querySelectorAll('a[href^="#"]')).length>=3,i=[r,n,o,s].filter(Boolean).length;return i<2&&e.push({ruleId:"wcc-only-one-way-to-find",wcagCriterion:"2.4.5",wcagLevel:"AA",impact:"moderate",description:`Page provides only ${i} navigation aid${i===1?"":"s"}. WCAG 2.4.5 requires at least TWO ways to locate a page within a set: typically navigation menu + site search, OR navigation + sitemap link. Home pages and search results are exempt.`,helpUrl:`${c}multiple-ways.html`,element:t.documentElement,failureSummary:`Found ${i} of 4 affordances (nav=${r}, search=${n}, sitemap=${o}, toc=${s}).`}),e}function J(t=document){const e=[],a=/\b(window\.location|location\.href|\.submit\s*\(|window\.open|fetch\s*\(|XMLHttpRequest)\b/,r=t.querySelectorAll("[onmousedown], [onpointerdown]");for(const n of Array.from(r)){const o=(n.getAttribute("onmousedown")??"")+";"+(n.getAttribute("onpointerdown")??"");a.test(o)&&e.push({ruleId:"wcc-down-event-fires-action",wcagCriterion:"2.5.2",wcagLevel:"A",impact:"serious",description:"Element's mousedown/pointerdown handler fires a navigation, submit, or network action. WCAG 2.5.2 requires that single-pointer actions execute on UP-EVENT (mouseup, click), not down-event, so users can abort by dragging away. Move the action to the click handler or onmouseup.",helpUrl:`${c}pointer-cancellation.html`,element:n,failureSummary:"Action fires on pointer-down; user cannot abort by dragging away before release."})}return e}function Q(t=document){const e=[],a=t.querySelectorAll("script:not([src])");for(const r of Array.from(a)){const n=r.textContent??"";if(/\b(devicemotion|deviceorientation)\b/.test(n)&&/\baddEventListener\s*\(\s*['"`](devicemotion|deviceorientation)/.test(n)){e.push({ruleId:"wcc-motion-actuation-no-alt",wcagCriterion:"2.5.4",wcagLevel:"A",impact:"serious",description:"Page registers a `devicemotion` or `deviceorientation` listener (shake / tilt to act). WCAG 2.5.4 requires that any function triggered by device motion is ALSO operable via standard UI controls AND can be disabled to prevent accidental actuation. Add an on-screen button equivalent.",helpUrl:`${c}motion-actuation.html`,element:r,failureSummary:"Device-motion listener present. Confirm UI-control alternative + disable mechanism."});break}}return e}function ee(t=document){const e=[],a=t.querySelectorAll("form");for(const r of Array.from(a)){const n=r.querySelectorAll("input[required], select[required], textarea[required]");if(n.length===0||Array.from(n).some(i=>i.hasAttribute("aria-describedby")||i.hasAttribute("aria-invalid")||i.hasAttribute("aria-errormessage")))continue;const s=/\b(required|please|must|\*)\b/i.test(r.textContent??"");e.push({ruleId:"wcc-form-no-aria-error-pattern",wcagCriterion:"3.3.1",wcagLevel:"A",impact:s?"moderate":"serious",description:`Form has ${n.length} required field${n.length===1?"":"s"} but no fields use ARIA error patterns (\`aria-invalid\`, \`aria-describedby\`, \`aria-errormessage\`). WCAG 3.3.1 requires that input errors be identified in text the user can perceive. Browser-default HTML5 validation bubbles aren't reliably announced by all screen readers; wire each required field to a visible error region via aria-describedby and toggle aria-invalid when validation fails.`,helpUrl:`${c}error-identification.html`,element:r,failureSummary:`${n.length} required input(s) without ARIA error pattern.`})}return e}function te(t=document){const e=[],a=t.querySelectorAll("[onkeydown], [onkeypress], [onkeyup]");if(a.length===0)return e;const r=Array.from(a).slice(0,5);for(const n of r)e.push({ruleId:"wcc-inline-key-handler",wcagCriterion:"2.1.4",wcagLevel:"A",impact:"moderate",description:"Element has an inline keyboard event handler (onkeydown / onkeypress / onkeyup). WCAG 2.1.4 requires single-character key shortcuts to be togglable, remappable, or only-on-focus. Verify this handler complies, OR — preferred — replace inline handlers with addEventListener-attached handlers gated by a focused-element check.",helpUrl:`${c}character-key-shortcuts.html`,element:n,failureSummary:"Inline keyboard handler detected — verify shortcuts are togglable / scoped."});return e}function ne(t=document){const e=[];if(t.querySelectorAll('[role="status"], [role="alert"], [role="log"], [aria-live]').length>0)return e;const r=t.querySelector("form input[required], form input[pattern]")!=null,n=t.getElementById("root")!=null||t.getElementById("app")!=null||t.querySelector("[data-reactroot], [data-vue-app]")!=null,o=t.querySelector('[class*="toast" i], [class*="snackbar" i], [class*="notif" i]')!=null;return(r||n||o)&&e.push({ruleId:"wcc-no-live-regions",wcagCriterion:"4.1.3",wcagLevel:"AA",impact:"moderate",description:'Page appears to contain dynamic content (form validation, SPA mount, toast/snackbar container) but has no `role="status"` / `role="alert"` / `aria-live` regions. WCAG 4.1.3 requires status updates that don\'t cause a focus change to be announced via a live region. Add `role="status"` (polite) or `role="alert"` (assertive) to your status / error / toast containers. If your dynamic updates already steal focus, this finding may be N/A.',helpUrl:`${c}status-messages.html`,element:t.documentElement,failureSummary:"No live regions detected on a page that appears to have dynamic content."}),e}const oe=360,ie=10;function re(t=document){if(typeof window>"u"||typeof document>"u")return[];if(window.innerWidth>oe)return[];const e=t.documentElement;if(!e)return[];const a=e.scrollWidth-e.clientWidth;return a<=ie?[]:[{ruleId:"wcc-reflow-horizontal-scroll",wcagCriterion:"1.4.10",wcagLevel:"AA",impact:"serious",description:`Page produces horizontal scroll at narrow viewport (${window.innerWidth}px wide; documentElement.scrollWidth=${e.scrollWidth}px vs clientWidth=${e.clientWidth}px, overflow=${a}px). WCAG 1.4.10 requires content to reflow at 320 CSS pixels without requiring scrolling in two dimensions. Common causes: fixed-width container exceeding the viewport, image without max-width:100%, white-space:nowrap on a long string, table without overflow handling, or a third-party widget that doesn't respect responsive constraints.`,helpUrl:`${c}reflow.html`,element:e,failureSummary:"Horizontal scroll detected at narrow viewport. Find the element producing the overflow (try Chrome DevTools → Elements → 3-dots → Capture full-size screenshot at 320px width) and add max-width / overflow-x:auto / responsive layout to keep content within 320px."}]}function ae(t=document){return[]}function se(t=document){const e=[],a=t.querySelectorAll("form");if(a.length===0)return e;let r=!1,n=!1;for(const o of Array.from(a)){const s=o.querySelectorAll('input[required], input[pattern], input[type="email"], input[type="url"], input[type="tel"], input[type="number"]');if(s.length!==0){r=!0;for(const i of Array.from(s))if(i.getAttribute("aria-describedby")||i.getAttribute("aria-errormessage")||i.getAttribute("list")){n=!0;break}if(n)break}}return!r||n||e.push({ruleId:"wcc-form-no-error-suggestion",wcagCriterion:"3.3.3",wcagLevel:"AA",impact:"moderate",description:"Form has inputs with required / pattern / typed (email / url / tel / number) constraints but none of them wire to a `<datalist>`, `aria-describedby`, or `aria-errormessage`. WCAG 3.3.3 requires error suggestions when corrections are knowable. Add either a `<datalist>` of valid values OR an `aria-describedby` pointing at a visible help / error region with example-correct values.",helpUrl:`${c}error-suggestion.html`,element:a[0],failureSummary:"Form has constrained inputs but no suggestion-infrastructure (datalist / aria-describedby / aria-errormessage)."}),e}function le(t=document){var u;const e=[],a=t.querySelectorAll("form");if(a.length===0)return e;const r=/\b(pay|payment|order|purchase|checkout|charge|transfer|donate|subscribe|agree|sign|delete account|cancel subscription|consent|enroll|legally)\b/i,n=/\b(free|demo|trial|preview|sample)\b/i,o=/\b(review|preview|confirm|verify|are you sure|please confirm|double-check)\b/i,s=/\b(undo|reverse|cancel|edit|update later|change later)\b/i;let i=!1,l=null;for(const p of Array.from(a)){const d=(p.textContent??"")+" "+(p.getAttribute("aria-label")??"");if(!r.test(d)||n.test(d)&&!/\$|usd|eur|gbp/i.test(d))continue;i=!0,l=p;const m=d+" "+(((u=p.closest("section, main, body"))==null?void 0:u.textContent)??"");if(o.test(m)||s.test(m))return e}return i&&e.push({ruleId:"wcc-commit-form-no-review-step",wcagCriterion:"3.3.4",wcagLevel:"AA",impact:"serious",description:"Form appears to commit a legal, financial, or data-modification action (matched keywords: pay / order / purchase / transfer / agree / sign / delete-account / etc.) but no review, confirm, or reversibility step was detected nearby. WCAG 3.3.4 requires ONE of: (a) reversibility (undo / cancel after submit), (b) error-checking with explicit confirmation, OR (c) a review-and-confirm screen before final submit. Add at least one. Heuristic — verify manually if this form is actually a no-commitment lead-capture.",helpUrl:`${c}error-prevention-legal-financial-data.html`,element:l??t.documentElement,failureSummary:"Commit-style form with no detected review/confirm/reversibility cue."}),e}function ce(t=document){const e=[],a=t.querySelectorAll("audio[autoplay], video[autoplay]");if(a.length===0)return e;for(const r of Array.from(a))r.hasAttribute("controls")||r.tagName.toLowerCase()==="video"&&r.hasAttribute("muted")||e.push({ruleId:"wcc-autoplay-no-controls",wcagCriterion:"1.4.2",wcagLevel:"A",impact:"serious",description:`${r.tagName.toLowerCase()} element has \`autoplay\` but no \`controls\` attribute and is not muted. WCAG 1.4.2 (A) requires a mechanism to pause / stop / control volume for any audio playing automatically for more than 3 seconds. EITHER add the \`controls\` attribute, OR add \`muted\` to the element, OR provide a visible custom control adjacent to the media.`,helpUrl:`${c}audio-control.html`,element:r,failureSummary:"Autoplay media without controls — needs pause/stop/volume mechanism."});return e}function ue(t=document){const e=[],a=t.querySelectorAll('header, footer, [class*="banner" i], [class*="cookie" i], [class*="modal" i], [class*="chat" i], [class*="sticky" i], [class*="fixed" i], [class*="overlay" i], [role="banner"], [role="contentinfo"]');for(const r of Array.from(a).slice(0,30)){const n=getComputedStyle(r),o=n.position;if(o!=="sticky"&&o!=="fixed"||n.display==="none"||n.visibility==="hidden"||n.opacity==="0")continue;const s=Number(n.opacity);if(Number.isFinite(s)&&s<=.1)continue;const i=n.zIndex;if(i&&i!=="auto"){const g=Number(i);if(Number.isFinite(g)&&g<0)continue}const l=n.backgroundColor,u=/rgba?\([^,]+,[^,]+,[^,]+,\s*([\d.]+)\s*\)/.exec(l);if((u?Number(u[1]):1)<.5&&!n.backgroundImage.match(/url\(/))continue;const d=r.getBoundingClientRect();if(d.width===0||d.height===0)continue;const m=window.innerHeight||document.documentElement.clientHeight,f=d.top<80&&d.bottom>0,b=d.bottom>m-80&&d.top<m;if(!f&&!b)continue;const C=getComputedStyle(document.documentElement),w=t.body?getComputedStyle(t.body):null;if(f){const g=parseFloat(C.scrollPaddingTop)||0,A=w&&parseFloat(w.scrollPaddingTop)||0;if(Math.max(g,A)>=d.height-2)continue}if(b){const g=parseFloat(C.scrollPaddingBottom)||0,A=w&&parseFloat(w.scrollPaddingBottom)||0;if(Math.max(g,A)>=d.height-2)continue}e.push({ruleId:"wcc-sticky-may-obscure-focus",wcagCriterion:"2.4.11",wcagLevel:"AA",impact:"moderate",description:`Element is ${o}-positioned and overlaps the viewport's ${f?"top":"bottom"} edge with an opaque background, and we did NOT detect a sufficient ${f?"`scroll-padding-top`":"`scroll-padding-bottom`"} on \`html\` / \`body\` to push focused elements out from under it. WCAG 2.4.11 (AA, WCAG 2.2) requires that focused components NOT be entirely hidden by such overlays. Common fixes (any one is sufficient): (1) \`${f?"scroll-padding-top":"scroll-padding-bottom"}: ${Math.ceil(d.height)}px\` on the scroll container (\`html\` or \`body\`) — the wcagcheckr rule detects this automatically and will stop firing once present; (2) \`${f?"scroll-margin-top":"scroll-margin-bottom"}\` on each focusable element below the overlay; (3) a JS focus-aware reveal that hides the sticky overlay when focus lands beneath it (this one the rule CANNOT detect; mark this finding as acknowledged in the per-page panel once it's in place).`,helpUrl:`${c}focus-not-obscured-minimum.html`,element:r,failureSummary:`${o} element overlapping viewport edge — verify focus visibility.`})}return e}function de(t=document){const e=[],a=t.querySelectorAll("form");if(a.length===0)return e;const r=/\b(step\s*\d|wizard|stage\s*\d|page\s*\d\s*of\s*\d|continue|next|previous|back to (cart|review))\b/i,n='[role="progressbar"], [class*="step" i], [class*="wizard" i], [class*="progress" i]';let o=!1;for(const s of Array.from(a)){const i=s.textContent??"";if(r.test(i)){o=!0;break}}return!o&&t.querySelectorAll(n).length>0&&(o=!0),o&&e.push({ruleId:"wcc-redundant-entry-needs-site-crawl",wcagCriterion:"3.3.7",wcagLevel:"A",impact:"minor",description:'This page appears to be part of a multi-step flow (step indicators, "continue"/"next" cues, progress markers). WCAG 3.3.7 (A, WCAG 2.2) requires that previously-entered information be auto-populated or selectable across steps — except when re-entry is essential (password confirmation, security). A single-page audit cannot verify cross-step redundancy. Run the Site Crawl flow on the full step sequence, then re-export — the crawler will compare field names across pages and flag duplicates.',helpUrl:`${c}redundant-entry.html`,element:t.documentElement,failureSummary:"Multi-step flow signals detected — needs site-crawl coverage."}),e}function me(t=document){return[]}const pe=/\b(click|tap|press|select|find|see|hear|use|choose) (?:the |a |an )?(red|orange|yellow|green|blue|purple|pink|black|white|round|square|triangular|left|right|top|bottom|upper|lower) (button|link|icon|tab|box|arrow|menu|control|element|item)\b/gi,he=/\b(listen for|hear) (?:the |a |an )?(chime|beep|click|ding|sound|tone)\b/gi;function fe(t=document){const e=[],a=t.body;if(!a)return e;const r=(a.innerText||a.textContent||"").slice(0,5e4);if(r.trim().length<40)return e;const n=new Set;for(const o of[pe,he]){o.lastIndex=0;let s;for(;(s=o.exec(r))!==null;){const i=s[0].toLowerCase().trim();if(!n.has(i)){if(n.add(i),n.size>5)break;e.push({ruleId:"wcc-sensory-only-directive",wcagCriterion:"1.3.3",wcagLevel:"A",impact:"moderate",description:`Found an instruction that appears to rely on sensory characteristics alone: "${i}". WCAG 1.3.3 requires that directions to users NOT depend solely on color, shape, size, position, orientation, or sound — there must also be a text alternative ("click the Submit button" rather than just "click the green button"). Verify the instruction includes a non-sensory cue (text label, ordinal position, accessible name). If the page provides additional context elsewhere, this can be marked verified.`,helpUrl:`${c}sensory-characteristics.html`,element:a,failureSummary:`Sensory-only directive phrase: "${i}"`})}}}return e}const ge=/\b(logo|icon|avatar|photo|portrait|headshot|illustration|chart|graph|diagram|map|screenshot|thumbnail)\b/i;function be(t=document){const e=[];let a=0;const r=t.querySelectorAll("img[alt]");for(const o of Array.from(r)){if(a>=5)break;const s=(o.getAttribute("alt")??"").trim();if(s.length<40||ge.test(s))continue;const i=/[a-z][.,;:]\s+[A-Z]/.test(s),l=(s.match(/\b[A-Z][a-z]+/g)??[]).length;!i&&l<4||(a++,e.push({ruleId:"wcc-image-of-text-candidate",wcagCriterion:"1.4.5",wcagLevel:"AA",impact:"moderate",description:`<img> alt text reads like prose content ("${s.slice(0,80)}${s.length>80?"…":""}"), suggesting the image may be RENDERING text instead of describing a non-text image. WCAG 1.4.5 prefers actual text (HTML + CSS) over text-baked-into-images so users can resize / restyle it. Common exceptions: logos, charts where the visual IS the information, screenshots of UI. If this image is one of those, mark verified.`,helpUrl:`${c}images-of-text.html`,element:o,failureSummary:`<img alt="${s.slice(0,60)}${s.length>60?"…":""}"> — long sentence-like alt suggests image-of-text.`}))}const n=t.querySelectorAll("svg");for(const o of Array.from(n)){if(a>=8)break;const s=o.querySelectorAll("text");if(s.length===0)continue;let i=0;for(const l of Array.from(s))i+=(l.textContent??"").trim().length;i<20||(a++,e.push({ruleId:"wcc-svg-text-as-content",wcagCriterion:"1.4.5",wcagLevel:"AA",impact:"minor",description:`<svg> contains <text> elements totaling ${i} characters. Stylized SVG text often substitutes for HTML text + CSS; users can't resize / restyle it the same way. Confirm the SVG text is genuinely graphical (chart axis labels, decorative logo text) rather than substantive content that should be HTML.`,helpUrl:`${c}images-of-text.html`,element:o,failureSummary:`SVG with ${s.length} <text> element(s), ${i} chars total.`}))}return e}function ye(t=document){const e=[];if(t!==document)return e;const a=Array.from(t.querySelectorAll("div, section, article, p, li, td, th, button, a")).filter(i=>{let l="";for(const p of i.childNodes)p.nodeType===Node.TEXT_NODE&&(l+=(p.textContent??"").trim());if(l.length<20)return!1;const u=getComputedStyle(i);return!(u.visibility==="hidden"||u.display==="none"||u.overflow!=="hidden"&&u.overflowY!=="hidden")});if(a.length===0)return e;const r=a.map(i=>({el:i,scrollHeight:i.scrollHeight,clientHeight:i.clientHeight,scrollWidth:i.scrollWidth,clientWidth:i.clientWidth})),n="__wcagcheckr_c36_probe__",o=document.createElement("style");o.id=n,o.textContent=`body *:not(script):not(style) {
2
+ line-height: 1.5 !important;
3
+ letter-spacing: 0.12em !important;
4
+ word-spacing: 0.16em !important;
5
+ }
6
+ body p:not(script):not(style) {
7
+ margin-bottom: 2em !important;
8
+ }`,document.head.appendChild(o),document.body.scrollHeight;const s=[];for(const i of r){const l=i.scrollHeight>i.clientHeight||i.scrollWidth>i.clientWidth;(i.el.scrollHeight>i.el.clientHeight||i.el.scrollWidth>i.el.clientWidth)&&!l&&s.push(i)}document.head.removeChild(o),document.body.scrollHeight;for(const i of s.slice(0,5)){let l="";for(const u of i.el.childNodes)u.nodeType===Node.TEXT_NODE&&(l+=(u.textContent??"").trim());e.push({ruleId:"wcc-text-spacing-clip-risk",wcagCriterion:"1.4.12",wcagLevel:"AA",impact:"minor",description:`WCAG technique C36 probe confirmed clipping: when WCAG 1.4.12 text-spacing values (line-height 1.5, letter-spacing 0.12em, word-spacing 0.16em, paragraph-spacing 2em) are applied, this container's content overflows the box (scrollHeight > clientHeight). Text content: "${l.slice(0,60)}${l.length>60?"…":""}". Remove fixed height, replace with min-height, or set overflow to visible.`,helpUrl:`${c}text-spacing.html`,element:i.el,failureSummary:"Container clips under WCAG 1.4.12 text-spacing overrides (verified via C36 CSS injection probe)."})}return e}function k(t){if(t.id)return`#${t.id}`;const e=t.classList[0];return`${t.tagName.toLowerCase()}${e?"."+e:""}`}function we(t=document){return[...H(t),..._(t),...B(t),...j(t),...V(t),...K(t),...X(t),...Y(t),...Z(t),...J(t),...Q(t),...ee(t),...te(t),...ne(t),...me(t),...ae(t),...se(t),...re(t),...le(t),...ce(t),...ue(t),...de(t),...U(t),...O(t),...fe(t),...be(t),...ye(t),...D(t)]}const Ae=["2.2.1","2.2.2","2.3.1","2.5.1","2.5.7","1.2.1","1.2.2","1.2.3","1.2.4","1.2.5","3.2.1","3.2.2","3.3.8","1.3.4","1.4.4","1.4.13","2.4.5","2.5.2","2.5.4","3.3.1","2.1.4","4.1.3","4.1.1","3.3.3","1.4.10","3.3.4","1.4.2","2.4.11","3.3.7","1.3.3","1.4.5","1.4.12"];export{Ae as DOM_ANALYZER_COVERED_CRITERIA,_ as analyzeAnimation,ce as analyzeAudioControl,te as analyzeCharacterKeyShortcuts,K as analyzeCognitiveAuth,ae as analyzeConsistencyHints,Y as analyzeContentOnHover,V as analyzeContextChangeOnFocusInput,ee as analyzeErrorIdentification,le as analyzeErrorPreventionLegalFinancial,se as analyzeErrorSuggestion,ue as analyzeFocusNotObscured,be as analyzeImagesOfText,j as analyzeMedia,Q as analyzeMotionActuation,Z as analyzeMultipleWays,X as analyzeOrientation,me as analyzeParsingObsoleted,J as analyzePointerCancellation,B as analyzePointerGestures,de as analyzeRedundantEntry,re as analyzeReflow,fe as analyzeSensoryCharacteristics,ne as analyzeStatusMessages,ye as analyzeTextSpacing,H as analyzeTimingAdjustable,M as hasReducedMotionMitigation,we as runAllDomCriterionAnalyzers};
@@ -0,0 +1,6 @@
1
+ import"./modulepreload-polyfill-B5Qt9EMX.js";import{a as q,R as D,u as z,j as e,b as X,r as o,d as be,P,e as L,f as ge,g as Ge,h as Be,i as R,C as Ke,A as He,c as Ve}from"./styles-Cn731SYD.js";import{c as ye,a as T,o as Je,s as E,O as Z,b as Ye}from"./crash-reporter-Bu2p8K-p.js";import{T as ze,P as _,r as We,D as qe,A as K,g as Qe,a as Xe,s as ee,c as Ze,l as et,b as tt,d as st,e as H,f as at,h as nt,i as te}from"./ai-usage-log-BX3L6bKl.js";import{l as rt,s as se,v as lt}from"./custom-rules-CAe0nbES.js";import"./_commonjsHelpers-Cpj98o6Y.js";function ot(t){const s=t+"CollectionProvider",[a,r]=q(s),[n,d]=a(s,{collectionRef:{current:null},itemMap:new Map}),c=j=>{const{scope:p,children:x}=j,b=D.useRef(null),N=D.useRef(new Map).current;return e.jsx(n,{scope:p,itemMap:N,collectionRef:b,children:x})};c.displayName=s;const l=t+"CollectionSlot",u=X(l),i=D.forwardRef((j,p)=>{const{scope:x,children:b}=j,N=d(l,x),S=z(p,N.collectionRef);return e.jsx(u,{ref:S,children:b})});i.displayName=l;const m=t+"CollectionItemSlot",h="data-radix-collection-item",f=X(m),g=D.forwardRef((j,p)=>{const{scope:x,children:b,...N}=j,S=D.useRef(null),I=z(p,S),w=d(m,x);return D.useEffect(()=>(w.itemMap.set(S,{ref:S,...N}),()=>void w.itemMap.delete(S))),e.jsx(f,{[h]:"",ref:I,children:b})});g.displayName=m;function v(j){const p=d(t+"CollectionConsumer",j);return D.useCallback(()=>{const b=p.collectionRef.current;if(!b)return[];const N=Array.from(b.querySelectorAll(`[${h}]`));return Array.from(p.itemMap.values()).sort((w,F)=>N.indexOf(w.ref.current)-N.indexOf(F.ref.current))},[p.collectionRef,p.itemMap])}return[{Provider:c,Slot:i,ItemSlot:g},v,r]}var it=o.createContext(void 0);function ve(t){const s=o.useContext(it);return t||s||"ltr"}var V="rovingFocusGroup.onEntryFocus",ct={bubbles:!1,cancelable:!0},O="RovingFocusGroup",[W,je,dt]=ot(O),[ut,Ne]=q(O,[dt]),[xt,mt]=ut(O),Se=o.forwardRef((t,s)=>e.jsx(W.Provider,{scope:t.__scopeRovingFocusGroup,children:e.jsx(W.Slot,{scope:t.__scopeRovingFocusGroup,children:e.jsx(ht,{...t,ref:s})})}));Se.displayName=O;var ht=o.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:a,orientation:r,loop:n=!1,dir:d,currentTabStopId:c,defaultCurrentTabStopId:l,onCurrentTabStopIdChange:u,onEntryFocus:i,preventScrollOnEntryFocus:m=!1,...h}=t,f=o.useRef(null),g=z(s,f),v=ve(d),[j,p]=ge({prop:c,defaultProp:l??null,onChange:u,caller:O}),[x,b]=o.useState(!1),N=Ge(i),S=je(a),I=o.useRef(!1),[w,F]=o.useState(0);return o.useEffect(()=>{const y=f.current;if(y)return y.addEventListener(V,N),()=>y.removeEventListener(V,N)},[N]),e.jsx(xt,{scope:a,orientation:r,dir:v,loop:n,currentTabStopId:j,onItemFocus:o.useCallback(y=>p(y),[p]),onItemShiftTab:o.useCallback(()=>b(!0),[]),onFocusableItemAdd:o.useCallback(()=>F(y=>y+1),[]),onFocusableItemRemove:o.useCallback(()=>F(y=>y-1),[]),children:e.jsx(P.div,{tabIndex:x||w===0?-1:0,"data-orientation":r,...h,ref:g,style:{outline:"none",...t.style},onMouseDown:L(t.onMouseDown,()=>{I.current=!0}),onFocus:L(t.onFocus,y=>{const k=!I.current;if(y.target===y.currentTarget&&k&&!x){const A=new CustomEvent(V,ct);if(y.currentTarget.dispatchEvent(A),!A.defaultPrevented){const C=S().filter(M=>M.focusable),Ue=C.find(M=>M.active),Oe=C.find(M=>M.id===j),$e=[Ue,Oe,...C].filter(Boolean).map(M=>M.ref.current);we($e,m)}}I.current=!1}),onBlur:L(t.onBlur,()=>b(!1))})})}),ke="RovingFocusGroupItem",Te=o.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:a,focusable:r=!0,active:n=!1,tabStopId:d,children:c,...l}=t,u=be(),i=d||u,m=mt(ke,a),h=m.currentTabStopId===i,f=je(a),{onFocusableItemAdd:g,onFocusableItemRemove:v,currentTabStopId:j}=m;return o.useEffect(()=>{if(r)return g(),()=>v()},[r,g,v]),e.jsx(W.ItemSlot,{scope:a,id:i,focusable:r,active:n,children:e.jsx(P.span,{tabIndex:h?0:-1,"data-orientation":m.orientation,...l,ref:s,onMouseDown:L(t.onMouseDown,p=>{r?m.onItemFocus(i):p.preventDefault()}),onFocus:L(t.onFocus,()=>m.onItemFocus(i)),onKeyDown:L(t.onKeyDown,p=>{if(p.key==="Tab"&&p.shiftKey){m.onItemShiftTab();return}if(p.target!==p.currentTarget)return;const x=bt(p,m.orientation,m.dir);if(x!==void 0){if(p.metaKey||p.ctrlKey||p.altKey||p.shiftKey)return;p.preventDefault();let N=f().filter(S=>S.focusable).map(S=>S.ref.current);if(x==="last")N.reverse();else if(x==="prev"||x==="next"){x==="prev"&&N.reverse();const S=N.indexOf(p.currentTarget);N=m.loop?gt(N,S+1):N.slice(S+1)}setTimeout(()=>we(N))}}),children:typeof c=="function"?c({isCurrentTabStop:h,hasTabStop:j!=null}):c})})});Te.displayName=ke;var pt={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function ft(t,s){return s!=="rtl"?t:t==="ArrowLeft"?"ArrowRight":t==="ArrowRight"?"ArrowLeft":t}function bt(t,s,a){const r=ft(t.key,a);if(!(s==="vertical"&&["ArrowLeft","ArrowRight"].includes(r))&&!(s==="horizontal"&&["ArrowUp","ArrowDown"].includes(r)))return pt[r]}function we(t,s=!1){const a=document.activeElement;for(const r of t)if(r===a||(r.focus({preventScroll:s}),document.activeElement!==a))return}function gt(t,s){return t.map((a,r)=>t[(s+r)%t.length])}var yt=Se,vt=Te,B="Tabs",[jt]=q(B,[Ne]),Ee=Ne(),[Nt,Q]=jt(B),Ce=o.forwardRef((t,s)=>{const{__scopeTabs:a,value:r,onValueChange:n,defaultValue:d,orientation:c="horizontal",dir:l,activationMode:u="automatic",...i}=t,m=ve(l),[h,f]=ge({prop:r,onChange:n,defaultProp:d??"",caller:B});return e.jsx(Nt,{scope:a,baseId:be(),value:h,onValueChange:f,orientation:c,dir:m,activationMode:u,children:e.jsx(P.div,{dir:m,"data-orientation":c,...i,ref:s})})});Ce.displayName=B;var Ae="TabsList",Ie=o.forwardRef((t,s)=>{const{__scopeTabs:a,loop:r=!0,...n}=t,d=Q(Ae,a),c=Ee(a);return e.jsx(yt,{asChild:!0,...c,orientation:d.orientation,dir:d.dir,loop:r,children:e.jsx(P.div,{role:"tablist","aria-orientation":d.orientation,...n,ref:s})})});Ie.displayName=Ae;var Re="TabsTrigger",_e=o.forwardRef((t,s)=>{const{__scopeTabs:a,value:r,disabled:n=!1,...d}=t,c=Q(Re,a),l=Ee(a),u=De(c.baseId,r),i=Me(c.baseId,r),m=r===c.value;return e.jsx(vt,{asChild:!0,...l,focusable:!n,active:m,children:e.jsx(P.button,{type:"button",role:"tab","aria-selected":m,"aria-controls":i,"data-state":m?"active":"inactive","data-disabled":n?"":void 0,disabled:n,id:u,...d,ref:s,onMouseDown:L(t.onMouseDown,h=>{!n&&h.button===0&&h.ctrlKey===!1?c.onValueChange(r):h.preventDefault()}),onKeyDown:L(t.onKeyDown,h=>{[" ","Enter"].includes(h.key)&&c.onValueChange(r)}),onFocus:L(t.onFocus,()=>{const h=c.activationMode!=="manual";!m&&!n&&h&&c.onValueChange(r)})})})});_e.displayName=Re;var Le="TabsContent",Fe=o.forwardRef((t,s)=>{const{__scopeTabs:a,value:r,forceMount:n,children:d,...c}=t,l=Q(Le,a),u=De(l.baseId,r),i=Me(l.baseId,r),m=r===l.value,h=o.useRef(m);return o.useEffect(()=>{const f=requestAnimationFrame(()=>h.current=!1);return()=>cancelAnimationFrame(f)},[]),e.jsx(Be,{present:n||m,children:({present:f})=>e.jsx(P.div,{"data-state":m?"active":"inactive","data-orientation":l.orientation,role:"tabpanel","aria-labelledby":u,hidden:!f,id:i,tabIndex:0,...c,ref:s,style:{...t.style,animationDuration:h.current?"0s":void 0},children:f&&d})})});Fe.displayName=Le;function De(t,s){return`${t}-trigger-${s}`}function Me(t,s){return`${t}-content-${s}`}var St=Ce,kt=Ie,Tt=_e,$=Fe;const wt=["default","hover","focus","focus-visible","active","disabled"],Et=["light","dark","forced-colors-active","forced-colors-none"],Ct=["ltr","rtl"];function At({value:t,onChange:s}){function a(n,d){return n.includes(d)?n.filter(c=>c!==d):[...n,d]}function r(){const n=t.ariaVariations.length===0?1:t.ariaVariations.length;return t.pseudoStates.length*n*t.themes.length*t.directions.length*t.breakpoints.length}return e.jsxs("div",{className:"space-y-3 border border-slate-200 rounded p-3 bg-white",children:[e.jsx(G,{label:"Pseudo-states",all:wt,selected:t.pseudoStates,onToggle:n=>s({...t,pseudoStates:a(t.pseudoStates,n)})}),e.jsx(G,{label:"Themes",all:Et,selected:t.themes,onToggle:n=>s({...t,themes:a(t.themes,n)})}),e.jsx(G,{label:"Directions",all:Ct,selected:t.directions,onToggle:n=>s({...t,directions:a(t.directions,n)})}),e.jsx(G,{label:"Breakpoints",all:t.breakpointPresets.map(n=>n.id),selected:t.breakpoints,onToggle:n=>s({...t,breakpoints:a(t.breakpoints,n)})}),e.jsxs("p",{className:"text-xs text-slate-500 pt-2 border-t border-slate-100",children:[e.jsx("strong",{children:r()})," audits per component"]})]})}function G({label:t,all:s,selected:a,onToggle:r}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium mb-1.5",children:t}),e.jsx("div",{className:"flex flex-wrap gap-1.5",children:s.map(n=>{const d=a.includes(n);return e.jsx("button",{type:"button",onClick:()=>r(n),className:d?"text-xs px-2 py-1 rounded bg-brand-500 text-white":"text-xs px-2 py-1 rounded bg-slate-100 text-slate-700 hover:bg-slate-200",children:n},n)})})]})}function It({value:t,onChange:s}){const[a,r]=o.useState(""),[n,d]=o.useState("");function c(i){i.preventDefault();const m=a.trim(),h=n.trim();!m||!h||(s({...t,[m]:h}),r(""),d(""))}function l(i){const m={...t};delete m[i],s(m)}const u=Object.entries(t);return e.jsxs("div",{className:"space-y-3 border border-slate-200 rounded p-3 bg-white",children:[u.length===0?e.jsx("p",{className:"text-xs text-slate-500 italic",children:"no aliases"}):e.jsx("ul",{className:"space-y-1",children:u.map(([i,m])=>e.jsxs("li",{className:"text-xs flex items-center justify-between gap-2 border border-slate-100 rounded p-1.5",children:[e.jsxs("span",{className:"font-mono truncate",title:`${i} → ${m}`,children:[i," ",e.jsx("span",{className:"text-slate-500",children:"→"})," ",m]}),e.jsx("button",{onClick:()=>l(i),className:"text-slate-500 hover:text-red-600 shrink-0","aria-label":`Remove alias ${i}`,children:"×"})]},i))}),e.jsxs("form",{onSubmit:c,className:"grid grid-cols-[1fr_1fr_auto] gap-2 items-end",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-slate-500 mb-1",children:"From"}),e.jsx("input",{type:"text",value:a,onChange:i=>r(i.target.value),placeholder:"https://example.com::testid:btn-a",className:"w-full text-xs border border-slate-300 rounded px-2 py-1 font-mono"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs text-slate-500 mb-1",children:"Treat as"}),e.jsx("input",{type:"text",value:n,onChange:i=>d(i.target.value),placeholder:"https://example.com::testid:btn-canonical",className:"w-full text-xs border border-slate-300 rounded px-2 py-1 font-mono"})]}),e.jsx("button",{type:"submit",className:"text-xs px-3 py-1 bg-brand-500 text-white rounded disabled:opacity-50",disabled:!a.trim()||!n.trim(),children:"Add"})]})]})}const ae=ye("billing-portal-client"),Rt="https://api.wcagcheckr.com",_t="wcagcheckr",Lt=15e3;async function Ft(t){const s=`${Rt}/v1/products/${_t}/billing-portal`;try{const a=await fetch(s,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:t.licenseToken}),signal:AbortSignal.timeout(Lt)}),r=await a.json().catch(()=>null);return a.ok?r!=null&&r.url?{ok:!0,url:r.url}:{ok:!1,error:"malformed response — no url",status:a.status}:(ae.warn(`billing portal HTTP ${a.status}`,r),{ok:!1,status:a.status,error:(r==null?void 0:r.hint)??(r==null?void 0:r.error)??`HTTP ${a.status}`})}catch(a){return ae.warn("billing portal request failed",a),{ok:!1,error:a instanceof Error?a.message:String(a)}}}const ne=ye("subscription-resume-client"),Dt="https://api.wcagcheckr.com",Mt="wcagcheckr",Pt=1e4;async function Ut(t){try{const s=await fetch(`${Dt}/v1/products/${Mt}/subscription/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:t.licenseToken}),signal:AbortSignal.timeout(Pt)}),a=await s.json().catch(()=>null);return s.ok?{ok:!0,alreadyActive:(a==null?void 0:a.alreadyActive)===!0}:(ne.warn(`resume http ${s.status}`,a),{ok:!1,status:s.status,error:(a==null?void 0:a.hint)??(a==null?void 0:a.error)??`HTTP ${s.status}`})}catch(s){return ne.warn("resume request failed",s),{ok:!1,error:s instanceof Error?s.message:String(s)}}}const Ot={trial:"Trial",free:"Free",solo:"Solo",team:"Team"},$t={free:"Free",solo:"Solo (monthly)","solo-yearly":"Solo (yearly)","solo-single-month":"Solo (single month — non-recurring)",team:"Team (5 seats, monthly)","team-yearly":"Team (5 seats, yearly)","team-15":"Team (15 seats, monthly)","team-15-yearly":"Team (15 seats, yearly)"},Gt=new Set(["solo-single-month"]);function Bt(t){if(!t)return null;const s=new Date(t).getTime()-Date.now();return Number.isFinite(s)?Math.ceil(s/(24*60*60*1e3)):null}function U(t){return t?$t[t]??t:"—"}function J(t){if(!t)return"no expiry on file";try{return new Date(t).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}catch{return t}}function Kt({tier:t,onTierChange:s}){const[a,r]=o.useState(null),[n,d]=o.useState(null),[c,l]=o.useState(!1),[u,i]=o.useState(""),[m,h]=o.useState(!1),[f,g]=o.useState(null),[v,j]=o.useState(!1),[p,x]=o.useState(!1),b=o.useCallback(async y=>{const A=(await chrome.storage.local.get("licenseToken")).licenseToken??null;if(r(A),!A){d(null);return}try{const C=await T({type:"LICENSE_VALIDATE_REQUEST",token:A,forceRefresh:(y==null?void 0:y.forceRefresh)===!0});d(C)}catch{d(null)}},[]);o.useEffect(()=>(b({forceRefresh:!0}),Je("LICENSE_CHANGED_EVENT",()=>{b()})),[b]);async function N(){if(u.trim()){h(!0),g(null);try{const y=await T({type:"LICENSE_SET_REQUEST",token:u.trim()}),k=await T({type:"LICENSE_VALIDATE_REQUEST",token:u.trim()});if(k.valid&&k.plan){const A=Jt(k.plan);s(A);let C=`Activated as ${U(k.plan)}.`;y.seatClaim.ok?y.seatClaim.overCapacity&&(C=`Activated as ${U(k.plan)}. Note: this license is currently OVER its seat cap (${y.seatClaim.seatsUsed} of ${y.seatClaim.seatsTotal} seats). Release one or upgrade.`):y.seatClaim.reason==="cap-reached"?C=`Activated as ${U(k.plan)}, BUT this license is at its seat capacity (${y.seatClaim.seatsUsed} of ${y.seatClaim.seatsTotal} seats used). Release a seat from another device, or upgrade to a higher-seat plan. This device's seat won't be active until you do.`:y.seatClaim.reason==="network"&&(C=`Activated as ${U(k.plan)}. (Seat-tracking ping failed — retrying in the background.)`),g(C),y.seatClaim.ok&&!y.seatClaim.overCapacity?R.polite(C):R.assertive(C),i(""),l(!1),await b()}else{const A="Token did not validate. Check the value and try again.";g(A),R.assertive(A)}}catch(y){const k=y instanceof Error?y.message:String(y);g(k),R.assertive(k)}finally{h(!1)}}}async function S(){if(a)try{await navigator.clipboard.writeText(a),j(!0),setTimeout(()=>j(!1),2e3)}catch{}}async function I(){if(window.confirm(`Remove the active license token from this extension?
2
+
3
+ Your subscription stays active server-side — you can paste the same token back in any time. The extension will fall back to trial / free until then.`)){a&&await We(a),await chrome.storage.local.remove("licenseToken"),r(null),d(null);try{const k=await T({type:"TIER_GET"});s(k.tier)}catch{s("free")}R.polite("License token removed.")}}const w=ze[t],F=a!==null&&(n==null?void 0:n.valid)===!0;return e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-xs text-slate-500",children:"Current tier"}),e.jsx("span",{className:"text-xs px-2 py-0.5 rounded-full bg-slate-100 text-slate-700",children:Ot[t]})]}),e.jsxs("ul",{className:"text-xs text-slate-600 space-y-1",children:[e.jsxs("li",{children:["Components:"," ",Number.isFinite(w.maxComponents)?w.maxComponents:"unlimited"]}),e.jsxs("li",{children:["Baselines:"," ",Number.isFinite(w.maxBaselines)?w.maxBaselines:"unlimited"]}),e.jsxs("li",{children:["State matrix: ",w.stateMatrix]}),e.jsxs("li",{children:["Storybook auto-iterate: ",w.storybookAutoIterate?"yes":"no"]}),e.jsxs("li",{children:["JSON export: ",w.exportJson?"yes":"no"]}),e.jsxs("li",{children:["SARIF / JUnit export: ",w.exportSarif?"yes":"no"]})]}),F&&n?e.jsx(Ht,{token:a,info:n,copied:v,onCopy:S,onRemove:I,onUseDifferent:()=>l(!0),onManageSubscription:async()=>{const y=await Ft({licenseToken:a});y.ok?window.open(y.url,"_blank","noopener,noreferrer"):(g(`Couldn't open billing portal: ${y.error}`),R.assertive("Could not open billing portal."))},onResumeSubscription:async()=>{const y=await Ut({licenseToken:a});if(y.ok){const k=y.alreadyActive?"Subscription was already active — no change needed.":"Subscription resumed. Cancellation has been reversed.";g(k),R.polite(k),await b({forceRefresh:!0})}else g(`Couldn't resume subscription: ${y.error}`),R.assertive("Could not resume subscription.")},onRenew:()=>x(!0),message:f}):a?e.jsx(Vt,{token:a,onRemove:I,onUseDifferent:()=>l(!0)}):e.jsx(re,{token:u,onTokenChange:i,submitting:m,message:f,onSubmit:N}),F&&c&&e.jsx(re,{token:u,onTokenChange:i,submitting:m,message:f,onSubmit:N,replacing:!0,onCancel:()=>{l(!1),i(""),g(null)}}),!F&&(t==="trial"||t==="free")&&e.jsxs("div",{className:"border-t border-slate-100 pt-3 space-y-2",children:[e.jsxs("p",{className:"text-xs text-slate-600",children:[e.jsx("strong",{children:"Solo"}),": $",_.solo.monthlyUsd,"/mo (recurring) ·"," ","$",_.solo.yearlyUsd,"/yr (save ",Math.round(100-_.solo.yearlyUsd/(_.solo.monthlyUsd*12)*100),"%) ·"," ","$",_.solo.singleMonthUsd," single month (no recurring) · single user."]}),e.jsxs("p",{className:"text-xs text-slate-600",children:[e.jsx("strong",{children:"Team"}),": $",_.team.fiveSeatMonthlyUsd,"/mo for 5 seats ·"," ","$",_.team.fifteenSeatMonthlyUsd,"/mo for 15 seats."]}),e.jsx("button",{type:"button",onClick:()=>x(!0),className:"inline-block text-xs px-3 py-1 bg-brand-500 text-white rounded hover:bg-brand-600",children:"Upgrade →"})]}),e.jsx(Ke,{open:p,onClose:()=>x(!1)})]})}function Ht({token:t,info:s,copied:a,onCopy:r,onRemove:n,onUseDifferent:d,onManageSubscription:c,onResumeSubscription:l,onRenew:u,message:i}){const m=s.features,h=typeof(m==null?void 0:m.seatsUsed)=="number"?m.seatsUsed:null,f=typeof(m==null?void 0:m.seatsTotal)=="number"?m.seatsTotal:null,g=f!==null,v=h!==null&&f!==null&&h>f,j=h!==null&&f!==null&&h===f,p=s.plan?Gt.has(s.plan):!1,x=Bt(s.expiresAt),b=p&&x!==null&&x<=7;return e.jsxs("div",{className:"border-t border-slate-100 pt-3 space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"text-xs font-medium text-slate-700",children:"Active license"}),e.jsx("span",{className:s.cancelAtPeriodEnd?"text-[10px] px-1.5 py-0.5 rounded-full bg-amber-100 text-amber-900":"text-[10px] px-1.5 py-0.5 rounded-full bg-emerald-100 text-emerald-800",children:s.cancelAtPeriodEnd?"cancellation scheduled":s.status??"unknown"})]}),s.pastDueSince&&e.jsxs("div",{className:"bg-rose-50 border border-rose-200 rounded p-2 text-[11px] text-rose-900",children:[e.jsx("strong",{children:"Payment failed."})," Stripe couldn't charge your card. Access continues during the grace period (usually up to 7 days while Stripe retries), then this license will cancel automatically."," ",e.jsx("button",{type:"button",onClick:c,className:"font-medium underline-offset-2 hover:underline",children:"Update your card via the Stripe portal →"})]}),s.cancelAtPeriodEnd&&e.jsxs("div",{className:"bg-amber-50 border border-amber-200 rounded p-2 text-[11px] text-amber-900 space-y-1",children:[e.jsxs("p",{children:[e.jsx("strong",{children:"Cancellation scheduled."})," Your subscription was cancelled via Stripe. Access continues until ",e.jsx("strong",{children:J(s.expiresAt)}),", then this license stops working."]}),e.jsx("button",{type:"button",onClick:l,className:"text-[11px] font-medium underline-offset-2 hover:underline",children:"Resume subscription →"})]}),v&&e.jsxs("div",{className:"bg-rose-50 border border-rose-200 rounded p-2 text-[11px] text-rose-900",children:[e.jsx("strong",{children:"Over seat capacity."})," This license has"," ",e.jsx("strong",{children:h})," seats in use but the plan only includes"," ",e.jsx("strong",{children:f}),". New devices will be rejected. Release a seat from another device, or upgrade to a higher-seat plan via Manage subscription below."]}),j&&!v&&e.jsxs("div",{className:"bg-amber-50 border border-amber-200 rounded p-2 text-[11px] text-amber-900",children:[e.jsx("strong",{children:"At seat capacity."})," All ",e.jsx("strong",{children:f})," seats are in use. The next new device that tries to activate this license will be rejected until a seat is released."]}),e.jsxs("dl",{className:"text-xs text-slate-600 grid grid-cols-[max-content_1fr] gap-x-3 gap-y-1",children:[e.jsx("dt",{className:"text-slate-500",children:"Plan"}),e.jsx("dd",{children:U(s.plan)}),e.jsx("dt",{className:"text-slate-500",children:"Email"}),e.jsx("dd",{className:"truncate",children:s.email??"—"}),e.jsx("dt",{className:"text-slate-500",children:p?"Expires":"Renews / ends"}),e.jsxs("dd",{children:[J(s.expiresAt),x!==null&&x>=0&&x<=14?e.jsx("span",{className:b?"ml-2 text-[10px] text-amber-900 bg-amber-100 rounded px-1.5 py-0.5":"ml-2 text-[10px] text-slate-500",children:x===0?"today":x===1?"1 day left":`${x} days left`}):null]}),s.trialEndsAt?e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-slate-500",children:"Trial ends"}),e.jsx("dd",{children:J(s.trialEndsAt)})]}):null,g?e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-slate-500",children:"Seats"}),e.jsx("dd",{children:h!==null?`${h} of ${f} used`:`${f} total`})]}):null]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-[11px] font-medium text-slate-500 mb-1",children:"Token"}),e.jsxs("div",{className:"flex items-stretch gap-1",children:[e.jsx("code",{className:"flex-1 font-mono text-[11px] bg-slate-100 border border-slate-200 rounded px-2 py-1.5 select-all break-all",children:t}),e.jsx("button",{type:"button",onClick:r,className:"text-[11px] px-2 py-1.5 border border-slate-300 rounded bg-white hover:bg-slate-50 shrink-0",children:a?"Copied ✓":"Copy"})]})]}),e.jsx("div",{className:"pt-1 flex flex-wrap gap-2",children:p?e.jsx("button",{type:"button",onClick:u,className:b?"text-xs px-3 py-1.5 bg-amber-500 text-white rounded hover:bg-amber-600":"text-xs px-3 py-1.5 bg-brand-500 text-white rounded hover:bg-brand-600",title:"Buy another month — extends your existing license, no new token to copy",children:b?`Renew now — $${_.solo.singleMonthUsd} →`:`Buy another month — $${_.solo.singleMonthUsd} →`}):e.jsx("button",{type:"button",onClick:c,className:"text-xs px-3 py-1.5 bg-brand-500 text-white rounded hover:bg-brand-600",title:"Open Stripe's billing portal — change plan or seat count, update card, view invoices, cancel",children:"Manage subscription →"})}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 pt-1",children:[e.jsx("button",{type:"button",onClick:d,className:"text-[11px] text-brand-600 hover:underline",children:"Use a different token"}),e.jsx("span",{className:"text-slate-300","aria-hidden":"true",children:"·"}),e.jsx("button",{type:"button",onClick:n,className:"text-[11px] text-rose-700 hover:underline",children:"Remove license from this extension"})]}),i&&e.jsx("p",{className:"text-xs text-slate-600 pt-1",children:i})]})}function Vt({token:t,onRemove:s,onUseDifferent:a}){return e.jsxs("div",{className:"border-t border-rose-100 pt-3 space-y-2 bg-rose-50/40 -mx-3 px-3 pb-2 rounded-b",children:[e.jsxs("p",{className:"text-xs text-rose-800",children:[e.jsx("strong",{children:"License token rejected by the server."})," The token may have been revoked, the subscription canceled, or the network is down. Verify your subscription and try a different token — or remove this one and continue on the trial / free tier."]}),e.jsx("p",{className:"text-[11px] text-rose-700 font-mono break-all",children:t}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",onClick:a,className:"text-[11px] text-brand-600 hover:underline",children:"Use a different token"}),e.jsx("span",{className:"text-slate-300","aria-hidden":"true",children:"·"}),e.jsx("button",{type:"button",onClick:s,className:"text-[11px] text-rose-700 hover:underline",children:"Remove and continue without a license"})]})]})}function re({token:t,onTokenChange:s,submitting:a,message:r,onSubmit:n,replacing:d,onCancel:c}){return e.jsxs("div",{className:"border-t border-slate-100 pt-3 space-y-2",children:[e.jsx("label",{htmlFor:"opt-license-token",className:"block text-xs font-medium",children:d?"Replace with a different token":"Activate license token"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{id:"opt-license-token",type:"text",value:t,onChange:l=>s(l.target.value),placeholder:"00000000-0000-0000-0000-000000000000",className:"flex-1 text-xs border border-slate-300 rounded px-2 py-1 font-mono"}),e.jsx("button",{onClick:n,disabled:a||!t.trim(),className:"text-xs px-3 py-1 bg-brand-500 text-white rounded disabled:opacity-50",children:a?"Validating…":d?"Replace":"Activate"}),d&&c&&e.jsx("button",{type:"button",onClick:c,className:"text-xs px-3 py-1 border border-slate-300 rounded text-slate-700 hover:bg-slate-50",children:"Cancel"})]}),r&&e.jsx("p",{className:"text-xs text-slate-600",children:r})]})}function Jt(t){return t==="solo"||t==="solo-yearly"||t==="solo-single-month"?"solo":t==="team"||t==="team-15"||t==="team-yearly"||t==="team-15-yearly"?"team":"free"}const Yt=new Set(qe.map(t=>t.id));function zt({presets:t,onChange:s}){const[a,r]=o.useState({id:"",label:"",width:1024,height:768,deviceScaleFactor:1,mobile:!1});function n(l){l.preventDefault();const u=a.id.trim();!u||t.some(i=>i.id===u)||(s([...t,{...a,id:u,label:a.label.trim()||`${u} (${a.width}×${a.height})`}]),r({id:"",label:"",width:1024,height:768,deviceScaleFactor:1,mobile:!1}))}function d(l){s(t.filter(u=>u.id!==l))}function c(l,u){s(t.map(i=>i.id===l?{...i,...u}:i))}return e.jsxs("div",{className:"space-y-3 border border-slate-200 rounded p-3 bg-white",children:[t.length===0?e.jsx("p",{className:"text-xs text-slate-500 italic",children:"no breakpoints"}):e.jsx("ul",{className:"space-y-1.5",children:t.map(l=>{const u=Yt.has(l.id);return e.jsxs("li",{className:"grid grid-cols-[1fr_70px_70px_auto_auto] gap-2 items-center text-xs",children:[e.jsxs("span",{className:"font-medium truncate",title:l.id,children:[l.label,u&&e.jsx("span",{className:"text-slate-500 font-normal ml-1",children:"(default)"})]}),e.jsx("input",{type:"number",value:l.width,onChange:i=>c(l.id,{width:Number(i.target.value)||0}),className:"text-xs border border-slate-300 rounded px-1.5 py-1 w-full","aria-label":`Width for ${l.label}`,min:1}),e.jsx("input",{type:"number",value:l.height,onChange:i=>c(l.id,{height:Number(i.target.value)||0}),className:"text-xs border border-slate-300 rounded px-1.5 py-1 w-full","aria-label":`Height for ${l.label}`,min:1}),e.jsxs("label",{className:"flex items-center gap-1 text-slate-600",children:[e.jsx("input",{type:"checkbox",checked:l.mobile,onChange:i=>c(l.id,{mobile:i.target.checked})}),"mobile"]}),u?e.jsx("span",{className:"w-4","aria-hidden":"true"}):e.jsx("button",{onClick:()=>d(l.id),className:"text-slate-500 hover:text-red-600","aria-label":`Remove ${l.label}`,children:"×"})]},l.id)})}),e.jsxs("form",{onSubmit:n,className:"grid grid-cols-[1fr_1fr_70px_70px_auto] gap-2 items-end pt-3 border-t border-slate-100",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"bp-draft-id",className:"block text-xs text-slate-500 mb-1",children:"ID"}),e.jsx("input",{id:"bp-draft-id",type:"text",value:a.id,onChange:l=>r({...a,id:l.target.value}),placeholder:"laptop",className:"w-full text-xs border border-slate-300 rounded px-2 py-1"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"bp-draft-label",className:"block text-xs text-slate-500 mb-1",children:"Label"}),e.jsx("input",{id:"bp-draft-label",type:"text",value:a.label,onChange:l=>r({...a,label:l.target.value}),placeholder:"Laptop (1440×900)",className:"w-full text-xs border border-slate-300 rounded px-2 py-1"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"bp-draft-width",className:"block text-xs text-slate-500 mb-1",children:"W"}),e.jsx("input",{id:"bp-draft-width",type:"number",value:a.width,onChange:l=>r({...a,width:Number(l.target.value)||0}),min:1,className:"w-full text-xs border border-slate-300 rounded px-1.5 py-1"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"bp-draft-height",className:"block text-xs text-slate-500 mb-1",children:"H"}),e.jsx("input",{id:"bp-draft-height",type:"number",value:a.height,onChange:l=>r({...a,height:Number(l.target.value)||0}),min:1,className:"w-full text-xs border border-slate-300 rounded px-1.5 py-1"})]}),e.jsx("button",{type:"submit",disabled:!a.id.trim()||t.some(l=>l.id===a.id.trim()),className:"text-xs px-3 py-1 bg-brand-500 text-white rounded disabled:opacity-50",children:"Add"})]})]})}function Wt({stateMatrix:t,componentIdAliases:s,onImport:a}){const r=o.useRef(null),[n,d]=o.useState(null);function c(){const u={schemaVersion:1,exportedAt:new Date().toISOString(),stateMatrix:t,componentIdAliases:s},i=new Blob([JSON.stringify(u,null,2)],{type:"application/json"}),m=URL.createObjectURL(i),h=document.createElement("a");h.href=m,h.download=`wcag-auditor-settings-${new Date().toISOString().slice(0,10)}.json`,h.click(),URL.revokeObjectURL(m),d("Exported.")}async function l(u){var i,m;d(null);try{const h=await u.text(),f=JSON.parse(h);if(f.schemaVersion!==1)throw new Error(`Unsupported schemaVersion: ${f.schemaVersion}`);if(!((i=f.stateMatrix)!=null&&i.pseudoStates)||!((m=f.stateMatrix)!=null&&m.breakpointPresets))throw new Error("stateMatrix is malformed");await E({type:"SETTINGS_SET",key:"stateMatrix",value:f.stateMatrix}),await E({type:"SETTINGS_SET",key:"componentIdAliases",value:f.componentIdAliases??{}}),a({stateMatrix:f.stateMatrix,componentIdAliases:f.componentIdAliases??{}}),d("Imported.")}catch(h){d(`Import failed: ${h instanceof Error?h.message:String(h)}`)}}return e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:c,className:"text-xs px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded",children:"Export settings"}),e.jsx("button",{onClick:()=>{var u;return(u=r.current)==null?void 0:u.click()},className:"text-xs px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded",children:"Import settings…"}),e.jsx("input",{ref:r,type:"file",accept:"application/json,.json",className:"hidden",onChange:u=>{var m;const i=(m=u.target.files)==null?void 0:m[0];i&&l(i),u.target.value=""}})]}),n&&e.jsx("p",{className:"text-xs text-slate-600",children:n})]})}function qt(){const[t,s]=o.useState(null);o.useEffect(()=>{chrome.storage.local.get(Z).then(r=>s(r[Z]===!0))},[]);async function a(){const r=!t;s(r),await Ye(r)}return t===null?e.jsx("p",{className:"text-xs text-slate-500",children:"Loading…"}):e.jsx("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:e.jsxs("label",{className:"flex items-start gap-2 text-xs cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:a,className:"mt-0.5"}),e.jsxs("span",{children:[e.jsx("span",{className:"font-medium",children:"Send anonymized crash reports"}),e.jsx("span",{className:"block text-slate-500 mt-0.5",children:"When the extension hits an unexpected error, send the error message + redacted stack trace + extension version. URLs, emails, and license tokens are stripped before sending. No audit data, page content, or browsing history is included."})]})]})})}function Qt(){const[t,s]=o.useState(null);o.useEffect(()=>{chrome.storage.local.get(K).then(r=>s(r[K]===!0))},[]);async function a(){const r=!t;s(r),await chrome.storage.local.set({[K]:r})}return t===null?e.jsx("p",{className:"text-xs text-slate-500",children:"Loading…"}):e.jsx("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:e.jsxs("label",{className:"flex items-start gap-2 text-xs cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:a,className:"mt-0.5"}),e.jsxs("span",{children:[e.jsx("span",{className:"font-medium",children:"Skip the download confirmation"}),e.jsx("span",{className:"block text-slate-500 mt-0.5",children:"By default, generating a defense or evidence bundle pops up a small confirmation asking whether to download or preview. Enable this to skip the prompt and have the file land directly in your Downloads folder. Keep it off if you'd rather decide each time (recommended for non-technical users — surprise downloads can be alarming)."})]})]})})}const Xt={"deposition-packet":{name:"Deposition packet",description:"Court-grade HTML with VPS-anchored RFC 3161 timestamp. Use for active litigation / regulatory submission."},"defense-bundle":{name:"Defense bundle",description:"Locally anchored attorney-ready HTML. The everyday remediation-trail artifact — exec summary, findings, screenshots, VPAT, methodology. Recommended baseline."},"html-print":{name:"Printable HTML",description:"Simple print-ready HTML for sharing with stakeholders. No anchoring, no legal framing — just the findings."},"ai-prompt":{name:"AI fix prompt (markdown)",description:"Markdown prompt for Claude / Cursor / Copilot Chat. Includes fix recipes per violation + acknowledged-findings context. Use for dev handoff after each audit."}};function Zt(){const[t,s]=o.useState(null);if(o.useEffect(()=>{let n=!1;return(async()=>{const d=await Qe();n||s(d)})(),()=>{n=!0}},[]),!t)return e.jsx("p",{className:"text-xs text-slate-500",children:"Loading…"});async function a(){const n={...t,enabled:!t.enabled};s(n),await ee(n)}async function r(n){const d=t.formats.includes(n);let c;d?(c=t.formats.filter(u=>u!==n),c.length===0&&t.enabled&&(c=t.formats)):c=[...t.formats,n];const l={...t,formats:c};s(l),await ee(l)}return e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-3",children:[e.jsxs("label",{className:"flex items-start gap-2 text-xs cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:t.enabled,onChange:()=>void a(),className:"mt-0.5"}),e.jsxs("span",{children:[e.jsx("span",{className:"font-medium",children:"Auto-export every audit"}),e.jsxs("span",{className:"block text-slate-500 mt-0.5",children:["Each completed audit silently downloads the formats checked below. Same setting applies to both manual and scheduled audits. Scheduled audits land in ",e.jsx("span",{className:"font-mono",children:"Downloads/wcagcheckr/{domain}/"}),"; scheduled audits only fire while Chrome is running."]})]})]}),t.enabled&&e.jsxs("fieldset",{className:"pl-6 space-y-2",children:[e.jsx("legend",{className:"text-xs font-medium text-slate-700",children:"Formats to export"}),Xe.map(n=>{const d=t.formats.includes(n),c=Xt[n];return e.jsxs("label",{className:"flex items-start gap-2 text-xs cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:d,onChange:()=>void r(n),className:"mt-0.5"}),e.jsxs("span",{className:"leading-snug",children:[e.jsx("span",{className:"font-medium",children:c.name}),e.jsx("span",{className:"block text-slate-500 mt-0.5",children:c.description})]})]},n)})]})]})}function es(){const[t,s]=o.useState(null),[a,r]=o.useState(!1);async function n(){const c=await chrome.storage.local.get(null),l=Object.keys(c).filter(u=>u.startsWith("auditCache:"));s(l.length)}o.useEffect(()=>{n()},[]);async function d(){r(!0);try{await Ze(),await n()}finally{r(!1)}}return e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:[e.jsxs("div",{className:"text-xs",children:[e.jsx("span",{className:"font-medium",children:"Audit cache"}),e.jsx("span",{className:"block text-slate-500 mt-0.5",children:"Repeat audits of the same component skip the state-matrix iteration when the DOM is unchanged from the last audit (10-50× faster). The fingerprint is DOM-only — if you change ONLY CSS, the cache won't notice and will return stale results. Clear it here when that happens."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:d,disabled:a||(t??0)===0,className:"text-xs px-3 py-1 bg-slate-100 hover:bg-slate-200 disabled:opacity-50 disabled:cursor-not-allowed border border-slate-300 rounded",children:a?"Clearing…":"Clear audit cache"}),e.jsx("span",{className:"text-xs text-slate-500",children:t===null?"Loading…":t===0?"Cache is empty.":`${t} cached audit${t===1?"":"s"}.`})]})]})}const le="licenseToken";function oe(t){const s=Date.now()-new Date(t).getTime(),a=Math.floor(s/6e4);if(a<1)return"just now";if(a<60)return`${a} min ago`;const r=Math.floor(a/60);if(r<24)return`${r}h ago`;const n=Math.floor(r/24);return n<30?`${n}d ago`:new Date(t).toLocaleDateString()}function ts(t){return t.slice(0,8)+"…"}function ss(t){return t?/Edg\//.test(t)?"Edge":/Chrome\//.test(t)?"Chrome":/Firefox\//.test(t)?"Firefox":/Safari\//.test(t)?"Safari":t.slice(0,30):"unknown"}function as(){const[t,s]=o.useState(null),[a,r]=o.useState(null),[n,d]=o.useState(null),[c,l]=o.useState(0),[u,i]=o.useState(null),[m,h]=o.useState(!1),[f,g]=o.useState(null),v=o.useCallback(async()=>{h(!0),g(null);try{const x=(await chrome.storage.local.get(le))[le]??null;if(s(x),!x){r(null);return}const b=await et(x);if(!b){g("Could not load seats — check network or license validity.");return}r(b.seats),d(b.seatsTotal),l(b.seatsUsed),i(await tt())}finally{h(!1)}},[]);o.useEffect(()=>{v()},[v]);async function j(p){if(!t)return;const b=p===u?"Revoke THIS device? You will have to re-claim a seat on the next audit (if a seat is available).":"Revoke this seat? The device will be denied audits until it re-claims a seat (subject to the seat cap).";if(window.confirm(b)){h(!0);try{if(!await st(t,p)){g("Revoke failed — try again or check network.");return}await v()}finally{h(!1)}}}return t?n===null?e.jsx("div",{className:"text-xs text-slate-500",children:"This license has no seat cap (Solo / single-month / free / trial). Upgrade to a Team plan to see and manage seats here."}):e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"text-xs",children:[e.jsx("span",{className:"font-medium",children:"Team seats"}),e.jsxs("span",{className:"text-slate-500 ml-2",children:[c," of ",n," used",c>n&&e.jsx("span",{className:"ml-2 text-amber-700",children:"(over capacity — release to bring under limit)"})]})]}),e.jsx("button",{onClick:v,disabled:m,className:"text-xs px-2 py-0.5 border border-slate-300 rounded hover:bg-slate-50 disabled:opacity-50",children:m?"Loading…":"Refresh"})]}),f&&e.jsx("p",{className:"text-xs text-red-700",children:f}),a&&a.length>0?e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-slate-500",children:[e.jsx("th",{className:"font-normal py-1",children:"Device"}),e.jsx("th",{className:"font-normal py-1",children:"Browser"}),e.jsx("th",{className:"font-normal py-1",children:"Claimed"}),e.jsx("th",{className:"font-normal py-1",children:"Last active"}),e.jsx("th",{className:"font-normal py-1"})]})}),e.jsx("tbody",{children:a.map(p=>e.jsxs("tr",{className:"border-t border-slate-100",children:[e.jsxs("td",{className:"py-1",children:[e.jsx("code",{className:"text-[10px] text-slate-600",children:ts(p.deviceId)}),p.deviceId===u&&e.jsx("span",{className:"ml-1 text-[10px] text-brand-700",children:"(this device)"})]}),e.jsx("td",{className:"py-1 text-slate-700",children:ss(p.userAgent)}),e.jsx("td",{className:"py-1 text-slate-500",children:oe(p.claimedAt)}),e.jsx("td",{className:"py-1 text-slate-500",children:oe(p.lastSeenAt)}),e.jsx("td",{className:"py-1 text-right",children:e.jsx("button",{onClick:()=>j(p.deviceId),disabled:m,className:"text-[11px] px-2 py-0.5 border border-slate-300 rounded hover:bg-red-50 hover:text-red-800 hover:border-red-300 disabled:opacity-50",children:"Revoke"})})]},p.deviceId))})]}):e.jsx("p",{className:"text-xs text-slate-500",children:"No seats claimed yet."})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Activate a Team license to manage seats here."})}const ns=[{id:"use-our-button",description:"Use the design-system Button, not raw <button>.",impact:"moderate",selector:"button:not([data-component='Button']):not([data-component^='ds-'])",check:{type:"fail-on-match",message:"Replace raw <button> with the design-system Button component."},enabled:!0},{id:"no-inline-styles",description:"Inline style attribute escapes the design tokens.",impact:"minor",selector:"[style]",check:{type:"fail-on-match",message:"Move this style into a design-token-aware CSS class."},enabled:!0},{id:"cta-needs-testid",description:"Every call-to-action button must have data-testid for E2E.",impact:"serious",selector:'button.cta, [data-component="Button"][data-variant="primary"]',check:{type:"attribute-required",attribute:"data-testid",message:"Add a data-testid attribute so QA can target this element."},enabled:!1}];function rs(){const[t,s]=o.useState(""),[a,r]=o.useState([]),[n,d]=o.useState(!1),[c,l]=o.useState(null);o.useEffect(()=>{rt().then(m=>{s(m.length>0?JSON.stringify(m,null,2):""),d(!0)})},[]);function u(){if(t.trim().length===0){se([]),r([]),l(Date.now());return}let m;try{m=JSON.parse(t)}catch(g){r([`Invalid JSON: ${g instanceof Error?g.message:String(g)}`]);return}const{valid:h,errors:f}=lt(m);if(f.length>0){r(f);return}r([]),se(h),l(Date.now()),s(JSON.stringify(h,null,2))}function i(){s(JSON.stringify(ns,null,2)),r([])}return n?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("p",{className:"text-xs text-slate-500",children:["Custom rules check your design-system contracts during every audit. Three check types supported:"," ",e.jsx("code",{className:"bg-slate-100 px-1 rounded",children:"fail-on-match"})," (every element matching the selector is a violation),"," ",e.jsx("code",{className:"bg-slate-100 px-1 rounded",children:"attribute-required"})," ","(the named attribute must be present), and"," ",e.jsx("code",{className:"bg-slate-100 px-1 rounded",children:"attribute-equals"})," ","(attribute must equal a specific value). Output appears in audit results alongside built-in WCAG rules."]}),e.jsx("textarea",{value:t,onChange:m=>s(m.target.value),rows:14,spellCheck:!1,placeholder:"[]",className:"w-full text-xs font-mono border border-slate-300 rounded p-2 resize-y"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:u,className:"text-xs px-3 py-1 bg-brand-500 text-white rounded hover:bg-brand-600",children:"Save"}),e.jsx("button",{onClick:i,className:"text-xs px-3 py-1 border border-slate-300 rounded hover:bg-slate-50",children:"Load example rules"}),c&&a.length===0&&e.jsxs("span",{className:"text-[11px] text-slate-500",children:["Saved at ",new Date(c).toLocaleTimeString(),"."]})]}),a.length>0&&e.jsx("div",{className:"border border-red-200 bg-red-50 rounded p-2 text-xs text-red-800 space-y-1",children:a.map((m,h)=>e.jsx("div",{children:m},h))})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const ls="com.wcagcheckr.native_host",os=5e3;async function is(){return new Promise(t=>{let s=null;const a=Date.now(),r=setTimeout(()=>{try{s==null||s.disconnect()}catch{}t({reachable:!1,reason:"timeout after 5s"})},os);try{s=chrome.runtime.connectNative(ls)}catch(n){clearTimeout(r),t({reachable:!1,reason:`connectNative failed: ${n instanceof Error?n.message:String(n)}`});return}s.onMessage.addListener(n=>{clearTimeout(r),(n==null?void 0:n.type)==="PONG"&&typeof n.version=="string"?t({reachable:!0,version:n.version,roundTripMs:Date.now()-a}):t({reachable:!1,reason:`unexpected response: ${JSON.stringify(n).slice(0,100)}`});try{s==null||s.disconnect()}catch{}}),s.onDisconnect.addListener(()=>{var d;clearTimeout(r);const n=(d=chrome.runtime.lastError)==null?void 0:d.message;t({reachable:!1,reason:n??"host disconnected before PONG (not installed?)"})});try{s.postMessage({type:"PING"})}catch(n){clearTimeout(r),t({reachable:!1,reason:`postMessage failed: ${n instanceof Error?n.message:String(n)}`})}})}function cs(){const[t,s]=o.useState(null),[a,r]=o.useState(!1);async function n(){r(!0);try{s(await is())}finally{r(!1)}}return e.jsxs("div",{className:"border border-slate-200 rounded p-3 bg-white space-y-2",children:[e.jsxs("div",{className:"text-xs",children:[e.jsx("span",{className:"font-medium",children:"Native messaging host (optional)"}),e.jsxs("span",{className:"block text-slate-500 mt-0.5",children:["Alternative state-driver for environments where"," ",e.jsx("code",{className:"bg-slate-100 px-1 rounded",children:"chrome.debugger"})," is blocked by enterprise IT policy. Today's host responds to PING and reports its version; the full CDP attach replacement is on the roadmap. See ",e.jsx("code",{className:"bg-slate-100 px-1 rounded",children:"native-host/README.md"})," ","for installation instructions."]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:n,disabled:a,className:"text-xs px-3 py-1 bg-slate-100 hover:bg-slate-200 disabled:opacity-50 disabled:cursor-not-allowed border border-slate-300 rounded",children:a?"Testing…":"Test connection"}),t&&t.reachable&&e.jsxs("span",{className:"text-xs text-green-700",children:["Reachable — version ",t.version," (",t.roundTripMs,"ms)"]}),t&&!t.reachable&&e.jsxs("span",{className:"text-xs text-amber-700",children:["Not reachable: ",t.reason]})]})]})}const ie="disabledRules";function ds(){const[t,s]=o.useState(""),[a,r]=o.useState(!1),[n,d]=o.useState(null);o.useEffect(()=>{T({type:"SETTINGS_GET",key:ie}).then(l=>{const u=Array.isArray(l.data)?l.data:[];s(u.join(`
4
+ `)),r(!0)})},[]);function c(l){const u=l.split(`
5
+ `).map(i=>i.trim()).filter(i=>i.length>0);E({type:"SETTINGS_SET",key:ie,value:u}),d(Date.now())}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("p",{className:"text-xs text-slate-500",children:["Rule IDs to skip during audits. One per line. Use exact axe-core rule IDs (e.g.,"," ",e.jsx("code",{className:"bg-slate-100 text-slate-700 px-1 rounded",children:"color-contrast"}),","," ",e.jsx("code",{className:"bg-slate-100 text-slate-700 px-1 rounded",children:"region"}),","," ",e.jsx("code",{className:"bg-slate-100 text-slate-700 px-1 rounded",children:"landmark-one-main"}),")."]}),e.jsx("textarea",{value:t,onChange:l=>s(l.target.value),onBlur:l=>c(l.target.value),rows:6,spellCheck:!1,placeholder:`region
6
+ landmark-one-main`,className:"w-full text-xs font-mono border border-slate-300 rounded p-2 resize-y"}),n&&e.jsxs("p",{className:"text-[11px] text-slate-500",children:["Saved at ",new Date(n).toLocaleTimeString(),"."]}),e.jsxs("p",{className:"text-[11px] text-slate-500",children:["Full rule list:"," ",e.jsx("a",{href:"https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md",target:"_blank",rel:"noreferrer",className:"text-brand-600 hover:underline",children:"axe-core/doc/rule-descriptions.md"})]})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const ce="githubRepoUrl",us=/^https:\/\/github\.com\/[^/]+\/[^/]+\/?$/;function xs(){const[t,s]=o.useState(""),[a,r]=o.useState(!1),[n,d]=o.useState(null);o.useEffect(()=>{T({type:"SETTINGS_GET",key:ce}).then(l=>{const u=typeof l.data=="string"?l.data:"";s(u),r(!0)})},[]);function c(l){const u=l.trim().replace(/\/$/,"");if(u.length>0&&!us.test(u+"/")){d("Expected format: https://github.com/owner/repo");return}d(null),E({type:"SETTINGS_SET",key:ce,value:u})}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-xs text-slate-500",children:'Paste your repository URL to enable "File GitHub issue" buttons in the Delta view. Issues are opened in a new tab with title and body pre-filled — you confirm and submit on GitHub.'}),e.jsx("input",{type:"url",value:t,onChange:l=>s(l.target.value),onBlur:l=>c(l.target.value),placeholder:"https://github.com/owner/repo",className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),n&&e.jsx("p",{className:"text-[11px] text-rose-600",children:n})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const de="jiraInstanceUrl",ms=/^https:\/\/[^/]+\.atlassian\.net\/?$/;function hs(){const[t,s]=o.useState(""),[a,r]=o.useState(!1),[n,d]=o.useState(null);o.useEffect(()=>{T({type:"SETTINGS_GET",key:de}).then(l=>{const u=typeof l.data=="string"?l.data:"";s(u),r(!0)})},[]);function c(l){const u=l.trim().replace(/\/$/,"");if(u.length>0&&!ms.test(u+"/")){d("Expected format: https://your-team.atlassian.net");return}d(null),E({type:"SETTINGS_SET",key:de,value:u})}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-xs text-slate-500",children:'Paste your Jira Cloud instance URL to enable "File Jira issue" in the Delta view. Issues open in a new tab pre-filled — you confirm and submit on Jira.'}),e.jsx("input",{type:"url",value:t,onChange:l=>s(l.target.value),onBlur:l=>c(l.target.value),placeholder:"https://your-team.atlassian.net",className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),n&&e.jsx("p",{className:"text-[11px] text-rose-600",children:n})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const ue="azureDevOpsProjectUrl",ps=/^https?:\/\/[^/]+\/[^/]+\/[^/]+\/?$/;function fs(){const[t,s]=o.useState(""),[a,r]=o.useState(!1),[n,d]=o.useState(null);o.useEffect(()=>{T({type:"SETTINGS_GET",key:ue}).then(l=>{const u=typeof l.data=="string"?l.data:"";s(u),r(!0)})},[]);function c(l){const u=l.trim().replace(/\/$/,"");if(u.length>0&&!ps.test(u+"/")){d("Expected format: https://dev.azure.com/org/project");return}d(null),E({type:"SETTINGS_SET",key:ue,value:u})}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-xs text-slate-500",children:'Paste your Azure DevOps project URL to enable "File Azure DevOps work item" buttons in the Delta view. The new-work-item form opens in a new tab with title and description pre-filled — you pick the work-item type and submit on Azure DevOps.'}),e.jsx("input",{type:"url",value:t,onChange:l=>s(l.target.value),onBlur:l=>c(l.target.value),placeholder:"https://dev.azure.com/myorg/myproject",className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),n&&e.jsx("p",{className:"text-[11px] text-rose-600",children:n})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const xe="gitlabProjectUrl",bs=/^https?:\/\/[^/]+\/[^/]+(\/[^/]+)+\/?$/;function gs(){const[t,s]=o.useState(""),[a,r]=o.useState(!1),[n,d]=o.useState(null);o.useEffect(()=>{T({type:"SETTINGS_GET",key:xe}).then(l=>{const u=typeof l.data=="string"?l.data:"";s(u),r(!0)})},[]);function c(l){const u=l.trim().replace(/\/$/,"");if(u.length>0&&!bs.test(u+"/")){d("Expected format: https://gitlab.com/group/project (or self-hosted)");return}d(null),E({type:"SETTINGS_SET",key:xe,value:u})}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-xs text-slate-500",children:'Paste your GitLab project URL to enable "File GitLab issue" buttons in the Delta view. Issues are opened in a new tab with title and description pre-filled — you confirm and submit on GitLab.'}),e.jsx("input",{type:"url",value:t,onChange:l=>s(l.target.value),onBlur:l=>c(l.target.value),placeholder:"https://gitlab.com/group/project",className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),n&&e.jsx("p",{className:"text-[11px] text-rose-600",children:n})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const me="cloudSyncEnabled",he="cloudSyncEndpoint",ys="https://api.wcagcheckr.com";function vs(){const[t,s]=o.useState(!1),[a,r]=o.useState(ys),[n,d]=o.useState(!1),[c,l]=o.useState(!1),[u,i]=o.useState(null);o.useEffect(()=>{Promise.all([T({type:"SETTINGS_GET",key:me}),T({type:"SETTINGS_GET",key:he})]).then(([g,v])=>{s(g.data===!0),typeof v.data=="string"&&v.data&&r(v.data),d(!0)})},[]);function m(g){s(g),E({type:"SETTINGS_SET",key:me,value:g})}function h(g){const v=g.trim().replace(/\/$/,"");r(v),E({type:"SETTINGS_SET",key:he,value:v})}async function f(){l(!0),i(null);try{const g="To pull baselines now, reload the extension at chrome://extensions. The service worker pulls on every start.";i(g),R.polite(g)}finally{l(!1)}}return n?e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-slate-500",children:"Sync baselines across devices via your license. Disabled by default — local-first storage means the extension works fully offline. Cloud is mirror, not source of truth on the local machine."}),e.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[e.jsx("input",{type:"checkbox",checked:t,onChange:g=>m(g.target.checked)}),e.jsx("span",{children:"Enable cloud sync"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-slate-500 block mb-1",children:"Sync endpoint"}),e.jsx("input",{type:"url",value:a,onChange:g=>r(g.target.value),onBlur:g=>h(g.target.value),disabled:!t,className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5 disabled:bg-slate-50 disabled:text-slate-500"}),e.jsx("p",{className:"text-[11px] text-slate-500 mt-1",children:"Default points at the WCAG Auditor cloud-sync VPS. Replace with your own server URL if you self-host the baseline endpoints."})]}),e.jsx("button",{type:"button",onClick:f,disabled:!t||c,className:"text-xs px-3 py-1 border border-slate-300 rounded hover:bg-slate-50 disabled:opacity-50",children:c?"Pulling…":"Pull now"}),u&&e.jsx("p",{className:"text-[11px] text-slate-500",children:u})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}const pe="runsPerState";function js(){const[t,s]=o.useState(1),[a,r]=o.useState(!1);o.useEffect(()=>{T({type:"SETTINGS_GET",key:pe}).then(d=>{const c=typeof d.data=="number"?d.data:1;s(c),r(!0)})},[]);function n(d){s(d),E({type:"SETTINGS_SET",key:pe,value:d})}return a?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("p",{className:"text-xs text-slate-500",children:["Real-world pages are non-deterministic — animations, third-party scripts, lazy-loaded content can produce different violation counts on identical re-runs. Higher run counts let the auditor classify violations as ",e.jsx("strong",{children:"stable"})," (seen in every run) vs"," ",e.jsx("strong",{children:"flaky"})," (only some runs). Tradeoff: each step costs an extra audit pass."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("label",{htmlFor:"reliability-runs-per-state",className:"text-xs text-slate-700",children:"Audit runs per state:"}),e.jsxs("select",{id:"reliability-runs-per-state",value:t,onChange:d=>n(Number(d.target.value)),className:"text-xs border border-slate-300 rounded px-2 py-1",children:[e.jsx("option",{value:1,children:"1 (fastest)"}),e.jsx("option",{value:2,children:"2 (balanced)"}),e.jsx("option",{value:3,children:"3 (most reliable)"})]})]})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}function Ns(){const[t,s]=o.useState("owner"),[a,r]=o.useState(!1);o.useEffect(()=>{T({type:"SETTINGS_GET",key:"userMode"}).then(d=>{const c=d.data;(c==="owner"||c==="dev")&&s(c),r(!0)})},[]);function n(d){s(d),E({type:"SETTINGS_SET",key:"userMode",value:d})}return a?e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-slate-500",children:"Switches the side panel between two surfaces. Owner mode is simpler and avoids jargon; developer mode shows the full feature set (visualizers, baselines, exports, AI fixit prompt)."}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(fe,{active:t==="owner",icon:"🏪",label:"Site owner",desc:"Plain-language results, whole-site scan, send-to-developer report.",onClick:()=>n("owner")}),e.jsx(fe,{active:t==="dev",icon:"⚙️",label:"Developer / agency",desc:"Full feature surface — visualizers, exports, baselines, IGT, AI fixit prompt.",onClick:()=>n("dev")})]})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}function fe({active:t,icon:s,label:a,desc:r,onClick:n}){return e.jsx("button",{type:"button",onClick:n,className:`text-left rounded p-3 border transition-colors ${t?"border-brand-500 bg-brand-50 ring-2 ring-brand-500/30":"border-slate-300 bg-white hover:border-slate-400 hover:bg-slate-50"}`,children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx("span",{className:"text-lg","aria-hidden":"true",children:s}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-xs",children:a}),e.jsx("div",{className:"text-[11px] text-slate-500 leading-snug mt-0.5",children:r})]})]})})}const Y="aiConfig";function Ss(){const[t,s]=o.useState(H),[a,r]=o.useState(!1),[n,d]=o.useState(!1),[c,l]=o.useState(null),[u,i]=o.useState(null),[m,h]=o.useState(!1);async function f(){l(await at(10))}o.useEffect(()=>{f()},[]);async function g(){h(!0),i(null);try{if(!t.apiKey){i({ok:!1,message:"No API key entered yet."});return}const x=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"x-api-key":t.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json","anthropic-dangerous-direct-browser-access":"true"},body:JSON.stringify({model:t.model||"claude-haiku-4-5",max_tokens:5,messages:[{role:"user",content:"ok"}]})}),b=await x.json().catch(()=>null);if(!b){i({ok:!1,message:`Provider returned no JSON (HTTP ${x.status}).`});return}if("error"in b){i({ok:!1,message:`${b.error.type}: ${b.error.message}`});return}i({ok:!0,message:`Authenticated, account funded. Test call used ${b.usage.input_tokens}+${b.usage.output_tokens} tokens (~$0.0001).`})}catch(x){i({ok:!1,message:x instanceof Error?x.message:String(x)})}finally{h(!1)}}async function v(){typeof confirm=="function"&&!confirm("Clear the local AI usage log? Provider-side billing records are unaffected.")||(await nt(),await f())}o.useEffect(()=>{T({type:"SETTINGS_GET",key:Y}).then(x=>{const b=x.data;b&&s({...H,...b,enabledChecks:{...H.enabledChecks,...b.enabledChecks??{}}}),r(!0)})},[]);function j(x){const b={...t,...x};s(b),E({type:"SETTINGS_SET",key:Y,value:b})}function p(x){const b={...t,enabledChecks:{...t.enabledChecks,...x}};s(b),E({type:"SETTINGS_SET",key:Y,value:b})}return a?e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-slate-600 leading-snug",children:"Adds vision-verified alt-text checking, heading-quality judgment, sensory-language detection, and ARIA semantic verification to every audit. Each check uses a small AI call against your configured provider; per-audit cost is hard-capped to prevent surprise bills."}),e.jsxs("label",{className:"flex items-center gap-2 text-xs",children:[e.jsx("input",{type:"checkbox",checked:t.enabled,onChange:x=>j({enabled:x.target.checked})}),e.jsx("span",{children:e.jsx("strong",{children:"Enable AI augmentation"})})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"ai-provider",className:"block text-xs text-slate-500 mb-1",children:"Provider"}),e.jsxs("select",{id:"ai-provider",value:t.provider,onChange:x=>j({provider:x.target.value}),disabled:!t.enabled,className:"text-xs border border-slate-300 rounded px-2 py-1.5",children:[e.jsx("option",{value:"anthropic",children:"Anthropic (Claude)"}),e.jsx("option",{value:"openai",children:"OpenAI (GPT) — coming soon"}),e.jsx("option",{value:"gemini",children:"Google (Gemini) — coming soon"})]})]}),e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"ai-key",className:"block text-xs text-slate-500 mb-1",children:["API key",e.jsx("span",{className:"text-[10px] text-slate-400 ml-2",children:"stored locally; never sent anywhere except your chosen provider"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{id:"ai-key",type:n?"text":"password",value:t.apiKey,onChange:x=>j({apiKey:x.target.value.trim()}),disabled:!t.enabled,placeholder:"sk-ant-…",className:"flex-1 text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),e.jsx("button",{type:"button",onClick:()=>d(!n),className:"text-[11px] px-2 border border-slate-300 rounded hover:bg-slate-50",children:n?"Hide":"Show"})]})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"ai-model",className:"block text-xs text-slate-500 mb-1",children:"Model override (optional)"}),e.jsx("input",{id:"ai-model",type:"text",value:t.model??"",onChange:x=>j({model:x.target.value.trim()}),disabled:!t.enabled,placeholder:"claude-3-5-sonnet-20241022 (default)",className:"w-full text-xs font-mono border border-slate-300 rounded px-2 py-1.5"}),e.jsx("p",{className:"text-[10px] text-slate-500 mt-1",children:"Leave blank for provider default. Use a haiku-class model for cheap-fast checks."})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"ai-cap",className:"block text-xs text-slate-500 mb-1",children:"Per-audit cost cap (USD)"}),e.jsx("input",{id:"ai-cap",type:"number",step:.5,min:0,value:t.costCapUsd,onChange:x=>j({costCapUsd:Math.max(0,parseFloat(x.target.value)||0)}),disabled:!t.enabled,className:"w-32 text-xs border border-slate-300 rounded px-2 py-1.5"}),e.jsx("p",{className:"text-[10px] text-slate-500 mt-1",children:"Hard ceiling — once exceeded, remaining AI checks for the audit are skipped."})]}),e.jsxs("fieldset",{className:"border border-slate-200 rounded p-3",children:[e.jsx("legend",{className:"text-xs font-medium px-1",children:"Checks to run"}),e.jsxs("div",{className:"space-y-1.5 text-xs",children:[e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.altText,onChange:x=>p({altText:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Alt text"})," — verify every image's alt accurately describes it (vision call, ~$0.005 each)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.headings,onChange:x=>p({headings:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Headings"})," — judge whether headings describe their sections (text-only, cheap)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.sensory,onChange:x=>p({sensory:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Sensory language"}),' — flag instructions like "click the round button" (text-only, cheap)']})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.aria,onChange:x=>p({aria:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"ARIA semantics"})," — verify role= attributes match element behavior (more expensive; opt-in)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.imageOfText,onChange:x=>p({imageOfText:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Images of text"})," (WCAG 1.4.5) — flag banner / share-card / infographic images that bake text into the raster (vision; capped to ",t.imageOfTextMaxImages," largest images / audit)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.colorOnlyMeaning,onChange:x=>p({colorOnlyMeaning:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Color-only meaning"})," (WCAG 1.4.1) — flag status indicators / icons / instructions where only color conveys meaning (vision call)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.genericLinkText,onChange:x=>p({genericLinkText:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Generic link text"}),` (WCAG 2.4.4) — flag "click here"-style links where surrounding context doesn't clarify the destination (text-only, cheap)`]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.wallOfText,onChange:x=>p({wallOfText:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Wall of text"})," (WCAG 3.1.5) — flag long-form content with no subheadings, lists, or paragraph breaks (text-only, cheap)"]})]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"checkbox",checked:t.enabledChecks.languageMismatch,onChange:x=>p({languageMismatch:x.target.checked}),disabled:!t.enabled}),e.jsxs("span",{children:[e.jsx("strong",{children:"Language mismatch"})," (WCAG 3.1.1 / 3.1.2) — flag content that doesn't match the declared ",e.jsx("code",{children:"lang"})," attribute (text-only, cheap)"]})]})]})]}),e.jsxs("fieldset",{className:"border border-slate-200 rounded p-3",children:[e.jsx("legend",{className:"text-xs font-medium px-1",children:"Connection test"}),e.jsx("p",{className:"text-[11px] text-slate-500 mb-2",children:"Fires a 5-token call to your provider to confirm the key authenticates and the account is funded. Costs ≈ $0.0001."}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>void g(),disabled:!t.apiKey||m,className:"text-xs px-3 py-1 border border-slate-300 rounded hover:bg-slate-50 disabled:opacity-50",children:m?"Testing…":"Test connection"}),u&&e.jsxs("span",{className:`text-[11px] ${u.ok?"text-emerald-700":"text-rose-700"}`,children:[u.ok?"✓ ":"✗ ",u.message]})]})]}),e.jsxs("fieldset",{className:"border border-slate-200 rounded p-3",children:[e.jsx("legend",{className:"text-xs font-medium px-1",children:"Local usage"}),e.jsxs("p",{className:"text-[11px] text-slate-500 mb-2",children:["Tracked locally per audit. Providers don't expose live balance via API, so check"," ",e.jsx("a",{href:"https://console.anthropic.com/settings/billing",target:"_blank",rel:"noopener noreferrer",className:"text-brand-700 underline",children:"console.anthropic.com → Plans & Billing"})," ","for your real balance."]}),c&&c.totalAudits===0&&e.jsx("p",{className:"text-[11px] text-slate-500 italic",children:"No AI-augmented audits recorded yet."}),c&&c.totalAudits>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"grid grid-cols-3 gap-2 text-xs",children:[e.jsxs("div",{className:"border border-slate-200 rounded p-2",children:[e.jsx("div",{className:"text-[10px] uppercase tracking-wide text-slate-500",children:"All-time spent"}),e.jsxs("div",{className:"font-semibold text-slate-800",children:["$",c.totalSpentUsd.toFixed(4)]}),e.jsxs("div",{className:"text-[10px] text-slate-500",children:[c.totalAudits," audit",c.totalAudits===1?"":"s"]})]}),e.jsxs("div",{className:"border border-slate-200 rounded p-2",children:[e.jsx("div",{className:"text-[10px] uppercase tracking-wide text-slate-500",children:"This month"}),e.jsxs("div",{className:"font-semibold text-slate-800",children:["$",c.spentThisMonthUsd.toFixed(4)]}),e.jsxs("div",{className:"text-[10px] text-slate-500",children:[c.auditsThisMonth," audit",c.auditsThisMonth===1?"":"s"]})]}),e.jsxs("div",{className:"border border-slate-200 rounded p-2",children:[e.jsx("div",{className:"text-[10px] uppercase tracking-wide text-slate-500",children:"Avg / audit"}),e.jsx("div",{className:"font-semibold text-slate-800",children:c.averageCostUsd!=null?`$${c.averageCostUsd.toFixed(4)}`:"—"})]})]}),e.jsxs("details",{children:[e.jsx("summary",{className:"text-[11px] cursor-pointer text-slate-600",children:"By check type"}),e.jsx("ul",{className:"mt-1 text-[11px] text-slate-700",children:Object.entries(c.byCheck).map(([x,b])=>e.jsxs("li",{className:"flex items-center justify-between py-0.5",children:[e.jsx("code",{className:"font-mono",children:x}),e.jsxs("span",{children:["$",(b??0).toFixed(4)]})]},x))})]}),e.jsxs("details",{children:[e.jsx("summary",{className:"text-[11px] cursor-pointer text-slate-600",children:"Recent audits (last 10)"}),e.jsxs("table",{className:"mt-1 w-full text-[11px]",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-slate-500 text-left",children:[e.jsx("th",{className:"py-0.5 pr-2 font-medium",children:"When"}),e.jsx("th",{className:"py-0.5 pr-2 font-medium",children:"Target"}),e.jsx("th",{className:"py-0.5 pr-2 font-medium text-right",children:"Cost"}),e.jsx("th",{className:"py-0.5 font-medium text-right",children:"Findings"})]})}),e.jsx("tbody",{children:c.recent.map((x,b)=>e.jsxs("tr",{className:"border-t border-slate-100",children:[e.jsx("td",{className:"py-0.5 pr-2 text-slate-600",children:new Date(x.at).toLocaleDateString()}),e.jsx("td",{className:"py-0.5 pr-2 text-slate-700 truncate max-w-[180px]",title:x.pageUrl,children:x.pageUrl}),e.jsxs("td",{className:"py-0.5 pr-2 text-right font-mono",children:["$",x.totalCostUsd.toFixed(4),x.capExceeded&&e.jsx("span",{className:"text-amber-700 ml-1",title:"Cost cap exceeded",children:"⚠"}),x.failureReason&&e.jsx("span",{className:"text-red-700 ml-1",title:`AI failure: ${x.failureReason}`,children:"✗"})]}),e.jsx("td",{className:"py-0.5 text-right",children:x.findingsCount})]},b))})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{type:"button",onClick:()=>void v(),className:"text-[11px] text-slate-500 hover:text-rose-600 underline-offset-2 hover:underline",children:"Clear local usage log"})})]})]})]}):e.jsx("div",{className:"text-xs text-slate-500",children:"Loading…"})}function ks(){const[t,s]=o.useState(null),[a,r]=o.useState("trial");o.useEffect(()=>{T({type:"SETTINGS_GET_ALL"}).then(i=>{const m=i.data??{};s({stateMatrix:m.stateMatrix??te,componentIdAliases:m.componentIdAliases??{}})}),T({type:"TIER_GET"}).then(i=>r(i.tier))},[]);function n(i){t&&(s({...t,stateMatrix:i}),E({type:"SETTINGS_SET",key:"stateMatrix",value:i}))}function d(i){if(!t)return;const m=new Set(i.map(f=>f.id)),h=t.stateMatrix.breakpoints.filter(f=>m.has(f));n({...t.stateMatrix,breakpointPresets:i,breakpoints:h.length>0?h:i[0]?[i[0].id]:[]})}function c(i){t&&(s({...t,componentIdAliases:i}),E({type:"SETTINGS_SET",key:"componentIdAliases",value:i}))}function l(){t&&(typeof confirm=="function"&&!confirm("Reset state matrix to defaults?")||n(te))}if(!t)return e.jsx("div",{className:"p-8 text-sm text-slate-500",children:"Loading…"});const u=a==="free";return e.jsxs("div",{className:"max-w-2xl mx-auto p-3 sm:p-6 space-y-6 text-sm",children:[e.jsxs("header",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold",children:"Settings"}),e.jsx("p",{className:"text-xs text-slate-500 mt-1",children:"Changes are saved automatically. Close this tab to return to the audit panel."})]}),e.jsx("button",{type:"button",onClick:()=>{window.close()},className:"text-xs px-3 py-1.5 bg-brand-500 text-white rounded hover:bg-brand-600 shrink-0",children:"Done"})]}),e.jsx("main",{"aria-label":"Settings",children:e.jsxs(St,{defaultValue:"audit",className:"space-y-4",children:[e.jsx(kt,{className:"flex flex-wrap gap-1 border-b border-slate-200","aria-label":"Settings categories",children:[{value:"audit",label:"Audit"},{value:"integrations",label:"Integrations"},{value:"account",label:"Account"},{value:"advanced",label:"Advanced"}].map(i=>e.jsx(Tt,{value:i.value,className:"text-xs px-3 py-1.5 text-slate-600 hover:text-slate-900 data-[state=active]:text-brand-700 data-[state=active]:border-b-2 data-[state=active]:border-brand-500 -mb-px",children:i.label},i.value))}),e.jsxs($,{value:"audit",className:"space-y-8 pt-2",children:[e.jsxs("section",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"State matrix"}),e.jsx("button",{onClick:l,className:"text-xs text-slate-500 hover:text-slate-900",children:"Reset to defaults"})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Which states each audit covers. Larger matrix = more coverage but slower runs."}),u&&e.jsx("div",{className:"text-xs bg-amber-50 border border-amber-200 rounded p-2 text-amber-900",children:"Free tier audits the default state only — your matrix selections below will be ignored until you upgrade."}),e.jsx(At,{value:t.stateMatrix,onChange:n})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Breakpoint presets"}),e.jsx("p",{className:"text-xs text-slate-500",children:"Customize widths/heights and add your own breakpoints. Toggle which ones audit under in the State matrix section above."}),e.jsx(zt,{presets:t.stateMatrix.breakpointPresets,onChange:d})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Audit reliability"}),e.jsx(js,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Disabled rules"}),e.jsx(ds,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Component identity aliases"}),e.jsx("p",{className:"text-xs text-slate-500",children:"Map two component IDs to the same canonical ID — useful when the same component is identified differently across pages."}),e.jsx(It,{value:t.componentIdAliases,onChange:c})]})]}),e.jsxs($,{value:"integrations",className:"space-y-8 pt-2",children:[e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"GitHub issue tracker"}),e.jsx(xs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Jira issue tracker"}),e.jsx(hs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Azure DevOps tracker"}),e.jsx(fs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"GitLab issue tracker"}),e.jsx(gs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Cloud sync (baselines)"}),e.jsx(vs,{})]})]}),e.jsxs($,{value:"account",className:"space-y-8 pt-2",children:[e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"User mode"}),e.jsx(Ns,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"License"}),e.jsx(Kt,{tier:a,onTierChange:r})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Crash reporting"}),e.jsx(qt,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"AI augmentation"}),e.jsx(Ss,{})]})]}),e.jsxs($,{value:"advanced",className:"space-y-8 pt-2",children:[e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Remediation trail"}),e.jsx("p",{className:"text-xs text-slate-500",children:"Build a defensible record by automatically saving every audit as a dated, anchored report. Useful for pre-litigation / demand-letter defense and for procurement evidence."}),e.jsx(Zt,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Report download behavior"}),e.jsx("p",{className:"text-xs text-slate-500",children:"Defense / evidence bundles default to a confirmation prompt before downloading. Power users who export many bundles can skip the prompt here."}),e.jsx(Qt,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Performance"}),e.jsx(es,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Custom rules"}),e.jsx(rs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Native messaging host"}),e.jsx(cs,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Team"}),e.jsx("p",{className:"text-xs text-slate-500",children:"For Team plans: see every device that's claimed a seat under this license, and revoke any of them. The license token itself authenticates this section — anyone with the token can manage seats."}),e.jsx(as,{})]}),e.jsxs("section",{className:"space-y-3",children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Import / export"}),e.jsx("p",{className:"text-xs text-slate-500",children:"Share matrix + alias config with your team, or back up before major changes."}),e.jsx(Wt,{stateMatrix:t.stateMatrix,componentIdAliases:t.componentIdAliases,onImport:i=>s(i)})]})]})]})}),e.jsx(He,{})]})}const Pe=document.getElementById("root");if(!Pe)throw new Error("options: #root not found");Ve(Pe).render(e.jsx(D.StrictMode,{children:e.jsx(ks,{})}));
@@ -0,0 +1 @@
1
+ import{aM as p,aN as g,aO as $,aP as v}from"./scheduled-audit-runner-DyKpb3zg.js";import{e as w,c as E,r as T}from"./crash-reporter-Bu2p8K-p.js";import"./diff-DA41zYPc.js";import"./ai-usage-log-BX3L6bKl.js";const m=E("parallel-tab-flow");async function M(s){const n=performance.now(),a=p(s.matrix),o=Math.max(1,Math.min(s.parallelism??4,8)),i=[];for(let e=0;e<o;e++)i.push([]);a.forEach((e,b)=>{i[b%o].push(e)}),m.info(`parallel-tab audit starting: ${a.length} states across ${o} tabs (~${Math.ceil(a.length/o)} states/tab)`);const r=a.length;let t=0;a[0]&&w({type:"AUDIT_PROGRESS_EVENT",current:0,total:r,currentState:a[0]});const l=e=>{t++,w({type:"AUDIT_PROGRESS_EVENT",current:t,total:r,currentState:e})},d=i.map((e,b)=>e.length===0?Promise.resolve({results:[],failed:!1}):y(s.targetUrl,s.scope,e,b,s.cancel,l)),h=await Promise.all(d),c=[];let u=0,f=0;for(const e of h)e.failed?f++:u++,c.push(...e.results);return{results:c,parallelDurationMs:performance.now()-n,tabsCompleted:u,tabsFailed:f}}async function y(s,n,a,o,i,r){let t;const l=[];try{const d=await chrome.tabs.create({url:s,active:!1});if(!d.id)throw new Error("chrome.tabs.create returned no id");if(t=d.id,m.debug(`worker ${o}: opened tab ${t}`),await U(t),i.isCanceled())throw new Error("canceled");const h=await g(t,0);if(!h.ok)throw new Error(`content script unreachable: ${h.reason}`);for(let c=0;c<a.length&&!i.isCanceled();c++){const u=a[c];try{if(!(await $(t,u,n)).success){m.warn(`worker ${o} state ${c+1}/${a.length} drive failed`),r==null||r(u);continue}const e=await T(t,{type:"AUDIT_REQUEST",selector:n,currentState:u});e.success&&e.result&&l.push({...e.result,violations:e.result.violations})}catch(f){m.debug(`worker ${o} state ${c+1} error`,f)}finally{r==null||r(u)}}try{await v(t,n)}catch{}return{results:l,failed:!1}}catch(d){return m.warn(`worker ${o} failed`,d),{results:l,failed:!0}}finally{if(t!==void 0)try{await chrome.tabs.remove(t)}catch{}}}function U(s,n=3e4){return new Promise((a,o)=>{const i=setTimeout(()=>{chrome.tabs.onUpdated.removeListener(r),o(new Error(`tab ${s} load timed out after ${n}ms`))},n),r=(t,l)=>{t===s&&l.status==="complete"&&(clearTimeout(i),chrome.tabs.onUpdated.removeListener(r),a())};chrome.tabs.onUpdated.addListener(r),chrome.tabs.get(s).then(t=>{t.status==="complete"&&(clearTimeout(i),chrome.tabs.onUpdated.removeListener(r),a())})})}export{M as runParallelTabAudit};