@wcag-checkr/ci 1.0.0-rc.98 → 1.0.0
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-C_dGDDCo.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-B-MMXqXA.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-BmQF2Qi9.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-DjD6Nlor.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-DvjbA4nG.js +1 -0
- package/dist/assets/scheduled-audit-runner-ZCuDk8-r.js +2019 -0
- package/dist/assets/service-worker.ts-CvO1EqpM.js +2 -0
- package/dist/assets/side-panel-Cq-w2yTn.css +1 -0
- package/dist/assets/side-panel-DaVp_XgU.js +4 -0
- package/dist/assets/site-report-renderer-MWuVmKOh.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-C2WBadbU.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-DDYcXAe7.js +0 -19
- package/dist/assets/crash-reporter-Dc5lvxvY.js +0 -4
- package/dist/assets/devtools-panel-CSy65hq-.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-D-KXUwm8.js +0 -129
- package/dist/assets/options-Byz5A0JD.js +0 -6
- package/dist/assets/parallel-tab-flow-BUjkjlHH.js +0 -1
- package/dist/assets/service-worker.ts-DwSYhM1S.js +0 -954
- package/dist/assets/side-panel-DIo5JGlH.js +0 -1
- package/dist/assets/site-report-renderer-D8y25osg.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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./modulepreload-polyfill-B5Qt9EMX.js";import{c as t,j as r,R as e}from"./styles-DhnON7zr.js";import{E as i,A as s}from"./ErrorBoundary-C2WBadbU.js";import{i as m}from"./crash-reporter-Dc5lvxvY.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./state-BIsozXtc.js";import"./preload-helper-D7HrI6pR.js";import"./forensic-log-D-KXUwm8.js";m("side-panel");const o=document.getElementById("root");if(!o)throw new Error("side-panel: #root not found");t(o).render(r.jsx(e.StrictMode,{children:r.jsx(i,{children:r.jsx(s,{})})}));
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import{X as c,R as g}from"./forensic-log-D-KXUwm8.js";import"./crash-reporter-Dc5lvxvY.js";import"./state-BIsozXtc.js";const n={A:"#16a34a",B:"#65a30d",C:"#ca8a04",D:"#dc2626",F:"#7f1d1d"},x={low:"#16a34a",moderate:"#ca8a04",high:"#dc2626",critical:"#7f1d1d"},s={critical:"#7f1d1d",serious:"#dc2626",moderate:"#ca8a04",minor:"#65a30d"};function o(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function r(t){if(t<1e3)return`${t}ms`;const i=Math.round(t/100)/10;if(i<60)return`${i}s`;const e=Math.floor(i/60),a=Math.round(i-e*60);return`${e}m ${a}s`}function f(t){return`<span style="display:inline-block;background:${n[t]};color:#fff;font-weight:700;padding:2px 10px;border-radius:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;">${t}</span>`}function l(t){return`<span style="display:inline-block;background:${x[t]};color:#fff;font-weight:600;padding:2px 10px;border-radius:12px;font-size:11px;text-transform:uppercase;letter-spacing:0.05em;">${t}</span>`}function h(t){return`<span style="display:inline-block;background:${s[t]};color:#fff;font-weight:600;padding:1px 8px;border-radius:10px;font-size:11px;">${t}</span>`}function m(t){return`
|
|
2
|
-
<section style="background:#0f172a;color:#fff;padding:32px 40px;border-radius:8px;margin-bottom:24px;">
|
|
3
|
-
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:24px;flex-wrap:wrap;">
|
|
4
|
-
<div>
|
|
5
|
-
<p style="margin:0 0 8px;font-size:13px;color:#94a3b8;text-transform:uppercase;letter-spacing:0.08em;">Site-wide audit</p>
|
|
6
|
-
<h1 style="margin:0 0 6px;font-size:24px;">${o(t.startUrl)}</h1>
|
|
7
|
-
<p style="margin:0;font-size:13px;color:#cbd5e1;">
|
|
8
|
-
${t.pagesAudited} page${t.pagesAudited===1?"":"s"} audited
|
|
9
|
-
${t.pagesFailed>0?`· <span style="color:#fca5a5;">${t.pagesFailed} failed</span>`:""}
|
|
10
|
-
· ${r(t.totalDurationMs)}
|
|
11
|
-
· started ${new Date(t.startedAt).toLocaleString()}
|
|
12
|
-
</p>
|
|
13
|
-
</div>
|
|
14
|
-
<div style="text-align:right;">
|
|
15
|
-
<div style="display:inline-block;background:${n[t.siteGrade]};color:#fff;font-size:64px;font-weight:800;width:96px;height:96px;line-height:96px;text-align:center;border-radius:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;">${t.siteGrade}</div>
|
|
16
|
-
<div style="margin-top:8px;">${l(t.siteRisk)}</div>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
<div style="margin-top:20px;display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;">
|
|
20
|
-
${["critical","serious","moderate","minor"].map(i=>`
|
|
21
|
-
<div style="background:#1e293b;padding:10px 14px;border-radius:6px;">
|
|
22
|
-
<div style="font-size:11px;color:#94a3b8;text-transform:uppercase;letter-spacing:0.06em;">${i}</div>
|
|
23
|
-
<div style="font-size:24px;font-weight:700;color:${s[i]};">${t.totals[i]}</div>
|
|
24
|
-
</div>
|
|
25
|
-
`).join("")}
|
|
26
|
-
<div style="background:#1e293b;padding:10px 14px;border-radius:6px;">
|
|
27
|
-
<div style="font-size:11px;color:#94a3b8;text-transform:uppercase;letter-spacing:0.06em;">Unique violations</div>
|
|
28
|
-
<div style="font-size:24px;font-weight:700;color:#fff;">${t.totalUniqueViolations}</div>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
<p style="margin:18px 0 0;font-size:12px;color:#cbd5e1;line-height:1.5;">
|
|
32
|
-
<strong>Grade:</strong> ${o(c[t.siteGrade])}<br/>
|
|
33
|
-
<strong>Risk:</strong> ${o(g[t.siteRisk])}
|
|
34
|
-
</p>
|
|
35
|
-
</section>
|
|
36
|
-
`}function u(t){return t.length===0?`
|
|
37
|
-
<section style="margin-bottom:24px;">
|
|
38
|
-
<h2 style="margin:0 0 8px;font-size:18px;">Top site-wide violations</h2>
|
|
39
|
-
<p style="color:#16a34a;font-weight:500;">No violations detected. (Manual checks still recommended — automation catches ~30–50% of WCAG.)</p>
|
|
40
|
-
</section>
|
|
41
|
-
`:`
|
|
42
|
-
<section style="margin-bottom:24px;">
|
|
43
|
-
<h2 style="margin:0 0 8px;font-size:18px;">Top site-wide violations</h2>
|
|
44
|
-
<p style="color:#64748b;font-size:13px;margin:0 0 12px;">
|
|
45
|
-
Sorted by blast radius — fix these first to clear the most pages with the least work.
|
|
46
|
-
</p>
|
|
47
|
-
<table style="width:100%;border-collapse:collapse;font-size:13px;">
|
|
48
|
-
<thead>
|
|
49
|
-
<tr style="background:#f1f5f9;text-align:left;">
|
|
50
|
-
<th style="padding:8px 12px;">Rule</th>
|
|
51
|
-
<th style="padding:8px 12px;">Impact</th>
|
|
52
|
-
<th style="padding:8px 12px;text-align:right;">URLs affected</th>
|
|
53
|
-
<th style="padding:8px 12px;text-align:right;">Total nodes</th>
|
|
54
|
-
<th style="padding:8px 12px;">Description</th>
|
|
55
|
-
</tr>
|
|
56
|
-
</thead>
|
|
57
|
-
<tbody>${t.slice(0,20).map(e=>`
|
|
58
|
-
<tr style="border-top:1px solid #e2e8f0;">
|
|
59
|
-
<td style="padding:8px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;">${o(e.ruleId)}</td>
|
|
60
|
-
<td style="padding:8px 12px;">${h(e.impact)}</td>
|
|
61
|
-
<td style="padding:8px 12px;text-align:right;font-weight:600;">${e.urlsAffected}</td>
|
|
62
|
-
<td style="padding:8px 12px;text-align:right;">${e.totalOccurrences}</td>
|
|
63
|
-
<td style="padding:8px 12px;font-size:13px;color:#475569;">${o(e.description)}</td>
|
|
64
|
-
</tr>
|
|
65
|
-
`).join("")}</tbody>
|
|
66
|
-
</table>
|
|
67
|
-
</section>
|
|
68
|
-
`}function y(t){const i=t.map((e,a)=>`
|
|
69
|
-
<tr style="border-top:1px solid #e2e8f0;">
|
|
70
|
-
<td style="padding:8px 12px;color:#64748b;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;">${a+1}</td>
|
|
71
|
-
<td style="padding:8px 12px;">${f(e.grade)}</td>
|
|
72
|
-
<td style="padding:8px 12px;">${l(e.risk)}</td>
|
|
73
|
-
<td style="padding:8px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;word-break:break-all;">
|
|
74
|
-
${o(e.url)}
|
|
75
|
-
${e.error?`<div style="color:#dc2626;font-size:11px;margin-top:4px;">⚠ ${o(e.error)}</div>`:""}
|
|
76
|
-
</td>
|
|
77
|
-
<td style="padding:8px 12px;text-align:right;color:${e.totals.critical>0?s.critical:"#94a3b8"};font-weight:${e.totals.critical>0?700:400};">${e.totals.critical}</td>
|
|
78
|
-
<td style="padding:8px 12px;text-align:right;color:${e.totals.serious>0?s.serious:"#94a3b8"};font-weight:${e.totals.serious>0?700:400};">${e.totals.serious}</td>
|
|
79
|
-
<td style="padding:8px 12px;text-align:right;color:#475569;">${e.totals.moderate}</td>
|
|
80
|
-
<td style="padding:8px 12px;text-align:right;color:#475569;">${e.totals.minor}</td>
|
|
81
|
-
<td style="padding:8px 12px;text-align:right;color:#94a3b8;font-size:12px;">${r(e.durationMs)}</td>
|
|
82
|
-
</tr>
|
|
83
|
-
`).join("");return`
|
|
84
|
-
<section style="margin-bottom:24px;">
|
|
85
|
-
<h2 style="margin:0 0 8px;font-size:18px;">Pages (${t.length})</h2>
|
|
86
|
-
<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Sorted worst-first. Errored pages bubble to the top with grade F.</p>
|
|
87
|
-
<table style="width:100%;border-collapse:collapse;font-size:13px;">
|
|
88
|
-
<thead>
|
|
89
|
-
<tr style="background:#f1f5f9;text-align:left;">
|
|
90
|
-
<th style="padding:8px 12px;">#</th>
|
|
91
|
-
<th style="padding:8px 12px;">Grade</th>
|
|
92
|
-
<th style="padding:8px 12px;">Risk</th>
|
|
93
|
-
<th style="padding:8px 12px;">URL</th>
|
|
94
|
-
<th style="padding:8px 12px;text-align:right;">Critical</th>
|
|
95
|
-
<th style="padding:8px 12px;text-align:right;">Serious</th>
|
|
96
|
-
<th style="padding:8px 12px;text-align:right;">Moderate</th>
|
|
97
|
-
<th style="padding:8px 12px;text-align:right;">Minor</th>
|
|
98
|
-
<th style="padding:8px 12px;text-align:right;">Time</th>
|
|
99
|
-
</tr>
|
|
100
|
-
</thead>
|
|
101
|
-
<tbody>${i}</tbody>
|
|
102
|
-
</table>
|
|
103
|
-
</section>
|
|
104
|
-
`}function b(t){const i=t.pages.length||1;return`
|
|
105
|
-
<section style="margin-bottom:24px;">
|
|
106
|
-
<h2 style="margin:0 0 8px;font-size:18px;">Pages by grade</h2>
|
|
107
|
-
${["A","B","C","D","F"].map(a=>{const d=t.pagesByGrade[a],p=d/i*100;return`
|
|
108
|
-
<div style="display:flex;align-items:center;gap:10px;font-size:13px;margin:4px 0;">
|
|
109
|
-
<div style="width:24px;font-weight:700;color:${n[a]};font-family:ui-monospace,SFMono-Regular,Menlo,monospace;">${a}</div>
|
|
110
|
-
<div style="flex:1;background:#e2e8f0;border-radius:3px;height:18px;overflow:hidden;">
|
|
111
|
-
<div style="height:100%;width:${p}%;background:${n[a]};"></div>
|
|
112
|
-
</div>
|
|
113
|
-
<div style="width:60px;text-align:right;color:#475569;">${d} page${d===1?"":"s"}</div>
|
|
114
|
-
</div>
|
|
115
|
-
`}).join("")}
|
|
116
|
-
</section>
|
|
117
|
-
`}function k(t){return`<!doctype html>
|
|
118
|
-
<html lang="en">
|
|
119
|
-
<head>
|
|
120
|
-
<meta charset="utf-8" />
|
|
121
|
-
<title>WCAG site audit · ${o(t.startUrl)}</title>
|
|
122
|
-
<meta name="generator" content="wcagcheckr — site mode" />
|
|
123
|
-
<style>
|
|
124
|
-
body { margin: 0; background: #f8fafc; color: #0f172a; font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif; }
|
|
125
|
-
.container { max-width: 1100px; margin: 0 auto; padding: 24px 32px 80px; }
|
|
126
|
-
h2 { color: #0f172a; }
|
|
127
|
-
p { margin: 4px 0; }
|
|
128
|
-
table { background: #fff; border: 1px solid #e2e8f0; border-radius: 6px; overflow: hidden; }
|
|
129
|
-
@media print {
|
|
130
|
-
body { background: #fff; }
|
|
131
|
-
.container { padding: 0; }
|
|
132
|
-
}
|
|
133
|
-
</style>
|
|
134
|
-
</head>
|
|
135
|
-
<body>
|
|
136
|
-
<div class="container">
|
|
137
|
-
${m(t)}
|
|
138
|
-
${u(t.topViolations)}
|
|
139
|
-
${b(t)}
|
|
140
|
-
${y(t.pages)}
|
|
141
|
-
<footer style="margin-top:32px;padding-top:16px;border-top:1px solid #e2e8f0;color:#94a3b8;font-size:12px;">
|
|
142
|
-
Generated by wcagcheckr · site-mode crawl from ${o(t.startUrl)} · finished ${new Date(t.finishedAt).toLocaleString()}.
|
|
143
|
-
<br/>This report covers automated WCAG 2.0/2.1/2.2 AA + best-practice rules. Automation catches ~30–50% of WCAG violations; full conformance requires manual screen-reader testing (see MANUAL_A11Y_CHECKLIST.md).
|
|
144
|
-
</footer>
|
|
145
|
-
</div>
|
|
146
|
-
</body>
|
|
147
|
-
</html>`}export{k as renderSiteReportHtml};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{c as m}from"./crash-reporter-Dc5lvxvY.js";const U=14,o={maxComponents:1/0,maxBaselines:1/0,stateMatrix:"all",storybookAutoIterate:!0,exportJson:!0,exportSarif:!0,exportJunit:!0,cloudSync:!0,forensicAnchoring:!0},p={trial:{...o},free:{...o},solo:{...o},team:{...o}},_={solo:{monthlyUsd:29,yearlyUsd:290,singleMonthUsd:37},team:{fiveSeatMonthlyUsd:149,fifteenSeatMonthlyUsd:299,fiveSeatYearlyUsd:1490,fifteenSeatYearlyUsd:2990}};let n=null;function k(t){n=t}function T(t){return(n==null?void 0:n[t])??p[t]}function E(t,e){return T(t)[e]}const d="deviceId";async function f(){let e=(await chrome.storage.local.get(d))[d];return e||(e=crypto.randomUUID(),await chrome.storage.local.set({[d]:e}),e)}const r=m("license-seat-client"),i="https://api.wcagcheckr.com",c="wcagcheckr",l=1e4;async function y(t){const e=await f();try{const a=await fetch(`${i}/v1/products/${c}/license/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:t,deviceId:e,userAgent:navigator.userAgent.slice(0,255)}),signal:AbortSignal.timeout(l)}),s=await a.json().catch(()=>null);return a.status===409&&s&&"error"in s&&s.error==="seat_cap_reached"?{ok:!1,reason:"cap-reached",seatsUsed:s.seatsUsed??0,seatsTotal:s.seatsTotal??0,hint:s.hint}:a.status===404?{ok:!1,reason:"not-found"}:a.ok?{ok:!0,seatsUsed:(s==null?void 0:s.seatsUsed)??0,seatsTotal:(s==null?void 0:s.seatsTotal)??null,overCapacity:(s==null?void 0:s.overCapacity)===!0}:(r.warn(`seat claim http ${a.status}`,s),{ok:!1,reason:"network",message:`HTTP ${a.status}`})}catch(a){return r.warn("seat claim failed",a),{ok:!1,reason:"network",message:a instanceof Error?a.message:String(a)}}}async function v(t){try{const e=await fetch(`${i}/v1/products/${c}/license/${encodeURIComponent(t)}/seats`,{method:"GET",headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(l)});return e.ok?await e.json():(r.warn(`listTeamSeats http ${e.status}`),null)}catch(e){return r.warn("listTeamSeats failed",e),null}}async function w(t,e){try{return(await fetch(`${i}/v1/products/${c}/license/${encodeURIComponent(t)}/seats/${encodeURIComponent(e)}`,{method:"DELETE",headers:{authorization:`Bearer ${t}`},signal:AbortSignal.timeout(l)})).ok}catch(a){return r.warn("revokeTeamSeat failed",a),!1}}async function A(t){const e=await f();try{return(await fetch(`${i}/v1/products/${c}/license/release`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({licenseToken:t,deviceId:e}),signal:AbortSignal.timeout(l)})).ok}catch(a){return r.warn("seat release failed",a),!1}}const u=[{id:"mobile",label:"Mobile (375×667)",width:375,height:667,deviceScaleFactor:2,mobile:!0},{id:"tablet",label:"Tablet (768×1024)",width:768,height:1024,deviceScaleFactor:2,mobile:!0},{id:"desktop",label:"Desktop (1280×800)",width:1280,height:800,deviceScaleFactor:1,mobile:!1}],h={pseudoStates:["default","hover","focus","disabled"],ariaVariations:[],themes:["light","dark"],directions:["ltr"],breakpoints:["desktop"],breakpointPresets:u},S={pseudoStates:["default","hover","focus","focus-visible","active","disabled"],ariaVariations:[],themes:["light","dark","forced-colors-active"],directions:["ltr","rtl"],breakpoints:["mobile","desktop"],breakpointPresets:u},g={pseudoStates:["default"],ariaVariations:[],themes:["light"],directions:["ltr"],breakpoints:["desktop"],breakpointPresets:u},b=[{id:"default-subset",name:"Default subset",matrix:h},{id:"full-matrix",name:"Full matrix",matrix:S}],R=Object.freeze(Object.defineProperty({__proto__:null,BUILT_IN_PRESETS:b,DEFAULT_BREAKPOINT_PRESETS:u,DEFAULT_STATE_MATRIX_SETTINGS:h,FULL_STATE_MATRIX_SETTINGS:S,QUICK_SCAN_MATRIX_SETTINGS:g},Symbol.toStringTag,{value:"Module"}));export{b as B,u as D,_ as P,p as T,w as a,h as b,y as c,U as d,R as e,f as g,E as i,v as l,A as r,k as s};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.right-0\.5{right:.125rem}.top-0\.5{top:.125rem}.top-1\/2{top:50%}.top-3{top:.75rem}.top-full{top:100%}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.-m-4{margin:-1rem}.m-0{margin:0}.-mx-3{margin-left:-.75rem;margin-right:-.75rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.-mb-px{margin-bottom:-1px}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-40{max-height:10rem}.max-h-96{max-height:24rem}.max-h-\[420px\]{max-height:420px}.max-h-\[60vh\]{max-height:60vh}.min-h-\[24px\]{min-height:24px}.min-h-\[540px\]{min-height:540px}.w-1{width:.25rem}.w-1\/3{width:33.333333%}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[min\(28rem\,90vw\)\]{width:min(28rem,90vw)}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[200px\]{min-width:200px}.min-w-\[24px\]{min-width:24px}.max-w-2xl{max-width:42rem}.max-w-\[180px\]{max-width:180px}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bell-pulse{0%,to{transform:rotate(0)}20%{transform:rotate(12deg)}40%{transform:rotate(-10deg)}60%{transform:rotate(8deg)}80%{transform:rotate(-6deg)}}.animate-bell-pulse{animation:bell-pulse .9s ease-in-out}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-y{resize:vertical}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-\[1fr_1fr_70px_70px_auto\]{grid-template-columns:1fr 1fr 70px 70px auto}.grid-cols-\[1fr_1fr_auto\]{grid-template-columns:1fr 1fr auto}.grid-cols-\[1fr_70px_70px_auto_auto\]{grid-template-columns:1fr 70px 70px auto auto}.grid-cols-\[400px_1fr\]{grid-template-columns:400px 1fr}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[max-content_1fr\]{grid-template-columns:max-content 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1{row-gap:.25rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-slate-100>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(241 245 249 / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-b{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity, 1))}.border-amber-300{--tw-border-opacity: 1;border-color:rgb(252 211 77 / var(--tw-border-opacity, 1))}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-brand-500{--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity, 1))}.border-emerald-100{--tw-border-opacity: 1;border-color:rgb(209 250 229 / var(--tw-border-opacity, 1))}.border-emerald-200{--tw-border-opacity: 1;border-color:rgb(167 243 208 / var(--tw-border-opacity, 1))}.border-emerald-300{--tw-border-opacity: 1;border-color:rgb(110 231 183 / var(--tw-border-opacity, 1))}.border-emerald-400{--tw-border-opacity: 1;border-color:rgb(52 211 153 / var(--tw-border-opacity, 1))}.border-emerald-500{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity, 1))}.border-emerald-600{--tw-border-opacity: 1;border-color:rgb(5 150 105 / var(--tw-border-opacity, 1))}.border-orange-200{--tw-border-opacity: 1;border-color:rgb(254 215 170 / var(--tw-border-opacity, 1))}.border-orange-300{--tw-border-opacity: 1;border-color:rgb(253 186 116 / var(--tw-border-opacity, 1))}.border-purple-200{--tw-border-opacity: 1;border-color:rgb(233 213 255 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-rose-100{--tw-border-opacity: 1;border-color:rgb(255 228 230 / var(--tw-border-opacity, 1))}.border-rose-200{--tw-border-opacity: 1;border-color:rgb(254 205 211 / var(--tw-border-opacity, 1))}.border-rose-300{--tw-border-opacity: 1;border-color:rgb(253 164 175 / var(--tw-border-opacity, 1))}.border-rose-400{--tw-border-opacity: 1;border-color:rgb(251 113 133 / var(--tw-border-opacity, 1))}.border-rose-500{--tw-border-opacity: 1;border-color:rgb(244 63 94 / var(--tw-border-opacity, 1))}.border-rose-600{--tw-border-opacity: 1;border-color:rgb(225 29 72 / var(--tw-border-opacity, 1))}.border-sky-200{--tw-border-opacity: 1;border-color:rgb(186 230 253 / var(--tw-border-opacity, 1))}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-slate-300{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity, 1))}.border-yellow-200{--tw-border-opacity: 1;border-color:rgb(254 240 138 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-amber-100{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.bg-amber-200{--tw-bg-opacity: 1;background-color:rgb(253 230 138 / var(--tw-bg-opacity, 1))}.bg-amber-50{--tw-bg-opacity: 1;background-color:rgb(255 251 235 / var(--tw-bg-opacity, 1))}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-black\/40{background-color:#0006}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-brand-100{--tw-bg-opacity: 1;background-color:rgb(224 231 255 / var(--tw-bg-opacity, 1))}.bg-brand-50{--tw-bg-opacity: 1;background-color:rgb(238 242 255 / var(--tw-bg-opacity, 1))}.bg-brand-50\/40{background-color:#eef2ff66}.bg-brand-500{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity, 1))}.bg-emerald-100{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity, 1))}.bg-emerald-200{--tw-bg-opacity: 1;background-color:rgb(167 243 208 / var(--tw-bg-opacity, 1))}.bg-emerald-50{--tw-bg-opacity: 1;background-color:rgb(236 253 245 / var(--tw-bg-opacity, 1))}.bg-emerald-50\/50{background-color:#ecfdf580}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity, 1))}.bg-indigo-100{--tw-bg-opacity: 1;background-color:rgb(224 231 255 / var(--tw-bg-opacity, 1))}.bg-lime-100{--tw-bg-opacity: 1;background-color:rgb(236 252 203 / var(--tw-bg-opacity, 1))}.bg-lime-500{--tw-bg-opacity: 1;background-color:rgb(132 204 22 / var(--tw-bg-opacity, 1))}.bg-orange-100{--tw-bg-opacity: 1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-orange-50{--tw-bg-opacity: 1;background-color:rgb(255 247 237 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-purple-50{--tw-bg-opacity: 1;background-color:rgb(250 245 255 / var(--tw-bg-opacity, 1))}.bg-purple-500{--tw-bg-opacity: 1;background-color:rgb(168 85 247 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-rose-100{--tw-bg-opacity: 1;background-color:rgb(255 228 230 / var(--tw-bg-opacity, 1))}.bg-rose-200{--tw-bg-opacity: 1;background-color:rgb(254 205 211 / var(--tw-bg-opacity, 1))}.bg-rose-50{--tw-bg-opacity: 1;background-color:rgb(255 241 242 / var(--tw-bg-opacity, 1))}.bg-rose-50\/40{background-color:#fff1f266}.bg-rose-50\/50{background-color:#fff1f280}.bg-rose-500{--tw-bg-opacity: 1;background-color:rgb(244 63 94 / var(--tw-bg-opacity, 1))}.bg-rose-600{--tw-bg-opacity: 1;background-color:rgb(225 29 72 / var(--tw-bg-opacity, 1))}.bg-sky-100{--tw-bg-opacity: 1;background-color:rgb(224 242 254 / var(--tw-bg-opacity, 1))}.bg-sky-50{--tw-bg-opacity: 1;background-color:rgb(240 249 255 / var(--tw-bg-opacity, 1))}.bg-slate-100{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.bg-slate-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.bg-slate-300{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.bg-slate-50{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.bg-slate-50\/50{background-color:#f8fafc80}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-violet-100{--tw-bg-opacity: 1;background-color:rgb(237 233 254 / var(--tw-bg-opacity, 1))}.bg-violet-500{--tw-bg-opacity: 1;background-color:rgb(139 92 246 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/60{background-color:#fff9}.bg-yellow-100{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity, 1))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity, 1))}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-brand-50{--tw-gradient-from: #eef2ff var(--tw-gradient-from-position);--tw-gradient-to: rgb(238 242 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-white{--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #fff var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-white{--tw-gradient-to: #fff var(--tw-gradient-to-position)}.p-0{padding:0}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pr-2{padding-right:.5rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.not-italic{font-style:normal}.ordinal{--tw-ordinal: ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.06em\]{letter-spacing:.06em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity, 1))}.text-amber-300{--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity, 1))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-amber-800{--tw-text-opacity: 1;color:rgb(146 64 14 / var(--tw-text-opacity, 1))}.text-amber-900{--tw-text-opacity: 1;color:rgb(120 53 15 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-900{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.text-brand-600{--tw-text-opacity: 1;color:rgb(67 56 202 / var(--tw-text-opacity, 1))}.text-brand-700{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity, 1))}.text-emerald-100{--tw-text-opacity: 1;color:rgb(209 250 229 / var(--tw-text-opacity, 1))}.text-emerald-300{--tw-text-opacity: 1;color:rgb(110 231 183 / var(--tw-text-opacity, 1))}.text-emerald-700{--tw-text-opacity: 1;color:rgb(4 120 87 / var(--tw-text-opacity, 1))}.text-emerald-800{--tw-text-opacity: 1;color:rgb(6 95 70 / var(--tw-text-opacity, 1))}.text-emerald-900{--tw-text-opacity: 1;color:rgb(6 78 59 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-indigo-700{--tw-text-opacity: 1;color:rgb(67 56 202 / var(--tw-text-opacity, 1))}.text-lime-700{--tw-text-opacity: 1;color:rgb(77 124 15 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity: 1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-orange-800{--tw-text-opacity: 1;color:rgb(154 52 18 / var(--tw-text-opacity, 1))}.text-orange-900{--tw-text-opacity: 1;color:rgb(124 45 18 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-red-800{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity, 1))}.text-rose-500{--tw-text-opacity: 1;color:rgb(244 63 94 / var(--tw-text-opacity, 1))}.text-rose-600{--tw-text-opacity: 1;color:rgb(225 29 72 / var(--tw-text-opacity, 1))}.text-rose-700{--tw-text-opacity: 1;color:rgb(190 18 60 / var(--tw-text-opacity, 1))}.text-rose-800{--tw-text-opacity: 1;color:rgb(159 18 57 / var(--tw-text-opacity, 1))}.text-rose-900{--tw-text-opacity: 1;color:rgb(136 19 55 / var(--tw-text-opacity, 1))}.text-rose-900\/90{color:#881337e6}.text-sky-700{--tw-text-opacity: 1;color:rgb(3 105 161 / var(--tw-text-opacity, 1))}.text-sky-800{--tw-text-opacity: 1;color:rgb(7 89 133 / var(--tw-text-opacity, 1))}.text-sky-900{--tw-text-opacity: 1;color:rgb(12 74 110 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-800{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-700{--tw-text-opacity: 1;color:rgb(161 98 7 / var(--tw-text-opacity, 1))}.text-yellow-800{--tw-text-opacity: 1;color:rgb(133 77 14 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.decoration-slate-400{text-decoration-color:#94a3b8}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.opacity-50{opacity:.5}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_2px_8px_-2px_rgba\(120\,53\,15\,0\.12\)\]{--tw-shadow: 0 2px 8px -2px rgba(120,53,15,.12);--tw-shadow-colored: 0 2px 8px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_2px_8px_-2px_rgba\(159\,18\,57\,0\.16\)\]{--tw-shadow: 0 2px 8px -2px rgba(159,18,57,.16);--tw-shadow-colored: 0 2px 8px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_2px_8px_-2px_rgba\(6\,78\,59\,0\.12\)\]{--tw-shadow: 0 2px 8px -2px rgba(6,78,59,.12);--tw-shadow-colored: 0 2px 8px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_4px_16px_-4px_rgba\(31\,41\,55\,0\.14\)\]{--tw-shadow: 0 4px 16px -4px rgba(31,41,55,.14);--tw-shadow-colored: 0 4px 16px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-brand-500\/30{--tw-ring-color: rgb(79 70 229 / .3)}.ring-rose-300{--tw-ring-opacity: 1;--tw-ring-color: rgb(253 164 175 / var(--tw-ring-opacity, 1))}.ring-white{--tw-ring-opacity: 1;--tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity, 1))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}html,body,#root{height:100%}:focus-visible{outline:2px solid #3730a3;outline-offset:2px}.last\:border-r-0:last-child{border-right-width:0px}.hover\:border-brand-500:hover{--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity, 1))}.hover\:border-red-300:hover{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.hover\:border-slate-300:hover{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity, 1))}.hover\:border-slate-400:hover{--tw-border-opacity: 1;border-color:rgb(148 163 184 / var(--tw-border-opacity, 1))}.hover\:bg-amber-100:hover{--tw-bg-opacity: 1;background-color:rgb(254 243 199 / var(--tw-bg-opacity, 1))}.hover\:bg-amber-600:hover{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity, 1))}.hover\:bg-brand-100:hover{--tw-bg-opacity: 1;background-color:rgb(224 231 255 / var(--tw-bg-opacity, 1))}.hover\:bg-brand-50:hover{--tw-bg-opacity: 1;background-color:rgb(238 242 255 / var(--tw-bg-opacity, 1))}.hover\:bg-brand-600:hover{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-100:hover{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-50:hover{--tw-bg-opacity: 1;background-color:rgb(236 253 245 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-700:hover{--tw-bg-opacity: 1;background-color:rgb(4 120 87 / var(--tw-bg-opacity, 1))}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:bg-red-700:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.hover\:bg-rose-100:hover{--tw-bg-opacity: 1;background-color:rgb(255 228 230 / var(--tw-bg-opacity, 1))}.hover\:bg-rose-50:hover{--tw-bg-opacity: 1;background-color:rgb(255 241 242 / var(--tw-bg-opacity, 1))}.hover\:bg-rose-600:hover{--tw-bg-opacity: 1;background-color:rgb(225 29 72 / var(--tw-bg-opacity, 1))}.hover\:bg-rose-700:hover{--tw-bg-opacity: 1;background-color:rgb(190 18 60 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-200:hover{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-300:hover{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-700:hover{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-800:hover{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.hover\:bg-white:hover{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.hover\:text-amber-700:hover{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.hover\:text-blue-900:hover{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.hover\:text-brand-600:hover{--tw-text-opacity: 1;color:rgb(67 56 202 / var(--tw-text-opacity, 1))}.hover\:text-emerald-900:hover{--tw-text-opacity: 1;color:rgb(6 78 59 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-red-800:hover{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.hover\:text-red-900:hover{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity, 1))}.hover\:text-rose-600:hover{--tw-text-opacity: 1;color:rgb(225 29 72 / var(--tw-text-opacity, 1))}.hover\:text-rose-700:hover{--tw-text-opacity: 1;color:rgb(190 18 60 / var(--tw-text-opacity, 1))}.hover\:text-rose-900:hover{--tw-text-opacity: 1;color:rgb(136 19 55 / var(--tw-text-opacity, 1))}.hover\:text-slate-700:hover{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.hover\:text-slate-800:hover{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity, 1))}.hover\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.hover\:opacity-70:hover{opacity:.7}.focus\:not-sr-only:focus{position:static;width:auto;height:auto;padding:0;margin:0;overflow:visible;clip:auto;white-space:normal}.focus\:fixed:focus{position:fixed}.focus\:left-2:focus{left:.5rem}.focus\:top-2:focus{top:.5rem}.focus\:z-50:focus{z-index:50}.focus\:rounded:focus{border-radius:.25rem}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.focus\:px-3:focus{padding-left:.75rem;padding-right:.75rem}.focus\:py-1\.5:focus{padding-top:.375rem;padding-bottom:.375rem}.focus\:text-slate-900:focus{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.focus\:shadow:focus{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:outline:focus{outline-style:solid}.focus\:outline-2:focus{outline-width:2px}.focus\:outline-brand-500:focus{outline-color:#4f46e5}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-2:focus-visible{outline-width:2px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.focus-visible\:outline-brand-500:focus-visible{outline-color:#4f46e5}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-slate-50:disabled{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.disabled\:text-slate-500:disabled{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:hover\:bg-white:hover:disabled{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-width:2px}.data-\[state\=active\]\:border-brand-500[data-state=active]{--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity, 1))}.data-\[state\=active\]\:text-brand-700[data-state=active]{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity, 1))}@media (prefers-reduced-motion: reduce){.motion-reduce\:animate-none{animation:none}}@media (min-width: 640px){.sm\:p-6{padding:1.5rem}}
|
package/dist/side-panel/App.tsx
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useStore } from './store';
|
|
3
|
-
// rc.79 — Reverted the rc.72 lazy-load NormalApp routing. Owner mode
|
|
4
|
-
// goes back to using OwnerView (lawfare-risk grade, Quick/Thorough
|
|
5
|
-
// scan depth, USER_RECIPES, full export set, no Suspense boundary).
|
|
6
|
-
// rc.72's NormalApp stripped those features and added a chunk-load
|
|
7
|
-
// step that wasn't there before; the regression wasn't worth the
|
|
8
|
-
// "two code paths" structural symmetry it claimed.
|
|
9
|
-
import {
|
|
10
|
-
wireMessaging,
|
|
11
|
-
refreshBaselineList,
|
|
12
|
-
refreshLicenseTier,
|
|
13
|
-
refreshUserMode,
|
|
14
|
-
startKeepalive,
|
|
15
|
-
loadLastAudit,
|
|
16
|
-
} from './wire-messaging';
|
|
17
|
-
import { primeAuditLauncher } from './audit-launcher';
|
|
18
|
-
import { sendToTab } from '../shared/messaging';
|
|
19
|
-
import { getAuditTargetTabId } from '../shared/active-tab';
|
|
20
|
-
import { loadAcknowledged } from '../shared/acknowledged-findings';
|
|
21
|
-
import { Header } from './components/Header';
|
|
22
|
-
import { AuditControls } from './components/AuditControls';
|
|
23
|
-
import { VisualizerTools } from './components/VisualizerTools';
|
|
24
|
-
import { ProgressBar } from './components/ProgressBar';
|
|
25
|
-
import { MatrixView } from './views/MatrixView';
|
|
26
|
-
import { GeneralReportView } from './views/GeneralReportView';
|
|
27
|
-
import { DeltaView } from './views/DeltaView';
|
|
28
|
-
import { ActivityView } from './views/ActivityView';
|
|
29
|
-
import { GuidedView } from './views/GuidedView';
|
|
30
|
-
import { FlowsView } from './views/FlowsView';
|
|
31
|
-
import { ScorecardView } from './views/ScorecardView';
|
|
32
|
-
import { SiteCrawlPanel } from './components/SiteCrawlPanel';
|
|
33
|
-
import { OnboardingModal } from './components/OnboardingModal';
|
|
34
|
-
import { ErrorBanner } from './components/ErrorBanner';
|
|
35
|
-
import { AiFailureBanner } from './components/AiFailureBanner';
|
|
36
|
-
import { DebuggerBusyModal } from './components/DebuggerBusyModal';
|
|
37
|
-
import { ResumeAuditBanner } from './components/ResumeAuditBanner';
|
|
38
|
-
import { StorybookHint } from './components/StorybookHint';
|
|
39
|
-
import { AuditFooter } from './components/AuditFooter';
|
|
40
|
-
import { ComplianceDisclaimer } from './components/ComplianceDisclaimer';
|
|
41
|
-
import { Announcer } from '../shared/announcer';
|
|
42
|
-
import { UserModeWizard } from './components/UserModeWizard';
|
|
43
|
-
import { OwnerView } from './views/OwnerView';
|
|
44
|
-
import { ForensicLogView } from './views/ForensicLogView';
|
|
45
|
-
import { WcagEmView } from './views/WcagEmView';
|
|
46
|
-
import { UpgradeCard } from './components/UpgradeCard';
|
|
47
|
-
import { CriticalBanner } from './components/MessagesBell';
|
|
48
|
-
|
|
49
|
-
export function App() {
|
|
50
|
-
const view = useStore((s) => s.view);
|
|
51
|
-
const userMode = useStore((s) => s.userMode);
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const port = startKeepalive();
|
|
55
|
-
// Detect runtime context: iframe-overlay vs chrome.sidePanel.
|
|
56
|
-
// ?context=overlay → loaded by modules/sidebar-handle.ts inside the page
|
|
57
|
-
// no query param → loaded by chrome.sidePanel (the fallback during audits)
|
|
58
|
-
// Only the chrome.sidePanel instance opens the tracker port — its disconnect
|
|
59
|
-
// is the SW's signal that the fallback UI just closed, time to restore the
|
|
60
|
-
// in-page overlay.
|
|
61
|
-
const isOverlayContext =
|
|
62
|
-
new URLSearchParams(window.location.search).get('context') === 'overlay';
|
|
63
|
-
const trackerPort = isOverlayContext
|
|
64
|
-
? null
|
|
65
|
-
: chrome.runtime.connect({ name: 'sidepanel-tracker' });
|
|
66
|
-
const off = wireMessaging();
|
|
67
|
-
// Defensive .catch — these are bootstrapping side effects; failures should not
|
|
68
|
-
// surface as uncaught promise rejections in the console.
|
|
69
|
-
// First load: bypass the 24h license cache so the UpgradeCard reads
|
|
70
|
-
// any newly-added server fields (seats counts, cancel-at-period-end,
|
|
71
|
-
// single-month plan code, etc.). Subsequent LICENSE_CHANGED_EVENT
|
|
72
|
-
// refreshes use the cache normally — the SW already invalidates it
|
|
73
|
-
// on every LICENSE_SET_REQUEST.
|
|
74
|
-
refreshLicenseTier({ forceRefresh: true }).catch(() => {});
|
|
75
|
-
refreshBaselineList().catch(() => {});
|
|
76
|
-
refreshUserMode().catch(() => {});
|
|
77
|
-
// Pre-cache windowId so audit-start click handlers can open
|
|
78
|
-
// chrome.sidePanel synchronously (preserves user-gesture context).
|
|
79
|
-
primeAuditLauncher().catch(() => {});
|
|
80
|
-
// Load any persisted audit. Results stay until the user clicks Clear —
|
|
81
|
-
// switching tabs or navigating the audited page no longer wipes them.
|
|
82
|
-
// The Header shows the audited domain so the user always knows which
|
|
83
|
-
// page the displayed results belong to.
|
|
84
|
-
loadLastAudit().catch(() => {});
|
|
85
|
-
// rc.37 — load the user's "acknowledged" matchKeys so every
|
|
86
|
-
// ViolationCard can render the acknowledged pill immediately on
|
|
87
|
-
// mount (in every view, not just Delta).
|
|
88
|
-
loadAcknowledged()
|
|
89
|
-
.then((all) => {
|
|
90
|
-
useStore.getState().setAcknowledgedKeys(new Set(all.map((a) => a.matchKey)));
|
|
91
|
-
})
|
|
92
|
-
.catch(() => {});
|
|
93
|
-
|
|
94
|
-
// Esc inside the side panel clears the highlight pin. The page's own keydown
|
|
95
|
-
// handler (in element-highlighter) only fires when the page has focus.
|
|
96
|
-
const onEsc = (e: KeyboardEvent) => {
|
|
97
|
-
if (e.key !== 'Escape') return;
|
|
98
|
-
const { pinnedMatchKey, setPinned, results } = useStore.getState();
|
|
99
|
-
if (!pinnedMatchKey) return;
|
|
100
|
-
setPinned(null);
|
|
101
|
-
void getAuditTargetTabId().then((tabId) => {
|
|
102
|
-
if (!tabId) return;
|
|
103
|
-
sendToTab(
|
|
104
|
-
tabId,
|
|
105
|
-
{ type: 'HIGHLIGHT_CLEAR_REQUEST', tabId },
|
|
106
|
-
results[0]?.frameId
|
|
107
|
-
).catch(() => {});
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
window.addEventListener('keydown', onEsc);
|
|
111
|
-
|
|
112
|
-
return () => {
|
|
113
|
-
off();
|
|
114
|
-
port.disconnect();
|
|
115
|
-
trackerPort?.disconnect();
|
|
116
|
-
window.removeEventListener('keydown', onEsc);
|
|
117
|
-
};
|
|
118
|
-
}, []);
|
|
119
|
-
|
|
120
|
-
// First launch — show the persona picker. Once chosen it persists in
|
|
121
|
-
// chrome.storage.local; subsequent loads bypass the wizard.
|
|
122
|
-
if (userMode === null) {
|
|
123
|
-
return (
|
|
124
|
-
<>
|
|
125
|
-
<UserModeWizard />
|
|
126
|
-
<Announcer />
|
|
127
|
-
</>
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Owner mode — simplified surface. No view tabs, no visualizers, no IGT.
|
|
132
|
-
// OwnerView holds its own header + footer for the simplified flow.
|
|
133
|
-
// (rc.79 reverted the rc.72 NormalApp routing; OwnerView is the right
|
|
134
|
-
// surface for Owner mode and was working before I broke it.)
|
|
135
|
-
if (userMode === 'owner') {
|
|
136
|
-
return (
|
|
137
|
-
<>
|
|
138
|
-
<OwnerView />
|
|
139
|
-
<DebuggerBusyModal />
|
|
140
|
-
<Announcer />
|
|
141
|
-
</>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Dev mode — full feature surface (everything that existed before).
|
|
146
|
-
return (
|
|
147
|
-
<div className="flex flex-col h-screen bg-slate-50 text-slate-900 text-sm">
|
|
148
|
-
{/* Skip link — visually hidden by default; revealed on focus so keyboard
|
|
149
|
-
users can jump past the header/UpgradeCard chrome straight to the
|
|
150
|
-
audit results. Required for WCAG 2.4.1 (Bypass Blocks) when there
|
|
151
|
-
are many tab stops before the main content. */}
|
|
152
|
-
<a
|
|
153
|
-
href="#main-content"
|
|
154
|
-
className="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-50 focus:bg-white focus:text-slate-900 focus:px-3 focus:py-1.5 focus:rounded focus:shadow focus:outline focus:outline-2 focus:outline-brand-500"
|
|
155
|
-
>
|
|
156
|
-
Skip to main content
|
|
157
|
-
</a>
|
|
158
|
-
<UpgradeCard />
|
|
159
|
-
<CriticalBanner />
|
|
160
|
-
<Header />
|
|
161
|
-
<main
|
|
162
|
-
id="main-content"
|
|
163
|
-
className="flex-1 flex flex-col overflow-hidden"
|
|
164
|
-
aria-label="wcagcheckr"
|
|
165
|
-
>
|
|
166
|
-
<AuditControls />
|
|
167
|
-
<VisualizerTools />
|
|
168
|
-
<StorybookHint />
|
|
169
|
-
<ResumeAuditBanner />
|
|
170
|
-
<ProgressBar />
|
|
171
|
-
<ErrorBanner />
|
|
172
|
-
<AiFailureBanner />
|
|
173
|
-
<div className="flex-1 overflow-y-auto" role="region" aria-label={`${view} view`}>
|
|
174
|
-
{view === 'matrix' && <MatrixView />}
|
|
175
|
-
{view === 'report' && <GeneralReportView />}
|
|
176
|
-
{view === 'delta' && <DeltaView />}
|
|
177
|
-
{view === 'activity' && <ActivityView />}
|
|
178
|
-
{view === 'guided' && <GuidedView />}
|
|
179
|
-
{view === 'flows' && <FlowsView />}
|
|
180
|
-
{view === 'scorecard' && <ScorecardView />}
|
|
181
|
-
{view === 'crawl' && <SiteCrawlPanel />}
|
|
182
|
-
{view === 'forensic' && <ForensicLogView />}
|
|
183
|
-
{view === 'compliance' && <WcagEmView />}
|
|
184
|
-
</div>
|
|
185
|
-
</main>
|
|
186
|
-
<ComplianceDisclaimer />
|
|
187
|
-
<AuditFooter />
|
|
188
|
-
<OnboardingModal />
|
|
189
|
-
<DebuggerBusyModal />
|
|
190
|
-
<Announcer />
|
|
191
|
-
</div>
|
|
192
|
-
);
|
|
193
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# side-panel/
|
|
2
|
-
|
|
3
|
-
The user-facing UI surface. Spec: `phase-1-specs.md` §9 (Zustand) + §11 (panel structure).
|
|
4
|
-
|
|
5
|
-
## Component map
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
App.tsx
|
|
9
|
-
├── Header (title + version + tier badge + Upgrade/License/Settings/Support buttons + view tabs)
|
|
10
|
-
├── AuditControls (mode select, Pick/Audit-all button, Stop button, upgrade-modal trigger)
|
|
11
|
-
├── StorybookHint (banner: shown if active tab is a Storybook page on first open)
|
|
12
|
-
├── ResumeAuditBanner (banner: shown if a previous audit was interrupted)
|
|
13
|
-
├── ProgressBar (shown only while status === 'running')
|
|
14
|
-
├── ErrorBanner (shown only while status === 'failed')
|
|
15
|
-
├── <view> (matrix | delta | scorecard, picked by store.view)
|
|
16
|
-
├── AuditFooter (always-visible: tracked count + last-audit relative time)
|
|
17
|
-
├── OnboardingModal (first-run, explains chrome.debugger banner)
|
|
18
|
-
└── DebuggerBusyModal (DEBUGGER_BUSY events open this)
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## State
|
|
22
|
-
|
|
23
|
-
`store.ts` defines a single Zustand store. Slices: `auditState`, `progress`, `results`, `delta`, `componentId`, `errorMessage`, `baselineList`, `tier`, `view`. Setters are flat methods on the store.
|
|
24
|
-
|
|
25
|
-
`wire-messaging.ts` subscribes the store to messaging events:
|
|
26
|
-
- `AUDIT_PROGRESS_EVENT` → `setProgress` + `setStatus('running')`
|
|
27
|
-
- `AUDIT_COMPLETE_EVENT` → `setResults` + persist to `chrome.storage.local` for next-open hydrate
|
|
28
|
-
- `AUDIT_FAILED_EVENT` → `setError`
|
|
29
|
-
- `LICENSE_CHANGED_EVENT` → re-fetch tier
|
|
30
|
-
- `SCORECARD_UPDATED_EVENT` → re-fetch baseline list
|
|
31
|
-
|
|
32
|
-
`loadLastAudit()` runs on App mount to restore previous results.
|
|
33
|
-
|
|
34
|
-
## ErrorBoundary
|
|
35
|
-
|
|
36
|
-
Wraps the App root in `main.tsx`. Catches React render errors so a single broken view doesn't blank the whole panel. Shows a Reload button that calls `location.reload()`.
|
|
37
|
-
|
|
38
|
-
## Keepalive
|
|
39
|
-
|
|
40
|
-
`startKeepalive()` opens a `chrome.runtime.connect({ name: 'audit-keepalive' })` port on App mount. While this port is open, Chrome won't suspend the service worker — keeps in-flight audits alive.
|
|
41
|
-
|
|
42
|
-
## Reusable bits
|
|
43
|
-
|
|
44
|
-
- `IconButton` — consistent text-button styling for icon-only triggers (settings ⚙, support ?). Required `ariaLabel`.
|
|
45
|
-
- `Modal` — Radix Dialog wrapper with consistent overlay + sizing.
|
|
46
|
-
- `ViolationCard` — used by both Matrix and Delta views.
|
|
47
|
-
- `UpgradePrompt` — used by Header upgrade modal + AuditControls upgrade modal.
|
|
48
|
-
- `format-component-id.ts` — pretty-display of canonical IDs (e.g., `::story:atoms-button--primary` → "Atoms Button / Primary").
|
|
49
|
-
|
|
50
|
-
## Tier gating in the UI
|
|
51
|
-
|
|
52
|
-
Performed locally against `TIER_RULES` from `shared/tier-rules` once `tier` is in the store. No round-trip per gate check.
|
|
53
|
-
|
|
54
|
-
- `AuditControls` blocks "All stories" mode when `!isFeatureAllowed(tier, 'storybookAutoIterate')`
|
|
55
|
-
- `DeltaView` blocks "Accept as baseline" when free + already has 1 baseline; blocks Export when below paid tier
|
|
56
|
-
- `ScorecardView` shows a banner when free user is at the baseline limit
|
|
57
|
-
- `Header` shows the Upgrade CTA when tier is `trial` or `free`
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { openFallbackPanel, primeAuditLauncher } from './audit-launcher';
|
|
3
|
-
|
|
4
|
-
// chrome.sidePanel.open requires a live user-gesture and silently no-ops
|
|
5
|
-
// without one. The contract this test guards: openFallbackPanel runs
|
|
6
|
-
// SYNCHRONOUSLY relative to its caller — it does not await — so when
|
|
7
|
-
// invoked from a click handler the user-gesture is still alive at call
|
|
8
|
-
// time. Any future refactor that awaits inside this function silently
|
|
9
|
-
// breaks the bug fix it backs (Load state on narrow-breakpoint violations
|
|
10
|
-
// must open chrome.sidePanel as fallback before the viewport shrinks the
|
|
11
|
-
// overlay out of existence).
|
|
12
|
-
|
|
13
|
-
describe('openFallbackPanel', () => {
|
|
14
|
-
const openSpy = vi.fn();
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
openSpy.mockReset();
|
|
17
|
-
(globalThis as unknown as { chrome: unknown }).chrome = {
|
|
18
|
-
sidePanel: { open: openSpy.mockResolvedValue(undefined) },
|
|
19
|
-
windows: { getCurrent: vi.fn().mockResolvedValue({ id: 42 }) },
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('does nothing when not primed (no cached windowId)', () => {
|
|
24
|
-
// primeAuditLauncher hasn't run yet → no cached windowId → fallback
|
|
25
|
-
// open should silently no-op rather than throw.
|
|
26
|
-
openFallbackPanel();
|
|
27
|
-
expect(openSpy).not.toHaveBeenCalled();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('opens chrome.sidePanel with the cached windowId after priming', async () => {
|
|
31
|
-
await primeAuditLauncher();
|
|
32
|
-
openFallbackPanel();
|
|
33
|
-
expect(openSpy).toHaveBeenCalledOnce();
|
|
34
|
-
expect(openSpy).toHaveBeenCalledWith({ windowId: 42 });
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('does not throw when chrome.sidePanel is missing (ui-preview / test contexts)', async () => {
|
|
38
|
-
(globalThis as unknown as { chrome: unknown }).chrome = {
|
|
39
|
-
windows: { getCurrent: vi.fn().mockResolvedValue({ id: 7 }) },
|
|
40
|
-
};
|
|
41
|
-
await primeAuditLauncher();
|
|
42
|
-
expect(() => openFallbackPanel()).not.toThrow();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('the call is synchronous — returns before chrome.sidePanel.open resolves', async () => {
|
|
46
|
-
// Promise that never resolves, simulating Chrome holding the open()
|
|
47
|
-
// promise pending. If openFallbackPanel awaited it, the caller would
|
|
48
|
-
// hang forever — the test would time out.
|
|
49
|
-
const neverResolves = new Promise<void>(() => {});
|
|
50
|
-
openSpy.mockReturnValue(neverResolves);
|
|
51
|
-
await primeAuditLauncher();
|
|
52
|
-
// No await — must return immediately even though open() never settles.
|
|
53
|
-
openFallbackPanel();
|
|
54
|
-
expect(openSpy).toHaveBeenCalled();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// Audit launcher — wraps every START_AUDIT / START_SITE_CRAWL dispatch with
|
|
2
|
-
// an opening of chrome.sidePanel as the fallback UI.
|
|
3
|
-
//
|
|
4
|
-
// Why this exists: chrome.debugger viewport emulation during an audit affects
|
|
5
|
-
// everything in the audited tab — including our in-page sidebar overlay
|
|
6
|
-
// (which then gets squished into the emulated viewport and visually trapped).
|
|
7
|
-
// The in-page overlay therefore HIDES during audits (service-worker broadcasts
|
|
8
|
-
// SIDEBAR_HIDE_REQUEST). chrome.sidePanel is the only UI surface that renders
|
|
9
|
-
// OUTSIDE the tab's render tree, so we open it as the fallback so users still
|
|
10
|
-
// see progress + stop controls.
|
|
11
|
-
//
|
|
12
|
-
// Why this can't live in the SW: chrome.sidePanel.open() requires a user-
|
|
13
|
-
// gesture context. User gestures DO propagate through chrome.runtime.send-
|
|
14
|
-
// Message into the SW, but Chrome consumes the gesture as soon as the SW
|
|
15
|
-
// awaits anything (chrome.tabs.query, etc.). Calling chrome.sidePanel.open
|
|
16
|
-
// synchronously from the original click handler — before any await — is the
|
|
17
|
-
// only reliable path. To do that we need the windowId synchronously, so we
|
|
18
|
-
// pre-cache it on side-panel mount.
|
|
19
|
-
|
|
20
|
-
import { send } from '../shared/messaging';
|
|
21
|
-
import type { StartAuditAction, StartSiteCrawl } from '../shared/messages';
|
|
22
|
-
|
|
23
|
-
let cachedWindowId: number | null = null;
|
|
24
|
-
|
|
25
|
-
/** Pre-fetch the side-panel's window id so audit launches can open
|
|
26
|
-
* chrome.sidePanel synchronously without burning user-gesture context on
|
|
27
|
-
* an await. Call once on side-panel mount. Idempotent. */
|
|
28
|
-
export async function primeAuditLauncher(): Promise<void> {
|
|
29
|
-
if (cachedWindowId !== null) return;
|
|
30
|
-
try {
|
|
31
|
-
const w = await chrome.windows.getCurrent();
|
|
32
|
-
if (typeof w.id === 'number') cachedWindowId = w.id;
|
|
33
|
-
} catch {
|
|
34
|
-
// chrome.windows is unavailable in some contexts (ui-preview shim) —
|
|
35
|
-
// launcher gracefully degrades; user just loses the fallback panel.
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Open chrome.sidePanel synchronously while the click-handler user-gesture
|
|
40
|
-
* is still live. Returns immediately; the open() promise resolves later but
|
|
41
|
-
* the gesture is consumed at call time, which is what matters.
|
|
42
|
-
*
|
|
43
|
-
* Exported so call sites OTHER than audit-launch (e.g. ViolationCard's
|
|
44
|
-
* Load state link, which drives the page through a narrow-breakpoint
|
|
45
|
-
* state) can pre-open the fallback before issuing their async work. */
|
|
46
|
-
export function openFallbackPanel(): void {
|
|
47
|
-
if (cachedWindowId === null) return;
|
|
48
|
-
// Guard chrome.sidePanel access — the API isn't present in non-extension
|
|
49
|
-
// contexts (tests, ui-preview).
|
|
50
|
-
const api = chrome.sidePanel;
|
|
51
|
-
if (!api || typeof api.open !== 'function') return;
|
|
52
|
-
api.open({ windowId: cachedWindowId }).catch(() => {
|
|
53
|
-
// best-effort — failures here just mean the user won't see the fallback
|
|
54
|
-
// panel, which is acceptable. The audit still runs.
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Drop-in replacement for `send(startAuditMessage)` at audit-start sites.
|
|
59
|
-
* Opens chrome.sidePanel first (preserving user-gesture), then dispatches
|
|
60
|
-
* the audit start to the service worker. Use for both START_AUDIT and
|
|
61
|
-
* START_SITE_CRAWL — both run the state-matrix audit pipeline. */
|
|
62
|
-
export function launchAudit(msg: StartAuditAction | StartSiteCrawl): void {
|
|
63
|
-
openFallbackPanel();
|
|
64
|
-
void send(msg);
|
|
65
|
-
}
|