@accesslint/core 0.3.13 → 0.3.14

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/index.js CHANGED
@@ -1,15 +1,15 @@
1
- let W = /* @__PURE__ */ new WeakMap();
1
+ let O = /* @__PURE__ */ new WeakMap();
2
2
  function Se() {
3
- W = /* @__PURE__ */ new WeakMap();
3
+ O = /* @__PURE__ */ new WeakMap();
4
4
  }
5
- function he(e) {
5
+ function he(t) {
6
6
  var i;
7
- const a = e.tagName.toLowerCase(), t = (i = e.getAttribute("type")) == null ? void 0 : i.toLowerCase();
7
+ const a = t.tagName.toLowerCase(), e = (i = t.getAttribute("type")) == null ? void 0 : i.toLowerCase();
8
8
  switch (a) {
9
9
  case "a":
10
- return e.hasAttribute("href") ? "link" : null;
10
+ return t.hasAttribute("href") ? "link" : null;
11
11
  case "area":
12
- return e.hasAttribute("href") ? "link" : null;
12
+ return t.hasAttribute("href") ? "link" : null;
13
13
  case "article":
14
14
  return "article";
15
15
  case "aside":
@@ -27,7 +27,7 @@ function he(e) {
27
27
  case "figure":
28
28
  return "figure";
29
29
  case "footer":
30
- return e.closest("article, aside, main, nav, section") ? null : "contentinfo";
30
+ return t.closest("article, aside, main, nav, section") ? null : "contentinfo";
31
31
  case "form":
32
32
  return "form";
33
33
  case "h1":
@@ -38,13 +38,13 @@ function he(e) {
38
38
  case "h6":
39
39
  return "heading";
40
40
  case "header":
41
- return e.closest("article, aside, main, nav, section") ? null : "banner";
41
+ return t.closest("article, aside, main, nav, section") ? null : "banner";
42
42
  case "hr":
43
43
  return "separator";
44
44
  case "img":
45
- return e.getAttribute("alt") === "" ? "presentation" : "img";
45
+ return t.getAttribute("alt") === "" ? "presentation" : "img";
46
46
  case "input":
47
- switch (t) {
47
+ switch (e) {
48
48
  case "button":
49
49
  case "image":
50
50
  case "reset":
@@ -71,7 +71,7 @@ function he(e) {
71
71
  return "textbox";
72
72
  }
73
73
  case "li":
74
- return e.closest("ul, ol, menu") ? "listitem" : null;
74
+ return t.closest("ul, ol, menu") ? "listitem" : null;
75
75
  case "main":
76
76
  return "main";
77
77
  case "math":
@@ -94,9 +94,9 @@ function he(e) {
94
94
  case "progress":
95
95
  return "progressbar";
96
96
  case "section":
97
- return e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby") ? "region" : null;
97
+ return t.hasAttribute("aria-label") || t.hasAttribute("aria-labelledby") ? "region" : null;
98
98
  case "select":
99
- return e.hasAttribute("multiple") || e.size > 1 ? "listbox" : "combobox";
99
+ return t.hasAttribute("multiple") || t.size > 1 ? "listbox" : "combobox";
100
100
  case "summary":
101
101
  return "button";
102
102
  case "table":
@@ -117,69 +117,69 @@ function he(e) {
117
117
  return null;
118
118
  }
119
119
  }
120
- function q(e) {
120
+ function q(t) {
121
121
  var n;
122
- const a = W.get(e);
122
+ const a = O.get(t);
123
123
  if (a !== void 0) return a;
124
- const i = ((n = e.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || he(e);
125
- return W.set(e, i), i;
124
+ const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || he(t);
125
+ return O.set(t, i), i;
126
126
  }
127
- let O = /* @__PURE__ */ new WeakMap();
127
+ let B = /* @__PURE__ */ new WeakMap();
128
128
  function ke() {
129
- O = /* @__PURE__ */ new WeakMap();
129
+ B = /* @__PURE__ */ new WeakMap();
130
130
  }
131
- function v(e) {
132
- const a = O.get(e);
131
+ function v(t) {
132
+ const a = B.get(t);
133
133
  if (a !== void 0) return a;
134
- const t = Ie(e);
135
- return O.set(e, t), t;
134
+ const e = Ie(t);
135
+ return B.set(t, e), e;
136
136
  }
137
- function Ie(e) {
138
- var r, o, s, l, p;
139
- const a = e.getAttribute("aria-labelledby");
137
+ function Ie(t) {
138
+ var r, o, s, l, h;
139
+ const a = t.getAttribute("aria-labelledby");
140
140
  if (a) {
141
141
  const c = a.split(/\s+/).map((u) => {
142
- const h = e.ownerDocument.getElementById(u);
143
- return h ? A(h).trim() : "";
142
+ const p = t.ownerDocument.getElementById(u);
143
+ return p ? A(p).trim() : "";
144
144
  }).filter(Boolean);
145
145
  if (c.length) return c.join(" ");
146
146
  }
147
- const t = (r = e.getAttribute("aria-label")) == null ? void 0 : r.trim();
148
- if (t) return t;
149
- if (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement) {
150
- if (e.id) {
151
- const h = e.ownerDocument.querySelector(`label[for="${CSS.escape(e.id)}"]`), b = h ? A(h).trim() : "";
147
+ const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
148
+ if (e) return e;
149
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
150
+ if (t.id) {
151
+ const p = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`), b = p ? A(p).trim() : "";
152
152
  if (b) return b;
153
153
  }
154
- const c = e.closest("label"), u = c ? A(c).trim() : "";
154
+ const c = t.closest("label"), u = c ? A(c).trim() : "";
155
155
  if (u) return u;
156
156
  }
157
- const i = (o = e.getAttribute("title")) == null ? void 0 : o.trim();
157
+ const i = (o = t.getAttribute("title")) == null ? void 0 : o.trim();
158
158
  if (i) return i;
159
- if (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) {
160
- const c = (s = e.getAttribute("placeholder")) == null ? void 0 : s.trim();
159
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
160
+ const c = (s = t.getAttribute("placeholder")) == null ? void 0 : s.trim();
161
161
  if (c) return c;
162
162
  }
163
- const n = e.tagName.toLowerCase();
163
+ const n = t.tagName.toLowerCase();
164
164
  if (n === "fieldset") {
165
- const c = e.querySelector(":scope > legend");
165
+ const c = t.querySelector(":scope > legend");
166
166
  if (c) {
167
167
  const u = A(c).trim();
168
168
  if (u) return u;
169
169
  }
170
170
  }
171
171
  if (n === "table") {
172
- const c = e.querySelector(":scope > caption");
172
+ const c = t.querySelector(":scope > caption");
173
173
  if (c) {
174
174
  const u = A(c).trim();
175
175
  if (u) return u;
176
176
  }
177
177
  }
178
- if (!(e instanceof HTMLInputElement)) {
179
- const c = A(e).trim();
178
+ if (!(t instanceof HTMLInputElement)) {
179
+ const c = A(t).trim();
180
180
  if (c) return c;
181
181
  }
182
- return e instanceof HTMLImageElement || e instanceof HTMLAreaElement ? ((l = e.alt) == null ? void 0 : l.trim()) ?? "" : e instanceof HTMLInputElement && e.type === "image" ? ((p = e.alt) == null ? void 0 : p.trim()) ?? "" : "";
182
+ return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((l = t.alt) == null ? void 0 : l.trim()) ?? "" : t instanceof HTMLInputElement && t.type === "image" ? ((h = t.alt) == null ? void 0 : h.trim()) ?? "" : "";
183
183
  }
184
184
  const Te = /* @__PURE__ */ new Set([
185
185
  "alert",
@@ -265,53 +265,53 @@ const Te = /* @__PURE__ */ new Set([
265
265
  "treegrid",
266
266
  "treeitem"
267
267
  ]);
268
- function Ee(e) {
269
- const a = e.trim().toLowerCase().replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "");
268
+ function Ee(t) {
269
+ const a = t.trim().toLowerCase().replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "");
270
270
  return Te.has(a);
271
271
  }
272
- function T(e) {
273
- let a = e;
272
+ function T(t) {
273
+ let a = t;
274
274
  for (; a; ) {
275
275
  if (pe(a)) return !0;
276
276
  a = a.parentElement;
277
277
  }
278
278
  return !1;
279
279
  }
280
- let B = /* @__PURE__ */ new WeakMap();
280
+ let _ = /* @__PURE__ */ new WeakMap();
281
281
  function Ce() {
282
- B = /* @__PURE__ */ new WeakMap();
282
+ _ = /* @__PURE__ */ new WeakMap();
283
283
  }
284
- function g(e) {
285
- const a = B.get(e);
284
+ function g(t) {
285
+ const a = _.get(t);
286
286
  if (a !== void 0) return a;
287
- let t;
288
- return e.getAttribute("aria-hidden") === "true" || e instanceof HTMLElement && (e.hidden || e.style.display === "none") ? t = !0 : e.parentElement ? t = g(e.parentElement) : t = !1, B.set(e, t), t;
287
+ let e;
288
+ return t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none") ? e = !0 : t.parentElement ? e = g(t.parentElement) : e = !1, _.set(t, e), e;
289
289
  }
290
- function pe(e) {
291
- if (e.getAttribute("aria-hidden") === "true" || e instanceof HTMLElement && e.hidden) return !0;
290
+ function pe(t) {
291
+ if (t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && t.hidden) return !0;
292
292
  if (typeof getComputedStyle == "function") {
293
- const a = getComputedStyle(e);
293
+ const a = getComputedStyle(t);
294
294
  if (a.display === "none" || a.visibility === "hidden") return !0;
295
- } else if (e instanceof HTMLElement && e.style.display === "none")
295
+ } else if (t instanceof HTMLElement && t.style.display === "none")
296
296
  return !0;
297
297
  return !1;
298
298
  }
299
- function A(e) {
300
- var t, i, n, r, o;
299
+ function A(t) {
300
+ var e, i, n, r, o;
301
301
  let a = "";
302
- for (const s of e.childNodes)
302
+ for (const s of t.childNodes)
303
303
  if (s.nodeType === 3)
304
304
  a += s.textContent ?? "";
305
305
  else if (s.nodeType === 1) {
306
306
  const l = s;
307
307
  if (!pe(l)) {
308
- const p = (t = l.tagName) == null ? void 0 : t.toLowerCase();
309
- if (p === "img" || p === "area") {
308
+ const h = (e = l.tagName) == null ? void 0 : e.toLowerCase();
309
+ if (h === "img" || h === "area") {
310
310
  const c = l.getAttribute("aria-labelledby");
311
311
  if (c) {
312
- const u = c.split(/\s+/).map((h) => {
312
+ const u = c.split(/\s+/).map((p) => {
313
313
  var b, f;
314
- return ((f = (b = l.ownerDocument.getElementById(h)) == null ? void 0 : b.textContent) == null ? void 0 : f.trim()) ?? "";
314
+ return ((f = (b = l.ownerDocument.getElementById(p)) == null ? void 0 : b.textContent) == null ? void 0 : f.trim()) ?? "";
315
315
  }).filter(Boolean);
316
316
  if (u.length) {
317
317
  a += u.join(" ");
@@ -319,7 +319,7 @@ function A(e) {
319
319
  }
320
320
  }
321
321
  a += ((i = l.getAttribute("aria-label")) == null ? void 0 : i.trim()) ?? l.getAttribute("alt") ?? ((n = l.getAttribute("title")) == null ? void 0 : n.trim()) ?? "";
322
- } else if (p === "svg") {
322
+ } else if (h === "svg") {
323
323
  const c = (r = l.getAttribute("aria-label")) == null ? void 0 : r.trim();
324
324
  if (c)
325
325
  a += c;
@@ -332,12 +332,12 @@ function A(e) {
332
332
  }
333
333
  return a;
334
334
  }
335
- let _ = /* @__PURE__ */ new WeakMap();
335
+ let P = /* @__PURE__ */ new WeakMap();
336
336
  function Le() {
337
- _ = /* @__PURE__ */ new WeakMap();
337
+ P = /* @__PURE__ */ new WeakMap();
338
338
  }
339
- function qe(e) {
340
- return e.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
339
+ function qe(t) {
340
+ return t.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
341
341
  }
342
342
  const Re = [
343
343
  "data-testid",
@@ -349,29 +349,29 @@ const Re = [
349
349
  "for",
350
350
  "aria-label"
351
351
  ];
352
- function Ne(e) {
353
- const a = e.tagName.toLowerCase();
352
+ function Ne(t) {
353
+ const a = t.tagName.toLowerCase();
354
354
  for (const i of Re) {
355
- const n = e.getAttribute(i);
355
+ const n = t.getAttribute(i);
356
356
  if (n != null && n.length > 0 && n.length < 100)
357
357
  return `${a}[${i}="${qe(n)}"]`;
358
358
  }
359
- const t = e.parentElement;
360
- if (t) {
359
+ const e = t.parentElement;
360
+ if (e) {
361
361
  let i = 0, n = 0;
362
- for (let r = 0; r < t.children.length; r++)
363
- t.children[r].tagName === e.tagName && (i++, t.children[r] === e && (n = i));
362
+ for (let r = 0; r < e.children.length; r++)
363
+ e.children[r].tagName === t.tagName && (i++, e.children[r] === t && (n = i));
364
364
  if (i > 1)
365
365
  return `${a}:nth-of-type(${n})`;
366
366
  }
367
367
  return a;
368
368
  }
369
- function H(e) {
370
- if (e.id) return `#${CSS.escape(e.id)}`;
371
- const a = e.getRootNode(), t = a instanceof ShadowRoot ? null : a.documentElement, i = [];
372
- let n = e;
373
- for (; n && n !== t; ) {
374
- if (n !== e && n.id) {
369
+ function H(t) {
370
+ if (t.id) return `#${CSS.escape(t.id)}`;
371
+ const a = t.getRootNode(), e = a instanceof ShadowRoot ? null : a.documentElement, i = [];
372
+ let n = t;
373
+ for (; n && n !== e; ) {
374
+ if (n !== t && n.id) {
375
375
  i.unshift(`#${CSS.escape(n.id)}`);
376
376
  break;
377
377
  }
@@ -379,7 +379,7 @@ function H(e) {
379
379
  const r = i.join(" > ");
380
380
  try {
381
381
  const o = a.querySelectorAll(r);
382
- if (o.length === 1 && o[0] === e) return r;
382
+ if (o.length === 1 && o[0] === t) return r;
383
383
  } catch {
384
384
  }
385
385
  }
@@ -387,38 +387,38 @@ function H(e) {
387
387
  }
388
388
  return i.join(" > ");
389
389
  }
390
- function m(e) {
390
+ function m(t) {
391
391
  var r;
392
- const a = _.get(e);
392
+ const a = P.get(t);
393
393
  if (a !== void 0) return a;
394
- const t = [];
395
- let i = e;
394
+ const e = [];
395
+ let i = t;
396
396
  for (; i; ) {
397
397
  const o = i.getRootNode();
398
398
  if (o instanceof ShadowRoot)
399
- t.unshift({ selector: H(i), delimiter: " >>> " }), i = o.host;
399
+ e.unshift({ selector: H(i), delimiter: " >>> " }), i = o.host;
400
400
  else {
401
401
  const s = (r = o.defaultView) == null ? void 0 : r.frameElement;
402
402
  if (s)
403
- t.unshift({ selector: H(i), delimiter: " >>>iframe> " }), i = s;
403
+ e.unshift({ selector: H(i), delimiter: " >>>iframe> " }), i = s;
404
404
  else {
405
- t.unshift({ selector: H(i), delimiter: "" });
405
+ e.unshift({ selector: H(i), delimiter: "" });
406
406
  break;
407
407
  }
408
408
  }
409
409
  }
410
- const n = t.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
411
- return _.set(e, n), n;
410
+ const n = e.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
411
+ return P.set(t, n), n;
412
412
  }
413
- function Ri(e) {
414
- const a = [], t = [];
415
- let i = e;
413
+ function Ri(t) {
414
+ const a = [], e = [];
415
+ let i = t;
416
416
  for (; i; ) {
417
417
  const r = i.indexOf(" >>>iframe> "), o = i.indexOf(" >>> ");
418
418
  if (r !== -1 && (o === -1 || r <= o))
419
- a.push(i.slice(0, r).trim()), t.push("iframe"), i = i.slice(r + 12);
419
+ a.push(i.slice(0, r).trim()), e.push("iframe"), i = i.slice(r + 12);
420
420
  else if (o !== -1)
421
- a.push(i.slice(0, o).trim()), t.push("shadow"), i = i.slice(o + 5);
421
+ a.push(i.slice(0, o).trim()), e.push("shadow"), i = i.slice(o + 5);
422
422
  else {
423
423
  a.push(i.trim());
424
424
  break;
@@ -429,7 +429,7 @@ function Ri(e) {
429
429
  const o = n.querySelector(a[r]);
430
430
  if (!o) return null;
431
431
  if (r < a.length - 1)
432
- if (t[r] === "iframe") {
432
+ if (e[r] === "iframe") {
433
433
  const s = o.contentDocument;
434
434
  if (!s) return null;
435
435
  n = s;
@@ -443,8 +443,8 @@ function Ri(e) {
443
443
  }
444
444
  return null;
445
445
  }
446
- function d(e) {
447
- const a = e.outerHTML;
446
+ function d(t) {
447
+ const a = t.outerHTML;
448
448
  return a.length > 200 ? a.slice(0, 200) + "..." : a;
449
449
  }
450
450
  const $e = /* @__PURE__ */ new Set([
@@ -501,7 +501,7 @@ const $e = /* @__PURE__ */ new Set([
501
501
  "aria-valuemin",
502
502
  "aria-valuenow",
503
503
  "aria-valuetext"
504
- ]), Y = /* @__PURE__ */ new Set([
504
+ ]), X = /* @__PURE__ */ new Set([
505
505
  "aria-atomic",
506
506
  "aria-busy",
507
507
  "aria-disabled",
@@ -512,7 +512,7 @@ const $e = /* @__PURE__ */ new Set([
512
512
  "aria-multiselectable",
513
513
  "aria-readonly",
514
514
  "aria-required"
515
- ]), X = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), Me = /* @__PURE__ */ new Set([
515
+ ]), K = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), Me = /* @__PURE__ */ new Set([
516
516
  "aria-colcount",
517
517
  "aria-colindex",
518
518
  "aria-colspan",
@@ -526,7 +526,7 @@ const $e = /* @__PURE__ */ new Set([
526
526
  "aria-valuemax",
527
527
  "aria-valuemin",
528
528
  "aria-valuenow"
529
- ]), K = {
529
+ ]), J = {
530
530
  "aria-autocomplete": /* @__PURE__ */ new Set(["inline", "list", "both", "none"]),
531
531
  "aria-expanded": /* @__PURE__ */ new Set(["true", "false", "undefined"]),
532
532
  "aria-current": /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"]),
@@ -537,7 +537,7 @@ const $e = /* @__PURE__ */ new Set([
537
537
  "aria-orientation": /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]),
538
538
  "aria-relevant": /* @__PURE__ */ new Set(["additions", "all", "removals", "text"]),
539
539
  "aria-sort": /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"])
540
- }, J = /* @__PURE__ */ new Set([
540
+ }, Q = /* @__PURE__ */ new Set([
541
541
  "caption",
542
542
  "code",
543
543
  "deletion",
@@ -619,11 +619,11 @@ let C = null, L = null;
619
619
  function We() {
620
620
  C = null, L = null;
621
621
  }
622
- function U(e) {
622
+ function G(t) {
623
623
  var n;
624
- if (L && (C == null ? void 0 : C.deref()) === e) return L;
625
- const a = [], t = [], i = [];
626
- for (const r of e.querySelectorAll("*")) {
624
+ if (L && (C == null ? void 0 : C.deref()) === t) return L;
625
+ const a = [], e = [], i = [];
626
+ for (const r of t.querySelectorAll("*")) {
627
627
  let o = !1;
628
628
  for (const c of r.attributes)
629
629
  if (c.name.startsWith("aria-")) {
@@ -632,10 +632,10 @@ function U(e) {
632
632
  }
633
633
  if (!o) continue;
634
634
  let s, l;
635
- const p = () => (s === void 0 && (s = m(r), l = d(r)), { selector: s, html: l });
635
+ const h = () => (s === void 0 && (s = m(r), l = d(r)), { selector: s, html: l });
636
636
  for (const c of r.attributes)
637
637
  if (c.name.startsWith("aria-") && !$e.has(c.name)) {
638
- const u = p();
638
+ const u = h();
639
639
  a.push({
640
640
  ruleId: "aria-valid-attr",
641
641
  selector: u.selector,
@@ -648,57 +648,57 @@ function U(e) {
648
648
  for (const c of r.attributes) {
649
649
  if (!c.name.startsWith("aria-")) continue;
650
650
  const u = c.value.trim();
651
- if (!(u === "" && !Y.has(c.name) && !X.has(c.name))) {
652
- if (Y.has(c.name)) {
651
+ if (!(u === "" && !X.has(c.name) && !K.has(c.name))) {
652
+ if (X.has(c.name)) {
653
653
  if (u !== "true" && u !== "false") {
654
- const h = p();
655
- t.push({
654
+ const p = h();
655
+ e.push({
656
656
  ruleId: "aria-valid-attr-value",
657
- selector: h.selector,
658
- html: h.html,
657
+ selector: p.selector,
658
+ html: p.html,
659
659
  impact: "critical",
660
660
  message: `${c.name} must be "true" or "false", got "${u}".`
661
661
  });
662
662
  }
663
- } else if (X.has(c.name)) {
663
+ } else if (K.has(c.name)) {
664
664
  if (u !== "true" && u !== "false" && u !== "mixed") {
665
- const h = p();
666
- t.push({
665
+ const p = h();
666
+ e.push({
667
667
  ruleId: "aria-valid-attr-value",
668
- selector: h.selector,
669
- html: h.html,
668
+ selector: p.selector,
669
+ html: p.html,
670
670
  impact: "critical",
671
671
  message: `${c.name} must be "true", "false", or "mixed", got "${u}".`
672
672
  });
673
673
  }
674
674
  } else if (Me.has(c.name)) {
675
675
  if (u === "" || !/^-?\d+$/.test(u)) {
676
- const h = p();
677
- t.push({
676
+ const p = h();
677
+ e.push({
678
678
  ruleId: "aria-valid-attr-value",
679
- selector: h.selector,
680
- html: h.html,
679
+ selector: p.selector,
680
+ html: p.html,
681
681
  impact: "critical",
682
682
  message: `${c.name} must be an integer, got "${u}".`
683
683
  });
684
684
  }
685
685
  } else if (He.has(c.name)) {
686
686
  if (u === "" || isNaN(Number(u))) {
687
- const h = p();
688
- t.push({
687
+ const p = h();
688
+ e.push({
689
689
  ruleId: "aria-valid-attr-value",
690
- selector: h.selector,
691
- html: h.html,
690
+ selector: p.selector,
691
+ html: p.html,
692
692
  impact: "critical",
693
693
  message: `${c.name} must be a number, got "${u}".`
694
694
  });
695
695
  }
696
- } else if (K[c.name]) {
697
- const h = u.split(/\s+/);
698
- for (const b of h)
699
- if (!K[c.name].has(b)) {
700
- const f = p();
701
- t.push({
696
+ } else if (J[c.name]) {
697
+ const p = u.split(/\s+/);
698
+ for (const b of p)
699
+ if (!J[c.name].has(b)) {
700
+ const f = h();
701
+ e.push({
702
702
  ruleId: "aria-valid-attr-value",
703
703
  selector: f.selector,
704
704
  html: f.html,
@@ -713,9 +713,9 @@ function U(e) {
713
713
  if (!g(r)) {
714
714
  const c = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase(), u = r.tagName.toLowerCase();
715
715
  if (!c && De[u]) {
716
- const h = r.hasAttribute("aria-label"), b = r.hasAttribute("aria-labelledby");
717
- if (h || b) {
718
- const f = p();
716
+ const p = r.hasAttribute("aria-label"), b = r.hasAttribute("aria-labelledby");
717
+ if (p || b) {
718
+ const f = h();
719
719
  i.push({
720
720
  ruleId: "aria-prohibited-attr",
721
721
  selector: f.selector,
@@ -725,26 +725,26 @@ function U(e) {
725
725
  });
726
726
  }
727
727
  } else if (c) {
728
- if (J.has(c)) {
728
+ if (Q.has(c)) {
729
729
  const b = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
730
730
  if (b || f) {
731
- const w = p();
731
+ const y = h();
732
732
  i.push({
733
733
  ruleId: "aria-prohibited-attr",
734
- selector: w.selector,
735
- html: w.html,
734
+ selector: y.selector,
735
+ html: y.html,
736
736
  impact: "serious",
737
737
  message: `aria-label and aria-labelledby are prohibited on role "${c}".`
738
738
  });
739
739
  }
740
740
  }
741
- const h = Fe[c];
742
- if (h) {
741
+ const p = Fe[c];
742
+ if (p) {
743
743
  for (const b of r.attributes)
744
- if (b.name.startsWith("aria-") && h.has(b.name)) {
745
- if ((b.name === "aria-label" || b.name === "aria-labelledby") && J.has(c))
744
+ if (b.name.startsWith("aria-") && p.has(b.name)) {
745
+ if ((b.name === "aria-label" || b.name === "aria-labelledby") && Q.has(c))
746
746
  continue;
747
- const f = p();
747
+ const f = h();
748
748
  i.push({
749
749
  ruleId: "aria-prohibited-attr",
750
750
  selector: f.selector,
@@ -757,28 +757,28 @@ function U(e) {
757
757
  }
758
758
  }
759
759
  }
760
- return C = new WeakRef(e), L = { validAttr: a, validAttrValue: t, prohibitedAttr: i }, L;
760
+ return C = new WeakRef(t), L = { validAttr: a, validAttrValue: e, prohibitedAttr: i }, L;
761
761
  }
762
- let P = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap(), V = /* @__PURE__ */ new WeakMap();
762
+ let j = /* @__PURE__ */ new WeakMap(), V = /* @__PURE__ */ new WeakMap(), z = /* @__PURE__ */ new WeakMap();
763
763
  function Oe() {
764
- P = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap(), V = /* @__PURE__ */ new WeakMap();
764
+ j = /* @__PURE__ */ new WeakMap(), V = /* @__PURE__ */ new WeakMap(), z = /* @__PURE__ */ new WeakMap();
765
765
  }
766
- function y(e) {
767
- let a = P.get(e);
768
- return a || (a = getComputedStyle(e), P.set(e, a), a);
766
+ function w(t) {
767
+ let a = j.get(t);
768
+ return a || (a = getComputedStyle(t), j.set(t, a), a);
769
769
  }
770
- function R(e, a, t) {
771
- const [i, n, r] = [e, a, t].map((o) => {
770
+ function R(t, a, e) {
771
+ const [i, n, r] = [t, a, e].map((o) => {
772
772
  const s = o / 255;
773
773
  return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
774
774
  });
775
775
  return 0.2126 * i + 0.7152 * n + 0.0722 * r;
776
776
  }
777
- function ge(e, a) {
778
- const t = Math.max(e, a), i = Math.min(e, a);
779
- return (t + 0.05) / (i + 0.05);
777
+ function ge(t, a) {
778
+ const e = Math.max(t, a), i = Math.min(t, a);
779
+ return (e + 0.05) / (i + 0.05);
780
780
  }
781
- const Q = {
781
+ const Z = {
782
782
  black: [0, 0, 0],
783
783
  white: [255, 255, 255],
784
784
  red: [255, 0, 0],
@@ -798,37 +798,37 @@ const Q = {
798
798
  lime: [0, 255, 0],
799
799
  olive: [128, 128, 0]
800
800
  };
801
- function N(e) {
802
- const a = e.trim().toLowerCase();
803
- if (Q[a]) return Q[a];
804
- const t = a.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/);
805
- if (t)
806
- return [parseInt(t[1] + t[1], 16), parseInt(t[2] + t[2], 16), parseInt(t[3] + t[3], 16)];
801
+ function N(t) {
802
+ const a = t.trim().toLowerCase();
803
+ if (Z[a]) return Z[a];
804
+ const e = a.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/);
805
+ if (e)
806
+ return [parseInt(e[1] + e[1], 16), parseInt(e[2] + e[2], 16), parseInt(e[3] + e[3], 16)];
807
807
  const i = a.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/);
808
808
  if (i)
809
809
  return [parseInt(i[1], 16), parseInt(i[2], 16), parseInt(i[3], 16)];
810
- const n = e.match(
810
+ const n = t.match(
811
811
  /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+)?\s*\)/
812
812
  );
813
813
  if (n)
814
814
  return [parseInt(n[1]), parseInt(n[2]), parseInt(n[3])];
815
- const r = e.match(
815
+ const r = t.match(
816
816
  /rgba?\(\s*(\d+)\s+(\d+)\s+(\d+)\s*(?:\/\s*[\d.]+%?)?\s*\)/
817
817
  );
818
818
  return r ? [parseInt(r[1]), parseInt(r[2]), parseInt(r[3])] : null;
819
819
  }
820
- function Be(e) {
821
- const a = j.get(e);
820
+ function Be(t) {
821
+ const a = V.get(t);
822
822
  if (a !== void 0) return a;
823
- const t = _e(e);
824
- return j.set(e, t), t;
823
+ const e = _e(t);
824
+ return V.set(t, e), e;
825
825
  }
826
- function _e(e) {
827
- let a = e;
826
+ function _e(t) {
827
+ let a = t;
828
828
  for (; a; ) {
829
- const t = y(a), i = t.backgroundImage;
829
+ const e = w(a), i = e.backgroundImage;
830
830
  if (i && i !== "none" && i !== "initial") return null;
831
- const n = t.backgroundColor;
831
+ const n = e.backgroundColor;
832
832
  if (n === "transparent" || n === "rgba(0, 0, 0, 0)" || n === "rgba(0 0 0 / 0)") {
833
833
  a = a.parentElement;
834
834
  continue;
@@ -843,59 +843,59 @@ function _e(e) {
843
843
  return [255, 255, 255];
844
844
  }
845
845
  const Pe = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
846
- function je(e) {
847
- const a = V.get(e);
846
+ function je(t) {
847
+ const a = z.get(t);
848
848
  if (a !== void 0) return a;
849
- const t = Ve(e);
850
- return V.set(e, t), t;
849
+ const e = Ve(t);
850
+ return z.set(t, e), e;
851
851
  }
852
- function Ve(e) {
853
- let a = e, t = !1;
852
+ function Ve(t) {
853
+ let a = t, e = !1;
854
854
  for (; a; ) {
855
- const i = y(a).position;
856
- if ((i === "absolute" || i === "fixed") && (t = !0), a !== e && i !== "static") {
855
+ const i = w(a).position;
856
+ if ((i === "absolute" || i === "fixed") && (e = !0), a !== t && i !== "static") {
857
857
  for (const n of a.children)
858
- if (!(n === e || n.contains(e)) && Pe.has(n.tagName)) {
859
- if (t) return !0;
860
- const r = y(n).position;
858
+ if (!(n === t || n.contains(t)) && Pe.has(n.tagName)) {
859
+ if (e) return !0;
860
+ const r = w(n).position;
861
861
  if (r === "absolute" || r === "fixed") return !0;
862
862
  }
863
- if (t) break;
863
+ if (e) break;
864
864
  }
865
865
  a = a.parentElement;
866
866
  }
867
867
  return !1;
868
868
  }
869
- function ze(e) {
870
- const a = parseFloat(e);
871
- return e.endsWith("pt") ? a * (4 / 3) : a;
869
+ function ze(t) {
870
+ const a = parseFloat(t);
871
+ return t.endsWith("pt") ? a * (4 / 3) : a;
872
872
  }
873
- function Ue(e) {
874
- const a = y(e), t = ze(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
875
- return t >= 23.5 || t >= 18.5 && i >= 700;
873
+ function Ue(t) {
874
+ const a = w(t), e = ze(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
875
+ return e >= 23.5 || e >= 18.5 && i >= 700;
876
876
  }
877
- function D(e) {
877
+ function D(t) {
878
878
  var r, o;
879
- const a = [], t = e.closest("a");
880
- if (t) {
881
- const s = t.getAttribute("href");
879
+ const a = [], e = t.closest("a");
880
+ if (e) {
881
+ const s = e.getAttribute("href");
882
882
  s && a.push(`Link href: ${s}`);
883
883
  }
884
- const i = e.closest("figure");
884
+ const i = t.closest("figure");
885
885
  if (i) {
886
886
  const s = i.querySelector("figcaption");
887
887
  (r = s == null ? void 0 : s.textContent) != null && r.trim() && a.push(`Figcaption: ${s.textContent.trim().slice(0, 100)}`);
888
888
  }
889
- const n = e.parentElement;
890
- if (n && n !== t) {
891
- const s = e instanceof HTMLImageElement && e.alt || "", l = (o = n.textContent) == null ? void 0 : o.replace(s, "").trim().slice(0, 100);
889
+ const n = t.parentElement;
890
+ if (n && n !== e) {
891
+ const s = t instanceof HTMLImageElement && t.alt || "", l = (o = n.textContent) == null ? void 0 : o.replace(s, "").trim().slice(0, 100);
892
892
  l && a.push(`Adjacent text: ${l}`);
893
893
  }
894
894
  return a.length > 0 ? a.join(`
895
895
  `) : void 0;
896
896
  }
897
- function Z(e) {
898
- let a = e;
897
+ function ee(t) {
898
+ let a = t;
899
899
  for (; a; ) {
900
900
  if (a instanceof HTMLElement && a.style.visibility === "hidden") return !0;
901
901
  a = a.parentElement;
@@ -909,63 +909,63 @@ const Ge = {
909
909
  description: `Images must have alternate text. Add an alt attribute to <img> elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.`,
910
910
  guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.",
911
911
  prompt: "Describe what alt text to add. If the image appears decorative based on context (spacer, background, icon next to text that already describes it), recommend alt=''. Otherwise suggest descriptive alt text based on the src or surrounding context.",
912
- run(e) {
912
+ run(t) {
913
913
  const a = [];
914
- for (const t of e.querySelectorAll("img")) {
915
- if (g(t) || Z(t)) continue;
916
- const i = t.getAttribute("role");
914
+ for (const e of t.querySelectorAll("img")) {
915
+ if (g(e) || ee(e)) continue;
916
+ const i = e.getAttribute("role");
917
917
  if (i === "presentation" || i === "none") {
918
- const r = t.getAttribute("tabindex");
918
+ const r = e.getAttribute("tabindex");
919
919
  if (!r || r === "-1") continue;
920
920
  }
921
- const n = t.getAttribute("alt");
921
+ const n = e.getAttribute("alt");
922
922
  if (n !== null && n.trim() === "" && n !== "") {
923
923
  a.push({
924
924
  ruleId: "img-alt",
925
- selector: m(t),
926
- html: d(t),
925
+ selector: m(e),
926
+ html: d(e),
927
927
  impact: "critical",
928
928
  message: 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.',
929
- context: D(t)
929
+ context: D(e)
930
930
  });
931
931
  continue;
932
932
  }
933
- !t.hasAttribute("alt") && !v(t) && a.push({
933
+ !e.hasAttribute("alt") && !v(e) && a.push({
934
934
  ruleId: "img-alt",
935
- selector: m(t),
936
- html: d(t),
935
+ selector: m(e),
936
+ html: d(e),
937
937
  impact: "critical",
938
938
  message: "Image element missing alt attribute.",
939
- context: D(t)
939
+ context: D(e)
940
940
  });
941
941
  }
942
- for (const t of e.querySelectorAll('[role="img"]:not(img):not(svg)'))
943
- g(t) || Z(t) || v(t) || a.push({
942
+ for (const e of t.querySelectorAll('[role="img"]:not(img):not(svg)'))
943
+ g(e) || ee(e) || v(e) || a.push({
944
944
  ruleId: "img-alt",
945
- selector: m(t),
946
- html: d(t),
945
+ selector: m(e),
946
+ html: d(e),
947
947
  impact: "critical",
948
948
  message: 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.',
949
- context: D(t)
949
+ context: D(e)
950
950
  });
951
951
  return a;
952
952
  }
953
953
  };
954
- function Ye(e) {
954
+ function Ye(t) {
955
955
  var r, o, s;
956
- const a = e.getAttribute("aria-labelledby");
956
+ const a = t.getAttribute("aria-labelledby");
957
957
  if (a) {
958
- const l = a.split(/\s+/).map((p) => {
958
+ const l = a.split(/\s+/).map((h) => {
959
959
  var c, u;
960
- return ((u = (c = e.ownerDocument.getElementById(p)) == null ? void 0 : c.textContent) == null ? void 0 : u.trim()) ?? "";
960
+ return ((u = (c = t.ownerDocument.getElementById(h)) == null ? void 0 : c.textContent) == null ? void 0 : u.trim()) ?? "";
961
961
  }).filter(Boolean);
962
962
  if (l.length) return l.join(" ");
963
963
  }
964
- const t = (r = e.getAttribute("aria-label")) == null ? void 0 : r.trim();
965
- if (t) return t;
966
- const i = e.querySelector("title");
964
+ const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
965
+ if (e) return e;
966
+ const i = t.querySelector("title");
967
967
  if ((o = i == null ? void 0 : i.textContent) != null && o.trim()) return i.textContent.trim();
968
- const n = (s = e.getAttribute("title")) == null ? void 0 : s.trim();
968
+ const n = (s = t.getAttribute("title")) == null ? void 0 : s.trim();
969
969
  return n || "";
970
970
  }
971
971
  const Xe = {
@@ -975,9 +975,9 @@ const Xe = {
975
975
  description: "SVG elements with an img, graphics-document, or graphics-symbol role must have an accessible name via a <title> element, aria-label, or aria-labelledby.",
976
976
  guidance: "Inline SVGs with role='img' need accessible names. Add a <title> element as the first child of the SVG (screen readers will announce it), or use aria-label on the SVG element. For complex SVGs, use aria-labelledby referencing both a <title> and <desc> element. Decorative SVGs should use aria-hidden='true' instead.",
977
977
  prompt: "Based on the SVG content or context, suggest either adding aria-label with a description, or if decorative, replacing role='img' with aria-hidden='true'.",
978
- run(e) {
979
- const a = [], t = 'svg[role="img"], [role="graphics-document"], [role="graphics-symbol"]';
980
- for (const i of e.querySelectorAll(t)) {
978
+ run(t) {
979
+ const a = [], e = 'svg[role="img"], [role="graphics-document"], [role="graphics-symbol"]';
980
+ for (const i of t.querySelectorAll(e)) {
981
981
  if (g(i)) continue;
982
982
  if (!Ye(i)) {
983
983
  const r = i.getAttribute("role");
@@ -999,13 +999,13 @@ const Xe = {
999
999
  description: 'Image inputs (<input type="image">) must have alternate text via alt, aria-label, or aria-labelledby. The text should describe the button action, not the image.',
1000
1000
  guidance: "Image buttons (<input type='image'>) must have alternate text via alt, aria-label, or aria-labelledby. The text should describe the button action, not the image.",
1001
1001
  prompt: "Based on the src attribute or form context, suggest alt text describing the button's action (e.g., 'Submit', 'Search', 'Go').",
1002
- run(e) {
1002
+ run(t) {
1003
1003
  const a = [];
1004
- for (const t of e.querySelectorAll('input[type="image"]'))
1005
- g(t) || v(t) || a.push({
1004
+ for (const e of t.querySelectorAll('input[type="image"]'))
1005
+ g(e) || v(e) || a.push({
1006
1006
  ruleId: "input-image-alt",
1007
- selector: m(t),
1008
- html: d(t),
1007
+ selector: m(e),
1008
+ html: d(e),
1009
1009
  impact: "critical",
1010
1010
  message: "Image input missing alt text."
1011
1011
  });
@@ -1019,15 +1019,15 @@ const Xe = {
1019
1019
  description: "Image alt text should not duplicate adjacent link or button text. When alt text repeats surrounding text, screen reader users hear the same information twice.",
1020
1020
  guidance: "When an image is inside a link or button that also has text, make the alt text complementary rather than identical. If the image is purely decorative in that context, use alt='' to avoid repetition.",
1021
1021
  prompt: "The image alt text is identical to the text already visible in the parent link or button. Screen reader users hear the same words twice. If the image is decorative in this context (e.g. an icon next to a label), recommend alt=''. Otherwise suggest brief complementary alt text that adds information the visible text doesn't convey — for example what the image depicts, not what the link says.",
1022
- run(e) {
1023
- var t;
1022
+ run(t) {
1023
+ var e;
1024
1024
  const a = [];
1025
- for (const i of e.querySelectorAll("img[alt]")) {
1025
+ for (const i of t.querySelectorAll("img[alt]")) {
1026
1026
  const n = i.getAttribute("alt").trim().toLowerCase();
1027
1027
  if (!n) continue;
1028
1028
  const r = i.closest("a, button");
1029
1029
  if (r) {
1030
- const o = ((t = r.textContent) == null ? void 0 : t.trim().toLowerCase()) || "";
1030
+ const o = ((e = r.textContent) == null ? void 0 : e.trim().toLowerCase()) || "";
1031
1031
  if (o && o === n) {
1032
1032
  const s = r.tagName.toLowerCase(), l = r.getAttribute("href");
1033
1033
  a.push({
@@ -1051,19 +1051,19 @@ const Xe = {
1051
1051
  description: "Image alt text should not contain words like 'image', 'photo', or 'picture' — screen readers already announce the element type.",
1052
1052
  guidance: "Screen readers already announce 'image' or 'graphic' before reading alt text, so phrases like 'image of', 'photo of', or 'picture of' are redundant. Remove these words and describe what the image shows. For example, change 'image of a dog' to 'golden retriever playing fetch'.",
1053
1053
  prompt: "The alt text contains a word like 'image', 'photo', or 'picture' that is already announced by the screen reader. Rewrite the alt text with the redundant word removed while keeping the description meaningful. For example: 'image of a sunset over the ocean' → 'sunset over the ocean'; 'photo of team members' → 'team members at the 2024 offsite'; 'icon for settings' → 'settings'.",
1054
- run(e) {
1054
+ run(t) {
1055
1055
  const a = [];
1056
- for (const t of e.querySelectorAll("img[alt]")) {
1057
- const i = t.getAttribute("alt").toLowerCase();
1056
+ for (const e of t.querySelectorAll("img[alt]")) {
1057
+ const i = e.getAttribute("alt").toLowerCase();
1058
1058
  if (!i) continue;
1059
1059
  const n = Qe.filter((r) => i.split(/\s+/).includes(r));
1060
1060
  n.length > 0 && a.push({
1061
1061
  ruleId: "image-alt-redundant-words",
1062
- selector: m(t),
1063
- html: d(t),
1062
+ selector: m(e),
1063
+ html: d(e),
1064
1064
  impact: "minor",
1065
- message: `Alt text "${t.getAttribute("alt")}" contains redundant word(s): ${n.join(", ")}.`,
1066
- context: `Current alt: "${t.getAttribute("alt")}", redundant word(s): ${n.join(", ")}`
1065
+ message: `Alt text "${e.getAttribute("alt")}" contains redundant word(s): ${n.join(", ")}.`,
1066
+ context: `Current alt: "${e.getAttribute("alt")}", redundant word(s): ${n.join(", ")}`
1067
1067
  });
1068
1068
  }
1069
1069
  return a;
@@ -1075,14 +1075,14 @@ const Xe = {
1075
1075
  description: "Image map <area> elements must have alternative text.",
1076
1076
  guidance: "Each clickable region in an image map needs alternative text so screen reader users know what the region represents. Add an alt attribute to every <area> element describing its purpose. For complex image maps, consider using alternative approaches like SVG with embedded links, or a list of text links.",
1077
1077
  prompt: "Based on the href or shape/coords, suggest alt text describing where this area links or what it represents.",
1078
- run(e) {
1078
+ run(t) {
1079
1079
  const a = [];
1080
- for (const t of e.querySelectorAll("area[href]")) {
1081
- if (g(t)) continue;
1082
- v(t) || a.push({
1080
+ for (const e of t.querySelectorAll("area[href]")) {
1081
+ if (g(e)) continue;
1082
+ v(e) || a.push({
1083
1083
  ruleId: "area-alt",
1084
- selector: m(t),
1085
- html: d(t),
1084
+ selector: m(e),
1085
+ html: d(e),
1086
1086
  impact: "critical",
1087
1087
  message: "Image map <area> element is missing alternative text."
1088
1088
  });
@@ -1090,19 +1090,19 @@ const Xe = {
1090
1090
  return a;
1091
1091
  }
1092
1092
  };
1093
- function tt(e) {
1093
+ function tt(t) {
1094
1094
  var n, r;
1095
- const a = e.getAttribute("aria-labelledby");
1095
+ const a = t.getAttribute("aria-labelledby");
1096
1096
  if (a) {
1097
1097
  const o = a.split(/\s+/).map((s) => {
1098
- var l, p;
1099
- return ((p = (l = e.ownerDocument.getElementById(s)) == null ? void 0 : l.textContent) == null ? void 0 : p.trim()) ?? "";
1098
+ var l, h;
1099
+ return ((h = (l = t.ownerDocument.getElementById(s)) == null ? void 0 : l.textContent) == null ? void 0 : h.trim()) ?? "";
1100
1100
  }).filter(Boolean);
1101
1101
  if (o.length) return o.join(" ");
1102
1102
  }
1103
- const t = (n = e.getAttribute("aria-label")) == null ? void 0 : n.trim();
1104
- if (t) return t;
1105
- const i = (r = e.getAttribute("title")) == null ? void 0 : r.trim();
1103
+ const e = (n = t.getAttribute("aria-label")) == null ? void 0 : n.trim();
1104
+ if (e) return e;
1105
+ const i = (r = t.getAttribute("title")) == null ? void 0 : r.trim();
1106
1106
  return i || "";
1107
1107
  }
1108
1108
  const at = {
@@ -1112,10 +1112,10 @@ const at = {
1112
1112
  description: "<object> elements must have alternative text.",
1113
1113
  guidance: "Object elements embed external content that may not be accessible to all users. Provide alternative text via aria-label, aria-labelledby, or a title attribute. The fallback content inside <object> is only shown when the object fails to load and does not serve as an accessible name.",
1114
1114
  prompt: "Based on the data/type attributes, suggest adding aria-label or a title attribute describing what the embedded content represents.",
1115
- run(e) {
1116
- var t;
1115
+ run(t) {
1116
+ var e;
1117
1117
  const a = [];
1118
- for (const i of e.querySelectorAll("object")) {
1118
+ for (const i of t.querySelectorAll("object")) {
1119
1119
  if (g(i) || i instanceof HTMLElement && i.style.visibility === "hidden") continue;
1120
1120
  let n = i.parentElement, r = !1;
1121
1121
  for (; n; ) {
@@ -1128,8 +1128,8 @@ const at = {
1128
1128
  if (r || i.getAttribute("role") === "presentation" || i.getAttribute("role") === "none" || tt(i)) continue;
1129
1129
  const o = i.getAttribute("data") || "";
1130
1130
  if (!((i.getAttribute("type") || "").startsWith("image/") || /\.(png|jpg|jpeg|gif|svg|webp|bmp|ico)$/i.test(o))) {
1131
- const p = i.querySelector("img[alt]");
1132
- if (p && ((t = p.getAttribute("alt")) != null && t.trim())) continue;
1131
+ const h = i.querySelector("img[alt]");
1132
+ if (h && ((e = h.getAttribute("alt")) != null && e.trim())) continue;
1133
1133
  }
1134
1134
  a.push({
1135
1135
  ruleId: "object-alt",
@@ -1148,14 +1148,14 @@ const at = {
1148
1148
  description: "Elements with role='img' must have an accessible name.",
1149
1149
  guidance: "When you assign role='img' to an element (like a div containing icon fonts or CSS backgrounds), you must provide an accessible name via aria-label or aria-labelledby. Without this, screen reader users have no way to understand what the image represents. If the image is decorative, use role='presentation' or role='none' instead.",
1150
1150
  prompt: "Based on the element's content or class names, suggest either an aria-label describing the image, or if decorative, recommend removing role='img' or adding aria-hidden='true'.",
1151
- run(e) {
1151
+ run(t) {
1152
1152
  const a = [];
1153
- for (const t of e.querySelectorAll('[role="img"]')) {
1154
- if (g(t) || t.tagName.toLowerCase() === "svg" || t.tagName.toLowerCase() === "img") continue;
1155
- v(t) || a.push({
1153
+ for (const e of t.querySelectorAll('[role="img"]')) {
1154
+ if (g(e) || e.tagName.toLowerCase() === "svg" || e.tagName.toLowerCase() === "img") continue;
1155
+ v(e) || a.push({
1156
1156
  ruleId: "role-img-alt",
1157
- selector: m(t),
1158
- html: d(t),
1157
+ selector: m(e),
1158
+ html: d(e),
1159
1159
  impact: "serious",
1160
1160
  message: "Element with role='img' has no accessible name. Add aria-label or aria-labelledby."
1161
1161
  });
@@ -1163,17 +1163,17 @@ const at = {
1163
1163
  return a;
1164
1164
  }
1165
1165
  };
1166
- function Ni(e) {
1167
- if (typeof e != "object" || e === null)
1166
+ function Ni(t) {
1167
+ if (typeof t != "object" || t === null)
1168
1168
  return "Rule spec must be an object";
1169
- const a = e;
1169
+ const a = t;
1170
1170
  if (typeof a.id != "string" || a.id.length === 0)
1171
1171
  return "Rule must have a non-empty string id";
1172
1172
  if (typeof a.selector != "string" || a.selector.length === 0)
1173
1173
  return "Rule must have a non-empty string selector";
1174
1174
  if (typeof a.check != "object" || a.check === null)
1175
1175
  return "Rule must have a check object";
1176
- const t = a.check;
1176
+ const e = a.check;
1177
1177
  if (![
1178
1178
  "selector-exists",
1179
1179
  "attribute-value",
@@ -1181,8 +1181,8 @@ function Ni(e) {
1181
1181
  "attribute-regex",
1182
1182
  "child-required",
1183
1183
  "child-invalid"
1184
- ].includes(t.type))
1185
- return `Invalid check type: ${String(t.type)}`;
1184
+ ].includes(e.type))
1185
+ return `Invalid check type: ${String(e.type)}`;
1186
1186
  if (typeof a.impact != "string" || !["critical", "serious", "moderate", "minor"].includes(a.impact))
1187
1187
  return "Rule must have a valid impact (critical|serious|moderate|minor)";
1188
1188
  if (typeof a.message != "string" || a.message.length === 0)
@@ -1193,171 +1193,171 @@ function Ni(e) {
1193
1193
  return "Rule must have a wcag array";
1194
1194
  if (typeof a.level != "string" || !["A", "AA"].includes(a.level))
1195
1195
  return "Rule must have level A or AA";
1196
- const n = nt(t);
1196
+ const n = nt(e);
1197
1197
  return n || null;
1198
1198
  }
1199
- function nt(e) {
1200
- switch (e.type) {
1199
+ function nt(t) {
1200
+ switch (t.type) {
1201
1201
  case "selector-exists":
1202
1202
  return null;
1203
1203
  case "attribute-value":
1204
- return typeof e.attribute != "string" ? "attribute-value check requires attribute string" : [">", "<", "=", "!=", "in", "not-in"].includes(e.operator) ? e.value === void 0 ? "attribute-value check requires value" : null : "attribute-value check requires valid operator";
1204
+ return typeof t.attribute != "string" ? "attribute-value check requires attribute string" : [">", "<", "=", "!=", "in", "not-in"].includes(t.operator) ? t.value === void 0 ? "attribute-value check requires value" : null : "attribute-value check requires valid operator";
1205
1205
  case "attribute-missing":
1206
- return typeof e.attribute != "string" ? "attribute-missing check requires attribute string" : null;
1206
+ return typeof t.attribute != "string" ? "attribute-missing check requires attribute string" : null;
1207
1207
  case "attribute-regex":
1208
- return typeof e.attribute != "string" ? "attribute-regex check requires attribute string" : typeof e.pattern != "string" ? "attribute-regex check requires pattern string" : typeof e.shouldMatch != "boolean" ? "attribute-regex check requires shouldMatch boolean" : null;
1208
+ return typeof t.attribute != "string" ? "attribute-regex check requires attribute string" : typeof t.pattern != "string" ? "attribute-regex check requires pattern string" : typeof t.shouldMatch != "boolean" ? "attribute-regex check requires shouldMatch boolean" : null;
1209
1209
  case "child-required":
1210
- return typeof e.childSelector != "string" ? "child-required check requires childSelector string" : null;
1210
+ return typeof t.childSelector != "string" ? "child-required check requires childSelector string" : null;
1211
1211
  case "child-invalid":
1212
- return Array.isArray(e.allowedChildren) ? null : "child-invalid check requires allowedChildren array";
1212
+ return Array.isArray(t.allowedChildren) ? null : "child-invalid check requires allowedChildren array";
1213
1213
  default:
1214
- return `Unknown check type: ${String(e.type)}`;
1214
+ return `Unknown check type: ${String(t.type)}`;
1215
1215
  }
1216
1216
  }
1217
- function S(e, a, t) {
1218
- let i = e;
1217
+ function k(t, a, e) {
1218
+ let i = t;
1219
1219
  if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
1220
1220
  let n = "";
1221
- "attribute" in t && t.attribute && (n = a.getAttribute(t.attribute) ?? ""), i = i.replace(/\{\{value\}\}/g, n);
1221
+ "attribute" in e && e.attribute && (n = a.getAttribute(e.attribute) ?? ""), i = i.replace(/\{\{value\}\}/g, n);
1222
1222
  }
1223
1223
  return i;
1224
1224
  }
1225
- function k(e) {
1226
- const a = e.skipAriaHidden !== !1;
1225
+ function I(t) {
1226
+ const a = t.skipAriaHidden !== !1;
1227
1227
  return {
1228
- id: e.id,
1229
- wcag: e.wcag,
1230
- level: e.level,
1231
- tags: e.tags,
1232
- description: e.description,
1233
- guidance: e.guidance,
1234
- prompt: e.prompt,
1235
- run(t) {
1228
+ id: t.id,
1229
+ wcag: t.wcag,
1230
+ level: t.level,
1231
+ tags: t.tags,
1232
+ description: t.description,
1233
+ guidance: t.guidance,
1234
+ prompt: t.prompt,
1235
+ run(e) {
1236
1236
  var n, r;
1237
1237
  const i = [];
1238
- switch (e.check.type) {
1238
+ switch (t.check.type) {
1239
1239
  case "selector-exists": {
1240
- for (const o of t.querySelectorAll(e.selector))
1240
+ for (const o of e.querySelectorAll(t.selector))
1241
1241
  a && g(o) || i.push({
1242
- ruleId: e.id,
1242
+ ruleId: t.id,
1243
1243
  selector: m(o),
1244
1244
  html: d(o),
1245
- impact: e.impact,
1246
- message: S(e.message, o, e.check),
1245
+ impact: t.impact,
1246
+ message: k(t.message, o, t.check),
1247
1247
  element: o
1248
1248
  });
1249
1249
  break;
1250
1250
  }
1251
1251
  case "attribute-value": {
1252
- const { attribute: o, operator: s, value: l } = e.check;
1253
- for (const p of t.querySelectorAll(e.selector)) {
1254
- if (a && g(p)) continue;
1255
- const c = p.getAttribute(o);
1252
+ const { attribute: o, operator: s, value: l } = t.check;
1253
+ for (const h of e.querySelectorAll(t.selector)) {
1254
+ if (a && g(h)) continue;
1255
+ const c = h.getAttribute(o);
1256
1256
  c !== null && rt(c, s, l) && i.push({
1257
- ruleId: e.id,
1258
- selector: m(p),
1259
- html: d(p),
1260
- impact: e.impact,
1261
- message: S(e.message, p, e.check),
1262
- element: p
1257
+ ruleId: t.id,
1258
+ selector: m(h),
1259
+ html: d(h),
1260
+ impact: t.impact,
1261
+ message: k(t.message, h, t.check),
1262
+ element: h
1263
1263
  });
1264
1264
  }
1265
1265
  break;
1266
1266
  }
1267
1267
  case "attribute-missing": {
1268
- const { attribute: o } = e.check;
1269
- for (const s of t.querySelectorAll(e.selector))
1268
+ const { attribute: o } = t.check;
1269
+ for (const s of e.querySelectorAll(t.selector))
1270
1270
  a && g(s) || s.hasAttribute(o) || i.push({
1271
- ruleId: e.id,
1271
+ ruleId: t.id,
1272
1272
  selector: m(s),
1273
1273
  html: d(s),
1274
- impact: e.impact,
1275
- message: S(e.message, s, e.check),
1274
+ impact: t.impact,
1275
+ message: k(t.message, s, t.check),
1276
1276
  element: s
1277
1277
  });
1278
1278
  break;
1279
1279
  }
1280
1280
  case "attribute-regex": {
1281
- const { attribute: o, pattern: s, flags: l, shouldMatch: p } = e.check;
1281
+ const { attribute: o, pattern: s, flags: l, shouldMatch: h } = t.check;
1282
1282
  let c;
1283
1283
  try {
1284
1284
  c = new RegExp(s, l);
1285
1285
  } catch {
1286
1286
  break;
1287
1287
  }
1288
- for (const u of t.querySelectorAll(e.selector)) {
1288
+ for (const u of e.querySelectorAll(t.selector)) {
1289
1289
  if (a && g(u)) continue;
1290
- const h = u.getAttribute(o);
1291
- if (h === null) continue;
1292
- const b = c.test(h);
1293
- p && !b ? i.push({
1294
- ruleId: e.id,
1290
+ const p = u.getAttribute(o);
1291
+ if (p === null) continue;
1292
+ const b = c.test(p);
1293
+ h && !b ? i.push({
1294
+ ruleId: t.id,
1295
1295
  selector: m(u),
1296
1296
  html: d(u),
1297
- impact: e.impact,
1298
- message: S(e.message, u, e.check),
1297
+ impact: t.impact,
1298
+ message: k(t.message, u, t.check),
1299
1299
  element: u
1300
- }) : !p && b && i.push({
1301
- ruleId: e.id,
1300
+ }) : !h && b && i.push({
1301
+ ruleId: t.id,
1302
1302
  selector: m(u),
1303
1303
  html: d(u),
1304
- impact: e.impact,
1305
- message: S(e.message, u, e.check),
1304
+ impact: t.impact,
1305
+ message: k(t.message, u, t.check),
1306
1306
  element: u
1307
1307
  });
1308
1308
  }
1309
1309
  break;
1310
1310
  }
1311
1311
  case "child-required": {
1312
- const { childSelector: o } = e.check;
1313
- for (const s of t.querySelectorAll(e.selector))
1312
+ const { childSelector: o } = t.check;
1313
+ for (const s of e.querySelectorAll(t.selector))
1314
1314
  a && g(s) || s.querySelector(o) || i.push({
1315
- ruleId: e.id,
1315
+ ruleId: t.id,
1316
1316
  selector: m(s),
1317
1317
  html: d(s),
1318
- impact: e.impact,
1319
- message: S(e.message, s, e.check),
1318
+ impact: t.impact,
1319
+ message: k(t.message, s, t.check),
1320
1320
  element: s
1321
1321
  });
1322
1322
  break;
1323
1323
  }
1324
1324
  case "child-invalid": {
1325
1325
  const o = new Set(
1326
- e.check.allowedChildren.map((l) => l.toLowerCase())
1327
- ), s = e.check.allowedChildRoles ? new Set(e.check.allowedChildRoles.map((l) => l.toLowerCase())) : null;
1328
- for (const l of t.querySelectorAll(e.selector)) {
1326
+ t.check.allowedChildren.map((l) => l.toLowerCase())
1327
+ ), s = t.check.allowedChildRoles ? new Set(t.check.allowedChildRoles.map((l) => l.toLowerCase())) : null;
1328
+ for (const l of e.querySelectorAll(t.selector)) {
1329
1329
  if (a && g(l)) continue;
1330
- const p = (n = l.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase();
1331
- if (p === "presentation" || p === "none") continue;
1330
+ const h = (n = l.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase();
1331
+ if (h === "presentation" || h === "none") continue;
1332
1332
  let c = !1;
1333
- const u = e.check.allowedChildren.filter(
1334
- (h) => h !== "script" && h !== "template"
1333
+ const u = t.check.allowedChildren.filter(
1334
+ (p) => p !== "script" && p !== "template"
1335
1335
  );
1336
- for (const h of l.childNodes)
1337
- if (h.nodeType === 3 && h.textContent && h.textContent.trim()) {
1336
+ for (const p of l.childNodes)
1337
+ if (p.nodeType === 3 && p.textContent && p.textContent.trim()) {
1338
1338
  const b = u.map((f) => `<${f}>`).join(" or ");
1339
1339
  i.push({
1340
- ruleId: e.id,
1340
+ ruleId: t.id,
1341
1341
  selector: m(l),
1342
1342
  html: d(l),
1343
- impact: e.impact,
1343
+ impact: t.impact,
1344
1344
  message: `<${l.tagName.toLowerCase()}> contains direct text content. Wrap in ${b}.`,
1345
1345
  element: l
1346
1346
  }), c = !0;
1347
1347
  break;
1348
1348
  }
1349
1349
  if (!c)
1350
- for (const h of l.children) {
1351
- if (o.has(h.tagName.toLowerCase())) continue;
1352
- const b = (r = h.getAttribute("role")) == null ? void 0 : r.trim().toLowerCase();
1350
+ for (const p of l.children) {
1351
+ if (o.has(p.tagName.toLowerCase())) continue;
1352
+ const b = (r = p.getAttribute("role")) == null ? void 0 : r.trim().toLowerCase();
1353
1353
  if (!(b && (s != null && s.has(b))) && !(b === "presentation" || b === "none")) {
1354
1354
  i.push({
1355
- ruleId: e.id,
1356
- selector: m(h),
1357
- html: d(h),
1358
- impact: e.impact,
1359
- message: S(e.message, h, e.check),
1360
- element: h
1355
+ ruleId: t.id,
1356
+ selector: m(p),
1357
+ html: d(p),
1358
+ impact: t.impact,
1359
+ message: k(t.message, p, t.check),
1360
+ element: p
1361
1361
  });
1362
1362
  break;
1363
1363
  }
@@ -1370,20 +1370,20 @@ function k(e) {
1370
1370
  }
1371
1371
  };
1372
1372
  }
1373
- function rt(e, a, t) {
1373
+ function rt(t, a, e) {
1374
1374
  switch (a) {
1375
1375
  case ">":
1376
- return parseFloat(e) > t;
1376
+ return parseFloat(t) > e;
1377
1377
  case "<":
1378
- return parseFloat(e) < t;
1378
+ return parseFloat(t) < e;
1379
1379
  case "=":
1380
- return e === String(t);
1380
+ return t === String(e);
1381
1381
  case "!=":
1382
- return e !== String(t);
1382
+ return t !== String(e);
1383
1383
  case "in":
1384
- return Array.isArray(t) && t.includes(e);
1384
+ return Array.isArray(e) && e.includes(t);
1385
1385
  case "not-in":
1386
- return Array.isArray(t) && !t.includes(e);
1386
+ return Array.isArray(e) && !e.includes(t);
1387
1387
  default:
1388
1388
  return !1;
1389
1389
  }
@@ -1399,7 +1399,7 @@ const ot = {
1399
1399
  level: "A",
1400
1400
  guidance: "Server-side image maps (using ismap attribute) send click coordinates to the server, which is inaccessible to keyboard users and screen readers who can't precisely click specific regions. Replace with client-side image maps (<map> with <area> elements) that provide keyboard access and accessible names, or use linked images/buttons instead.",
1401
1401
  prompt: "Explain that the ismap attribute should be removed and the functionality replaced with a client-side <map> element with <area> children, or separate linked images/buttons."
1402
- }, st = k(ot), lt = [
1402
+ }, st = I(ot), lt = [
1403
1403
  '[role="checkbox"]',
1404
1404
  '[role="combobox"]',
1405
1405
  '[role="listbox"]',
@@ -1425,39 +1425,39 @@ const ot = {
1425
1425
  "spinbutton",
1426
1426
  "textbox"
1427
1427
  ]);
1428
- function dt(e) {
1429
- var o, s, l, p;
1430
- const a = (o = e.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
1431
- if (a && ct.has(a) || (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && !(a && ut.has(a)))
1432
- return v(e);
1433
- const i = e.getAttribute("aria-labelledby");
1428
+ function dt(t) {
1429
+ var o, s, l, h;
1430
+ const a = (o = t.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
1431
+ if (a && ct.has(a) || (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) && !(a && ut.has(a)))
1432
+ return v(t);
1433
+ const i = t.getAttribute("aria-labelledby");
1434
1434
  if (i) {
1435
1435
  const c = i.split(/\s+/).map((u) => {
1436
- const h = e.ownerDocument.getElementById(u);
1437
- return h ? A(h).trim() : "";
1436
+ const p = t.ownerDocument.getElementById(u);
1437
+ return p ? A(p).trim() : "";
1438
1438
  }).filter(Boolean);
1439
1439
  if (c.length) return c.join(" ");
1440
1440
  }
1441
- const n = (s = e.getAttribute("aria-label")) == null ? void 0 : s.trim();
1441
+ const n = (s = t.getAttribute("aria-label")) == null ? void 0 : s.trim();
1442
1442
  if (n) return n;
1443
- if (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement) {
1444
- if (e.id) {
1445
- const u = e.ownerDocument.querySelector(`label[for="${CSS.escape(e.id)}"]`);
1443
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
1444
+ if (t.id) {
1445
+ const u = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`);
1446
1446
  if (u) {
1447
- const h = A(u).trim();
1448
- if (h) return h;
1447
+ const p = A(u).trim();
1448
+ if (p) return p;
1449
1449
  }
1450
1450
  }
1451
- const c = e.closest("label");
1451
+ const c = t.closest("label");
1452
1452
  if (c) {
1453
1453
  const u = A(c).trim();
1454
1454
  if (u) return u;
1455
1455
  }
1456
1456
  }
1457
- const r = (l = e.getAttribute("title")) == null ? void 0 : l.trim();
1457
+ const r = (l = t.getAttribute("title")) == null ? void 0 : l.trim();
1458
1458
  if (r) return r;
1459
- if (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) {
1460
- const c = (p = e.getAttribute("placeholder")) == null ? void 0 : p.trim();
1459
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
1460
+ const c = (h = t.getAttribute("placeholder")) == null ? void 0 : h.trim();
1461
1461
  if (c) return c;
1462
1462
  }
1463
1463
  return "";
@@ -1469,20 +1469,20 @@ const mt = {
1469
1469
  description: "Form elements must have labels. Use <label>, aria-label, or aria-labelledby.",
1470
1470
  guidance: "Every form input needs an accessible label so users understand what information to enter. Use a <label> element with a for attribute matching the input's id, wrap the input in a <label>, or use aria-label/aria-labelledby for custom components. Placeholders are not sufficient as labels since they disappear when typing.",
1471
1471
  prompt: `This form field has no accessible label. Based on the context (input type, name attribute, placeholder, or surrounding elements), suggest adding a <label for="id"> element with descriptive text, or an aria-label attribute. The label should describe what information the user should enter, not the field type. For example: 'Email address', 'Search', 'Phone number'.`,
1472
- run(e) {
1472
+ run(t) {
1473
1473
  var n;
1474
- const a = [], i = e.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select, ${lt}`);
1474
+ const a = [], i = t.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select, ${lt}`);
1475
1475
  for (const r of i) {
1476
1476
  if (g(r) || T(r) || (r instanceof HTMLInputElement || r instanceof HTMLTextAreaElement || r instanceof HTMLSelectElement || r instanceof HTMLButtonElement) && r.disabled || r.closest("fieldset[disabled]") || r.getAttribute("aria-disabled") === "true") continue;
1477
1477
  const o = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase();
1478
1478
  if (o === "presentation" || o === "none") continue;
1479
1479
  if (!dt(r)) {
1480
- const l = [], p = r.tagName.toLowerCase(), c = r.getAttribute("type");
1481
- c && p === "input" && l.push(`type: ${c}`);
1480
+ const l = [], h = r.tagName.toLowerCase(), c = r.getAttribute("type");
1481
+ c && h === "input" && l.push(`type: ${c}`);
1482
1482
  const u = r.getAttribute("name");
1483
1483
  u && l.push(`name: "${u}"`);
1484
- const h = r.getAttribute("placeholder");
1485
- h && l.push(`placeholder: "${h}"`), o && l.push(`role: ${o}`);
1484
+ const p = r.getAttribute("placeholder");
1485
+ p && l.push(`placeholder: "${p}"`), o && l.push(`role: ${o}`);
1486
1486
  const b = r.getAttribute("id");
1487
1487
  b && l.push(`id: "${b}"`), a.push({
1488
1488
  ruleId: "label",
@@ -1504,11 +1504,11 @@ const mt = {
1504
1504
  description: "Form fields should not have multiple label elements.",
1505
1505
  guidance: "When a form field has multiple <label> elements pointing to it, assistive technologies may announce only one label or behave inconsistently. Use a single <label> and combine any additional text into it, or use aria-describedby for supplementary information.",
1506
1506
  prompt: "Identify the multiple labels and recommend consolidating them into a single <label> element or using aria-describedby for supplementary text.",
1507
- run(e) {
1508
- const a = [], t = e.querySelectorAll('input:not([type="hidden"]), textarea, select');
1509
- for (const i of t) {
1507
+ run(t) {
1508
+ const a = [], e = t.querySelectorAll('input:not([type="hidden"]), textarea, select');
1509
+ for (const i of e) {
1510
1510
  if (g(i) || !i.id) continue;
1511
- const n = e.querySelectorAll(`label[for="${CSS.escape(i.id)}"]`);
1511
+ const n = t.querySelectorAll(`label[for="${CSS.escape(i.id)}"]`);
1512
1512
  let r = 0, o = i.parentElement;
1513
1513
  for (; o; ) {
1514
1514
  if (o.tagName.toLowerCase() === "label" && !o.hasAttribute("for")) {
@@ -1535,13 +1535,13 @@ const mt = {
1535
1535
  description: "Select elements must have a programmatically associated label via <label>, aria-label, or aria-labelledby.",
1536
1536
  guidance: "Select dropdowns need labels so users understand what choice they're making. Use a <label> element with a for attribute matching the select's id, or wrap the select in a <label>. For selects without visible labels, use aria-label. The first <option> is not a substitute for a proper label.",
1537
1537
  prompt: "Based on the options or context, suggest a label element or aria-label describing what this select controls.",
1538
- run(e) {
1538
+ run(t) {
1539
1539
  const a = [];
1540
- for (const t of e.querySelectorAll("select"))
1541
- g(t) || v(t) || a.push({
1540
+ for (const e of t.querySelectorAll("select"))
1541
+ g(e) || v(e) || a.push({
1542
1542
  ruleId: "select-name",
1543
- selector: m(t),
1544
- html: d(t),
1543
+ selector: m(e),
1544
+ html: d(e),
1545
1545
  impact: "critical",
1546
1546
  message: "Select element has no accessible name."
1547
1547
  });
@@ -1554,14 +1554,14 @@ const mt = {
1554
1554
  description: "Input buttons must have discernible text via value, aria-label, or aria-labelledby.",
1555
1555
  guidance: "Input buttons (<input type='submit'>, type='button', type='reset'>) need accessible names so users know what action the button performs. Add a value attribute with descriptive text (e.g., value='Submit Form'), or use aria-label if the value must differ from the accessible name.",
1556
1556
  prompt: "Based on the input type and form context, suggest a value attribute describing the button's action.",
1557
- run(e) {
1558
- var t, i;
1557
+ run(t) {
1558
+ var e, i;
1559
1559
  const a = [];
1560
- for (const n of e.querySelectorAll(
1560
+ for (const n of t.querySelectorAll(
1561
1561
  'input[type="submit"], input[type="button"], input[type="reset"]'
1562
1562
  )) {
1563
1563
  if (g(n)) continue;
1564
- const r = (t = n.getAttribute("value")) == null ? void 0 : t.trim(), o = (i = n.getAttribute("type")) == null ? void 0 : i.toLowerCase(), s = (o === "submit" || o === "reset") && !n.hasAttribute("value");
1564
+ const r = (e = n.getAttribute("value")) == null ? void 0 : e.trim(), o = (i = n.getAttribute("type")) == null ? void 0 : i.toLowerCase(), s = (o === "submit" || o === "reset") && !n.hasAttribute("value");
1565
1565
  !r && !s && !v(n) && a.push({
1566
1566
  ruleId: "input-button-name",
1567
1567
  selector: m(n),
@@ -1636,16 +1636,16 @@ const mt = {
1636
1636
  "tel-extension",
1637
1637
  "email",
1638
1638
  "impp"
1639
- ]), vt = /* @__PURE__ */ new Set(["home", "work", "mobile", "fax", "pager"]), wt = /* @__PURE__ */ new Set(["shipping", "billing"]), yt = /* @__PURE__ */ new Set(["webauthn"]);
1640
- function At(e) {
1641
- const a = e.toLowerCase().split(/\s+/).filter(Boolean);
1639
+ ]), vt = /* @__PURE__ */ new Set(["home", "work", "mobile", "fax", "pager"]), yt = /* @__PURE__ */ new Set(["shipping", "billing"]), wt = /* @__PURE__ */ new Set(["webauthn"]);
1640
+ function At(t) {
1641
+ const a = t.toLowerCase().split(/\s+/).filter(Boolean);
1642
1642
  if (a.length === 0) return !0;
1643
- let t = 0;
1644
- a[t].startsWith("section-") && t++, t < a.length && wt.has(a[t]) && t++;
1643
+ let e = 0;
1644
+ a[e].startsWith("section-") && e++, e < a.length && yt.has(a[e]) && e++;
1645
1645
  let i = !1;
1646
- if (t < a.length && vt.has(a[t]) && (i = !0, t++), t >= a.length) return !1;
1647
- const n = a[t];
1648
- return !bt.has(n) || i && !ft.has(n) ? !1 : (t++, t < a.length && yt.has(a[t]) && t++, t === a.length);
1646
+ if (e < a.length && vt.has(a[e]) && (i = !0, e++), e >= a.length) return !1;
1647
+ const n = a[e];
1648
+ return !bt.has(n) || i && !ft.has(n) ? !1 : (e++, e < a.length && wt.has(a[e]) && e++, e === a.length);
1649
1649
  }
1650
1650
  const xt = {
1651
1651
  id: "autocomplete-valid",
@@ -1654,15 +1654,15 @@ const xt = {
1654
1654
  description: "Autocomplete attribute must use valid values from the HTML specification.",
1655
1655
  guidance: "The autocomplete attribute helps users fill forms by identifying input purposes. Use standard values like 'name', 'email', 'tel', 'street-address', 'postal-code', 'cc-number'. This benefits users with cognitive disabilities, motor impairments, and anyone using password managers or autofill. Check the HTML specification for the complete list of valid tokens.",
1656
1656
  prompt: "Show the invalid autocomplete value and suggest the correct standard value based on the input's apparent purpose.",
1657
- run(e) {
1657
+ run(t) {
1658
1658
  const a = [];
1659
- for (const t of e.querySelectorAll("[autocomplete]")) {
1660
- if (g(t) || t instanceof HTMLElement && t.style.display === "none" || t.disabled || t.getAttribute("aria-disabled") === "true") continue;
1661
- const i = t.getAttribute("autocomplete").trim();
1659
+ for (const e of t.querySelectorAll("[autocomplete]")) {
1660
+ if (g(e) || e instanceof HTMLElement && e.style.display === "none" || e.disabled || e.getAttribute("aria-disabled") === "true") continue;
1661
+ const i = e.getAttribute("autocomplete").trim();
1662
1662
  i && (At(i) || a.push({
1663
1663
  ruleId: "autocomplete-valid",
1664
- selector: m(t),
1665
- html: d(t),
1664
+ selector: m(e),
1665
+ html: d(e),
1666
1666
  impact: "serious",
1667
1667
  message: `Invalid autocomplete value "${i}".`
1668
1668
  }));
@@ -1670,26 +1670,26 @@ const xt = {
1670
1670
  return a;
1671
1671
  }
1672
1672
  };
1673
- function ee(e) {
1674
- return e.toLowerCase().replace(/\s+/g, " ").trim();
1673
+ function te(t) {
1674
+ return t.toLowerCase().replace(/\s+/g, " ").trim();
1675
1675
  }
1676
- function te(e, a) {
1677
- const t = ee(e), i = ee(a);
1678
- if (!t || !i || t.includes(i) || i.includes(t)) return !0;
1676
+ function ae(t, a) {
1677
+ const e = te(t), i = te(a);
1678
+ if (!e || !i || e.includes(i) || i.includes(e)) return !0;
1679
1679
  const n = i.split(/\s+/).map((r) => r.replace(/[.,;:!?\u2026]+$/g, "")).filter((r) => r.length > 2);
1680
- return n.length >= 2 && n.filter((o) => t.includes(o)).length / n.length > 0.5;
1680
+ return n.length >= 2 && n.filter((o) => e.includes(o)).length / n.length > 0.5;
1681
1681
  }
1682
- function z(e) {
1682
+ function U(t) {
1683
1683
  let a = "";
1684
- for (const t of e.childNodes)
1685
- if (t.nodeType === 3)
1686
- a += t.textContent ?? "";
1687
- else if (t.nodeType === 1) {
1688
- const i = t, n = i.tagName.toLowerCase();
1684
+ for (const e of t.childNodes)
1685
+ if (e.nodeType === 3)
1686
+ a += e.textContent ?? "";
1687
+ else if (e.nodeType === 1) {
1688
+ const i = e, n = i.tagName.toLowerCase();
1689
1689
  if (n === "style" || n === "script" || n === "svg" || i.getAttribute("aria-hidden") === "true" || i instanceof HTMLElement && i.style.display === "none") continue;
1690
1690
  const r = i.getAttribute("role");
1691
1691
  if (r === "img" || r === "presentation" || r === "none") continue;
1692
- a += z(i);
1692
+ a += U(i);
1693
1693
  }
1694
1694
  return a;
1695
1695
  }
@@ -1701,39 +1701,39 @@ const St = {
1701
1701
  description: "Interactive elements with visible text must have accessible names that contain that text.",
1702
1702
  guidance: "For voice control users who activate controls by speaking their visible label, the accessible name must include the visible text. If aria-label is 'Submit form' but the button shows 'Send', voice users saying 'click Send' won't activate it. Ensure aria-label/aria-labelledby contains or matches the visible text.",
1703
1703
  prompt: "Show the mismatch between the visible text and accessible name, and suggest updating aria-label to include the visible text.",
1704
- run(e) {
1704
+ run(t) {
1705
1705
  const a = [];
1706
- for (const t of e.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
1707
- if (g(t)) continue;
1708
- const i = v(t);
1706
+ for (const e of t.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
1707
+ if (g(e)) continue;
1708
+ const i = v(e);
1709
1709
  if (!i) continue;
1710
1710
  let n = "";
1711
- t instanceof HTMLInputElement ? n = t.value || "" : n = z(t);
1711
+ e instanceof HTMLInputElement ? n = e.value || "" : n = U(e);
1712
1712
  const r = n.trim();
1713
1713
  if (!r || r.length <= 2) continue;
1714
- const o = t.hasAttribute("aria-label"), s = t.hasAttribute("aria-labelledby");
1715
- !o && !s || te(i, n) || a.push({
1714
+ const o = e.hasAttribute("aria-label"), s = e.hasAttribute("aria-labelledby");
1715
+ !o && !s || ae(i, n) || a.push({
1716
1716
  ruleId: "label-content-name-mismatch",
1717
- selector: m(t),
1718
- html: d(t),
1717
+ selector: m(e),
1718
+ html: d(e),
1719
1719
  impact: "serious",
1720
1720
  message: `Accessible name "${i}" does not contain visible text "${n.trim()}".`
1721
1721
  });
1722
1722
  }
1723
- for (const t of e.querySelectorAll("input, select, textarea")) {
1724
- if (g(t) || t instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(t.type)) continue;
1725
- const i = v(t);
1726
- if (!i || !t.hasAttribute("aria-label")) continue;
1727
- const r = t.id;
1723
+ for (const e of t.querySelectorAll("input, select, textarea")) {
1724
+ if (g(e) || e instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(e.type)) continue;
1725
+ const i = v(e);
1726
+ if (!i || !e.hasAttribute("aria-label")) continue;
1727
+ const r = e.id;
1728
1728
  let o = "";
1729
1729
  if (r) {
1730
- const s = e.querySelector(`label[for="${CSS.escape(r)}"]`);
1731
- s && (o = z(s));
1730
+ const s = t.querySelector(`label[for="${CSS.escape(r)}"]`);
1731
+ s && (o = U(s));
1732
1732
  }
1733
- o.trim() && (te(i, o) || a.push({
1733
+ o.trim() && (ae(i, o) || a.push({
1734
1734
  ruleId: "label-content-name-mismatch",
1735
- selector: m(t),
1736
- html: d(t),
1735
+ selector: m(e),
1736
+ html: d(e),
1737
1737
  impact: "serious",
1738
1738
  message: `Accessible name "${i}" does not contain visible label "${o.trim()}".`
1739
1739
  }));
@@ -1748,22 +1748,22 @@ const St = {
1748
1748
  description: "Form elements should not use title attribute as the only accessible name.",
1749
1749
  guidance: "The title attribute is unreliable as a label because it only appears on hover/focus (not visible to touch users) and is often ignored by assistive technologies. Use a visible <label> element, aria-label, or aria-labelledby instead. Title can supplement a label but should not replace it.",
1750
1750
  prompt: "The title attribute text should be moved to a visible <label> element or aria-label. Show what text to use based on the current title.",
1751
- run(e) {
1751
+ run(t) {
1752
1752
  var i, n, r, o;
1753
- const a = [], t = e.querySelectorAll(
1753
+ const a = [], e = t.querySelectorAll(
1754
1754
  'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
1755
1755
  );
1756
- for (const s of t) {
1756
+ for (const s of e) {
1757
1757
  if (g(s)) continue;
1758
- const l = s.hasAttribute("title") && ((i = s.getAttribute("title")) == null ? void 0 : i.trim()), p = s.hasAttribute("aria-label") && ((n = s.getAttribute("aria-label")) == null ? void 0 : n.trim()), c = s.hasAttribute("aria-labelledby");
1758
+ const l = s.hasAttribute("title") && ((i = s.getAttribute("title")) == null ? void 0 : i.trim()), h = s.hasAttribute("aria-label") && ((n = s.getAttribute("aria-label")) == null ? void 0 : n.trim()), c = s.hasAttribute("aria-labelledby");
1759
1759
  let u = !1;
1760
- const h = s.id;
1761
- if (h) {
1762
- const f = s.ownerDocument.querySelector(`label[for="${CSS.escape(h)}"]`);
1760
+ const p = s.id;
1761
+ if (p) {
1762
+ const f = s.ownerDocument.querySelector(`label[for="${CSS.escape(p)}"]`);
1763
1763
  (r = f == null ? void 0 : f.textContent) != null && r.trim() && (u = !0);
1764
1764
  }
1765
1765
  const b = s.closest("label");
1766
- (o = b == null ? void 0 : b.textContent) != null && o.trim() && (u = !0), l && !p && !c && !u && a.push({
1766
+ (o = b == null ? void 0 : b.textContent) != null && o.trim() && (u = !0), l && !h && !c && !u && a.push({
1767
1767
  ruleId: "label-title-only",
1768
1768
  selector: m(s),
1769
1769
  html: d(s),
@@ -1785,7 +1785,7 @@ const St = {
1785
1785
  tags: ["best-practice"],
1786
1786
  guidance: "Positive tabindex values force elements to the front of the tab order regardless of DOM position, creating unpredictable navigation for keyboard users. Use tabindex='0' to add elements to the natural tab order, or tabindex='-1' to make elements programmatically focusable but not in tab order. Rely on DOM order for tab sequence.",
1787
1787
  prompt: "Change the positive tabindex value to tabindex='0' and rely on DOM order for tab sequence instead."
1788
- }, Tt = k(It), Et = /* @__PURE__ */ new Set([
1788
+ }, Tt = I(It), Et = /* @__PURE__ */ new Set([
1789
1789
  "div",
1790
1790
  "span",
1791
1791
  "p",
@@ -1820,15 +1820,15 @@ const St = {
1820
1820
  description: "Elements that receive keyboard focus must have an appropriate role so assistive technologies can convey their purpose. Non-interactive elements with tabindex='0' need a valid interactive ARIA role.",
1821
1821
  guidance: "When adding tabindex='0' to non-interactive elements like <div> or <span>, screen readers announce them generically. Add an appropriate role (button, link, tab, etc.) so users understand the element's purpose. Also add keyboard event handlers (Enter/Space for buttons, Enter for links). Consider using native interactive elements instead.",
1822
1822
  prompt: "Based on the element's apparent purpose, suggest adding an appropriate role attribute (button, link, etc.) or converting to a native interactive element.",
1823
- run(e) {
1823
+ run(t) {
1824
1824
  const a = [];
1825
- for (const t of e.querySelectorAll('[tabindex="0"]')) {
1826
- const i = t.tagName.toLowerCase();
1825
+ for (const e of t.querySelectorAll('[tabindex="0"]')) {
1826
+ const i = e.tagName.toLowerCase();
1827
1827
  if (!Et.has(i)) continue;
1828
- t.getAttribute("role") || a.push({
1828
+ e.getAttribute("role") || a.push({
1829
1829
  ruleId: "focus-order-semantics",
1830
- selector: m(t),
1831
- html: d(t),
1830
+ selector: m(e),
1831
+ html: d(e),
1832
1832
  impact: "moderate",
1833
1833
  message: `Non-interactive <${i}> with tabindex="0" has no interactive role.`
1834
1834
  });
@@ -1878,24 +1878,24 @@ const St = {
1878
1878
  tree: /* @__PURE__ */ new Set(["treeitem"]),
1879
1879
  treegrid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader", "treeitem"])
1880
1880
  };
1881
- function Nt(e, a) {
1881
+ function Nt(t, a) {
1882
1882
  var n, r, o;
1883
- const t = (n = e.getAttribute("role")) == null ? void 0 : n.toLowerCase(), i = (r = a.getAttribute("role")) == null ? void 0 : r.toLowerCase();
1884
- return !t || !i ? !1 : ((o = Rt[t]) == null ? void 0 : o.has(i)) ?? !1;
1883
+ const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase(), i = (r = a.getAttribute("role")) == null ? void 0 : r.toLowerCase();
1884
+ return !e || !i ? !1 : ((o = Rt[e]) == null ? void 0 : o.has(i)) ?? !1;
1885
1885
  }
1886
- function $t(e) {
1886
+ function $t(t) {
1887
1887
  var n;
1888
- const a = e.tagName.toLowerCase();
1888
+ const a = t.tagName.toLowerCase();
1889
1889
  if (Lt.has(a))
1890
- return a === "a" && !e.hasAttribute("href") ? !1 : a === "audio" || a === "video" ? e.hasAttribute("controls") : !(a === "img" && !e.hasAttribute("usemap") || a === "input" && e.type === "hidden" || e.disabled);
1891
- const t = (n = e.getAttribute("role")) == null ? void 0 : n.toLowerCase();
1892
- if (t && qt.has(t)) return !0;
1893
- const i = e.getAttribute("tabindex");
1894
- return i !== null && i !== "-1" || e.getAttribute("contenteditable") === "true";
1890
+ return a === "a" && !t.hasAttribute("href") ? !1 : a === "audio" || a === "video" ? t.hasAttribute("controls") : !(a === "img" && !t.hasAttribute("usemap") || a === "input" && t.type === "hidden" || t.disabled);
1891
+ const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase();
1892
+ if (e && qt.has(e)) return !0;
1893
+ const i = t.getAttribute("tabindex");
1894
+ return i !== null && i !== "-1" || t.getAttribute("contenteditable") === "true";
1895
1895
  }
1896
- function Mt(e) {
1897
- const a = e.tagName.toLowerCase();
1898
- return !!(a === "a" && e.hasAttribute("href") || a === "button" && !e.disabled);
1896
+ function Mt(t) {
1897
+ const a = t.tagName.toLowerCase();
1898
+ return !!(a === "a" && t.hasAttribute("href") || a === "button" && !t.disabled);
1899
1899
  }
1900
1900
  const Ht = {
1901
1901
  id: "nested-interactive",
@@ -1904,10 +1904,10 @@ const Ht = {
1904
1904
  description: "Interactive controls must not be nested inside each other.",
1905
1905
  guidance: "Nesting interactive elements (like a button inside a link, or a link inside a button) creates unpredictable behavior and confuses assistive technologies. The browser may remove the inner element from the accessibility tree. Restructure the HTML so interactive elements are siblings, not nested. If you need a clickable card, use CSS and JavaScript rather than nesting.",
1906
1906
  prompt: "Identify which elements are nested and suggest restructuring them as siblings instead.",
1907
- run(e) {
1908
- const a = [], t = e.body ?? e;
1909
- if (!t) return a;
1910
- const n = (e.body ? e : e.ownerDocument).createTreeWalker(t, NodeFilter.SHOW_ELEMENT), r = [];
1907
+ run(t) {
1908
+ const a = [], e = t.body ?? t;
1909
+ if (!e) return a;
1910
+ const n = (t.body ? t : t.ownerDocument).createTreeWalker(e, NodeFilter.SHOW_ELEMENT), r = [];
1911
1911
  let o = n.currentNode;
1912
1912
  for (; o; ) {
1913
1913
  for (; r.length > 0 && !r[r.length - 1].contains(o); )
@@ -1936,22 +1936,22 @@ const Ht = {
1936
1936
  description: "Scrollable regions must be keyboard accessible.",
1937
1937
  guidance: "Content that scrolls must be accessible to keyboard users. If a region has overflow:scroll or overflow:auto and contains scrollable content, it needs either tabindex='0' to be focusable, or it must contain focusable elements. Without this, keyboard users cannot scroll the content.",
1938
1938
  prompt: "Explain how to make this scrollable region keyboard accessible.",
1939
- run(e) {
1940
- var t;
1939
+ run(t) {
1940
+ var e;
1941
1941
  const a = [];
1942
- for (const i of e.querySelectorAll("*")) {
1942
+ for (const i of t.querySelectorAll("*")) {
1943
1943
  if (g(i) || !(i instanceof HTMLElement)) continue;
1944
1944
  const n = i.tagName.toLowerCase();
1945
1945
  if (n === "body" || n === "html") continue;
1946
1946
  const r = i.getAttribute("role");
1947
1947
  if (r === "presentation" || r === "none") continue;
1948
- const o = y(i), s = o.overflowX, l = o.overflowY;
1948
+ const o = w(i), s = o.overflowX, l = o.overflowY;
1949
1949
  if (!(s === "scroll" || s === "auto" || l === "scroll" || l === "auto")) continue;
1950
1950
  if (i.scrollHeight > 0 || i.clientHeight > 0) {
1951
1951
  const b = i.scrollHeight - i.clientHeight, f = i.scrollWidth - i.clientWidth;
1952
1952
  if (b <= 0 && f <= 0 || b < 14 && f < 14 || i.clientWidth < 64 && i.clientHeight < 64) continue;
1953
1953
  } else {
1954
- const b = o.height !== "" || o.maxHeight !== "", f = ((t = i.textContent) == null ? void 0 : t.trim().length) ?? 0;
1954
+ const b = o.height !== "" || o.maxHeight !== "", f = ((e = i.textContent) == null ? void 0 : e.trim().length) ?? 0;
1955
1955
  if (!b || f <= 50) continue;
1956
1956
  }
1957
1957
  const u = i.getAttribute("tabindex");
@@ -1975,17 +1975,17 @@ const Ht = {
1975
1975
  description: "Accesskey attribute values must be unique.",
1976
1976
  guidance: "When multiple elements share the same accesskey, browser behavior becomes unpredictable - usually only the first element is activated. Ensure each accesskey value is unique within the page. Also consider that accesskeys can conflict with browser and screen reader shortcuts, so use them sparingly.",
1977
1977
  prompt: "Suggest removing or changing this duplicate accesskey to a unique value.",
1978
- run(e) {
1978
+ run(t) {
1979
1979
  var i;
1980
- const a = [], t = /* @__PURE__ */ new Map();
1981
- for (const n of e.querySelectorAll("[accesskey]")) {
1980
+ const a = [], e = /* @__PURE__ */ new Map();
1981
+ for (const n of t.querySelectorAll("[accesskey]")) {
1982
1982
  if (g(n)) continue;
1983
1983
  const r = (i = n.getAttribute("accesskey")) == null ? void 0 : i.trim().toLowerCase();
1984
1984
  if (!r) continue;
1985
- const o = t.get(r) || [];
1986
- o.push(n), t.set(r, o);
1985
+ const o = e.get(r) || [];
1986
+ o.push(n), e.set(r, o);
1987
1987
  }
1988
- for (const [n, r] of t)
1988
+ for (const [n, r] of e)
1989
1989
  if (r.length > 1)
1990
1990
  for (const o of r.slice(1))
1991
1991
  a.push({
@@ -2005,10 +2005,10 @@ const Ht = {
2005
2005
  description: "Heading levels should increase by one; skipping levels (e.g. h2 to h4) makes navigation harder.",
2006
2006
  guidance: "Screen reader users navigate by headings to understand page structure. Skipping levels (h2 to h4) suggests missing content and creates confusion. Start with h1 for the page title, then use h2 for main sections, h3 for subsections, etc. You can go back up (h3 to h2) when starting a new section.",
2007
2007
  prompt: "State which heading level was expected and suggest changing this heading to the appropriate level.",
2008
- run(e) {
2009
- const a = [], t = e.querySelectorAll("h1, h2, h3, h4, h5, h6, [role='heading']");
2008
+ run(t) {
2009
+ const a = [], e = t.querySelectorAll("h1, h2, h3, h4, h5, h6, [role='heading']");
2010
2010
  let i = 0, n = null;
2011
- for (const r of t) {
2011
+ for (const r of e) {
2012
2012
  if (g(r)) continue;
2013
2013
  let o;
2014
2014
  r.hasAttribute("aria-level") ? o = parseInt(r.getAttribute("aria-level"), 10) : o = parseInt(r.tagName[1], 10), i > 0 && o > i + 1 && a.push({
@@ -2022,7 +2022,7 @@ const Ht = {
2022
2022
  }
2023
2023
  return a;
2024
2024
  }
2025
- }, $ = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', ae = 'main, [role="main"], header, [role="banner"], footer, [role="contentinfo"], nav, [role="navigation"], aside, [role="complementary"], section[aria-label], section[aria-labelledby], [role="region"][aria-label], [role="region"][aria-labelledby], form[aria-label], form[aria-labelledby], [role="form"][aria-label], [role="form"][aria-labelledby], [role="search"]', Ot = {
2025
+ }, $ = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', ie = 'main, [role="main"], header, [role="banner"], footer, [role="contentinfo"], nav, [role="navigation"], aside, [role="complementary"], section[aria-label], section[aria-labelledby], [role="region"][aria-label], [role="region"][aria-labelledby], form[aria-label], form[aria-labelledby], [role="form"][aria-label], [role="form"][aria-labelledby], [role="search"]', Ot = {
2026
2026
  id: "landmark-one-main",
2027
2027
  wcag: [],
2028
2028
  level: "A",
@@ -2030,18 +2030,18 @@ const Ht = {
2030
2030
  description: "Page should have exactly one main landmark.",
2031
2031
  guidance: "The main landmark contains the primary content of the page. Screen readers allow users to jump directly to main content. Use a single <main> element (or role='main') to wrap the central content, excluding headers, footers, and navigation.",
2032
2032
  prompt: "Identify the primary content area and explain how to wrap it in a <main> element.",
2033
- run(e) {
2034
- const a = e.querySelectorAll('main, [role="main"]');
2033
+ run(t) {
2034
+ const a = t.querySelectorAll('main, [role="main"]');
2035
2035
  return a.length === 0 ? [{
2036
2036
  ruleId: "landmark-one-main",
2037
2037
  selector: "html",
2038
2038
  html: "<html>",
2039
2039
  impact: "moderate",
2040
2040
  message: "Page has no main landmark."
2041
- }] : a.length > 1 ? Array.from(a).slice(1).map((t) => ({
2041
+ }] : a.length > 1 ? Array.from(a).slice(1).map((e) => ({
2042
2042
  ruleId: "landmark-one-main",
2043
- selector: m(t),
2044
- html: d(t),
2043
+ selector: m(e),
2044
+ html: d(e),
2045
2045
  impact: "moderate",
2046
2046
  message: "Page has multiple main landmarks."
2047
2047
  })) : [];
@@ -2054,8 +2054,8 @@ const Ht = {
2054
2054
  description: "Page should not have more than one banner landmark.",
2055
2055
  guidance: "The banner landmark (typically <header>) identifies site-oriented content like logos and search. Only one top-level banner is allowed per page. If you need multiple headers, nest them inside sectioning elements (article, section, aside) where they become scoped headers rather than page-level banners.",
2056
2056
  prompt: "Explain whether to remove this duplicate banner or nest it inside a sectioning element.",
2057
- run(e) {
2058
- const a = [], t = e.querySelectorAll('header, [role="banner"]'), i = Array.from(t).filter((n) => !n.closest($));
2057
+ run(t) {
2058
+ const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest($));
2059
2059
  return i.length > 1 && i.slice(1).forEach(
2060
2060
  (n) => a.push({
2061
2061
  ruleId: "landmark-no-duplicate-banner",
@@ -2074,8 +2074,8 @@ const Ht = {
2074
2074
  description: "Page should not have more than one contentinfo landmark.",
2075
2075
  guidance: "The contentinfo landmark (typically <footer>) contains information about the page like copyright and contact info. Only one top-level contentinfo is allowed per page. Nest additional footers inside sectioning elements to scope them.",
2076
2076
  prompt: "Explain whether to remove this duplicate footer or nest it inside a sectioning element.",
2077
- run(e) {
2078
- const a = [], t = e.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(t).filter((n) => !n.closest($));
2077
+ run(t) {
2078
+ const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest($));
2079
2079
  return i.length > 1 && i.slice(1).forEach(
2080
2080
  (n) => a.push({
2081
2081
  ruleId: "landmark-no-duplicate-contentinfo",
@@ -2094,9 +2094,9 @@ const Ht = {
2094
2094
  description: "Page should not have more than one main landmark.",
2095
2095
  guidance: "Only one main landmark should exist per page. The main landmark identifies the primary content area. If you have multiple content sections, use <section> with appropriate headings instead of multiple main elements.",
2096
2096
  prompt: "Explain which main landmark to keep and how to restructure the duplicate.",
2097
- run(e) {
2098
- const a = [], t = e.querySelectorAll('main, [role="main"]');
2099
- return t.length > 1 && Array.from(t).slice(1).forEach(
2097
+ run(t) {
2098
+ const a = [], e = t.querySelectorAll('main, [role="main"]');
2099
+ return e.length > 1 && Array.from(e).slice(1).forEach(
2100
2100
  (i) => a.push({
2101
2101
  ruleId: "landmark-no-duplicate-main",
2102
2102
  selector: m(i),
@@ -2114,9 +2114,9 @@ const Ht = {
2114
2114
  description: "Banner landmark should not be nested within another landmark.",
2115
2115
  guidance: "The banner landmark should be a top-level landmark, not nested inside article, aside, main, nav, or section. If a header is inside these elements, it automatically becomes a generic header rather than a banner. Remove explicit role='banner' from nested headers or restructure the page.",
2116
2116
  prompt: "Explain why this banner is incorrectly nested and how to fix it.",
2117
- run(e) {
2118
- const a = [], t = e.querySelectorAll('[role="banner"]');
2119
- for (const i of t)
2117
+ run(t) {
2118
+ const a = [], e = t.querySelectorAll('[role="banner"]');
2119
+ for (const i of e)
2120
2120
  i.closest($) && a.push({
2121
2121
  ruleId: "landmark-banner-is-top-level",
2122
2122
  selector: m(i),
@@ -2134,9 +2134,9 @@ const Ht = {
2134
2134
  description: "Contentinfo landmark should not be nested within another landmark.",
2135
2135
  guidance: "The contentinfo landmark should be a top-level landmark. A footer inside article, aside, main, nav, or section becomes a scoped footer, not a contentinfo landmark. Remove explicit role='contentinfo' from nested footers or move the footer outside sectioning elements.",
2136
2136
  prompt: "Explain why this contentinfo is incorrectly nested and how to fix it.",
2137
- run(e) {
2138
- const a = [], t = e.querySelectorAll('[role="contentinfo"]');
2139
- for (const i of t)
2137
+ run(t) {
2138
+ const a = [], e = t.querySelectorAll('[role="contentinfo"]');
2139
+ for (const i of e)
2140
2140
  i.closest($) && a.push({
2141
2141
  ruleId: "landmark-contentinfo-is-top-level",
2142
2142
  selector: m(i),
@@ -2154,9 +2154,9 @@ const Ht = {
2154
2154
  description: "Main landmark should not be nested within another landmark.",
2155
2155
  guidance: "The main landmark must be a top-level landmark since it represents the primary content of the page. Do not nest <main> or role='main' inside article, aside, nav, or section elements.",
2156
2156
  prompt: "Explain why the main landmark must be top-level and where to move it.",
2157
- run(e) {
2158
- const a = [], t = e.querySelectorAll('main, [role="main"]');
2159
- for (const i of t) {
2157
+ run(t) {
2158
+ const a = [], e = t.querySelectorAll('main, [role="main"]');
2159
+ for (const i of e) {
2160
2160
  const n = i.parentElement;
2161
2161
  n != null && n.closest('article, aside, nav, section, [role="article"], [role="complementary"], [role="navigation"], [role="region"]') && a.push({
2162
2162
  ruleId: "landmark-main-is-top-level",
@@ -2176,9 +2176,9 @@ const Ht = {
2176
2176
  description: "Aside (complementary) landmark should be top-level or directly inside main.",
2177
2177
  guidance: "The complementary landmark (aside) should be top-level or a direct child of main. Nesting aside deep within other landmarks reduces its discoverability for screen reader users navigating by landmarks.",
2178
2178
  prompt: "Explain why this aside should be repositioned and suggest where to move it.",
2179
- run(e) {
2180
- const a = [], t = e.querySelectorAll('aside, [role="complementary"]');
2181
- for (const i of t) {
2179
+ run(t) {
2180
+ const a = [], e = t.querySelectorAll('aside, [role="complementary"]');
2181
+ for (const i of e) {
2182
2182
  const n = i.parentElement;
2183
2183
  n && !n.matches('body, main, [role="main"]') && i.closest('article, nav, section, [role="article"], [role="navigation"], [role="region"]') && a.push({
2184
2184
  ruleId: "landmark-complementary-is-top-level",
@@ -2198,28 +2198,28 @@ const Ht = {
2198
2198
  description: "Landmarks should have unique labels when there are multiple of the same type.",
2199
2199
  guidance: "When a page has multiple landmarks of the same type (e.g., multiple nav elements), each should have a unique accessible name via aria-label or aria-labelledby. This helps screen reader users distinguish between them (e.g., 'Main navigation' vs 'Footer navigation').",
2200
2200
  prompt: "Suggest a unique aria-label that distinguishes this landmark based on its purpose.",
2201
- run(e) {
2202
- const a = [], t = [
2201
+ run(t) {
2202
+ const a = [], e = [
2203
2203
  { selector: 'nav, [role="navigation"]', type: "navigation" },
2204
2204
  { selector: 'aside, [role="complementary"]', type: "complementary" },
2205
2205
  { selector: 'section[aria-label], section[aria-labelledby], [role="region"]', type: "region" },
2206
2206
  { selector: 'form[aria-label], form[aria-labelledby], [role="form"], [role="search"]', type: "form" }
2207
2207
  ];
2208
- for (const { selector: i, type: n } of t) {
2209
- const r = Array.from(e.querySelectorAll(i)).filter((s) => !g(s));
2208
+ for (const { selector: i, type: n } of e) {
2209
+ const r = Array.from(t.querySelectorAll(i)).filter((s) => !g(s));
2210
2210
  if (r.length <= 1) continue;
2211
2211
  const o = /* @__PURE__ */ new Map();
2212
2212
  for (const s of r) {
2213
- const l = v(s).toLowerCase() || "", p = o.get(l) || [];
2214
- p.push(s), o.set(l, p);
2213
+ const l = v(s).toLowerCase() || "", h = o.get(l) || [];
2214
+ h.push(s), o.set(l, h);
2215
2215
  }
2216
2216
  for (const [s, l] of o)
2217
2217
  if (l.length > 1)
2218
- for (const p of l.slice(1))
2218
+ for (const h of l.slice(1))
2219
2219
  a.push({
2220
2220
  ruleId: "landmark-unique",
2221
- selector: m(p),
2222
- html: d(p),
2221
+ selector: m(h),
2222
+ html: d(h),
2223
2223
  impact: "moderate",
2224
2224
  message: s ? `Multiple ${n} landmarks have the same label "${s}".` : `Multiple ${n} landmarks have no label. Add unique aria-label attributes.`
2225
2225
  });
@@ -2234,14 +2234,14 @@ const Ht = {
2234
2234
  description: "All page content should be contained within landmarks.",
2235
2235
  guidance: "Screen reader users navigate pages by landmarks. Content outside landmarks is harder to find and understand. Wrap all visible content in appropriate landmarks: <header>, <nav>, <main>, <aside>, <footer>, or <section> with a label. Skip links may exist outside landmarks.",
2236
2236
  prompt: "Based on the content, suggest which landmark element would be most appropriate.",
2237
- run(e) {
2237
+ run(t) {
2238
2238
  var i;
2239
- const a = [], t = e.body;
2240
- if (!t) return [];
2241
- for (const n of t.children) {
2239
+ const a = [], e = t.body;
2240
+ if (!e) return [];
2241
+ for (const n of e.children) {
2242
2242
  if (g(n) || n instanceof HTMLScriptElement || n instanceof HTMLStyleElement || n.tagName === "NOSCRIPT" || n instanceof HTMLElement && n.hidden || n.matches('a[href^="#"]')) continue;
2243
- const r = n.matches(ae), o = (i = n.textContent) == null ? void 0 : i.trim();
2244
- !r && o && (n.querySelector(ae) || a.push({
2243
+ const r = n.matches(ie), o = (i = n.textContent) == null ? void 0 : i.trim();
2244
+ !r && o && (n.querySelector(ie) || a.push({
2245
2245
  ruleId: "region",
2246
2246
  selector: m(n),
2247
2247
  html: d(n),
@@ -2262,22 +2262,22 @@ const Ht = {
2262
2262
  level: "A",
2263
2263
  guidance: "Screen readers announce list structure ('list with 5 items') based on proper markup. Placing non-<li> elements directly inside <ul> or <ol> breaks this structure. Wrap content in <li> elements, or if you need wrapper divs for styling, restructure your CSS to style the <li> elements directly.",
2264
2264
  prompt: "Explain how to restructure this element within the list properly."
2265
- }, Kt = k(Xt), Jt = {
2265
+ }, Kt = I(Xt), Jt = {
2266
2266
  id: "dlitem",
2267
2267
  wcag: ["1.3.1"],
2268
2268
  level: "A",
2269
2269
  description: "<dt> and <dd> elements must be contained in a <dl>.",
2270
2270
  guidance: "Definition terms (<dt>) and definitions (<dd>) only have semantic meaning inside a definition list (<dl>). Outside of <dl>, they're treated as generic text. Wrap related <dt> and <dd> pairs in a <dl> element to convey the term/definition relationship to assistive technologies.",
2271
2271
  prompt: "Explain how to properly structure this term/definition content.",
2272
- run(e) {
2272
+ run(t) {
2273
2273
  const a = [];
2274
- for (const t of e.querySelectorAll("dt, dd"))
2275
- (!t.parentElement || t.parentElement.tagName.toLowerCase() !== "dl") && a.push({
2274
+ for (const e of t.querySelectorAll("dt, dd"))
2275
+ (!e.parentElement || e.parentElement.tagName.toLowerCase() !== "dl") && a.push({
2276
2276
  ruleId: "dlitem",
2277
- selector: m(t),
2278
- html: d(t),
2277
+ selector: m(e),
2278
+ html: d(e),
2279
2279
  impact: "serious",
2280
- message: `<${t.tagName.toLowerCase()}> is not contained in a <dl>.`
2280
+ message: `<${e.tagName.toLowerCase()}> is not contained in a <dl>.`
2281
2281
  });
2282
2282
  return a;
2283
2283
  }
@@ -2292,22 +2292,22 @@ const Ht = {
2292
2292
  level: "A",
2293
2293
  guidance: "Definition lists have strict content requirements. Only <dt> (terms), <dd> (definitions), and <div> (for grouping dt/dd pairs) are valid children. Other elements break the list structure for screen readers. Move invalid elements outside the <dl>, or restructure using proper definition list markup.",
2294
2294
  prompt: "Explain whether to move this element outside the <dl> or convert it to dt/dd."
2295
- }, Zt = k(Qt), ea = {
2295
+ }, Zt = I(Qt), ea = {
2296
2296
  id: "listitem",
2297
2297
  wcag: ["1.3.1"],
2298
2298
  level: "A",
2299
2299
  description: "<li> elements must be contained in a <ul>, <ol>, or <menu>.",
2300
2300
  guidance: "List items (<li>) only have semantic meaning inside a list container (<ul>, <ol>, or <menu>). Outside of these containers, assistive technologies cannot convey the list relationship. Wrap <li> elements in the appropriate list container.",
2301
2301
  prompt: "Explain that this <li> must be placed inside a <ul>, <ol>, or <menu> element.",
2302
- run(e) {
2303
- var t;
2302
+ run(t) {
2303
+ var e;
2304
2304
  const a = [];
2305
- for (const i of e.querySelectorAll("li")) {
2305
+ for (const i of t.querySelectorAll("li")) {
2306
2306
  if (g(i)) continue;
2307
2307
  const n = i.parentElement;
2308
2308
  if (!n) continue;
2309
2309
  const r = n.tagName.toLowerCase();
2310
- r === "ul" || r === "ol" || r === "menu" || ((t = n.getAttribute("role")) == null ? void 0 : t.trim().toLowerCase()) === "list" || a.push({
2310
+ r === "ul" || r === "ol" || r === "menu" || ((e = n.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase()) === "list" || a.push({
2311
2311
  ruleId: "listitem",
2312
2312
  selector: m(i),
2313
2313
  html: d(i),
@@ -2324,16 +2324,16 @@ const Ht = {
2324
2324
  description: "Documents must have a <title> element to provide users with an overview of content.",
2325
2325
  guidance: "Screen reader users rely on page titles to identify and navigate between tabs/windows. Add a descriptive <title> element in <head> that summarizes the page purpose. Keep titles unique across the site, placing specific content before the site name (e.g., 'Contact Us - Acme Corp').",
2326
2326
  prompt: "The page has no title or an empty title. Suggest a concise, descriptive <title> based on the page content sample in context. Good titles are specific and front-load the unique part: 'Product Details - Store Name' rather than 'Store Name - Product Details'.",
2327
- run(e) {
2328
- var t, i, n;
2329
- const a = e.querySelector("title");
2330
- if (!a || !((t = a.textContent) != null && t.trim())) {
2327
+ run(t) {
2328
+ var e, i, n;
2329
+ const a = t.querySelector("title");
2330
+ if (!a || !((e = a.textContent) != null && e.trim())) {
2331
2331
  let r;
2332
- const o = e.querySelector("h1");
2332
+ const o = t.querySelector("h1");
2333
2333
  if ((i = o == null ? void 0 : o.textContent) != null && i.trim())
2334
2334
  r = `h1: "${o.textContent.trim().slice(0, 100)}"`;
2335
- else if (e.body) {
2336
- const s = ((n = e.body.textContent) == null ? void 0 : n.trim().replace(/\s+/g, " ")) || "";
2335
+ else if (t.body) {
2336
+ const s = ((n = t.body.textContent) == null ? void 0 : n.trim().replace(/\s+/g, " ")) || "";
2337
2337
  s && (r = `Page text: "${s.slice(0, 150)}"`);
2338
2338
  }
2339
2339
  return [{
@@ -2355,19 +2355,19 @@ const Ht = {
2355
2355
  description: "Page must have a mechanism to bypass repeated blocks of content.",
2356
2356
  guidance: 'Keyboard users must be able to skip repetitive content like navigation. Provide a skip link at the top of the page that links to the main content (e.g., <a href="#main">Skip to main content</a>), or use a <main> landmark. Screen readers can jump directly to landmarks, so a properly marked-up <main> element satisfies this requirement.',
2357
2357
  prompt: 'The page has no mechanism for keyboard users to skip repeated content. The simplest fix is to wrap the primary content area in a <main> element — screen readers can jump directly to it. Alternatively, add a skip link as the first element in <body>: <a href="#main" class="skip-link">Skip to main content</a>, with a matching id on the target element. Use the context to understand what the page is missing.',
2358
- run(e) {
2359
- if (e.querySelector(
2358
+ run(t) {
2359
+ if (t.querySelector(
2360
2360
  'main, [role="main"], nav, [role="navigation"], aside, [role="complementary"], header, [role="banner"], footer, [role="contentinfo"], [role="search"], [role="region"]'
2361
2361
  )) return [];
2362
- const t = e.querySelector('a[href^="#"]');
2363
- if (t) {
2364
- const r = t.getAttribute("href");
2362
+ const e = t.querySelector('a[href^="#"]');
2363
+ if (e) {
2364
+ const r = e.getAttribute("href");
2365
2365
  if (r && r.length > 1) {
2366
2366
  const o = r.slice(1);
2367
- if (e.getElementById(o)) return [];
2367
+ if (t.getElementById(o)) return [];
2368
2368
  }
2369
2369
  }
2370
- if (e.querySelector("h1, h2, h3, [role='heading']")) return [];
2370
+ if (t.querySelector("h1, h2, h3, [role='heading']")) return [];
2371
2371
  const n = [];
2372
2372
  return n.push("no landmarks (<main>, <nav>, <header>, <footer>)"), n.push("no skip link"), n.push("no headings"), [{
2373
2373
  ruleId: "bypass",
@@ -2386,19 +2386,19 @@ const Ht = {
2386
2386
  description: "Page should contain a level-one heading.",
2387
2387
  guidance: "A level-one heading (<h1> or role='heading' with aria-level='1') helps users understand the page topic and provides a landmark for screen reader navigation. Each page should have exactly one h1 that describes the main content, typically matching or similar to the page title.",
2388
2388
  prompt: "The page has no <h1> heading. Suggest appropriate h1 text based on the page title or content sample in context. The h1 should describe the page's main topic and typically be placed at the start of the main content area.",
2389
- run(e) {
2389
+ run(t) {
2390
2390
  var o, s, l;
2391
- const a = e.querySelector("h1");
2391
+ const a = t.querySelector("h1");
2392
2392
  if (a && v(a)) return [];
2393
- const t = e.querySelectorAll('[role="heading"][aria-level="1"]');
2394
- for (const p of t)
2395
- if (v(p)) return [];
2396
- const i = [], n = (s = (o = e.querySelector("title")) == null ? void 0 : o.textContent) == null ? void 0 : s.trim();
2393
+ const e = t.querySelectorAll('[role="heading"][aria-level="1"]');
2394
+ for (const h of e)
2395
+ if (v(h)) return [];
2396
+ const i = [], n = (s = (o = t.querySelector("title")) == null ? void 0 : o.textContent) == null ? void 0 : s.trim();
2397
2397
  n && i.push(`Page title: "${n}"`);
2398
- const r = e.querySelector("main");
2398
+ const r = t.querySelector("main");
2399
2399
  if (r) {
2400
- const p = ((l = r.textContent) == null ? void 0 : l.trim().replace(/\s+/g, " ")) || "";
2401
- p && i.push(`Main content: "${p.slice(0, 100)}"`);
2400
+ const h = ((l = r.textContent) == null ? void 0 : l.trim().replace(/\s+/g, " ")) || "";
2401
+ h && i.push(`Main content: "${h.slice(0, 100)}"`);
2402
2402
  }
2403
2403
  return [{
2404
2404
  ruleId: "page-has-heading-one",
@@ -2410,11 +2410,11 @@ const Ht = {
2410
2410
  }];
2411
2411
  }
2412
2412
  };
2413
- function be(e) {
2414
- if (!(e instanceof HTMLElement)) return !1;
2415
- if (e.style.display === "none" || e.style.visibility === "hidden") return !0;
2416
- const a = e.getAttribute("width"), t = e.getAttribute("height");
2417
- return (a === "0" || a === "1") && (t === "0" || t === "1");
2413
+ function be(t) {
2414
+ if (!(t instanceof HTMLElement)) return !1;
2415
+ if (t.style.display === "none" || t.style.visibility === "hidden") return !0;
2416
+ const a = t.getAttribute("width"), e = t.getAttribute("height");
2417
+ return (a === "0" || a === "1") && (e === "0" || e === "1");
2418
2418
  }
2419
2419
  const na = {
2420
2420
  id: "frame-title",
@@ -2423,16 +2423,16 @@ const na = {
2423
2423
  description: "Frames must have an accessible name.",
2424
2424
  guidance: "Screen readers announce frame titles when users navigate frames. Add a title attribute to <iframe> and <frame> elements that describes the frame's purpose (e.g., <iframe title='Video player'>). Avoid generic titles like 'frame' or 'iframe'. If the frame is decorative, use aria-hidden='true'.",
2425
2425
  prompt: "This iframe has no accessible name. Based on the src URL in context, suggest a descriptive title attribute that tells screen reader users what the frame contains. For example: 'YouTube video player', 'Google Map', 'Payment form', 'Chat widget'. If the frame appears decorative or non-essential, recommend adding aria-hidden='true' instead.",
2426
- run(e) {
2426
+ run(t) {
2427
2427
  const a = [];
2428
- for (const t of e.querySelectorAll("iframe, frame")) {
2429
- if (g(t) || be(t)) continue;
2430
- if (!v(t)) {
2431
- const n = t.getAttribute("src");
2428
+ for (const e of t.querySelectorAll("iframe, frame")) {
2429
+ if (g(e) || be(e)) continue;
2430
+ if (!v(e)) {
2431
+ const n = e.getAttribute("src");
2432
2432
  a.push({
2433
2433
  ruleId: "frame-title",
2434
- selector: m(t),
2435
- html: d(t),
2434
+ selector: m(e),
2435
+ html: d(e),
2436
2436
  impact: "serious",
2437
2437
  message: "Frame is missing an accessible name. Add a title attribute.",
2438
2438
  context: n ? `src: "${n}"` : void 0
@@ -2449,10 +2449,10 @@ const na = {
2449
2449
  description: "Frame titles should be unique.",
2450
2450
  guidance: "When multiple frames have identical titles, screen reader users cannot distinguish between them. Give each frame a unique, descriptive title that explains its specific purpose or content.",
2451
2451
  prompt: "Suggest a more specific title to distinguish this frame from others.",
2452
- run(e) {
2452
+ run(t) {
2453
2453
  var n;
2454
- const a = [], t = Array.from(e.querySelectorAll("iframe[title], frame[title]")), i = /* @__PURE__ */ new Map();
2455
- for (const r of t) {
2454
+ const a = [], e = Array.from(t.querySelectorAll("iframe[title], frame[title]")), i = /* @__PURE__ */ new Map();
2455
+ for (const r of e) {
2456
2456
  if (g(r) || be(r)) continue;
2457
2457
  const o = (n = r.getAttribute("title")) == null ? void 0 : n.trim().toLowerCase();
2458
2458
  if (o) {
@@ -2480,10 +2480,10 @@ const na = {
2480
2480
  description: "Headings must have discernible text.",
2481
2481
  guidance: "Screen reader users navigate pages by headings, so empty headings create confusing navigation points. Ensure all headings contain visible text or accessible names. If a heading is used purely for visual styling, use CSS instead of heading elements.",
2482
2482
  prompt: "This heading element has no text content, so screen reader users encounter a blank heading when navigating. Either add descriptive text that summarizes the following section, or if this element is used only for visual styling, replace it with a styled <p> or <div> and use CSS for appearance. The context includes nearby content to help suggest appropriate heading text.",
2483
- run(e) {
2483
+ run(t) {
2484
2484
  var i;
2485
- const a = [], t = e.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
2486
- for (const n of t)
2485
+ const a = [], e = t.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
2486
+ for (const n of e)
2487
2487
  if (!g(n) && !v(n)) {
2488
2488
  let r;
2489
2489
  const o = n.nextElementSibling;
@@ -2509,16 +2509,16 @@ const na = {
2509
2509
  description: "Viewport meta tag must not disable user scaling.",
2510
2510
  guidance: "Users with low vision need to zoom content up to 200% or more. Setting user-scalable=no or maximum-scale=1 prevents zooming and fails WCAG. Remove these restrictions. If your layout breaks at high zoom, fix the responsive design rather than preventing zoom.",
2511
2511
  prompt: "The viewport meta tag restricts zooming, which prevents low-vision users from enlarging content. Show the current content attribute and a corrected version with the problematic properties removed. Keep other viewport properties (like width=device-width, initial-scale=1) intact — only remove user-scalable=no and maximum-scale restrictions.",
2512
- run(e) {
2513
- const a = [], t = e.querySelector('meta[name="viewport"]');
2514
- if (!t) return [];
2515
- const i = t.getAttribute("content") || "", n = i.toLowerCase(), r = n.match(/user-scalable\s*=\s*([^\s,;]+)/i);
2512
+ run(t) {
2513
+ const a = [], e = t.querySelector('meta[name="viewport"]');
2514
+ if (!e) return [];
2515
+ const i = e.getAttribute("content") || "", n = i.toLowerCase(), r = n.match(/user-scalable\s*=\s*([^\s,;]+)/i);
2516
2516
  if (r) {
2517
2517
  const s = r[1], l = parseFloat(s);
2518
2518
  (s === "no" || !isNaN(l) && l > -1 && l < 1) && a.push({
2519
2519
  ruleId: "meta-viewport",
2520
- selector: m(t),
2521
- html: d(t),
2520
+ selector: m(e),
2521
+ html: d(e),
2522
2522
  impact: "critical",
2523
2523
  message: `Viewport disables user scaling (user-scalable=${s}). Remove this restriction.`,
2524
2524
  context: `content: "${i}"`
@@ -2529,8 +2529,8 @@ const na = {
2529
2529
  const s = o[1], l = s.toLowerCase() === "yes" ? 1 : parseFloat(s);
2530
2530
  l < 2 && a.push({
2531
2531
  ruleId: "meta-viewport",
2532
- selector: m(t),
2533
- html: d(t),
2532
+ selector: m(e),
2533
+ html: d(e),
2534
2534
  impact: "critical",
2535
2535
  message: `Viewport maximum-scale=${l} restricts zooming. Set to at least 2 or remove.`,
2536
2536
  context: `content: "${i}"`
@@ -2545,12 +2545,12 @@ const na = {
2545
2545
  description: "Meta refresh must not redirect or refresh automatically.",
2546
2546
  guidance: "Automatic page refreshes or redirects can disorient users, especially those using screen readers or with cognitive disabilities. They may lose their place or not have time to read content. If a redirect is needed, use a server-side redirect (HTTP 301/302) instead. For timed refreshes, provide user controls.",
2547
2547
  prompt: "Explain why meta refresh is problematic and suggest server-side alternatives.",
2548
- run(e) {
2549
- for (const a of e.querySelectorAll('meta[http-equiv="refresh"]')) {
2550
- const t = a.getAttribute("content") || "", i = t.match(/^(\d+)/);
2548
+ run(t) {
2549
+ for (const a of t.querySelectorAll('meta[http-equiv="refresh"]')) {
2550
+ const e = a.getAttribute("content") || "", i = e.match(/^(\d+)/);
2551
2551
  if (!i) continue;
2552
2552
  const n = parseInt(i[1], 10);
2553
- if (/^\d+\s*[;,]\s*url\s*=/i.test(t) || /^\d+\s*[;,]\s*['"]?\s*https?:/i.test(t))
2553
+ if (/^\d+\s*[;,]\s*url\s*=/i.test(e) || /^\d+\s*[;,]\s*['"]?\s*https?:/i.test(e))
2554
2554
  return n > 0 && n <= 72e3 ? [{
2555
2555
  ruleId: "meta-refresh",
2556
2556
  selector: m(a),
@@ -2580,7 +2580,7 @@ const na = {
2580
2580
  level: "A",
2581
2581
  guidance: "Blinking content can cause seizures in users with photosensitive epilepsy and is distracting for users with attention disorders. The <blink> element is deprecated and should never be used. If you need to draw attention to content, use less intrusive methods like color, borders, or icons.",
2582
2582
  prompt: "Suggest static alternatives to the blinking effect."
2583
- }, ua = k(ca), da = {
2583
+ }, ua = I(ca), da = {
2584
2584
  id: "marquee",
2585
2585
  selector: "marquee",
2586
2586
  check: { type: "selector-exists" },
@@ -2591,7 +2591,7 @@ const na = {
2591
2591
  level: "A",
2592
2592
  guidance: "Scrolling or moving content is difficult for many users to read, especially those with cognitive or visual disabilities. The <marquee> element is deprecated. Replace scrolling text with static content. If content must scroll, provide pause/stop controls and ensure it stops after 5 seconds.",
2593
2593
  prompt: "Suggest static alternatives or accessible carousel patterns."
2594
- }, ma = k(da), ha = {
2594
+ }, ma = I(da), ha = {
2595
2595
  id: "p-as-heading",
2596
2596
  wcag: [],
2597
2597
  level: "A",
@@ -2599,15 +2599,15 @@ const na = {
2599
2599
  description: "Paragraphs should not be styled to look like headings.",
2600
2600
  guidance: "When paragraphs are styled with bold, large fonts to look like headings, screen reader users miss the semantic structure. Use proper heading elements (h1-h6) instead of styled paragraphs. If you need specific styling, apply CSS to the heading elements while maintaining proper heading hierarchy.",
2601
2601
  prompt: "Suggest the appropriate heading level based on the document structure.",
2602
- run(e) {
2603
- var t, i;
2602
+ run(t) {
2603
+ var e, i;
2604
2604
  const a = [];
2605
- for (const n of e.querySelectorAll("p")) {
2605
+ for (const n of t.querySelectorAll("p")) {
2606
2606
  if (g(n)) continue;
2607
- const r = n.getAttribute("style") || "", o = /font-weight\s*:\s*(bold|[6-9]00)/i.test(r), s = /font-size\s*:\s*(\d+)\s*(px|em|rem)/i.test(r), l = ((t = n.className) == null ? void 0 : t.toLowerCase()) || "", p = /\bh[1-6]\b|\bheading\b/.test(l), c = ((i = n.textContent) == null ? void 0 : i.trim()) || "", u = c.length > 0 && c.length < 50, h = !c.match(/[.!?,;:]$/);
2608
- if ((o && s || o && p) && u && h) {
2609
- const w = n.nextElementSibling;
2610
- w && (w.tagName === "P" || w.tagName === "DIV" || w.tagName === "UL") && a.push({
2607
+ const r = n.getAttribute("style") || "", o = /font-weight\s*:\s*(bold|[6-9]00)/i.test(r), s = /font-size\s*:\s*(\d+)\s*(px|em|rem)/i.test(r), l = ((e = n.className) == null ? void 0 : e.toLowerCase()) || "", h = /\bh[1-6]\b|\bheading\b/.test(l), c = ((i = n.textContent) == null ? void 0 : i.trim()) || "", u = c.length > 0 && c.length < 50, p = !c.match(/[.!?,;:]$/);
2608
+ if ((o && s || o && h) && u && p) {
2609
+ const y = n.nextElementSibling;
2610
+ y && (y.tagName === "P" || y.tagName === "DIV" || y.tagName === "UL") && a.push({
2611
2611
  ruleId: "p-as-heading",
2612
2612
  selector: m(n),
2613
2613
  html: d(n),
@@ -2625,14 +2625,14 @@ const na = {
2625
2625
  description: "ARIA role values must be valid.",
2626
2626
  guidance: "Invalid role values are ignored by assistive technologies, meaning the element will not have the intended semantics. Check the spelling and use only roles defined in the WAI-ARIA specification. Common roles include: button, link, navigation, main, dialog, alert, tab, tabpanel, menu, menuitem.",
2627
2627
  prompt: "Identify the invalid role and suggest the correct spelling or a valid alternative role that matches the intended purpose.",
2628
- run(e) {
2628
+ run(t) {
2629
2629
  const a = [];
2630
- for (const t of e.querySelectorAll("[role]")) {
2631
- const r = t.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/).filter(Boolean);
2630
+ for (const e of t.querySelectorAll("[role]")) {
2631
+ const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/).filter(Boolean);
2632
2632
  !r.some((s) => Ee(s)) && r.length > 0 && a.push({
2633
2633
  ruleId: "aria-roles",
2634
- selector: m(t),
2635
- html: d(t),
2634
+ selector: m(e),
2635
+ html: d(e),
2636
2636
  impact: "critical",
2637
2637
  message: `Invalid ARIA role "${r[0]}".`
2638
2638
  });
@@ -2646,8 +2646,8 @@ const na = {
2646
2646
  description: "ARIA attributes must be valid (correctly spelled).",
2647
2647
  guidance: "Misspelled ARIA attributes are ignored by assistive technologies. Check the spelling against the WAI-ARIA specification. Common mistakes: aria-labeledby (should be aria-labelledby), aria-role (should be role), aria-description (valid in ARIA 1.3+).",
2648
2648
  prompt: "Identify the misspelled attribute and provide the correct spelling.",
2649
- run(e) {
2650
- return U(e).validAttr;
2649
+ run(t) {
2650
+ return G(t).validAttr;
2651
2651
  }
2652
2652
  }, ba = {
2653
2653
  id: "aria-valid-attr-value",
@@ -2656,8 +2656,8 @@ const na = {
2656
2656
  description: "ARIA attributes must have valid values.",
2657
2657
  guidance: "Each ARIA attribute accepts specific value types. Boolean attributes (aria-hidden, aria-disabled) accept only 'true' or 'false'. Tristate attributes (aria-checked, aria-pressed) also accept 'mixed'. Token attributes (aria-live, aria-autocomplete) accept predefined values. ID reference attributes (aria-labelledby, aria-describedby) must reference existing element IDs.",
2658
2658
  prompt: "Show the invalid value and list the valid values for this specific attribute.",
2659
- run(e) {
2660
- return U(e).validAttrValue;
2659
+ run(t) {
2660
+ return G(t).validAttrValue;
2661
2661
  }
2662
2662
  }, fa = {
2663
2663
  checkbox: ["aria-checked"],
@@ -2680,23 +2680,23 @@ const na = {
2680
2680
  description: "Elements with ARIA roles must have all required ARIA attributes.",
2681
2681
  guidance: "Some ARIA roles require specific attributes to function correctly. For example, checkbox requires aria-checked, slider requires aria-valuenow, heading requires aria-level. Without these attributes, assistive technologies cannot convey the element's state or value to users. Add the missing required attribute with an appropriate value.",
2682
2682
  prompt: "State which attribute is required for this role and suggest an appropriate value based on the element's apparent state.",
2683
- run(e) {
2683
+ run(t) {
2684
2684
  const a = [];
2685
- for (const t of e.querySelectorAll("[role]")) {
2686
- if (g(t) || t instanceof HTMLElement && t.style.display === "none") continue;
2687
- const i = t.getAttribute("role").trim().toLowerCase(), n = fa[i];
2688
- if (n && !(i === "checkbox" && t instanceof HTMLInputElement && t.type === "checkbox") && !(i === "radio" && t instanceof HTMLInputElement && t.type === "radio") && !(i === "option" && t instanceof HTMLOptionElement) && !(i === "heading" && /^h[1-6]$/i.test(t.tagName))) {
2685
+ for (const e of t.querySelectorAll("[role]")) {
2686
+ if (g(e) || e instanceof HTMLElement && e.style.display === "none") continue;
2687
+ const i = e.getAttribute("role").trim().toLowerCase(), n = fa[i];
2688
+ if (n && !(i === "checkbox" && e instanceof HTMLInputElement && e.type === "checkbox") && !(i === "radio" && e instanceof HTMLInputElement && e.type === "radio") && !(i === "option" && e instanceof HTMLOptionElement) && !(i === "heading" && /^h[1-6]$/i.test(e.tagName))) {
2689
2689
  if (i === "separator") {
2690
- const r = t.getAttribute("tabindex");
2690
+ const r = e.getAttribute("tabindex");
2691
2691
  if (!r || r === "-1") continue;
2692
2692
  }
2693
- if (!(t.tagName.toLowerCase() === "hr" && !t.hasAttribute("role"))) {
2693
+ if (!(e.tagName.toLowerCase() === "hr" && !e.hasAttribute("role"))) {
2694
2694
  for (const r of n)
2695
- if (!t.hasAttribute(r)) {
2695
+ if (!e.hasAttribute(r)) {
2696
2696
  a.push({
2697
2697
  ruleId: "aria-required-attr",
2698
- selector: m(t),
2699
- html: d(t),
2698
+ selector: m(e),
2699
+ html: d(e),
2700
2700
  impact: "critical",
2701
2701
  message: `Role "${i}" requires attribute "${r}".`
2702
2702
  });
@@ -2708,16 +2708,16 @@ const na = {
2708
2708
  return a;
2709
2709
  }
2710
2710
  };
2711
- function wa(e) {
2711
+ function ya(t) {
2712
2712
  var r, o, s;
2713
- const a = [], t = e.className;
2714
- t && typeof t == "string" && t.trim() && a.push(`Classes: ${t.trim().slice(0, 100)}`);
2715
- const i = e.closest("form");
2713
+ const a = [], e = t.className;
2714
+ e && typeof e == "string" && e.trim() && a.push(`Classes: ${e.trim().slice(0, 100)}`);
2715
+ const i = t.closest("form");
2716
2716
  if (i) {
2717
2717
  const l = i.getAttribute("aria-label") || ((o = (r = i.querySelector("legend")) == null ? void 0 : r.textContent) == null ? void 0 : o.trim());
2718
2718
  l && a.push(`Form: ${l.slice(0, 60)}`);
2719
2719
  }
2720
- const n = e.parentElement;
2720
+ const n = t.parentElement;
2721
2721
  if (n) {
2722
2722
  const l = n.closest("h1, h2, h3, h4, h5, h6") || n.querySelector("h1, h2, h3, h4, h5, h6");
2723
2723
  (s = l == null ? void 0 : l.textContent) != null && s.trim() && a.push(`Nearby heading: ${l.textContent.trim().slice(0, 60)}`);
@@ -2725,26 +2725,26 @@ function wa(e) {
2725
2725
  return a.length > 0 ? a.join(`
2726
2726
  `) : void 0;
2727
2727
  }
2728
- const ya = {
2728
+ const wa = {
2729
2729
  id: "button-name",
2730
2730
  wcag: ["4.1.2"],
2731
2731
  level: "A",
2732
2732
  description: "Buttons must have discernible text.",
2733
2733
  guidance: "Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.",
2734
2734
  prompt: "Based on the button's content, class, or context, suggest an appropriate aria-label describing the action it performs.",
2735
- run(e) {
2735
+ run(t) {
2736
2736
  const a = [];
2737
- for (const t of e.querySelectorAll('button, [role="button"]')) {
2738
- if (g(t) || T(t)) continue;
2739
- const i = t.getAttribute("role");
2740
- if ((i === "none" || i === "presentation") && !(t.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || t.tagName.toLowerCase() === "button" && !t.disabled) || t.getRootNode() instanceof ShadowRoot) continue;
2741
- v(t) || a.push({
2737
+ for (const e of t.querySelectorAll('button, [role="button"]')) {
2738
+ if (g(e) || T(e)) continue;
2739
+ const i = e.getAttribute("role");
2740
+ if ((i === "none" || i === "presentation") && !(e.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || e.tagName.toLowerCase() === "button" && !e.disabled) || e.getRootNode() instanceof ShadowRoot) continue;
2741
+ v(e) || a.push({
2742
2742
  ruleId: "button-name",
2743
- selector: m(t),
2744
- html: d(t),
2743
+ selector: m(e),
2744
+ html: d(e),
2745
2745
  impact: "critical",
2746
2746
  message: "Button has no discernible text.",
2747
- context: wa(t)
2747
+ context: ya(e)
2748
2748
  });
2749
2749
  }
2750
2750
  return a;
@@ -2852,21 +2852,21 @@ const ya = {
2852
2852
  description: "ARIA attributes must be allowed for the element's role.",
2853
2853
  guidance: "Each ARIA role supports specific attributes. Using unsupported attributes creates confusion for assistive technologies. Check the ARIA specification for which attributes are valid for each role, or remove the attribute if it's not needed.",
2854
2854
  prompt: "The ARIA attribute listed in context is not supported on this element's role. Either remove the attribute (if the behavior it describes isn't needed), or change the element's role to one that supports it. The context lists which attributes ARE allowed on this role — use that to suggest alternatives if applicable.",
2855
- run(e) {
2855
+ run(t) {
2856
2856
  const a = [];
2857
- for (const t of e.querySelectorAll("[role], [aria-*]")) {
2858
- if (g(t)) continue;
2859
- const i = q(t);
2857
+ for (const e of t.querySelectorAll("[role], [aria-*]")) {
2858
+ if (g(e)) continue;
2859
+ const i = q(e);
2860
2860
  if (!i) continue;
2861
2861
  const n = Aa[i];
2862
2862
  if (n)
2863
- for (const r of t.attributes) {
2863
+ for (const r of e.attributes) {
2864
2864
  if (!r.name.startsWith("aria-") || xa.has(r.name) || n.has(r.name)) continue;
2865
2865
  const o = n.size > 0 ? [...n].join(", ") : "none (only global ARIA attributes)";
2866
2866
  a.push({
2867
2867
  ruleId: "aria-allowed-attr",
2868
- selector: m(t),
2869
- html: d(t),
2868
+ selector: m(e),
2869
+ html: d(e),
2870
2870
  impact: "critical",
2871
2871
  message: `ARIA attribute "${r.name}" is not allowed on role "${i}".`,
2872
2872
  context: `Attribute: ${r.name}="${r.value}", role: ${i}, allowed role-specific attributes: ${o}`
@@ -2997,17 +2997,17 @@ const ya = {
2997
2997
  video: /* @__PURE__ */ new Set(["application"]),
2998
2998
  wbr: /* @__PURE__ */ new Set(["none", "presentation"])
2999
2999
  };
3000
- function Ia(e) {
3001
- var t;
3002
- const a = e.tagName.toLowerCase();
3000
+ function Ia(t) {
3001
+ var e;
3002
+ const a = t.tagName.toLowerCase();
3003
3003
  if (ka.has(a))
3004
3004
  return "none";
3005
- if (a === "a" && e.hasAttribute("href"))
3005
+ if (a === "a" && t.hasAttribute("href"))
3006
3006
  return E["a[href]"];
3007
- if (a === "img" && e.getAttribute("alt") === "")
3007
+ if (a === "img" && t.getAttribute("alt") === "")
3008
3008
  return E["img[alt='']"];
3009
3009
  if (a === "input") {
3010
- const n = `input[type=${((t = e.getAttribute("type")) == null ? void 0 : t.toLowerCase()) || "text"}]`;
3010
+ const n = `input[type=${((e = t.getAttribute("type")) == null ? void 0 : e.toLowerCase()) || "text"}]`;
3011
3011
  return n in E ? E[n] : "none";
3012
3012
  }
3013
3013
  return E[a] || "any";
@@ -3019,12 +3019,12 @@ const Ta = {
3019
3019
  description: "ARIA role must be appropriate for the element.",
3020
3020
  guidance: "Not all ARIA roles can be applied to all HTML elements. Many elements have implicit roles (e.g., <header> is implicitly banner, <nav> is navigation, <main> is main). Adding an explicit role that matches the implicit role is redundant. Adding a conflicting role breaks semantics. Either remove the role attribute or use a different element.",
3021
3021
  prompt: "Consider implicit roles: header=banner, nav=navigation, main=main, footer=contentinfo, aside=complementary, article=article, section=region (when labeled). Explain if this role is redundant (matches implicit) or invalid (conflicts). Suggest removing it or restructuring.",
3022
- run(e) {
3023
- var t;
3022
+ run(t) {
3023
+ var e;
3024
3024
  const a = [];
3025
- for (const i of e.querySelectorAll("[role]")) {
3025
+ for (const i of t.querySelectorAll("[role]")) {
3026
3026
  if (g(i)) continue;
3027
- const n = (t = i.getAttribute("role")) == null ? void 0 : t.trim().toLowerCase();
3027
+ const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
3028
3028
  if (!n) continue;
3029
3029
  const r = he(i);
3030
3030
  if (r && n === r) continue;
@@ -3045,7 +3045,7 @@ const Ta = {
3045
3045
  }
3046
3046
  return a;
3047
3047
  }
3048
- }, ie = {
3048
+ }, ne = {
3049
3049
  // Each array is an OR group - at least one of each inner array must be present
3050
3050
  combobox: [["listbox", "tree", "grid", "dialog", "textbox"]],
3051
3051
  // Must own/contain one of these
@@ -3074,7 +3074,7 @@ const Ta = {
3074
3074
  "tablist",
3075
3075
  "tree",
3076
3076
  "treegrid"
3077
- ]), ne = {
3077
+ ]), re = {
3078
3078
  caption: ["figure", "table", "grid", "treegrid"],
3079
3079
  cell: ["row"],
3080
3080
  columnheader: ["row"],
@@ -3090,22 +3090,22 @@ const Ta = {
3090
3090
  tab: ["tablist"],
3091
3091
  treeitem: ["tree", "group"]
3092
3092
  };
3093
- function Ca(e, a) {
3093
+ function Ca(t, a) {
3094
3094
  var o;
3095
- const t = ((o = e.getAttribute("aria-owns")) == null ? void 0 : o.split(/\s+/)) || [], i = e.ownerDocument, n = /* @__PURE__ */ new Set();
3095
+ const e = ((o = t.getAttribute("aria-owns")) == null ? void 0 : o.split(/\s+/)) || [], i = t.ownerDocument, n = /* @__PURE__ */ new Set();
3096
3096
  let r = !1;
3097
- for (const s of e.querySelectorAll("*")) {
3097
+ for (const s of t.querySelectorAll("*")) {
3098
3098
  if (g(s)) continue;
3099
3099
  r = !0;
3100
3100
  const l = q(s);
3101
3101
  l && n.add(l);
3102
3102
  }
3103
- for (const s of t) {
3103
+ for (const s of e) {
3104
3104
  const l = i.getElementById(s);
3105
3105
  if (l && !g(l)) {
3106
3106
  r = !0;
3107
- const p = q(l);
3108
- p && n.add(p);
3107
+ const h = q(l);
3108
+ h && n.add(h);
3109
3109
  }
3110
3110
  }
3111
3111
  if (!r) return "empty";
@@ -3120,19 +3120,19 @@ const La = {
3120
3120
  description: "Certain ARIA roles require specific child roles to be present.",
3121
3121
  guidance: "Some ARIA roles represent containers that must contain specific child roles for proper semantics. For example, a list must contain listitems, a menu must contain menuitems. Add the required child elements with appropriate roles, or use native HTML elements that provide these semantics implicitly (e.g., <ul> with <li>).",
3122
3122
  prompt: "State which child role(s) are required and suggest adding elements with those roles, or using equivalent native HTML elements.",
3123
- run(e) {
3124
- var t;
3123
+ run(t) {
3124
+ var e;
3125
3125
  const a = [];
3126
- for (const i of e.querySelectorAll("[role]")) {
3126
+ for (const i of t.querySelectorAll("[role]")) {
3127
3127
  if (g(i)) continue;
3128
- const n = (t = i.getAttribute("role")) == null ? void 0 : t.trim().toLowerCase();
3129
- if (!n || !(n in ie) || i.getAttribute("aria-busy") === "true") continue;
3128
+ const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
3129
+ if (!n || !(n in ne) || i.getAttribute("aria-busy") === "true") continue;
3130
3130
  if (n === "combobox") {
3131
3131
  if (i.getAttribute("aria-expanded") !== "true") continue;
3132
3132
  const l = i.tagName.toLowerCase();
3133
3133
  if (l === "input" || l === "textarea") continue;
3134
3134
  }
3135
- const r = ie[n], o = Ca(i, r);
3135
+ const r = ne[n], o = Ca(i, r);
3136
3136
  if (o === "pass" || o === "empty" && Ea.has(n)) continue;
3137
3137
  const s = r.map((l) => l.join(" or ")).join(", ");
3138
3138
  a.push({
@@ -3152,16 +3152,16 @@ const La = {
3152
3152
  description: "Certain ARIA roles must be contained within specific parent roles.",
3153
3153
  guidance: "Some ARIA roles represent items that must exist within specific container roles. For example, a listitem must be within a list, a tab must be within a tablist. Wrap the element in the appropriate parent, or use native HTML elements that provide this structure (e.g., <li> inside <ul>).",
3154
3154
  prompt: "State which parent role is required and suggest wrapping in an element with that role, or using equivalent native HTML structure.",
3155
- run(e) {
3156
- var t;
3155
+ run(t) {
3156
+ var e;
3157
3157
  const a = [];
3158
- for (const i of e.querySelectorAll("[role]")) {
3158
+ for (const i of t.querySelectorAll("[role]")) {
3159
3159
  if (g(i)) continue;
3160
- const n = (t = i.getAttribute("role")) == null ? void 0 : t.trim().toLowerCase();
3161
- if (!n || !(n in ne)) continue;
3162
- const r = ne[n];
3160
+ const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
3161
+ if (!n || !(n in re)) continue;
3162
+ const r = re[n];
3163
3163
  let o = i.parentElement, s = !1;
3164
- for (; o && o !== e.documentElement; ) {
3164
+ for (; o && o !== t.documentElement; ) {
3165
3165
  const l = q(o);
3166
3166
  if (l && r.includes(l)) {
3167
3167
  s = !0;
@@ -3179,7 +3179,7 @@ const La = {
3179
3179
  }
3180
3180
  return a;
3181
3181
  }
3182
- }, re = [
3182
+ }, oe = [
3183
3183
  "a[href]",
3184
3184
  "button:not([disabled])",
3185
3185
  'input:not([disabled]):not([type="hidden"])',
@@ -3195,10 +3195,10 @@ const La = {
3195
3195
  "embed",
3196
3196
  "area[href]"
3197
3197
  ].join(", ");
3198
- function Ra(e) {
3199
- let a = e;
3200
- const t = e.ownerDocument, i = t.defaultView;
3201
- for (; a && a !== t.body; ) {
3198
+ function Ra(t) {
3199
+ let a = t;
3200
+ const e = t.ownerDocument, i = e.defaultView;
3201
+ for (; a && a !== e.body; ) {
3202
3202
  if (a.style.display === "none" || a.style.visibility === "hidden") return !1;
3203
3203
  if (i) {
3204
3204
  const n = i.getComputedStyle(a);
@@ -3220,19 +3220,19 @@ const Na = {
3220
3220
  guidance: "Setting aria-hidden='true' on the body element hides all page content from assistive technologies, making the page completely inaccessible to screen reader users. Remove aria-hidden from the body element. If you need to hide content temporarily (e.g., behind a modal), use aria-hidden on specific sections instead.",
3221
3221
  prompt: "Instruct to remove aria-hidden='true' from the body element.",
3222
3222
  skipAriaHidden: !1
3223
- }, $a = k(Na), Ma = {
3223
+ }, $a = I(Na), Ma = {
3224
3224
  id: "aria-hidden-focus",
3225
3225
  wcag: ["4.1.2"],
3226
3226
  level: "A",
3227
3227
  description: "Elements with aria-hidden='true' must not contain focusable elements.",
3228
3228
  guidance: "When aria-hidden='true' hides an element from assistive technologies but the element contains focusable children, keyboard users can focus those children but screen reader users won't know they exist. Either remove focusable elements from the hidden region, add tabindex='-1' to them, or remove aria-hidden.",
3229
3229
  prompt: "This element can receive keyboard focus but is inside an aria-hidden region, making it invisible to screen readers. The context explains why it's focusable. Fix by either: (1) adding tabindex='-1' to remove it from tab order, (2) moving it outside the aria-hidden region, or (3) removing aria-hidden='true' from the ancestor if the content should be accessible.",
3230
- run(e) {
3230
+ run(t) {
3231
3231
  const a = [];
3232
- for (const t of e.querySelectorAll('[aria-hidden="true"]')) {
3233
- if (t === e.body) continue;
3234
- const i = [...t.querySelectorAll(re)];
3235
- t.matches(re) && i.push(t);
3232
+ for (const e of t.querySelectorAll('[aria-hidden="true"]')) {
3233
+ if (e === t.body) continue;
3234
+ const i = [...e.querySelectorAll(oe)];
3235
+ e.matches(oe) && i.push(e);
3236
3236
  for (const n of i)
3237
3237
  if (n instanceof HTMLElement) {
3238
3238
  const r = n.getAttribute("tabindex");
@@ -3240,7 +3240,7 @@ const Na = {
3240
3240
  const o = n.tagName.toLowerCase();
3241
3241
  let s;
3242
3242
  r !== null ? s = `has tabindex="${r}"` : o === "a" && n.hasAttribute("href") ? s = "is a link with href" : o === "button" ? s = "is a <button>" : o === "input" ? s = `is an <input type="${n.type}">` : o === "select" ? s = "is a <select>" : o === "textarea" ? s = "is a <textarea>" : o === "iframe" ? s = "is an <iframe>" : s = `is a natively focusable <${o}>`;
3243
- const l = n === t ? n : n.closest('[aria-hidden="true"]');
3243
+ const l = n === e ? n : n.closest('[aria-hidden="true"]');
3244
3244
  a.push({
3245
3245
  ruleId: "aria-hidden-focus",
3246
3246
  selector: m(n),
@@ -3260,14 +3260,14 @@ const Na = {
3260
3260
  description: "ARIA commands must have an accessible name.",
3261
3261
  guidance: "Interactive ARIA command roles (button, link, menuitem) must have accessible names so users know what action they perform. Add visible text content, aria-label, or aria-labelledby to provide a name.",
3262
3262
  prompt: "Based on the element's content or context, suggest an aria-label describing what this command does.",
3263
- run(e) {
3264
- var t;
3263
+ run(t) {
3264
+ var e;
3265
3265
  const a = [];
3266
- for (const i of e.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
3266
+ for (const i of t.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
3267
3267
  if (g(i) || T(i) || i.getRootNode() instanceof ShadowRoot || i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") continue;
3268
3268
  if (!v(i)) {
3269
3269
  const r = i.querySelector("img[alt]");
3270
- if ((t = r == null ? void 0 : r.getAttribute("alt")) != null && t.trim()) continue;
3270
+ if ((e = r == null ? void 0 : r.getAttribute("alt")) != null && e.trim()) continue;
3271
3271
  a.push({
3272
3272
  ruleId: "aria-command-name",
3273
3273
  selector: m(i),
@@ -3286,9 +3286,9 @@ const Na = {
3286
3286
  description: "ARIA input fields must have an accessible name.",
3287
3287
  guidance: "ARIA input widgets (combobox, listbox, searchbox, slider, spinbutton, textbox) must have accessible names so users understand what data to enter. Add a visible label with aria-labelledby, or use aria-label if a visible label is not possible.",
3288
3288
  prompt: "Based on the context, suggest an aria-label describing what data this input field accepts.",
3289
- run(e) {
3290
- const a = [], t = '[role="combobox"], [role="listbox"], [role="searchbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
3291
- for (const i of e.querySelectorAll(t)) {
3289
+ run(t) {
3290
+ const a = [], e = '[role="combobox"], [role="listbox"], [role="searchbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
3291
+ for (const i of t.querySelectorAll(e)) {
3292
3292
  if (g(i) || T(i) || i.getRootNode() instanceof ShadowRoot || i.matches("input, select, textarea")) continue;
3293
3293
  v(i) || a.push({
3294
3294
  ruleId: "aria-input-field-name",
@@ -3307,9 +3307,9 @@ const Na = {
3307
3307
  description: "ARIA toggle fields must have an accessible name.",
3308
3308
  guidance: "ARIA toggle controls (checkbox, switch, radio, menuitemcheckbox, menuitemradio) must have accessible names so users understand what option they're selecting. Add visible text content, aria-label, or use aria-labelledby to reference a visible label.",
3309
3309
  prompt: "Based on the context, suggest an aria-label describing what option this toggle controls.",
3310
- run(e) {
3311
- const a = [], t = '[role="checkbox"], [role="switch"], [role="radio"], [role="menuitemcheckbox"], [role="menuitemradio"]';
3312
- for (const i of e.querySelectorAll(t)) {
3310
+ run(t) {
3311
+ const a = [], e = '[role="checkbox"], [role="switch"], [role="radio"], [role="menuitemcheckbox"], [role="menuitemradio"]';
3312
+ for (const i of t.querySelectorAll(e)) {
3313
3313
  if (g(i) || T(i) || i.getRootNode() instanceof ShadowRoot || i.matches('input[type="checkbox"], input[type="radio"]')) continue;
3314
3314
  v(i) || a.push({
3315
3315
  ruleId: "aria-toggle-field-name",
@@ -3328,14 +3328,14 @@ const Na = {
3328
3328
  description: "ARIA meter elements must have an accessible name.",
3329
3329
  guidance: "Meter elements display a value within a known range (like disk usage or password strength). They must have accessible names so screen reader users understand what is being measured. Use aria-label or aria-labelledby to provide context.",
3330
3330
  prompt: "Based on the context or value attributes, suggest an aria-label describing what this meter measures.",
3331
- run(e) {
3331
+ run(t) {
3332
3332
  const a = [];
3333
- for (const t of e.querySelectorAll('[role="meter"], meter')) {
3334
- if (g(t)) continue;
3335
- v(t) || a.push({
3333
+ for (const e of t.querySelectorAll('[role="meter"], meter')) {
3334
+ if (g(e)) continue;
3335
+ v(e) || a.push({
3336
3336
  ruleId: "aria-meter-name",
3337
- selector: m(t),
3338
- html: d(t),
3337
+ selector: m(e),
3338
+ html: d(e),
3339
3339
  impact: "serious",
3340
3340
  message: "Meter has no accessible name."
3341
3341
  });
@@ -3349,14 +3349,14 @@ const Na = {
3349
3349
  description: "ARIA progressbar elements must have an accessible name.",
3350
3350
  guidance: "Progress indicators must have accessible names so screen reader users understand what process is being tracked. Use aria-label (e.g., 'File upload progress') or aria-labelledby to reference a visible heading or label.",
3351
3351
  prompt: "Based on the context, suggest an aria-label describing what process this progressbar tracks.",
3352
- run(e) {
3352
+ run(t) {
3353
3353
  const a = [];
3354
- for (const t of e.querySelectorAll('[role="progressbar"], progress')) {
3355
- if (g(t)) continue;
3356
- v(t) || a.push({
3354
+ for (const e of t.querySelectorAll('[role="progressbar"], progress')) {
3355
+ if (g(e)) continue;
3356
+ v(e) || a.push({
3357
3357
  ruleId: "aria-progressbar-name",
3358
- selector: m(t),
3359
- html: d(t),
3358
+ selector: m(e),
3359
+ html: d(e),
3360
3360
  impact: "serious",
3361
3361
  message: "Progressbar has no accessible name."
3362
3362
  });
@@ -3370,14 +3370,14 @@ const Na = {
3370
3370
  description: "ARIA dialogs must have an accessible name.",
3371
3371
  guidance: "Dialog and alertdialog elements must have accessible names so screen reader users understand the dialog's purpose when it opens. Use aria-label or aria-labelledby pointing to the dialog's heading. Native <dialog> elements should also have an accessible name.",
3372
3372
  prompt: "Suggest adding aria-labelledby pointing to the dialog's heading element, or an aria-label describing the dialog's purpose.",
3373
- run(e) {
3373
+ run(t) {
3374
3374
  const a = [];
3375
- for (const t of e.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog')) {
3376
- if (g(t)) continue;
3377
- v(t) || a.push({
3375
+ for (const e of t.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog')) {
3376
+ if (g(e)) continue;
3377
+ v(e) || a.push({
3378
3378
  ruleId: "aria-dialog-name",
3379
- selector: m(t),
3380
- html: d(t),
3379
+ selector: m(e),
3380
+ html: d(e),
3381
3381
  impact: "serious",
3382
3382
  message: "Dialog has no accessible name."
3383
3383
  });
@@ -3391,14 +3391,14 @@ const Na = {
3391
3391
  description: "ARIA tooltips must have an accessible name.",
3392
3392
  guidance: "Tooltip elements must have accessible names (usually their text content). The tooltip content itself typically serves as the accessible name. Ensure the tooltip contains descriptive text content or has aria-label.",
3393
3393
  prompt: "Add text content to the tooltip describing the information it provides, or add aria-label.",
3394
- run(e) {
3394
+ run(t) {
3395
3395
  const a = [];
3396
- for (const t of e.querySelectorAll('[role="tooltip"]')) {
3397
- if (g(t)) continue;
3398
- v(t) || a.push({
3396
+ for (const e of t.querySelectorAll('[role="tooltip"]')) {
3397
+ if (g(e)) continue;
3398
+ v(e) || a.push({
3399
3399
  ruleId: "aria-tooltip-name",
3400
- selector: m(t),
3401
- html: d(t),
3400
+ selector: m(e),
3401
+ html: d(e),
3402
3402
  impact: "serious",
3403
3403
  message: "Tooltip has no accessible name."
3404
3404
  });
@@ -3412,14 +3412,14 @@ const Na = {
3412
3412
  description: "ARIA treeitem elements must have an accessible name.",
3413
3413
  guidance: "Tree items must have accessible names so screen reader users can understand the tree structure and navigate it effectively. Provide text content, aria-label, or aria-labelledby for each treeitem.",
3414
3414
  prompt: "Add text content describing this tree item, or add aria-label.",
3415
- run(e) {
3415
+ run(t) {
3416
3416
  const a = [];
3417
- for (const t of e.querySelectorAll('[role="treeitem"]')) {
3418
- if (g(t)) continue;
3419
- v(t) || a.push({
3417
+ for (const e of t.querySelectorAll('[role="treeitem"]')) {
3418
+ if (g(e)) continue;
3419
+ v(e) || a.push({
3420
3420
  ruleId: "aria-treeitem-name",
3421
- selector: m(t),
3422
- html: d(t),
3421
+ selector: m(e),
3422
+ html: d(e),
3423
3423
  impact: "serious",
3424
3424
  message: "Treeitem has no accessible name."
3425
3425
  });
@@ -3433,8 +3433,8 @@ const Na = {
3433
3433
  description: "ARIA attributes must not be prohibited for the element's role.",
3434
3434
  guidance: "Some ARIA roles prohibit certain attributes. For example, roles like 'none', 'presentation', 'generic', and text-level roles (code, emphasis, strong) prohibit aria-label and aria-labelledby because naming is not supported for these roles. Remove the prohibited attributes or change the role.",
3435
3435
  prompt: "Identify the prohibited attribute and recommend removing it from this element.",
3436
- run(e) {
3437
- return U(e).prohibitedAttr;
3436
+ run(t) {
3437
+ return G(t).prohibitedAttr;
3438
3438
  }
3439
3439
  }, Va = [
3440
3440
  "a[href]",
@@ -3458,15 +3458,15 @@ const Na = {
3458
3458
  "aria-owns",
3459
3459
  "aria-relevant"
3460
3460
  ];
3461
- function oe(e) {
3461
+ function se(t) {
3462
3462
  const a = [];
3463
- e.matches(Va) && a.push("element is focusable");
3464
- for (const t of za)
3465
- if (e.hasAttribute(t)) {
3466
- a.push(`has ${t}`);
3463
+ t.matches(Va) && a.push("element is focusable");
3464
+ for (const e of za)
3465
+ if (t.hasAttribute(e)) {
3466
+ a.push(`has ${e}`);
3467
3467
  break;
3468
3468
  }
3469
- return (e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
3469
+ return (t.hasAttribute("aria-label") || t.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
3470
3470
  }
3471
3471
  const Ua = {
3472
3472
  id: "presentation-role-conflict",
@@ -3475,26 +3475,26 @@ const Ua = {
3475
3475
  description: "Elements with role='presentation' or role='none' must not be focusable or have global ARIA attributes.",
3476
3476
  guidance: "When an element has role='presentation' or role='none', it's marked as decorative and removed from the accessibility tree. However, if the element is focusable or has certain ARIA attributes, the presentation role is ignored and the element remains accessible. This creates confusion. Either remove the presentation role, or remove the focusability/ARIA attributes.",
3477
3477
  prompt: "Identify the conflict (focusable or ARIA attribute) and suggest either removing the presentation role or removing the conflicting attribute/focusability.",
3478
- run(e) {
3478
+ run(t) {
3479
3479
  const a = [];
3480
- for (const t of e.querySelectorAll('[role="presentation"], [role="none"]')) {
3481
- if (g(t)) continue;
3482
- const i = oe(t);
3480
+ for (const e of t.querySelectorAll('[role="presentation"], [role="none"]')) {
3481
+ if (g(e)) continue;
3482
+ const i = se(e);
3483
3483
  i.length > 0 && a.push({
3484
3484
  ruleId: "presentation-role-conflict",
3485
- selector: m(t),
3486
- html: d(t),
3485
+ selector: m(e),
3486
+ html: d(e),
3487
3487
  impact: "serious",
3488
3488
  message: `Presentation role conflicts with: ${i.join(", ")}. The role will be ignored.`
3489
3489
  });
3490
3490
  }
3491
- for (const t of e.querySelectorAll('img[alt=""]')) {
3492
- if (g(t) || t.hasAttribute("role")) continue;
3493
- const i = oe(t);
3491
+ for (const e of t.querySelectorAll('img[alt=""]')) {
3492
+ if (g(e) || e.hasAttribute("role")) continue;
3493
+ const i = se(e);
3494
3494
  i.length > 0 && a.push({
3495
3495
  ruleId: "presentation-role-conflict",
3496
- selector: m(t),
3497
- html: d(t),
3496
+ selector: m(e),
3497
+ html: d(e),
3498
3498
  impact: "serious",
3499
3499
  message: `Element with implicit presentation role (alt="") conflicts with: ${i.join(", ")}. The decorative role will be ignored.`
3500
3500
  });
@@ -3508,14 +3508,14 @@ const Ua = {
3508
3508
  description: "<summary> elements must have an accessible name.",
3509
3509
  guidance: "The <summary> element provides the visible label for a <details> disclosure widget. It must have descriptive text content so screen reader users understand what will be revealed when expanded. Add clear, concise text that indicates what content is contained in the details section.",
3510
3510
  prompt: "Based on the surrounding context or details content, suggest text to add inside the <summary> element.",
3511
- run(e) {
3511
+ run(t) {
3512
3512
  const a = [];
3513
- for (const t of e.querySelectorAll("details > summary:first-of-type")) {
3514
- if (g(t)) continue;
3515
- v(t) || a.push({
3513
+ for (const e of t.querySelectorAll("details > summary:first-of-type")) {
3514
+ if (g(e)) continue;
3515
+ v(e) || a.push({
3516
3516
  ruleId: "summary-name",
3517
- selector: m(t),
3518
- html: d(t),
3517
+ selector: m(e),
3518
+ html: d(e),
3519
3519
  impact: "serious",
3520
3520
  message: "<summary> element has no accessible name. Add descriptive text."
3521
3521
  });
@@ -3523,11 +3523,11 @@ const Ua = {
3523
3523
  return a;
3524
3524
  }
3525
3525
  };
3526
- function Ya(e) {
3526
+ function Ya(t) {
3527
3527
  var n, r;
3528
- const a = [], t = e.getAttribute("href");
3529
- t && a.push(`href: ${t}`);
3530
- const i = e.parentElement;
3528
+ const a = [], e = t.getAttribute("href");
3529
+ e && a.push(`href: ${e}`);
3530
+ const i = t.parentElement;
3531
3531
  if (i) {
3532
3532
  const o = i.closest("h1, h2, h3, h4, h5, h6");
3533
3533
  if ((n = o == null ? void 0 : o.textContent) != null && n.trim())
@@ -3547,17 +3547,17 @@ const Xa = {
3547
3547
  description: "Links must have discernible text via content, aria-label, or aria-labelledby.",
3548
3548
  guidance: "Screen reader users need to know where a link goes. Add descriptive text content, aria-label, or use aria-labelledby. For image links, ensure the image has alt text describing the link destination. Avoid generic text like 'click here' or 'read more'—link text should make sense out of context.",
3549
3549
  prompt: "Based on the href or surrounding context, suggest descriptive link text or an aria-label.",
3550
- run(e) {
3550
+ run(t) {
3551
3551
  const a = [];
3552
- for (const t of e.querySelectorAll('a[href], area[href], [role="link"]')) {
3553
- if (g(t) || T(t) || t.getRootNode() instanceof ShadowRoot) continue;
3554
- v(t) || a.push({
3552
+ for (const e of t.querySelectorAll('a[href], area[href], [role="link"]')) {
3553
+ if (g(e) || T(e) || e.getRootNode() instanceof ShadowRoot) continue;
3554
+ v(e) || a.push({
3555
3555
  ruleId: "link-name",
3556
- selector: m(t),
3557
- html: d(t),
3556
+ selector: m(e),
3557
+ html: d(e),
3558
3558
  impact: "serious",
3559
3559
  message: "Link has no discernible text.",
3560
- context: Ya(t)
3560
+ context: Ya(e)
3561
3561
  });
3562
3562
  }
3563
3563
  return a;
@@ -3570,15 +3570,15 @@ const Xa = {
3570
3570
  description: "Skip links must point to a valid target on the page.",
3571
3571
  guidance: "Skip links allow keyboard users to bypass repetitive navigation and jump directly to main content. The skip link should be the first focusable element on the page, link to the main content (e.g., href='#main'), and become visible when focused. It can be visually hidden until focused using CSS.",
3572
3572
  prompt: "A skip link is a single <a href='#main'>Skip to main content</a> as the first element in <body>. It can be visually hidden with CSS until focused. Explain this simple pattern.",
3573
- run(e) {
3574
- const a = [], t = e.querySelectorAll('a[href^="#"]');
3575
- for (const i of t) {
3573
+ run(t) {
3574
+ const a = [], e = t.querySelectorAll('a[href^="#"]');
3575
+ for (const i of e) {
3576
3576
  const n = i.getAttribute("href");
3577
3577
  if (!n || n === "#") continue;
3578
3578
  const r = A(i).toLowerCase();
3579
3579
  if (!(r.includes("skip") || r.includes("jump") || r.includes("main content") || r.includes("navigation"))) continue;
3580
3580
  const s = n.slice(1);
3581
- e.getElementById(s) || a.push({
3581
+ t.getElementById(s) || a.push({
3582
3582
  ruleId: "skip-link",
3583
3583
  selector: m(i),
3584
3584
  html: d(i),
@@ -3602,46 +3602,47 @@ const Xa = {
3602
3602
  "inline-flex",
3603
3603
  "inline-grid"
3604
3604
  ]);
3605
- function Za(e) {
3606
- let a = e.parentElement;
3605
+ function Za(t) {
3606
+ let a = t.parentElement;
3607
3607
  for (; a; ) {
3608
- const t = y(a).display;
3609
- if (Ja.has(t))
3608
+ const e = w(a).display;
3609
+ if (Ja.has(e))
3610
3610
  return ei(a) ? a : null;
3611
3611
  a = a.parentElement;
3612
3612
  }
3613
3613
  return null;
3614
3614
  }
3615
- function ei(e) {
3616
- const a = e.ownerDocument.createTreeWalker(
3617
- e,
3615
+ function ei(t) {
3616
+ const a = t.ownerDocument.createTreeWalker(
3617
+ t,
3618
3618
  NodeFilter.SHOW_TEXT
3619
3619
  );
3620
- let t = "", i;
3620
+ let e = "", i;
3621
3621
  for (; i = a.nextNode(); ) {
3622
3622
  if (!i.data.trim()) continue;
3623
- let n = i.parentElement, r = !1;
3624
- for (; n && n !== e; ) {
3625
- if (n.tagName === "A") {
3626
- r = !0;
3623
+ let r = i.parentElement, o = !1;
3624
+ for (; r && r !== t; ) {
3625
+ if (r.tagName === "A") {
3626
+ o = !0;
3627
3627
  break;
3628
3628
  }
3629
- n = n.parentElement;
3629
+ r = r.parentElement;
3630
3630
  }
3631
- r || (t += i.data);
3631
+ o || (e += i.data);
3632
3632
  }
3633
- return new RegExp("\\p{L}{2,}", "u").test(t);
3633
+ const n = e.match(new RegExp("\\p{L}{2,}", "gu"));
3634
+ return n !== null && n.length >= 2;
3634
3635
  }
3635
- function ti(e, a) {
3636
- const t = e.ownerDocument.createTreeWalker(
3637
- e,
3636
+ function ti(t, a) {
3637
+ const e = t.ownerDocument.createTreeWalker(
3638
+ t,
3638
3639
  NodeFilter.SHOW_TEXT
3639
3640
  );
3640
3641
  let i;
3641
- for (; i = t.nextNode(); ) {
3642
+ for (; i = e.nextNode(); ) {
3642
3643
  if (!i.data.trim()) continue;
3643
3644
  let n = i.parentElement, r = !1, o = n;
3644
- for (; o && o !== e; ) {
3645
+ for (; o && o !== t; ) {
3645
3646
  if (o.tagName === "A") {
3646
3647
  r = !0;
3647
3648
  break;
@@ -3649,34 +3650,41 @@ function ti(e, a) {
3649
3650
  o = o.parentElement;
3650
3651
  }
3651
3652
  if (!r && n)
3652
- return N(y(n).color);
3653
+ return N(w(n).color);
3653
3654
  }
3654
3655
  return null;
3655
3656
  }
3656
- function ai(e, a) {
3657
- const t = e.textDecorationLine || e.textDecoration || "", i = a.textDecorationLine || a.textDecoration || "";
3658
- if ((t.includes("underline") || t.includes("line-through")) && t !== i)
3657
+ function ai(t, a, e) {
3658
+ const i = e.textDecorationLine || e.textDecoration || "", n = a.textDecorationLine || a.textDecoration || "";
3659
+ if ((n.includes("underline") || n.includes("line-through")) && n !== i)
3660
+ return !0;
3661
+ const r = parseFloat(a.borderBottomWidth) || 0, o = a.borderBottomStyle || "";
3662
+ if (r > 0 && o !== "none" && o !== "hidden")
3659
3663
  return !0;
3660
- const n = parseFloat(e.borderBottomWidth) || 0, r = e.borderBottomStyle || "";
3661
- if (n > 0 && r !== "none" && r !== "hidden")
3664
+ const s = parseFloat(a.outlineWidth) || 0, l = a.outlineStyle || "";
3665
+ if (s > 0 && l !== "none")
3662
3666
  return !0;
3663
- const o = parseFloat(e.outlineWidth) || 0, s = e.outlineStyle || "";
3664
- if (o > 0 && s !== "none")
3667
+ const h = a.backgroundImage || "";
3668
+ if (h && h !== "none" && h !== "initial")
3665
3669
  return !0;
3666
- const l = e.backgroundImage || "";
3667
- if (l && l !== "none" && l !== "initial")
3670
+ const c = F(e.fontWeight), u = F(a.fontWeight);
3671
+ if (Math.abs(u - c) >= 300 || a.fontStyle !== e.fontStyle)
3668
3672
  return !0;
3669
- const p = se(e.fontWeight), c = se(a.fontWeight);
3670
- if (Math.abs(p - c) >= 300 || e.fontStyle !== a.fontStyle)
3673
+ const p = parseFloat(a.fontSize) || 16, b = parseFloat(e.fontSize) || 16;
3674
+ if (b > 0 && p / b >= 1.2)
3671
3675
  return !0;
3672
- const u = parseFloat(e.fontSize) || 16, h = parseFloat(a.fontSize) || 16;
3673
- return h > 0 && u / h >= 1.2;
3676
+ for (const f of t.querySelectorAll("*")) {
3677
+ const y = w(f), x = y.textDecorationLine || y.textDecoration || "";
3678
+ if ((x.includes("underline") || x.includes("line-through")) && x !== i || Math.abs(F(y.fontWeight) - c) >= 300)
3679
+ return !0;
3680
+ }
3681
+ return !1;
3674
3682
  }
3675
- function se(e) {
3676
- return e === "bold" ? 700 : e === "normal" ? 400 : parseInt(e) || 400;
3683
+ function F(t) {
3684
+ return t === "bold" ? 700 : t === "normal" ? 400 : parseInt(t) || 400;
3677
3685
  }
3678
- function le(e, a, t) {
3679
- return "#" + [e, a, t].map((i) => i.toString(16).padStart(2, "0")).join("");
3686
+ function le(t, a, e) {
3687
+ return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
3680
3688
  }
3681
3689
  const ii = {
3682
3690
  id: "link-in-text-block",
@@ -3685,27 +3693,27 @@ const ii = {
3685
3693
  description: "Links within text blocks must be distinguishable by more than color alone.",
3686
3694
  guidance: "Users who cannot perceive color differences need other visual cues to identify links. Links in text should have underlines or other non-color indicators. If using color alone, ensure 3:1 contrast with surrounding text AND provide additional indication on focus/hover.",
3687
3695
  prompt: "Explain how to make this link visually distinguishable without relying on color alone.",
3688
- run(e) {
3696
+ run(t) {
3689
3697
  const a = [];
3690
- for (const t of e.querySelectorAll("a[href]")) {
3691
- if (g(t) || !A(t).trim() || t.closest('nav, header, footer, [role="navigation"], [role="banner"], [role="contentinfo"]')) continue;
3692
- const i = y(t), n = i.display || "inline";
3698
+ for (const e of t.querySelectorAll("a[href]")) {
3699
+ if (g(e) || !A(e).trim()) continue;
3700
+ const i = w(e), n = i.display || "inline";
3693
3701
  if (!Qa.has(n)) continue;
3694
- const r = Za(t);
3702
+ const r = Za(e);
3695
3703
  if (!r) continue;
3696
- const o = y(r);
3697
- if (ai(i, o)) continue;
3704
+ const o = w(r);
3705
+ if (ai(e, i, o)) continue;
3698
3706
  const s = N(i.color), l = ti(r);
3699
3707
  if (!s || !l) continue;
3700
- const p = R(...s), c = R(...l), u = ge(p, c);
3701
- if (u >= 3) continue;
3702
- const h = le(...s), b = le(...l), f = `link color: ${h} rgb(${s.join(", ")}), surrounding text: ${b} rgb(${l.join(", ")}), ratio: ${u.toFixed(2)}:1`;
3708
+ const h = R(...s), c = R(...l), u = ge(h, c);
3709
+ if (u < 1.1 || u >= 3) continue;
3710
+ const p = le(...s), b = le(...l), f = `link color: ${p} rgb(${s.join(", ")}), surrounding text: ${b} rgb(${l.join(", ")}), ratio: ${u.toFixed(2)}:1`;
3703
3711
  a.push({
3704
3712
  ruleId: "link-in-text-block",
3705
- selector: m(t),
3706
- html: d(t),
3713
+ selector: m(e),
3714
+ html: d(e),
3707
3715
  impact: "serious",
3708
- message: "Link in text block is not visually distinguishable from surrounding text. Add an underline, border, or ensure 3:1 color contrast with surrounding text.",
3716
+ message: "Link in text block is not visually distinguishable from surrounding text. Add a non-color visual indicator such as an underline or border.",
3709
3717
  context: f
3710
3718
  });
3711
3719
  }
@@ -3718,20 +3726,20 @@ const ii = {
3718
3726
  description: "The <html> element must have a lang attribute.",
3719
3727
  guidance: "Screen readers use the lang attribute to determine which language rules and pronunciation to use. Without it, content may be mispronounced. Set lang to the primary language of the page (e.g., lang='en' for English, lang='es' for Spanish).",
3720
3728
  prompt: `The page is missing a lang attribute on <html>. Use the text sample in context to determine the primary language and suggest the correct BCP 47 code (e.g. 'en' for English, 'es' for Spanish, 'fr' for French, 'de' for German, 'ja' for Japanese, 'zh' for Chinese, 'pt' for Portuguese, 'ar' for Arabic). Add lang to the <html> element: <html lang="...">.`,
3721
- run(e) {
3722
- var t, i;
3723
- const a = e.documentElement;
3729
+ run(t) {
3730
+ var e, i;
3731
+ const a = t.documentElement;
3724
3732
  if (a.tagName.toLowerCase() !== "html") return [];
3725
- if (!e.doctype && e.body) {
3726
- const n = e.body.children;
3733
+ if (!t.doctype && t.body) {
3734
+ const n = t.body.children;
3727
3735
  if (n.length > 0 && Array.from(n).every(
3728
3736
  (r) => r.tagName.toLowerCase() === "svg" || r.tagName.toLowerCase() === "math"
3729
3737
  )) return [];
3730
3738
  }
3731
- if (!((t = a.getAttribute("lang")) != null && t.trim())) {
3739
+ if (!((e = a.getAttribute("lang")) != null && e.trim())) {
3732
3740
  let n;
3733
- if (e.body) {
3734
- const r = ((i = e.body.textContent) == null ? void 0 : i.trim().replace(/\s+/g, " ")) || "";
3741
+ if (t.body) {
3742
+ const r = ((i = t.body.textContent) == null ? void 0 : i.trim().replace(/\s+/g, " ")) || "";
3735
3743
  r && (n = r.slice(0, 200));
3736
3744
  }
3737
3745
  return [{
@@ -3750,9 +3758,9 @@ const ii = {
3750
3758
  ), oi = new Set(
3751
3759
  "aar abk afr aka amh ara arg asm ava ave aym aze bak bam bel ben bih bis bod bos bre bul cat ces cha che chu chv cor cos cre cym dan deu div dzo ell eng epo est eus ewe fao fas fij fin fra fry ful gla gle glg glv grn guj hat hau hbs heb her hin hmo hrv hun hye ibo iii iku ile ina ind ipk isl ita jav jpn kal kan kas kat kau kaz khm kik kin kir kom kon kor kua kur lao lat lav lim lin lit ltz lub lug mah mal mar mkd mlg mlt mon mri msa mya nau nav nbl nde ndo nep nld nno nob nor nya oci oji ori orm oss pan pli pol por pus que roh ron run rus sag san sin slk slv sme smo sna snd som sot spa sqi srd srp ssw sun swa swe tah tam tat tel tgk tgl tha tir ton tsn tso tuk tur twi uig ukr urd uzb ven vie vol wln wol xho yid yor zha zho zul".split(" ")
3752
3760
  ), si = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
3753
- function fe(e) {
3754
- if (!si.test(e)) return !1;
3755
- const a = e.split("-")[0].toLowerCase();
3761
+ function fe(t) {
3762
+ if (!si.test(t)) return !1;
3763
+ const a = t.split("-")[0].toLowerCase();
3756
3764
  return a.length === 2 ? ri.has(a) : a.length === 3 ? !oi.has(a) : !1;
3757
3765
  }
3758
3766
  const li = {
@@ -3762,28 +3770,28 @@ const li = {
3762
3770
  description: "The lang attribute on <html> must have a valid value.",
3763
3771
  guidance: "The lang attribute must use a valid BCP 47 language tag. Use a 2 or 3 letter language code (e.g., 'en', 'fr', 'zh'), optionally followed by a region code (e.g., 'en-US', 'pt-BR'). Invalid tags prevent screen readers from correctly pronouncing content.",
3764
3772
  prompt: "Suggest the correct BCP 47 language tag based on the invalid value provided.",
3765
- run(e) {
3766
- var t;
3767
- const a = (t = e.documentElement.getAttribute("lang")) == null ? void 0 : t.trim();
3773
+ run(t) {
3774
+ var e;
3775
+ const a = (e = t.documentElement.getAttribute("lang")) == null ? void 0 : e.trim();
3768
3776
  return a && !fe(a) ? [{
3769
3777
  ruleId: "html-lang-valid",
3770
3778
  selector: "html",
3771
- html: d(e.documentElement),
3779
+ html: d(t.documentElement),
3772
3780
  impact: "serious",
3773
3781
  message: `Invalid lang attribute value "${a}".`
3774
3782
  }] : [];
3775
3783
  }
3776
3784
  };
3777
- function ce(e) {
3785
+ function ce(t) {
3778
3786
  var i;
3779
- const a = e.ownerDocument.createTreeWalker(e, NodeFilter.SHOW_TEXT);
3780
- let t;
3781
- for (; t = a.nextNode(); ) {
3782
- if (!t.data.trim()) continue;
3783
- const n = t.parentElement;
3787
+ const a = t.ownerDocument.createTreeWalker(t, NodeFilter.SHOW_TEXT);
3788
+ let e;
3789
+ for (; e = a.nextNode(); ) {
3790
+ if (!e.data.trim()) continue;
3791
+ const n = e.parentElement;
3784
3792
  if (!n || n instanceof HTMLElement && (n.hidden || n.style.display === "none")) continue;
3785
3793
  let r = n, o = !1;
3786
- for (; r && r !== e; ) {
3794
+ for (; r && r !== t; ) {
3787
3795
  if (r.hasAttribute("lang")) {
3788
3796
  o = !0;
3789
3797
  break;
@@ -3792,10 +3800,10 @@ function ce(e) {
3792
3800
  }
3793
3801
  if (!o) return !0;
3794
3802
  }
3795
- for (const n of e.querySelectorAll("img[alt]")) {
3803
+ for (const n of t.querySelectorAll("img[alt]")) {
3796
3804
  if (!((i = n.getAttribute("alt")) == null ? void 0 : i.trim())) continue;
3797
3805
  let o = n.parentElement, s = !1;
3798
- for (; o && o !== e; ) {
3806
+ for (; o && o !== t; ) {
3799
3807
  if (o.hasAttribute("lang")) {
3800
3808
  s = !0;
3801
3809
  break;
@@ -3813,25 +3821,25 @@ const ci = {
3813
3821
  description: "The lang attribute must have a valid value on all elements.",
3814
3822
  guidance: "When content in a different language appears within a page (e.g., a French quote in an English document), wrap it with a lang attribute to ensure correct pronunciation. The lang value must be a valid BCP 47 tag. Common codes: en, es, fr, de, zh, ja, pt, ar, ru.",
3815
3823
  prompt: "Identify the content's language and suggest the correct BCP 47 tag.",
3816
- run(e) {
3824
+ run(t) {
3817
3825
  const a = [];
3818
- for (const t of e.querySelectorAll("[lang]")) {
3819
- if (g(t) || t === e.documentElement) continue;
3820
- const i = t.getAttribute("lang"), n = i == null ? void 0 : i.trim();
3826
+ for (const e of t.querySelectorAll("[lang]")) {
3827
+ if (g(e) || e === t.documentElement) continue;
3828
+ const i = e.getAttribute("lang"), n = i == null ? void 0 : i.trim();
3821
3829
  if (i && !n) {
3822
- ce(t) && a.push({
3830
+ ce(e) && a.push({
3823
3831
  ruleId: "valid-lang",
3824
- selector: m(t),
3825
- html: d(t),
3832
+ selector: m(e),
3833
+ html: d(e),
3826
3834
  impact: "serious",
3827
3835
  message: "Empty lang attribute value."
3828
3836
  });
3829
3837
  continue;
3830
3838
  }
3831
- n && ce(t) && (fe(n) || a.push({
3839
+ n && ce(e) && (fe(n) || a.push({
3832
3840
  ruleId: "valid-lang",
3833
- selector: m(t),
3834
- html: d(t),
3841
+ selector: m(e),
3842
+ html: d(e),
3835
3843
  impact: "serious",
3836
3844
  message: `Invalid lang attribute value "${n}".`
3837
3845
  }));
@@ -3845,18 +3853,18 @@ const ci = {
3845
3853
  description: "The lang and xml:lang attributes on <html> must match.",
3846
3854
  guidance: "In XHTML documents, if both lang and xml:lang are present, they must specify the same base language. Mismatched values confuse assistive technologies. Either remove xml:lang (preferred for HTML5) or ensure both attributes have identical values.",
3847
3855
  prompt: "Explain whether to remove xml:lang or align it with the lang value.",
3848
- run(e) {
3856
+ run(t) {
3849
3857
  var n, r;
3850
- const a = e.documentElement, t = (n = a.getAttribute("lang")) == null ? void 0 : n.trim().toLowerCase(), i = (r = a.getAttribute("xml:lang")) == null ? void 0 : r.trim().toLowerCase();
3851
- if (t && i) {
3852
- const o = t.split("-")[0], s = i.split("-")[0];
3858
+ const a = t.documentElement, e = (n = a.getAttribute("lang")) == null ? void 0 : n.trim().toLowerCase(), i = (r = a.getAttribute("xml:lang")) == null ? void 0 : r.trim().toLowerCase();
3859
+ if (e && i) {
3860
+ const o = e.split("-")[0], s = i.split("-")[0];
3853
3861
  if (o !== s)
3854
3862
  return [{
3855
3863
  ruleId: "html-xml-lang-mismatch",
3856
3864
  selector: "html",
3857
3865
  html: d(a),
3858
3866
  impact: "moderate",
3859
- message: `lang="${t}" and xml:lang="${i}" do not match.`
3867
+ message: `lang="${e}" and xml:lang="${i}" do not match.`
3860
3868
  }];
3861
3869
  }
3862
3870
  return [];
@@ -3868,19 +3876,19 @@ const ci = {
3868
3876
  description: "All cells in a table using headers attribute must reference valid header IDs.",
3869
3877
  guidance: "The headers attribute on table cells must reference IDs of header cells (th or td) within the same table. This creates explicit associations for screen readers. Verify all referenced IDs exist and spell them correctly. For simple tables, consider using scope on th elements instead.",
3870
3878
  prompt: "Identify the invalid header ID reference and suggest the correct ID or how to fix it.",
3871
- run(e) {
3879
+ run(t) {
3872
3880
  const a = [];
3873
- for (const t of e.querySelectorAll("td[headers]")) {
3874
- if (g(t)) continue;
3875
- const i = t.closest("table");
3881
+ for (const e of t.querySelectorAll("td[headers]")) {
3882
+ if (g(e)) continue;
3883
+ const i = e.closest("table");
3876
3884
  if (!i) continue;
3877
- const n = t.getAttribute("id"), r = t.getAttribute("headers").split(/\s+/);
3885
+ const n = e.getAttribute("id"), r = e.getAttribute("headers").split(/\s+/);
3878
3886
  for (const o of r) {
3879
3887
  if (o === n) {
3880
3888
  a.push({
3881
3889
  ruleId: "td-headers-attr",
3882
- selector: m(t),
3883
- html: d(t),
3890
+ selector: m(e),
3891
+ html: d(e),
3884
3892
  impact: "serious",
3885
3893
  message: `Headers attribute references the cell itself ("${o}").`
3886
3894
  });
@@ -3889,8 +3897,8 @@ const ci = {
3889
3897
  if (!i.querySelector(`th#${CSS.escape(o)}, td#${CSS.escape(o)}`)) {
3890
3898
  a.push({
3891
3899
  ruleId: "td-headers-attr",
3892
- selector: m(t),
3893
- html: d(t),
3900
+ selector: m(e),
3901
+ html: d(e),
3894
3902
  impact: "serious",
3895
3903
  message: `Headers attribute references non-existent ID "${o}".`
3896
3904
  });
@@ -3907,15 +3915,15 @@ const ci = {
3907
3915
  description: "Table headers should be associated with data cells.",
3908
3916
  guidance: "A table with header cells (th) but no data cells (td) is likely a misuse of table markup for layout or has missing content. Either add data cells that the headers describe, or use appropriate non-table markup if this is not tabular data.",
3909
3917
  prompt: "Explain whether this table needs data cells or if non-table layout would be more appropriate.",
3910
- run(e) {
3918
+ run(t) {
3911
3919
  const a = [];
3912
- for (const t of e.querySelectorAll("table")) {
3913
- if (g(t) || t.getAttribute("role") === "presentation" || t.getAttribute("role") === "none") continue;
3914
- const i = t.querySelectorAll("th"), n = t.querySelectorAll("td");
3920
+ for (const e of t.querySelectorAll("table")) {
3921
+ if (g(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none") continue;
3922
+ const i = e.querySelectorAll("th"), n = e.querySelectorAll("td");
3915
3923
  i.length > 0 && n.length === 0 && a.push({
3916
3924
  ruleId: "th-has-data-cells",
3917
- selector: m(t),
3918
- html: d(t),
3925
+ selector: m(e),
3926
+ html: d(e),
3919
3927
  impact: "serious",
3920
3928
  message: "Table has header cells but no data cells."
3921
3929
  });
@@ -3929,39 +3937,39 @@ const ci = {
3929
3937
  description: "Data cells in tables larger than 3x3 should have associated headers.",
3930
3938
  guidance: "In complex tables, screen reader users need header associations to understand data cells. Use th elements with scope attribute, or the headers attribute on td elements. For simple tables (≤3x3), this is less critical as context is usually clear.",
3931
3939
  prompt: "Explain whether to use scope attributes on headers or headers attribute on this cell.",
3932
- run(e) {
3933
- var t, i;
3940
+ run(t) {
3941
+ var e, i;
3934
3942
  const a = [];
3935
- for (const n of e.querySelectorAll("table")) {
3943
+ for (const n of t.querySelectorAll("table")) {
3936
3944
  if (g(n) || n.getAttribute("role") === "presentation" || n.getAttribute("role") === "none") continue;
3937
3945
  const r = n.querySelectorAll("tr"), o = r.length;
3938
3946
  let s = 0;
3939
3947
  for (const u of r) {
3940
- const h = u.querySelectorAll("td, th");
3948
+ const p = u.querySelectorAll("td, th");
3941
3949
  let b = 0;
3942
- for (const f of h)
3950
+ for (const f of p)
3943
3951
  b += parseInt(f.getAttribute("colspan") || "1", 10);
3944
3952
  s = Math.max(s, b);
3945
3953
  }
3946
3954
  if (o <= 3 && s <= 3) continue;
3947
- const l = n.querySelector("th") !== null, p = n.querySelector("th[scope]") !== null, c = n.querySelector("td[headers]") !== null;
3955
+ const l = n.querySelector("th") !== null, h = n.querySelector("th[scope]") !== null, c = n.querySelector("td[headers]") !== null;
3948
3956
  if (l)
3949
3957
  for (const u of n.querySelectorAll("td")) {
3950
3958
  if (g(u) || u.hasAttribute("headers")) continue;
3951
- const h = u.closest("tr");
3952
- if (!h) continue;
3953
- const b = h.querySelector("th") !== null, f = Array.from(h.children).indexOf(u);
3954
- let w = !1;
3955
- const I = n.querySelector("thead");
3956
- if (I) {
3957
- const x = I.querySelector("tr");
3958
- x && ((t = x.querySelectorAll("th, td")[f]) == null ? void 0 : t.tagName.toLowerCase()) === "th" && (w = !0);
3959
+ const p = u.closest("tr");
3960
+ if (!p) continue;
3961
+ const b = p.querySelector("th") !== null, f = Array.from(p.children).indexOf(u);
3962
+ let y = !1;
3963
+ const x = n.querySelector("thead");
3964
+ if (x) {
3965
+ const S = x.querySelector("tr");
3966
+ S && ((e = S.querySelectorAll("th, td")[f]) == null ? void 0 : e.tagName.toLowerCase()) === "th" && (y = !0);
3959
3967
  }
3960
- if (!w) {
3961
- const x = n.querySelector("tbody > tr, tr");
3962
- x && ((i = x.querySelectorAll("th, td")[f]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (w = !0);
3968
+ if (!y) {
3969
+ const S = n.querySelector("tbody > tr, tr");
3970
+ S && ((i = S.querySelectorAll("th, td")[f]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (y = !0);
3963
3971
  }
3964
- if (!b && !w && !p && !c) {
3972
+ if (!b && !y && !h && !c) {
3965
3973
  a.push({
3966
3974
  ruleId: "td-has-header",
3967
3975
  selector: m(u),
@@ -3982,13 +3990,13 @@ const ci = {
3982
3990
  description: "The scope attribute on table headers must have a valid value.",
3983
3991
  guidance: "The scope attribute tells screen readers which cells a header applies to. Valid values are: row, col, rowgroup, colgroup. Using invalid values breaks the association between headers and cells.",
3984
3992
  prompt: "Explain which scope value (row, col, rowgroup, colgroup) is appropriate for this header.",
3985
- run(e) {
3993
+ run(t) {
3986
3994
  var i;
3987
- const a = [], t = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
3988
- for (const n of e.querySelectorAll("th[scope]")) {
3995
+ const a = [], e = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
3996
+ for (const n of t.querySelectorAll("th[scope]")) {
3989
3997
  if (g(n)) continue;
3990
3998
  const r = (i = n.getAttribute("scope")) == null ? void 0 : i.toLowerCase();
3991
- r && !t.has(r) && a.push({
3999
+ r && !e.has(r) && a.push({
3992
4000
  ruleId: "scope-attr-valid",
3993
4001
  selector: m(n),
3994
4002
  html: d(n),
@@ -4006,65 +4014,65 @@ const ci = {
4006
4014
  description: "Table header cells should have visible text.",
4007
4015
  guidance: "Empty table headers provide no information to screen reader users. Either add descriptive text to the header, or if the header is intentionally empty (like a corner cell), consider using a td element instead or adding a visually hidden label.",
4008
4016
  prompt: "Suggest header text based on the column/row content, or explain if this should be a td instead.",
4009
- run(e) {
4017
+ run(t) {
4010
4018
  const a = [];
4011
- for (const t of e.querySelectorAll("th")) {
4012
- if (g(t)) continue;
4013
- const i = t.closest("table");
4014
- (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || v(t) || a.push({
4019
+ for (const e of t.querySelectorAll("th")) {
4020
+ if (g(e)) continue;
4021
+ const i = e.closest("table");
4022
+ (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || v(e) || a.push({
4015
4023
  ruleId: "empty-table-header",
4016
- selector: m(t),
4017
- html: d(t),
4024
+ selector: m(e),
4025
+ html: d(e),
4018
4026
  impact: "minor",
4019
4027
  message: "Table header cell is empty. Add text or use aria-label."
4020
4028
  });
4021
4029
  }
4022
4030
  return a;
4023
4031
  }
4024
- }, F = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], bi = {
4032
+ }, W = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], bi = {
4025
4033
  id: "duplicate-id-aria",
4026
4034
  wcag: ["4.1.2"],
4027
4035
  level: "A",
4028
4036
  description: "IDs used in ARIA and label associations must be unique to avoid broken references.",
4029
4037
  guidance: "When aria-labelledby, aria-describedby, aria-controls, or label[for] reference a duplicate ID, only the first matching element is used. This breaks the intended relationship and may leave controls unnamed or descriptions missing. Ensure IDs referenced by ARIA attributes and label associations are unique throughout the document.",
4030
4038
  prompt: "Identify which attribute references this ID and suggest a unique replacement.",
4031
- run(e) {
4032
- const a = [], t = /* @__PURE__ */ new Set();
4033
- for (const n of e.querySelectorAll("[aria-labelledby], [aria-describedby], [aria-controls], [aria-owns], [aria-flowto]"))
4034
- for (const r of F) {
4039
+ run(t) {
4040
+ const a = [], e = /* @__PURE__ */ new Set();
4041
+ for (const n of t.querySelectorAll("[aria-labelledby], [aria-describedby], [aria-controls], [aria-owns], [aria-flowto]"))
4042
+ for (const r of W) {
4035
4043
  const o = n.getAttribute(r);
4036
- o && o.split(/\s+/).forEach((s) => t.add(s));
4044
+ o && o.split(/\s+/).forEach((s) => e.add(s));
4037
4045
  }
4038
- for (const n of e.querySelectorAll("label[for]")) {
4046
+ for (const n of t.querySelectorAll("label[for]")) {
4039
4047
  const r = n.getAttribute("for");
4040
- r && t.add(r);
4048
+ r && e.add(r);
4041
4049
  }
4042
4050
  const i = /* @__PURE__ */ new Map();
4043
- for (const n of e.querySelectorAll("[id]"))
4044
- t.has(n.id) && (n instanceof HTMLElement && (n.style.display === "none" || n.style.visibility === "hidden" || n.hidden) || i.set(n.id, (i.get(n.id) ?? 0) + 1));
4051
+ for (const n of t.querySelectorAll("[id]"))
4052
+ e.has(n.id) && (n instanceof HTMLElement && (n.style.display === "none" || n.style.visibility === "hidden" || n.hidden) || i.set(n.id, (i.get(n.id) ?? 0) + 1));
4045
4053
  for (const [n, r] of i) {
4046
4054
  if (r <= 1) continue;
4047
- const o = e.querySelectorAll(`#${CSS.escape(n)}`), s = e.querySelector(
4048
- F.map((c) => `[${c}~="${CSS.escape(n)}"]`).join(", ")
4049
- ), l = e.querySelector(`label[for="${CSS.escape(n)}"]`);
4050
- let p;
4055
+ const o = t.querySelectorAll(`#${CSS.escape(n)}`), s = t.querySelector(
4056
+ W.map((c) => `[${c}~="${CSS.escape(n)}"]`).join(", ")
4057
+ ), l = t.querySelector(`label[for="${CSS.escape(n)}"]`);
4058
+ let h;
4051
4059
  if (s) {
4052
- const c = F.find(
4060
+ const c = W.find(
4053
4061
  (u) => {
4054
- var h;
4055
- return (h = s.getAttribute(u)) == null ? void 0 : h.split(/\s+/).includes(n);
4062
+ var p;
4063
+ return (p = s.getAttribute(u)) == null ? void 0 : p.split(/\s+/).includes(n);
4056
4064
  }
4057
4065
  );
4058
- c && (p = c);
4059
- } else l && (p = "label[for]");
4066
+ c && (h = c);
4067
+ } else l && (h = "label[for]");
4060
4068
  a.push({
4061
4069
  ruleId: "duplicate-id-aria",
4062
4070
  selector: m(o[1]),
4063
4071
  html: d(o[1]),
4064
4072
  impact: "critical",
4065
- message: `Duplicate ID "${n}" referenced by ${p ?? "an accessibility attribute"}.`,
4066
- context: `First element: ${d(o[0])}${p ? `
4067
- Referenced by: ${p}` : ""}`
4073
+ message: `Duplicate ID "${n}" referenced by ${h ?? "an accessibility attribute"}.`,
4074
+ context: `First element: ${d(o[0])}${h ? `
4075
+ Referenced by: ${h}` : ""}`
4068
4076
  });
4069
4077
  }
4070
4078
  return a;
@@ -4076,14 +4084,14 @@ Referenced by: ${p}` : ""}`
4076
4084
  description: "Video elements must have captions via <track kind='captions'>.",
4077
4085
  guidance: "Captions provide text alternatives for audio content in videos, benefiting deaf users and those who cannot hear audio. Add a <track> element with kind='captions' pointing to a WebVTT caption file. Captions should include both dialogue and important sound effects.",
4078
4086
  prompt: "Explain how to add a captions track element to this video.",
4079
- run(e) {
4087
+ run(t) {
4080
4088
  const a = [];
4081
- for (const t of e.querySelectorAll("video")) {
4082
- if (g(t) || t.hasAttribute("muted") || t.hasAttribute("autoplay")) continue;
4083
- t.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
4089
+ for (const e of t.querySelectorAll("video")) {
4090
+ if (g(e) || e.hasAttribute("muted") || e.hasAttribute("autoplay")) continue;
4091
+ e.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
4084
4092
  ruleId: "video-caption",
4085
- selector: m(t),
4086
- html: d(t),
4093
+ selector: m(e),
4094
+ html: d(e),
4087
4095
  impact: "critical",
4088
4096
  message: "Video element has no captions track."
4089
4097
  });
@@ -4097,22 +4105,22 @@ Referenced by: ${p}` : ""}`
4097
4105
  description: "Audio elements should have a text alternative or transcript.",
4098
4106
  guidance: "Audio-only content like podcasts or recordings needs a text alternative for deaf users. Provide a transcript either on the same page or linked nearby. The transcript should include all spoken content and descriptions of relevant sounds.",
4099
4107
  prompt: "Explain options for providing a text alternative: transcript link or aria-describedby.",
4100
- run(e) {
4108
+ run(t) {
4101
4109
  const a = [];
4102
- for (const t of e.querySelectorAll("audio")) {
4103
- if (g(t) || t.querySelector('track[kind="captions"], track[kind="descriptions"]') || t.hasAttribute("aria-describedby")) continue;
4104
- const n = t.parentElement;
4110
+ for (const e of t.querySelectorAll("audio")) {
4111
+ if (g(e) || e.querySelector('track[kind="captions"], track[kind="descriptions"]') || e.hasAttribute("aria-describedby")) continue;
4112
+ const n = e.parentElement;
4105
4113
  n && n.querySelector('a[href*="transcript"], a[href*="text"]') || a.push({
4106
4114
  ruleId: "audio-caption",
4107
- selector: m(t),
4108
- html: d(t),
4115
+ selector: m(e),
4116
+ html: d(e),
4109
4117
  impact: "critical",
4110
4118
  message: "Audio element has no transcript or text alternative. Add a transcript or track element."
4111
4119
  });
4112
4120
  }
4113
4121
  return a;
4114
4122
  }
4115
- }, wi = /* @__PURE__ */ new Set([
4123
+ }, yi = /* @__PURE__ */ new Set([
4116
4124
  "SCRIPT",
4117
4125
  "STYLE",
4118
4126
  "NOSCRIPT",
@@ -4128,53 +4136,53 @@ Referenced by: ${p}` : ""}`
4128
4136
  "BR",
4129
4137
  "HR"
4130
4138
  ]);
4131
- function ue([e, a, t]) {
4132
- return "#" + [e, a, t].map((i) => i.toString(16).padStart(2, "0")).join("");
4139
+ function ue([t, a, e]) {
4140
+ return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
4133
4141
  }
4134
- function yi(e) {
4135
- return e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement || e instanceof HTMLButtonElement ? e.disabled : !!(e.closest("fieldset[disabled]") || e.getAttribute("aria-disabled") === "true");
4142
+ function wi(t) {
4143
+ return t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t instanceof HTMLButtonElement ? t.disabled : !!(t.closest("fieldset[disabled]") || t.getAttribute("aria-disabled") === "true");
4136
4144
  }
4137
- function Ai(e, a) {
4138
- if (e.tagName !== "LABEL") return !1;
4139
- const t = e, i = t.htmlFor;
4145
+ function Ai(t, a) {
4146
+ if (t.tagName !== "LABEL") return !1;
4147
+ const e = t, i = e.htmlFor;
4140
4148
  if (i) {
4141
4149
  const o = a.getElementById(i);
4142
4150
  if (o && (o.disabled || o.getAttribute("aria-disabled") === "true")) return !0;
4143
4151
  }
4144
- const n = t.querySelector("input, select, textarea, button");
4152
+ const n = e.querySelector("input, select, textarea, button");
4145
4153
  if (n && (n.disabled || n.getAttribute("aria-disabled") === "true")) return !0;
4146
- const r = t.id;
4154
+ const r = e.id;
4147
4155
  return !!(r && a.querySelector(`[aria-labelledby~="${r}"][aria-disabled="true"]`));
4148
4156
  }
4149
- function xi(e) {
4150
- const a = e.clip;
4157
+ function xi(t) {
4158
+ const a = t.clip;
4151
4159
  if (a && a.startsWith("rect(")) {
4152
4160
  const i = a.match(/[\d.]+/g);
4153
4161
  if (!i || i.every((n) => parseFloat(n) === 0)) return !0;
4154
4162
  }
4155
- const t = e.clipPath;
4156
- if (t === "inset(50%)" || t === "inset(100%)") return !0;
4157
- if (e.overflow === "hidden" && e.position === "absolute") {
4158
- const i = parseFloat(e.width), n = parseFloat(e.height);
4163
+ const e = t.clipPath;
4164
+ if (e === "inset(50%)" || e === "inset(100%)") return !0;
4165
+ if (t.overflow === "hidden" && t.position === "absolute") {
4166
+ const i = parseFloat(t.width), n = parseFloat(t.height);
4159
4167
  if (i <= 1 && n <= 1) return !0;
4160
4168
  }
4161
4169
  return !1;
4162
4170
  }
4163
- function Si(e) {
4164
- if (g(e)) return !0;
4165
- let a = e;
4171
+ function Si(t) {
4172
+ if (g(t)) return !0;
4173
+ let a = t;
4166
4174
  for (; a; ) {
4167
- const t = y(a);
4168
- if (t.display === "none" || t.visibility === "hidden" || xi(t)) return !0;
4175
+ const e = w(a);
4176
+ if (e.display === "none" || e.visibility === "hidden" || xi(e)) return !0;
4169
4177
  a = a.parentElement;
4170
4178
  }
4171
4179
  return !1;
4172
4180
  }
4173
- function ki(e) {
4174
- let a = 1, t = e;
4175
- for (; t; ) {
4176
- const i = y(t), n = parseFloat(i.opacity);
4177
- isNaN(n) || (a *= n), t = t.parentElement;
4181
+ function ki(t) {
4182
+ let a = 1, e = t;
4183
+ for (; e; ) {
4184
+ const i = w(e), n = parseFloat(i.opacity);
4185
+ isNaN(n) || (a *= n), e = e.parentElement;
4178
4186
  }
4179
4187
  return a;
4180
4188
  }
@@ -4189,35 +4197,35 @@ const Ii = {
4189
4197
  saturate: 1,
4190
4198
  opacity: 1
4191
4199
  };
4192
- function Ti(e) {
4193
- const a = parseFloat(e);
4194
- return isNaN(a) ? NaN : e.trim().endsWith("%") ? a / 100 : a;
4200
+ function Ti(t) {
4201
+ const a = parseFloat(t);
4202
+ return isNaN(a) ? NaN : t.trim().endsWith("%") ? a / 100 : a;
4195
4203
  }
4196
4204
  const de = /([a-z-]+)\(([^)]*)\)/g;
4197
- function me(e) {
4198
- let a, t = !1;
4199
- for (de.lastIndex = 0; a = de.exec(e); ) {
4200
- t = !0;
4205
+ function me(t) {
4206
+ let a, e = !1;
4207
+ for (de.lastIndex = 0; a = de.exec(t); ) {
4208
+ e = !0;
4201
4209
  const i = Ii[a[1]];
4202
4210
  if (i === void 0 || Ti(a[2]) !== i) return !1;
4203
4211
  }
4204
- return t;
4212
+ return e;
4205
4213
  }
4206
- function Ei(e) {
4207
- let a = e;
4214
+ function Ei(t) {
4215
+ let a = t;
4208
4216
  for (; a; ) {
4209
- const t = y(a), i = t.filter;
4217
+ const e = w(a), i = e.filter;
4210
4218
  if (i && i !== "none" && i !== "initial" && !me(i)) return !0;
4211
- const n = t.mixBlendMode;
4219
+ const n = e.mixBlendMode;
4212
4220
  if (n && n !== "normal" && n !== "initial") return !0;
4213
- const r = t.backdropFilter;
4221
+ const r = e.backdropFilter;
4214
4222
  if (r && r !== "none" && r !== "initial" && !me(r)) return !0;
4215
4223
  a = a.parentElement;
4216
4224
  }
4217
4225
  return !1;
4218
4226
  }
4219
- function Ci(e) {
4220
- return e.closest("select") !== null;
4227
+ function Ci(t) {
4228
+ return t.closest("select") !== null;
4221
4229
  }
4222
4230
  const Li = {
4223
4231
  id: "color-contrast",
@@ -4226,37 +4234,37 @@ const Li = {
4226
4234
  description: "Text elements must have sufficient color contrast against the background.",
4227
4235
  guidance: "WCAG SC 1.4.3 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (>=24px or >=18.66px bold). Increase the contrast by darkening the text or lightening the background, or vice versa.",
4228
4236
  prompt: "Suggest changing the text or background color to meet the minimum contrast ratio.",
4229
- run(e) {
4230
- const a = [], t = e.body;
4231
- if (!t) return [];
4232
- const i = e.createTreeWalker(t, NodeFilter.SHOW_TEXT), n = /* @__PURE__ */ new Set();
4237
+ run(t) {
4238
+ const a = [], e = t.body;
4239
+ if (!e) return [];
4240
+ const i = t.createTreeWalker(e, NodeFilter.SHOW_TEXT), n = /* @__PURE__ */ new Set();
4233
4241
  let r;
4234
4242
  for (; r = i.nextNode(); ) {
4235
4243
  if (!r.textContent || !r.textContent.trim()) continue;
4236
4244
  const o = r.parentElement;
4237
- if (!o || n.has(o) || (n.add(o), wi.has(o.tagName))) continue;
4245
+ if (!o || n.has(o) || (n.add(o), yi.has(o.tagName))) continue;
4238
4246
  const s = o.tagName;
4239
- if (s === "BODY" || s === "HTML" || Ci(o) || yi(o) || Ai(o, e) || Si(o)) continue;
4240
- const l = y(o);
4247
+ if (s === "BODY" || s === "HTML" || Ci(o) || wi(o) || Ai(o, t) || Si(o)) continue;
4248
+ const l = w(o);
4241
4249
  if (parseFloat(l.opacity) === 0 || ki(o) < 0.1) continue;
4242
- const p = l.textShadow;
4243
- if (p && p !== "none" && p !== "initial" || Ei(o)) continue;
4250
+ const h = l.textShadow;
4251
+ if (h && h !== "none" && h !== "initial" || Ei(o)) continue;
4244
4252
  const c = N(l.color);
4245
4253
  if (!c) continue;
4246
4254
  const u = l.color.match(/rgba\(.+?,\s*([\d.]+)\s*\)/) || l.color.match(/rgba?\(.+?\/\s*([\d.]+%?)\s*\)/);
4247
4255
  if (u && (u[1].endsWith("%") ? parseFloat(u[1]) / 100 : parseFloat(u[1])) === 0 || je(o)) continue;
4248
- const h = Be(o);
4249
- if (!h) continue;
4250
- const b = R(c[0], c[1], c[2]), f = R(h[0], h[1], h[2]), w = ge(b, f), I = Ue(o) ? 3 : 4.5;
4251
- if (w < I) {
4252
- const x = Math.round(w * 100) / 100, M = ue(c), xe = ue(h);
4256
+ const p = Be(o);
4257
+ if (!p) continue;
4258
+ const b = R(c[0], c[1], c[2]), f = R(p[0], p[1], p[2]), y = ge(b, f), x = Ue(o) ? 3 : 4.5;
4259
+ if (y < x) {
4260
+ const S = Math.round(y * 100) / 100, M = ue(c), xe = ue(p);
4253
4261
  a.push({
4254
4262
  ruleId: "color-contrast",
4255
4263
  selector: m(o),
4256
4264
  html: d(o),
4257
4265
  impact: "serious",
4258
- message: `Insufficient color contrast ratio of ${x}:1 (required ${I}:1).`,
4259
- context: `foreground: ${M} rgb(${c.join(", ")}), background: ${xe} rgb(${h.join(", ")}), ratio: ${x}:1, required: ${I}:1`
4266
+ message: `Insufficient color contrast ratio of ${S}:1 (required ${x}:1).`,
4267
+ context: `foreground: ${M} rgb(${c.join(", ")}), background: ${xe} rgb(${p.join(", ")}), ratio: ${S}:1, required: ${x}:1`
4260
4268
  });
4261
4269
  }
4262
4270
  }
@@ -4336,7 +4344,7 @@ const Li = {
4336
4344
  Pa,
4337
4345
  ja,
4338
4346
  Ua,
4339
- ya,
4347
+ wa,
4340
4348
  Ga,
4341
4349
  // Links
4342
4350
  Xa,
@@ -4361,23 +4369,23 @@ const Li = {
4361
4369
  // Color
4362
4370
  Li
4363
4371
  ];
4364
- let G = [], we = /* @__PURE__ */ new Set();
4365
- function $i(e) {
4366
- e.additionalRules && (G = e.additionalRules), e.disabledRules && (we = new Set(e.disabledRules));
4372
+ let Y = [], ye = /* @__PURE__ */ new Set();
4373
+ function $i(t) {
4374
+ t.additionalRules && (Y = t.additionalRules), t.disabledRules && (ye = new Set(t.disabledRules));
4367
4375
  }
4368
- function ye() {
4369
- return ve.filter((a) => !we.has(a.id)).concat(G);
4376
+ function we() {
4377
+ return ve.filter((a) => !ye.has(a.id)).concat(Y);
4370
4378
  }
4371
- function Mi(e) {
4379
+ function Mi(t) {
4372
4380
  Ae();
4373
- const a = ye(), t = [];
4381
+ const a = we(), e = [];
4374
4382
  let i = 0;
4375
4383
  return {
4376
4384
  processChunk(n) {
4377
4385
  const r = performance.now();
4378
4386
  for (; i < a.length; ) {
4379
4387
  try {
4380
- t.push(...a[i].run(e));
4388
+ e.push(...a[i].run(t));
4381
4389
  } catch {
4382
4390
  }
4383
4391
  if (i++, performance.now() - r >= n) break;
@@ -4385,33 +4393,33 @@ function Mi(e) {
4385
4393
  return i < a.length;
4386
4394
  },
4387
4395
  getViolations() {
4388
- return t;
4396
+ return e;
4389
4397
  }
4390
4398
  };
4391
4399
  }
4392
4400
  function Ae() {
4393
4401
  Ce(), Se(), ke(), Oe(), We(), Le();
4394
4402
  }
4395
- function Hi(e) {
4403
+ function Hi(t) {
4396
4404
  var i;
4397
4405
  Ae();
4398
- const a = ye(), t = [];
4406
+ const a = we(), e = [];
4399
4407
  for (const n of a)
4400
4408
  try {
4401
- t.push(...n.run(e));
4409
+ e.push(...n.run(t));
4402
4410
  } catch {
4403
4411
  }
4404
4412
  return {
4405
- url: ((i = e.location) == null ? void 0 : i.href) ?? "",
4413
+ url: ((i = t.location) == null ? void 0 : i.href) ?? "",
4406
4414
  timestamp: Date.now(),
4407
- violations: t,
4415
+ violations: e,
4408
4416
  ruleCount: a.length
4409
4417
  };
4410
4418
  }
4411
- const qi = new Map(ve.map((e) => [e.id, e]));
4412
- function Di(e) {
4413
- const a = qi.get(e);
4414
- return a || G.find((t) => t.id === e);
4419
+ const qi = new Map(ve.map((t) => [t.id, t]));
4420
+ function Di(t) {
4421
+ const a = qi.get(t);
4422
+ return a || Y.find((e) => e.id === t);
4415
4423
  }
4416
4424
  export {
4417
4425
  Ae as clearAllCaches,
@@ -4419,12 +4427,12 @@ export {
4419
4427
  Ce as clearAriaHiddenCache,
4420
4428
  Oe as clearColorCaches,
4421
4429
  Se as clearComputedRoleCache,
4422
- k as compileDeclarativeRule,
4430
+ I as compileDeclarativeRule,
4423
4431
  $i as configureRules,
4424
4432
  Mi as createChunkedAudit,
4425
4433
  v as getAccessibleName,
4426
4434
  A as getAccessibleTextContent,
4427
- ye as getActiveRules,
4435
+ we as getActiveRules,
4428
4436
  q as getComputedRole,
4429
4437
  d as getHtmlSnippet,
4430
4438
  he as getImplicitRole,