@wcag-checkr/ci 1.0.0-rc.99 → 1.0.1
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.
- package/dist/assets/ErrorBoundary-TPkmJFZP.js +594 -0
- package/dist/assets/ai-usage-log-CYyG5MT2.js +1 -0
- package/dist/assets/content-script.ts-DUFtdkRn.js +217 -0
- package/dist/assets/{content-script.ts-loader-BjJqq5Xq.js → content-script.ts-loader-BhZWdOHh.js} +1 -1
- package/dist/assets/copy-ai-fixer-prompt-DKUDhBLv.js +19 -0
- package/dist/assets/crash-reporter-KD5f4utB.js +4 -0
- package/dist/assets/design-system-audit-DpxJrxnb.js +1 -0
- package/dist/assets/devtools-panel-BAMmfrpT.js +1 -0
- package/dist/assets/diff-RnwNJg4F.js +1 -0
- package/dist/assets/dom-criterion-analyzers-DoUaJV5C.js +8 -0
- package/dist/assets/fraunces-latin-400-normal-6IfK1voy.woff2 +0 -0
- package/dist/assets/fraunces-latin-400-normal-NUPT2cO8.woff +0 -0
- package/dist/assets/fraunces-latin-500-normal-BTR4KCeb.woff +0 -0
- package/dist/assets/fraunces-latin-500-normal-DnGCNyPD.woff2 +0 -0
- package/dist/assets/fraunces-latin-600-normal-BFCDtZfi.woff2 +0 -0
- package/dist/assets/fraunces-latin-600-normal-DL5QCzvS.woff +0 -0
- package/dist/assets/fraunces-latin-ext-400-normal-D8gbi3Gu.woff2 +0 -0
- package/dist/assets/fraunces-latin-ext-400-normal-UihxqfOe.woff +0 -0
- package/dist/assets/fraunces-latin-ext-500-normal-BMcFk1Xs.woff +0 -0
- package/dist/assets/fraunces-latin-ext-500-normal-Z5DV8IzT.woff2 +0 -0
- package/dist/assets/fraunces-latin-ext-600-normal-B0Dy4lqi.woff +0 -0
- package/dist/assets/fraunces-latin-ext-600-normal-BtzmzP0X.woff2 +0 -0
- package/dist/assets/fraunces-vietnamese-400-normal-B65MOf9T.woff +0 -0
- package/dist/assets/fraunces-vietnamese-400-normal-CvGt0Ybw.woff2 +0 -0
- package/dist/assets/fraunces-vietnamese-500-normal-B-KbxExq.woff +0 -0
- package/dist/assets/fraunces-vietnamese-500-normal-GOH_-EGq.woff2 +0 -0
- package/dist/assets/fraunces-vietnamese-600-normal-BjlAJixd.woff2 +0 -0
- package/dist/assets/fraunces-vietnamese-600-normal-DlAl5EAR.woff +0 -0
- package/dist/assets/geist-sans-latin-400-normal-BOaIZNA2.woff +0 -0
- package/dist/assets/geist-sans-latin-400-normal-gapTbOY8.woff2 +0 -0
- package/dist/assets/geist-sans-latin-500-normal-CN2lyvyL.woff +0 -0
- package/dist/assets/geist-sans-latin-500-normal-uokXdC-Q.woff2 +0 -0
- package/dist/assets/geist-sans-latin-600-normal-CA1yjETN.woff +0 -0
- package/dist/assets/geist-sans-latin-600-normal-DFOURf8L.woff2 +0 -0
- package/dist/assets/geist-sans-latin-700-normal-BmN9tIp5.woff2 +0 -0
- package/dist/assets/geist-sans-latin-700-normal-CjScfYeH.woff +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-600-normal-8K4wrrwR.woff +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-600-normal-EVf6-Yzo.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
- package/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-600-normal-H7WoG9Et.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-600-normal-mc2nkWzM.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-600-normal-BfsvjouI.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-600-normal-BfB_LPfz.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-600-normal-DObL3zCW.woff +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-600-normal-OWROknRo.woff +0 -0
- package/dist/assets/offscreen-BAvM-6sh.js +1 -0
- package/dist/assets/options-D_6nRFjj.js +6 -0
- package/dist/assets/parallel-tab-flow-CecEndeb.js +1 -0
- package/dist/assets/pdf-DfaD4CCm.js +13 -0
- package/dist/assets/pdf.worker-B4IDxXWI.js +1 -0
- package/dist/assets/pdf.worker-ByF8NTMy.mjs +62201 -0
- package/dist/assets/rubric-config-client-DJcOQbG2.js +1 -0
- package/dist/assets/scheduled-audit-runner-Cad1yq0z.js +2035 -0
- package/dist/assets/service-worker.ts-B9F-ll_q.js +2 -0
- package/dist/assets/side-panel-Br-bhDHn.js +4 -0
- package/dist/assets/side-panel-Cq-w2yTn.css +1 -0
- package/dist/assets/site-report-renderer-klOJEyJa.js +248 -0
- package/dist/assets/styles-BJICDw6s.css +1 -0
- package/dist/assets/{styles-DhnON7zr.js → styles-B_kTykZT.js} +12 -12
- package/dist/assets/tier-config-client-85XOCE5d.js +1 -0
- package/dist/assets/zip-encoder-CtULHXx_.js +1 -0
- package/dist/devtools/panel.html +9 -7
- package/dist/manifest.json +10 -11
- package/dist/offscreen/offscreen.html +12 -0
- package/dist/options/options.html +6 -6
- package/dist/service-worker-loader.js +1 -1
- package/dist/side-panel/side-panel.html +13 -7
- package/package.json +2 -1
- package/wcagcheckr-ci.mjs +238 -39
- package/dist/assets/ErrorBoundary-DRi97B4x.js +0 -544
- package/dist/assets/ai-usage-log-Dj9Ub_DT.js +0 -1
- package/dist/assets/content-script.ts-vGsvD70K.js +0 -181
- package/dist/assets/copy-ai-fixer-prompt-CxzoaUL_.js +0 -19
- package/dist/assets/crash-reporter-Dc5lvxvY.js +0 -4
- package/dist/assets/devtools-panel-DCeWrjIb.js +0 -1
- package/dist/assets/diff-DIBMr3fQ.js +0 -1
- package/dist/assets/dom-criterion-analyzers-C2gMp3xS.js +0 -1
- package/dist/assets/forensic-log-z_FcTaq6.js +0 -129
- package/dist/assets/options-Byz5A0JD.js +0 -6
- package/dist/assets/parallel-tab-flow-Dd60Cor5.js +0 -1
- package/dist/assets/service-worker.ts-BeULiNbt.js +0 -954
- package/dist/assets/side-panel-C-Jo4m74.js +0 -1
- package/dist/assets/site-report-renderer-fqGucmuR.js +0 -147
- package/dist/assets/state-BIsozXtc.js +0 -1
- package/dist/assets/styles-Bh3rgVbO.css +0 -1
- package/dist/side-panel/App.tsx +0 -193
- package/dist/side-panel/README.md +0 -57
- package/dist/side-panel/audit-launcher.test.ts +0 -56
- package/dist/side-panel/audit-launcher.ts +0 -65
- package/dist/side-panel/format-component-id.test.ts +0 -89
- package/dist/side-panel/format-component-id.ts +0 -40
- package/dist/side-panel/github-issue.test.ts +0 -102
- package/dist/side-panel/github-issue.ts +0 -66
- package/dist/side-panel/jira-issue.ts +0 -64
- package/dist/side-panel/main.tsx +0 -19
- package/dist/side-panel/store.ts +0 -289
- package/dist/side-panel/styles.css +0 -16
- package/dist/side-panel/wire-messaging.test.ts +0 -202
- package/dist/side-panel/wire-messaging.ts +0 -288
package/dist/assets/{content-script.ts-loader-BjJqq5Xq.js → content-script.ts-loader-BhZWdOHh.js}
RENAMED
|
@@ -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-
|
|
8
|
+
chrome.runtime.getURL("assets/content-script.ts-DUFtdkRn.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-TPkmJFZP.js","assets/styles-B_kTykZT.js","assets/_commonjsHelpers-Cpj98o6Y.js","assets/crash-reporter-KD5f4utB.js","assets/ai-usage-log-CYyG5MT2.js","assets/styles-BJICDw6s.css","assets/scheduled-audit-runner-Cad1yq0z.js","assets/preload-helper-D7HrI6pR.js","assets/diff-RnwNJg4F.js","assets/design-system-audit-DpxJrxnb.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as l}from"./preload-helper-D7HrI6pR.js";import{a as v}from"./crash-reporter-KD5f4utB.js";async function C(e){var f,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=((f=e.results[0])==null?void 0:f.pageUrl)??((w=e.results[0])==null?void 0:w.scope)??"";if(i){const{getDismissalsForUrl:o}=await l(async()=>{const{getDismissalsForUrl:t}=await import("./ErrorBoundary-TPkmJFZP.js").then(n=>n.m);return{getDismissalsForUrl:t}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9])),r=await o(i);p=Object.keys(r);const{getResolutionsForPage:a}=await l(async()=>{const{getResolutionsForPage:t}=await import("./scheduled-audit-runner-Cad1yq0z.js").then(n=>n.aU);return{getResolutionsForPage:t}},__vite__mapDeps([6,7,3,8,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-Cad1yq0z.js").then(c=>c.aT);return{loadAcknowledgedKeysForComponent:a}},__vite__mapDeps([6,7,3,8,4])),r=await o(e.componentId);m=r.size>0?Array.from(r):void 0}const b=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(b.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">${b.content.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</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};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const f=[];function v(e){f.push(e),f.length>50&&f.shift()}function M(){return[...f]}const T={debug:0,info:1,warn:2,error:3,silent:4};let _="info";function S(e){return{debug:(t,...r)=>l("debug",e,t,r),info:(t,...r)=>l("info",e,t,r),warn:(t,...r)=>l("warn",e,t,r),error:(t,...r)=>l("error",e,t,r)}}function l(e,t,r,n){if(v(O(e,t,r,n)),T[e]<T[_])return;const o=`[${t}]`,a=e==="error"?console.error:e==="warn"?console.warn:console.log;n.length>0?a(o,r,...n):a(o,r)}function O(e,t,r,n){const o=new Date().toISOString(),a=n.length>0?` ${n.map(U).join(" ")}`:"";return`${o} ${e.toUpperCase()} [${t}] ${r}${a}`}function U(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}const b=S("messaging");function z(e){return chrome.runtime.sendMessage(e)}function H(e,t,r){const n=r!==void 0?{frameId:r}:void 0;return chrome.tabs.sendMessage(e,t,n)}async function K(e){const t=await chrome.runtime.sendMessage(e);if(!y(t))throw new Error(`messaging.request: response was not a Message (sent ${e.type}, got ${typeof t})`);return t}const $=45e3;async function Y(e,t,r){const n=r!==void 0?{frameId:r}:void 0,o=await Promise.race([chrome.tabs.sendMessage(e,t,n),new Promise((a,s)=>setTimeout(()=>s(new Error(`messaging.requestFromTab: ${t.type} timed out after ${$/1e3}s`)),$))]);if(!y(o))throw new Error(`messaging.requestFromTab: response was not a Message (sent ${t.type}, got ${typeof o})`);return o}function Q(e,t){const r=(n,o,a)=>{if(!y(n)||n.type!==e)return!1;let s;try{s=t(n,o)}catch(u){return k(e,u),a(void 0),!1}return s instanceof Promise?(s.then(u=>a(u??void 0)).catch(u=>{k(e,u),a(void 0)}),!0):(a(s??void 0),!1)};return chrome.runtime.onMessage.addListener(r),()=>chrome.runtime.onMessage.removeListener(r)}function W(e){chrome.runtime.sendMessage(e).catch(()=>{})}function y(e){return typeof e=="object"&&e!==null&&typeof e.type=="string"}function k(e,t){b.error(`handler for ${e} failed`,t)}const h="deviceId";async function I(){let t=(await chrome.storage.local.get(h))[h];return t||(t=crypto.randomUUID(),await chrome.storage.local.set({[h]:t}),t)}const c=S("license-seat-client"),p="https://api.wcagcheckr.com",g="wcagcheckr",m=1e4;async function Z(e){const t=await I();try{const r=await fetch(`${p}/v1/products/${g}/license/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:e,deviceId:t,userAgent:navigator.userAgent.slice(0,255)}),signal:AbortSignal.timeout(m)}),n=await r.json().catch(()=>null);return r.status===409&&n&&"error"in n&&n.error==="seat_cap_reached"?{ok:!1,reason:"cap-reached",seatsUsed:n.seatsUsed??0,seatsTotal:n.seatsTotal??0,hint:n.hint}:r.status===404?{ok:!1,reason:"not-found"}:r.ok?{ok:!0,seatsUsed:(n==null?void 0:n.seatsUsed)??0,seatsTotal:(n==null?void 0:n.seatsTotal)??null,overCapacity:(n==null?void 0:n.overCapacity)===!0}:(c.warn(`seat claim http ${r.status}`,n),{ok:!1,reason:"network",message:`HTTP ${r.status}`})}catch(r){return c.warn("seat claim failed",r),{ok:!1,reason:"network",message:r instanceof Error?r.message:String(r)}}}async function ee(e){try{const t=await fetch(`${p}/v1/products/${g}/license/${encodeURIComponent(e)}/seats`,{method:"GET",headers:{authorization:`Bearer ${e}`},signal:AbortSignal.timeout(m)});return t.ok?await t.json():(c.warn(`listTeamSeats http ${t.status}`),null)}catch(t){return c.warn("listTeamSeats failed",t),null}}async function te(e,t){try{return(await fetch(`${p}/v1/products/${g}/license/${encodeURIComponent(e)}/seats/${encodeURIComponent(t)}`,{method:"DELETE",headers:{authorization:`Bearer ${e}`},signal:AbortSignal.timeout(m)})).ok}catch(r){return c.warn("revokeTeamSeat failed",r),!1}}async function re(e){const t=await I();try{return(await fetch(`${p}/v1/products/${g}/license/release`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:e,deviceId:t}),signal:AbortSignal.timeout(m)})).ok}catch(r){return c.warn("seat release failed",r),!1}}const w={maxComponents:1/0,maxBaselines:1/0,stateMatrix:"all",siteCrawlMaxPages:1/0,scheduledAuditsMaxCount:1/0,aiCostCapDefaultUsd:5,aiMaxCandidatesPerCheck:10,storybookAutoIterate:!0,parallelScan:!0,allFramesAudit:!0,siteCrawl:!0,scheduledAudits:!0,emailAlerts:!0,webhookAlerts:!0,autoExportAuditReports:!0,aiJudgment:!0,aiWalkthroughs:!0,aiCopilot:!0,aiColorFix:!0,aiComplianceSummary:!0,aiIncompleteResolver:!0,aiConsistencySuppression:!0,visualizers:!0,flowRecorder:!0,igtWorkflows:!0,axTreeViewer:!0,pdfAudit:!0,exportJson:!0,exportSarif:!0,exportJunit:!0,exportHtmlPrint:!0,exportVpat:!0,exportDefenseBundle:!0,exportEvidenceBundle:!0,exportDeveloperLetter:!0,exportOwnerReport:!0,exportAiPrompts:!0,exportDepositionPacket:!0,exportMethodologyDoc:!0,exportConformanceCrosswalk:!0,exportEaaStatement:!0,exportTicketBundle:!0,exportExecutiveReport:!0,exportPreLitigationReport:!0,forensicLog:!0,forensicAnchoring:!0,wcagEmReport:!0,wcagEmAnchor:!0,statusBadge:!0,riskDashboard:!0,lawfareRisk:!0,wcag3Preview:!0,cloudSync:!0,issueTrackers:!0,cliRunner:!0,mcpServer:!0,vscodeExtension:!0,devtoolsPanel:!0,designSystemAudit:!0,customRules:!0},P={free:{...w},solo:{...w},team:{...w}};let d=null;function ne(e){d=e}function D(e){return(d==null?void 0:d[e])??P[e]}function oe(e,t){return D(e)[t]}const N=/https?:\/\/[^\s)]+/g,F=/[\w.+-]+@[\w-]+\.[\w.-]+/g,j=/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;function B(e){return e.replace(N,"[URL]").replace(F,"[EMAIL]").replace(j,"[TOKEN]")}function L(e){return e.map(B)}const J=S("crash-reporter"),q="https://api.wcagcheckr.com/v1/products/wcagcheckr/crash",E="crashReporting:enabled",x=10;let R="unknown",A=!1;const i=new Set;function ae(e){A||(A=!0,R=e,typeof window<"u"&&(window.addEventListener("error",t=>{C(t.error??new Error(t.message))}),window.addEventListener("unhandledrejection",t=>{const r=t.reason,n=r instanceof Error?r:new Error(String(r));C(n)})))}async function C(e){if(!await X())return;const t=G(e);if(i.has(t))return;if(i.add(t),i.size>x){const n=[...i].slice(-x);i.clear(),n.forEach(o=>i.add(o))}const r={productSlug:"wcagcheckr",context:R,fingerprint:t,message:e.message,stack:V(e.stack??""),extensionVersion:chrome.runtime.getManifest().version,occurredAt:new Date().toISOString(),logTail:L(M())};try{await fetch(q,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})}catch(n){J.warn("crash report failed to send",n)}}async function X(){try{return(await chrome.storage.local.get(E))[E]===!0}catch{return!1}}async function se(e){await chrome.storage.local.set({[E]:e})}function G(e){var r;const t=((r=(e.stack??"").split(`
|
|
2
|
+
`)[1])==null?void 0:r.trim())??"";return`${e.name}:${e.message}::${t}`.slice(0,200)}function V(e){return L(e.split(`
|
|
3
|
+
`)).join(`
|
|
4
|
+
`)}export{E as O,P as T,K as a,re as b,S as c,se as d,te as e,oe as f,I as g,H as h,ae as i,D as j,W as k,ee as l,L as m,M as n,Q as o,C as p,ne as q,Y as r,z as s,Z as t};
|
|
@@ -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 s,j as e,R as i}from"./styles-B_kTykZT.js";import{E as n,u as a,k as l}from"./ErrorBoundary-TPkmJFZP.js";import{i as p,f as m}from"./crash-reporter-KD5f4utB.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./ai-usage-log-CYyG5MT2.js";import"./scheduled-audit-runner-Cad1yq0z.js";import"./preload-helper-D7HrI6pR.js";import"./diff-RnwNJg4F.js";import"./design-system-audit-DpxJrxnb.js";p("devtools-panel");function c(){const t=a(r=>r.tier);return m(t,"devtoolsPanel")?e.jsx(l,{}):e.jsxs("div",{style:{padding:24,fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif'},children:[e.jsx("h2",{style:{margin:0,fontSize:16,fontWeight:600,color:"#1f2923"},children:"DevTools panel isn’t available on your current plan"}),e.jsx("p",{style:{marginTop:8,fontSize:13,color:"#64748b"},children:"The wcagcheckr DevTools panel is part of a higher-tier plan. The extension’s side panel is still available — open it from the extensions menu."})]})}const o=document.getElementById("root");if(!o)throw new Error("devtools panel: #root not found");s(o).render(e.jsx(i.StrictMode,{children:e.jsx(n,{children:e.jsx(c,{})})}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var K=Object.defineProperty;var U=(e,t,a)=>t in e?K(e,t,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[t]=a;var D=(e,t,a)=>U(e,typeof t!="symbol"?t+"":t,a);import{c as M,o as T,k as A,t as I}from"./crash-reporter-KD5f4utB.js";const h="license:cache",$=60*60*1e3,x=24*60*60*1e3,v=7*24*60*60*1e3;async function g(){return(await chrome.storage.local.get(h))[h]??null}async function m(e){await chrome.storage.local.set({[h]:e})}async function E(){await chrome.storage.local.remove(h)}function j(e,t=Date.now()){const a=t-e.validatedAt;return a<$?"fresh":a<x?"stale":a<v?"grace":"expired"}const f=M("license-gate"),G="https://api.wcagcheckr.com",H="wcagcheckr",P=`${G}/v1/products/${H}/license/validate`,V=1e4,N="licenseToken";async function C(){return(await chrome.storage.local.get(N))[N]??null}async function F(e){await chrome.storage.local.set({[N]:e})}async function _(e){const t=await fetch(P,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({token:e}),signal:AbortSignal.timeout(V)});if(!t.ok)throw new Error(`validate http ${t.status}`);return{type:"LICENSE_VALIDATE_RESPONSE",...await t.json()}}async function y(e){const t=await g();if(t&&t.token===e){const s=j(t);if(s==="fresh")return t.response;if(s==="stale")return _(e).then(n=>m({token:e,validatedAt:Date.now(),response:n})).catch(n=>f.warn("background refresh failed",n)),t.response;if(s==="grace")try{const n=await _(e);return await m({token:e,validatedAt:Date.now(),response:n}),n}catch(n){return f.warn("grace-period revalidation failed; using last-known-good",n),t.response}}const a=await _(e);return await m({token:e,validatedAt:Date.now(),response:a}),a}function J(e){return e==="solo"||e==="solo-yearly"||e==="solo-single-month"?"solo":e==="team"||e==="team-15"||e==="team-yearly"||e==="team-15-yearly"?"team":"free"}async function w(){const e=await C();if(e)try{const t=await y(e);if(t.valid&&t.plan)return J(t.plan)}catch(t){f.warn("validation failed, falling back",t)}return"free"}async function B(){const e=await g(),t=e==null?void 0:e.response.features;if(!t||typeof t!="object")return{};const a=t.seatsUsed,s=t.seatsTotal;return{seatsUsed:typeof a=="number"?a:void 0,seatsTotal:typeof s=="number"?s:void 0}}function q(){const e=[];e.push(T("TIER_GET",async n=>{n.forceRefresh&&await E();const o=await w(),c={type:"TIER_GET_RESPONSE",tier:o};if(o==="team"){const{seatsUsed:l,seatsTotal:d}=await B();l!==void 0&&(c.seatsUsed=l),d!==void 0&&(c.seatsTotal=d)}const i=await g();if(i!=null&&i.response.valid&&i.response.plan){if(c.planCode=i.response.plan,i.response.plan==="solo-single-month"&&i.response.expiresAt){const l=new Date(i.response.expiresAt).getTime()-Date.now();c.licenseDaysRemaining=Math.max(0,Math.ceil(l/864e5))}i.response.pastDueSince&&(c.pastDue=!0)}return c})),e.push(T("LICENSE_VALIDATE_REQUEST",async n=>{try{if(n.forceRefresh){await E();const o=await y(n.token);return A({type:"LICENSE_CHANGED_EVENT",tier:await w()}),o}return await y(n.token)}catch(o){return f.error("validate failed",o),{type:"LICENSE_VALIDATE_RESPONSE",valid:!1,plan:null,email:null,status:null,expiresAt:null}}})),e.push(T("LICENSE_SET_REQUEST",async n=>{await F(n.token),await E();let o=!1,c={ok:!1,reason:"not-attempted"};try{const p=await y(n.token);if(await m({token:n.token,validatedAt:Date.now(),response:p}),o=p.valid===!0,o){const u=await I(n.token);u.ok?c={ok:!0,seatsUsed:u.seatsUsed,seatsTotal:u.seatsTotal,overCapacity:u.overCapacity}:c=u}}catch(p){f.warn("validation after set failed",p)}const i=await w();A({type:"LICENSE_CHANGED_EVENT",tier:i});const l=await g(),d=(l==null?void 0:l.response.features)??void 0;return{type:"LICENSE_SET_RESPONSE",validated:o,tier:i,features:d,seatClaim:c}})),(async()=>{try{const n=await C();n&&await I(n)}catch(n){f.debug("boot-time seat claim failed",n)}})();const t="license:periodic-refresh",a=60;chrome.alarms.get(t,n=>{n||chrome.alarms.create(t,{periodInMinutes:a})});const s=async n=>{if(n.name===t)try{const o=await C();if(!o)return;await E();const c=await y(o);await m({token:o,validatedAt:Date.now(),response:c}),A({type:"LICENSE_CHANGED_EVENT",tier:await w()}),f.debug("periodic license refresh complete")}catch(o){f.warn("periodic license refresh failed",o)}};return chrome.alarms.onAlarm.addListener(s),e.push(()=>chrome.alarms.onAlarm.removeListener(s)),f.info("handlers registered"),()=>e.forEach(n=>n())}function W(e,t,a=!1,s){return{code:e,message:t,recoverable:a,details:s}}class Y extends Error{constructor(a){super(a.message);D(this,"payload");this.name="TypedError",this.payload=a}}function Z(e){return e instanceof Y}async function ee(e){const t=L(e.currentState),a=[e.target.tagName,e.target.role??"",e.target.accessibleName??"",e.target.textSnippet??"",e.target.attrId??"",e.target.attrTestid??""].join("|");return Q(`${e.ruleId}|${e.componentId}|${t}|${a}`)}function te(e,t,a,s,n){const o=new Map(e.map(r=>[r.matchKey,r])),c=new Map(t.map(r=>[r.matchKey,r])),i=n??new Set,l=t.filter(r=>!o.has(r.matchKey)&&!i.has(r.matchKey)),d=t.filter(r=>o.has(r.matchKey)&&!i.has(r.matchKey)),p=e.filter(r=>!c.has(r.matchKey)&&!i.has(r.matchKey)),u=t.filter(r=>i.has(r.matchKey));let R,k;if(s){if(s.currentAnnouncements){const r=new Set((s.baselineAnnouncements??[]).map(b));R=s.currentAnnouncements.filter(S=>!r.has(b(S)))}if(s.currentFocusEvents){const r=new Set((s.baselineFocusEvents??[]).map(O));k=s.currentFocusEvents.filter(S=>!r.has(O(S)))}}return{new:l,persistent:d,fixed:p,newCount:l.length,persistentCount:d.length,fixedCount:p.length,baselineSnapshotMeta:a,comparedAt:new Date().toISOString(),newAnnouncements:R,newFocusEvents:k,acknowledged:u,acknowledgedCount:u.length}}function b(e){return`${e.selector}::${e.text}::${e.politeness}`}function O(e){return`${e.toSelector}::${e.isFocusReset}`}function L(e){if(e===null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return"["+e.map(L).join(",")+"]";const t=e;return"{"+Object.keys(t).sort().map(n=>`${JSON.stringify(n)}:${L(t[n])}`).join(",")+"}"}async function Q(e){const t=new TextEncoder().encode(e),a=await crypto.subtle.digest("SHA-1",t);return Array.from(new Uint8Array(a)).map(s=>s.toString(16).padStart(2,"0")).join("")}export{Y as T,w as a,L as b,ee as c,te as d,C as g,Z as i,W as m,q as r};
|
|
@@ -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};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./modulepreload-polyfill-B5Qt9EMX.js";import{_ as V}from"./preload-helper-D7HrI6pR.js";const X=new Set(["Document","Part","Art","Sect","Div","BlockQuote","Caption","TOC","TOCI","Index","NonStruct","Private","H","H1","H2","H3","H4","H5","H6","P","L","LI","Lbl","LBody","Table","TR","TH","TD","THead","TBody","TFoot","Span","Quote","Note","Reference","BibEntry","Code","Link","Annot","Ruby","RB","RT","RP","Warichu","WT","WP","Figure","Formula","Form"]);function Z(){const t=new Map;let r=0;return{ruleAggregates:t,figureAltCandidates:[],get lastHeading(){return r},set lastHeading(e){r=e},bumpRule(e,i){let o=t.get(e);o||(o={count:0,pages:new Set},t.set(e,o)),o.count++,o.pages.add(i)},setLastHeadingLevel(e){r=e},getLastHeading(){return r}}}function K(t,r,n){if(!t||typeof t!="object")return;const e=t.role;if(e&&!X.has(e)&&n.bumpRule("pdf-non-standard-role",r),e==="Figure"){const i=(t.alt??"").trim();i?n.figureAltCandidates.push({pageNum:r,alt:i}):n.bumpRule("pdf-figure-missing-alt",r)}if(e&&/^H[1-6]$/.test(e)){const i=parseInt(e.slice(1),10),o=n.getLastHeading();o>0&&i>o+1&&n.bumpRule("pdf-heading-skip",r),n.setLastHeadingLevel(i)}if(e==="Table"&&!Y(t,"TH")&&n.bumpRule("pdf-table-no-header",r),e==="L"){const i=t.children??[],o=i.some(s=>s&&s.role&&s.role!=="LI"&&s.role!=="Caption");(i.length===0||o)&&n.bumpRule("pdf-list-malformed",r)}for(const i of t.children??[])K(i,r,n)}function Y(t,r){if(!t)return!1;if(t.role===r)return!0;for(const n of t.children??[])if(Y(n,r))return!0;return!1}function ee(t){if(!t)return 0;const r=t.filter(e=>e.subtype==="Widget");let n=0;for(const e of r){const i=(e.alternativeText??"").trim(),o=(e.fieldName??"").trim(),s=/^(field|text\s*box|check\s*box|radio|button)\s*\d*$/i.test(o);!i&&(!o||s)&&n++}return n}function te(t,r){if(!t)return[];const n=[];for(const e of t){if(e.subtype!=="Widget")continue;const i=(e.alternativeText??"").trim();i&&n.push({pageNum:r,fieldType:(e.fieldType??"").trim()||"unknown",fieldName:(e.fieldName??"").trim(),tooltip:i})}return n}function re(t){const r=[],n={"pdf-figure-missing-alt":{ruleId:"pdf-figure-missing-alt",impact:"serious",wcagCriterion:"1.1.1",describe:e=>({description:`${e.count} Figure tag${e.count===1?"":"s"} (across ${e.pages.size} page${e.pages.size===1?"":"s"}) have no alt text. Screen-reader users hear nothing for these images. PDF/UA-1 §7.4.`,failureSummary:"Open the PDF in Acrobat → Accessibility → Reading Order → click each Figure → Edit Alternate Text. Or, in source: add alt text to each image in Word/InDesign/PowerPoint before exporting."})},"pdf-heading-skip":{ruleId:"pdf-heading-skip",impact:"moderate",wcagCriterion:"1.3.1",describe:e=>({description:`Heading levels skip (e.g. H1 → H3 without H2). Detected ${e.count} skip${e.count===1?"":"s"} across ${e.pages.size} page${e.pages.size===1?"":"s"}. Screen-reader users hear the section hierarchy as broken.`,failureSummary:"Re-tag the headings sequentially. In Acrobat → Accessibility → Reading Order, change the offending tag to the correct heading level. In source documents use Heading 1 → Heading 2 → Heading 3 styles consistently."})},"pdf-table-no-header":{ruleId:"pdf-table-no-header",impact:"serious",wcagCriterion:"1.3.1",describe:e=>({description:`${e.count} Table tag${e.count===1?"":"s"} (across ${e.pages.size} page${e.pages.size===1?"":"s"}) have no TH (header) cells. Screen-reader table-navigation mode cannot announce headers when reading cells.`,failureSummary:"Open the PDF in Acrobat → Accessibility → Reading Order → select the table → Table Editor. Mark the first row (or first column) as headers. In source documents (Word: Table Tools → Layout → Repeat Header Rows; PowerPoint: tables need to be tagged as data tables)."})},"pdf-list-malformed":{ruleId:"pdf-list-malformed",impact:"moderate",wcagCriterion:"1.3.1",describe:e=>({description:`${e.count} List tag${e.count===1?"":"s"} (across ${e.pages.size} page${e.pages.size===1?"":"s"}) are malformed — L tags should contain LI children with optional Lbl + LBody. PDF/UA-1 §7.8.`,failureSummary:'Re-tag the lists in Acrobat → Accessibility → Reading Order, or recreate the PDF from a source document that produces proper list tagging (bullet/numbered lists in Word/Pages/Google Docs export correctly when "tagged PDF" is enabled).'})},"pdf-non-standard-role":{ruleId:"pdf-non-standard-role",impact:"minor",wcagCriterion:"1.3.1",describe:e=>{const i=Array.from(e.pages).slice(0,3).join(", ");return{description:`${e.count} structure-tree node${e.count===1?"":"s"} use non-standard tag roles (sample pages: ${i}). PDF/UA-1 §7.3 requires a RoleMap entry in StructTreeRoot mapping each custom role to a standard one.`,failureSummary:"Either replace the non-standard tags with PDF/UA standard ones (Document/Part/Art/Sect/Div/H1-H6/P/L/LI/Table/TR/TH/TD/Figure/Form/etc.), or add RoleMap entries in StructTreeRoot mapping each custom name to a standard equivalent."}}},"pdf-untagged-content":{ruleId:"pdf-untagged-content",impact:"critical",wcagCriterion:"1.3.1",describe:e=>({description:`${e.pages.size} page${e.pages.size===1?"":"s"} have no structure tree (untagged content). Screen-reader users get no reading order on these pages — content may be read in random visual-position order or skipped entirely.`,failureSummary:"Re-tag the document end-to-end. In Acrobat → Accessibility → Autotag Document is a starting point but rarely produces good results — re-export from the source document with tagging enabled, then refine in Acrobat's Reading Order tool."})}};for(const[e,i]of t.ruleAggregates){const o=n[e];if(!o)continue;const{description:s,failureSummary:p}=o.describe(i);r.push({ruleId:o.ruleId,impact:o.impact,wcagCriterion:o.wcagCriterion,description:s,failureSummary:p})}return r}function ne(t,r){return t===0?null:{ruleId:"pdf-field-no-name",impact:"serious",wcagCriterion:"4.1.2",description:`${t} form field${t===1?"":"s"} across ${r} page${r===1?"":"s"} have no accessible name (no /TU alternate text + no descriptive /T field name). Screen-reader users hear nothing or hear the field type generically ("text field", "check box").`,failureSummary:'In Acrobat: open the Tools → Prepare Form panel → right-click each field → Properties → General tab → fill in the "Tooltip" (this becomes the PDF /TU). Or rename the /T field name to something descriptive ("First name", "Total amount due"). PDF/UA-1 §7.15.'}}function oe(t,r,n){return r===0||n||t>0?null:{ruleId:"pdf-image-only",impact:"critical",wcagCriterion:"1.1.1",description:`PDF has no extractable text on any of its ${r} page${r===1?"":"s"} — appears to be a scanned document with no OCR layer. Screen-reader users hear silence; keyboard search returns no hits; copy/paste yields nothing.`,failureSummary:'Run OCR on the PDF before distributing it. Acrobat Pro → Tools → Scan & OCR → "Recognize Text". Free options: ocrmypdf (CLI), Google Drive (upload → open as Google Doc), or Tesseract. After OCR, re-tag the document (Acrobat → Accessibility → Autotag Document, then refine in Reading Order) so the recognized text gets a proper structure tree.'}}function ie(t,r,n){if(r===0)return null;const e=n!=null&&isFinite(n)?n.toFixed(2):"?";return{ruleId:"pdf-text-low-contrast",impact:"serious",wcagCriterion:"1.4.3",description:`${r} text run${r===1?"":"s"} across ${t} page${t===1?"":"s"} fall below the WCAG 1.4.3 AA contrast threshold (4.5:1 for normal text, 3:1 for large text). Worst observed ratio: ${e}:1. Low-vision readers cannot reliably read this text against its background.`,failureSummary:"Rebuild the source document with stronger contrast — typically darken the text or lighten the background. For brand color palettes, use a contrast checker (https://webaim.org/resources/contrastchecker/) to pick a compliant pair. Re-export the PDF with the new colors. Note: this check samples rendered pixels, so even if the source uses semantic colors, what the reader sees IS the verdict."}}function se(t,r){return t===0?null:{ruleId:"pdf-reading-order-mismatch",impact:"serious",wcagCriterion:"1.3.2",description:`${t} place${t===1?"":"s"} across ${r} page${r===1?"":"s"} where the content-stream reading order jumps backward (significant upward y-motion). Screen-reader users will hear the text in an order that doesn't match the visual layout. PDF/UA-1 §7.10 / WCAG 1.3.2.`,failureSummary:'Most common cause: multi-column layouts that were drawn column-by-column in the source document instead of being tagged with a proper reading order. Fix in Acrobat: Tools → Accessibility → Reading Order → "Show Order Panel" → drag the order entries into the correct sequence. In source documents (Word, InDesign), use proper linked text frames / column flow so the export-to-PDF preserves a top-down read.'}}function ae(t,r){return t<=5||r?null:{ruleId:"pdf-no-bookmarks",impact:"moderate",wcagCriterion:"2.4.5",description:`Multi-page PDF (${t} pages) has no bookmarks / outline. Keyboard and AT users cannot navigate the document structure without scrolling page-by-page.`,failureSummary:'Add bookmarks to the PDF in Acrobat (View → Show/Hide → Navigation Panes → Bookmarks, then add entries for each section heading). Or re-export from the source document with "Generate bookmarks" enabled (Word: Save As PDF → Options → Create bookmarks using: Headings).'}}function J({r:t,g:r,b:n}){const e=i=>{const o=i/255;return o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4)};return .2126*e(t)+.7152*e(r)+.0722*e(n)}function ce(t,r){const n=J(t),e=J(r),i=Math.max(n,e),o=Math.min(n,e);return(i+.05)/(o+.05)}function le(t,r){return!isFinite(t)||t<=0?!1:!!(r&&t>=14*1.333||t>=18*1.333)}function de(t){return t?3:4.5}let U=null;function ue(){return U||(U=(async()=>{try{const t=(await V(async()=>{const{default:n}=await import("./pdf.worker-B4IDxXWI.js");return{default:n}},[])).default,r=await V(()=>import("./pdf-DfaD4CCm.js"),[]);return r.GlobalWorkerOptions&&(r.GlobalWorkerOptions.workerSrc=t),r}catch(t){return{error:t instanceof Error?t.message:String(t)}}})()),U}async function fe(t,r){let n;try{n=await fetch(t)}catch(o){return{ok:!1,source:t,findings:[],pageCount:null,fatalError:`Network error fetching PDF: ${o instanceof Error?o.message:String(o)}`}}if(!n.ok)return{ok:!1,source:t,findings:[],pageCount:null,fatalError:`Fetch failed with HTTP ${n.status}`};const e=n.headers.get("content-length");if(e&&parseInt(e,10)>r)return{ok:!1,source:t,findings:[],pageCount:null,fatalError:`PDF exceeds size cap (${e} bytes > ${r}). Skipped — audit it manually via the CLI: \`wcagcheckr-ci pdf ${t}\`.`};const i=await n.arrayBuffer();return i.byteLength>r?{ok:!1,source:t,findings:[],pageCount:null,fatalError:`PDF exceeds size cap (${i.byteLength} bytes > ${r}). Skipped.`}:pe(new Uint8Array(i),t)}async function ge(t,r){const n={failingRuns:0,worstRatio:null,textItems:0,itemsSkippedTooSmall:0,itemsSkippedOutOfBounds:0,itemsSkippedBgOnly:0,itemsSampled:0,bestObservedRatio:null},e=r.OPS;if(!e)return n;let i;try{i=await t.getOperatorList()}catch(m){return n.renderError=`getOperatorList threw: ${m instanceof Error?m.message:String(m)}`,n}let o={r:0,g:0,b:0},s=12,p=!1;const F=[],S={r:255,g:255,b:255},$=.2126*S.r+.7152*S.g+.0722*S.b,A=i.fnArray,x=i.argsArray,v=A.length;for(let m=0;m<v;m++){const b=A[m],k=x[m]??[];if(b===e.save)F.push({fillColor:{...o},fontSize:s,fontIsBold:p});else if(b===e.restore){const l=F.pop();l&&(o=l.fillColor,s=l.fontSize,p=l.fontIsBold)}else if(b===e.setFillRGBColor){const l=Number(k[0])|0,h=Number(k[1])|0,R=Number(k[2])|0;isFinite(l)&&isFinite(h)&&isFinite(R)&&(o={r:l,g:h,b:R})}else if(b===e.setFillGray){const l=Number(k[0]);if(isFinite(l)){const h=Math.max(0,Math.min(255,Math.round(l*255)));o={r:h,g:h,b:h}}}else if(b===e.setFont){const l=Number(k[1]);isFinite(l)&&l>0&&(s=l);const h=String(k[0]??"");p=/-?(Bold|Black|Heavy)/i.test(h)}else if(b===e.showText||b===e.showSpacedText||b===e.nextLineShowText||b===e.nextLineSetSpacingShowText){n.textItems++;const l=.2126*o.r+.7152*o.g+.0722*o.b;if(Math.abs(l-$)<1){n.itemsSkippedBgOnly++;continue}n.itemsSampled++;const h=le(s,p),R=de(h),y=ce(o,S);(n.bestObservedRatio===null||y>n.bestObservedRatio)&&(n.bestObservedRatio=y),y<R&&(n.failingRuns++,(n.worstRatio===null||y<n.worstRatio)&&(n.worstRatio=y))}}return n}async function pe(t,r){var q,Q;const n=await ue();if("error"in n)return{ok:!1,source:r,findings:[],pageCount:null,fatalError:`pdfjs failed to load in offscreen document: ${n.error}`};const e=n;let i;try{i=await e.getDocument({data:t,verbosity:0,disableFontFace:!0,useSystemFonts:!1}).promise}catch(u){return{ok:!0,source:r,findings:[{ruleId:"pdf-structure-tree-unparseable",impact:"serious",wcagCriterion:"1.3.1",description:`pdfjs could not open the PDF: ${u instanceof Error?u.message:String(u)}. Usually means encrypted, malformed, or non-standard structure.`,failureSummary:"Try opening the PDF in a recent Acrobat Reader — if it opens there but fails the extension audit, the PDF uses uncommon encoding pdfjs cannot handle. If it fails everywhere the source document needs to be regenerated."}],pageCount:null}}const o=i.numPages;let s=!1;try{const u=await i.getOutline();s=Array.isArray(u)&&u.length>0}catch{}const p=Z();let F=0,S=0,$=0,A=0,x=0,v=0,m=null;const b=[];let k=0,l=0;const h=[],R=[];for(let u=1;u<=o;u++){let P;try{P=await i.getPage(u)}catch{continue}let I=null;try{I=await P.getStructTree()}catch{}I?K(I,u,p):p.bumpRule("pdf-untagged-content",u);try{const a=await P.getAnnotations();if((a??[]).filter(d=>d.subtype==="Widget").length>0){S++,F+=ee(a);for(const d of te(a,u))R.push(d)}}catch{}let c=null,E;try{c=await P.getTextContent();const a=(c==null?void 0:c.items)??[];let f=0;for(const d of a)f+=((d==null?void 0:d.str)??"").length;$+=f}catch(a){A++,E=a instanceof Error?a.message:String(a)}if(c!=null&&c.items&&c.items.length>0){const a=[];for(const f of c.items){const d=f.transform;if(!d||d.length<6)continue;const C=Math.abs(d[3]??0);C>0&&(f.str??"").trim()&&a.push(C)}if(a.length>=2){const f=new Map;for(const g of a){const w=Math.round(g*2)/2;f.set(w,(f.get(w)??0)+1)}let d=1/0,C=-1;for(const[g,w]of f)(w>C||w===C&&g<d)&&(C=w,d=g);const T=d*1.2;for(let g=0;g<c.items.length;g++){const w=c.items[g],D=w.transform;if(!D||D.length<6)continue;const H=Math.abs(D[3]??0),_=(w.str??"").trim();if(!_||H<T||_.length>200)continue;let O="";for(let L=g+1;L<c.items.length&&O.length<800;L++){const M=(((q=c.items[L])==null?void 0:q.str)??"").trim();if(!M)continue;const B=(Q=c.items[L])==null?void 0:Q.transform;if(B&&B.length>=6&&Math.abs(B[3]??0)>=T&&M.length<200)break;O+=(O?" ":"")+M}O.length!==0&&h.push({pageNum:u,headingText:_,sectionContent:O.slice(0,800)})}}}if(c!=null&&c.items&&c.items.length>=2){let a=0;for(let f=1;f<c.items.length;f++){const d=c.items[f-1],C=c.items[f],T=d.transform,g=C.transform;if(!T||T.length<6||!g||g.length<6||!(C.str??"").trim()||!(d.str??"").trim())continue;const w=T[5],D=g[5],H=Math.abs(g[3])||12;D-w>2*H&&a++}a>0&&(k+=a,l++)}try{const a=await ge(P,e);b.push({page:u,...a,...E?{textContentError:E}:{}}),a.failingRuns>0&&(x+=a.failingRuns,v++,a.worstRatio!==null&&(m===null||a.worstRatio<m)&&(m=a.worstRatio))}catch{}}const y=re(p),N=ne(F,S);N&&y.push(N);const W=ae(o,s);W&&y.push(W);const z=oe($,o,A===o);z&&y.push(z);const G=ie(v,x,m);G&&y.push(G);const j=se(k,l);return j&&y.push(j),{ok:!0,source:r,findings:y,pageCount:o,perPageContrast:b,aiCandidates:{figureAltTexts:p.figureAltCandidates,headings:h,formLabels:R}}}chrome.runtime.onMessage.addListener((t,r,n)=>{const e=t;if(!e||e.type!=="OFFSCREEN_PDF_AUDIT_REQUEST")return!1;const i=typeof e.url=="string"?e.url:"",o=typeof e.maxBytes=="number"?e.maxBytes:16*1024*1024;return(async()=>{let s;try{s=await fe(i,o)}catch(F){s={ok:!1,source:i,findings:[],pageCount:null,fatalError:`Offscreen audit threw: ${F instanceof Error?F.message:String(F)}`}}const p={type:"OFFSCREEN_PDF_AUDIT_RESPONSE",ok:s.ok,source:s.source,findings:s.findings,pageCount:s.pageCount,...s.fatalError?{fatalError:s.fatalError}:{},...s.perPageContrast?{_perPageContrast:s.perPageContrast}:{},...s.aiCandidates?{aiCandidates:s.aiCandidates}:{}};n(p)})(),!0});
|