@accesslint/core 0.3.0 → 0.3.2

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,8 +1,8 @@
1
- let M = /* @__PURE__ */ new WeakMap();
2
- function oe() {
3
- M = /* @__PURE__ */ new WeakMap();
1
+ let D = /* @__PURE__ */ new WeakMap();
2
+ function be() {
3
+ D = /* @__PURE__ */ new WeakMap();
4
4
  }
5
- function J(t) {
5
+ function le(t) {
6
6
  var i;
7
7
  const a = t.tagName.toLowerCase(), e = (i = t.getAttribute("type")) == null ? void 0 : i.toLowerCase();
8
8
  switch (a) {
@@ -117,71 +117,71 @@ function J(t) {
117
117
  return null;
118
118
  }
119
119
  }
120
- function E(t) {
120
+ function C(t) {
121
121
  var n;
122
- const a = M.get(t);
122
+ const a = D.get(t);
123
123
  if (a !== void 0) return a;
124
- const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || J(t);
125
- return M.set(t, i), i;
124
+ const i = ((n = t.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || le(t);
125
+ return D.set(t, i), i;
126
126
  }
127
- let $ = /* @__PURE__ */ new WeakMap();
128
- function se() {
129
- $ = /* @__PURE__ */ new WeakMap();
127
+ let O = /* @__PURE__ */ new WeakMap();
128
+ function fe() {
129
+ O = /* @__PURE__ */ new WeakMap();
130
130
  }
131
- function b(t) {
132
- const a = $.get(t);
131
+ function v(t) {
132
+ const a = O.get(t);
133
133
  if (a !== void 0) return a;
134
- const e = le(t);
135
- return $.set(t, e), e;
134
+ const e = ve(t);
135
+ return O.set(t, e), e;
136
136
  }
137
- function le(t) {
138
- var r, o, s, u, h;
137
+ function ve(t) {
138
+ var r, o, s, c, h;
139
139
  const a = t.getAttribute("aria-labelledby");
140
140
  if (a) {
141
- const d = a.split(/\s+/).map((p) => {
142
- const g = t.ownerDocument.getElementById(p);
141
+ const l = a.split(/\s+/).map((m) => {
142
+ const g = t.ownerDocument.getElementById(m);
143
143
  return g ? y(g).trim() : "";
144
144
  }).filter(Boolean);
145
- if (d.length) return d.join(" ");
145
+ if (l.length) return l.join(" ");
146
146
  }
147
147
  const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
148
148
  if (e) return e;
149
149
  if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
150
150
  if (t.id) {
151
- const g = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`), f = g ? y(g).trim() : "";
152
- if (f) return f;
151
+ const g = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`), b = g ? y(g).trim() : "";
152
+ if (b) return b;
153
153
  }
154
- const d = t.closest("label"), p = d ? y(d).trim() : "";
155
- if (p) return p;
154
+ const l = t.closest("label"), m = l ? y(l).trim() : "";
155
+ if (m) return m;
156
156
  }
157
157
  const i = (o = t.getAttribute("title")) == null ? void 0 : o.trim();
158
158
  if (i) return i;
159
159
  if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
160
- const d = (s = t.getAttribute("placeholder")) == null ? void 0 : s.trim();
161
- if (d) return d;
160
+ const l = (s = t.getAttribute("placeholder")) == null ? void 0 : s.trim();
161
+ if (l) return l;
162
162
  }
163
163
  const n = t.tagName.toLowerCase();
164
164
  if (n === "fieldset") {
165
- const d = t.querySelector(":scope > legend");
166
- if (d) {
167
- const p = y(d).trim();
168
- if (p) return p;
165
+ const l = t.querySelector(":scope > legend");
166
+ if (l) {
167
+ const m = y(l).trim();
168
+ if (m) return m;
169
169
  }
170
170
  }
171
171
  if (n === "table") {
172
- const d = t.querySelector(":scope > caption");
173
- if (d) {
174
- const p = y(d).trim();
175
- if (p) return p;
172
+ const l = t.querySelector(":scope > caption");
173
+ if (l) {
174
+ const m = y(l).trim();
175
+ if (m) return m;
176
176
  }
177
177
  }
178
178
  if (!(t instanceof HTMLInputElement)) {
179
- const d = y(t).trim();
180
- if (d) return d;
179
+ const l = y(t).trim();
180
+ if (l) return l;
181
181
  }
182
- return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((u = t.alt) == null ? void 0 : u.trim()) ?? "" : t instanceof HTMLInputElement && t.type === "image" ? ((h = t.alt) == null ? void 0 : h.trim()) ?? "" : "";
182
+ return t instanceof HTMLImageElement || t instanceof HTMLAreaElement ? ((c = t.alt) == null ? void 0 : c.trim()) ?? "" : t instanceof HTMLInputElement && t.type === "image" ? ((h = t.alt) == null ? void 0 : h.trim()) ?? "" : "";
183
183
  }
184
- const ce = /* @__PURE__ */ new Set([
184
+ const we = /* @__PURE__ */ new Set([
185
185
  "alert",
186
186
  "alertdialog",
187
187
  "application",
@@ -265,56 +265,67 @@ const ce = /* @__PURE__ */ new Set([
265
265
  "treegrid",
266
266
  "treeitem"
267
267
  ]);
268
- function de(t) {
268
+ function ye(t) {
269
269
  const a = t.trim().toLowerCase().replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "");
270
- return ce.has(a);
270
+ return we.has(a);
271
271
  }
272
- let H = /* @__PURE__ */ new WeakMap();
273
- function ue() {
274
- H = /* @__PURE__ */ new WeakMap();
272
+ let B = /* @__PURE__ */ new WeakMap();
273
+ function Ae() {
274
+ B = /* @__PURE__ */ new WeakMap();
275
275
  }
276
- function m(t) {
277
- const a = H.get(t);
276
+ function p(t) {
277
+ const a = B.get(t);
278
278
  if (a !== void 0) return a;
279
279
  let e;
280
- return t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none") ? e = !0 : t.parentElement ? e = m(t.parentElement) : e = !1, H.set(t, e), e;
280
+ return t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none") ? e = !0 : t.parentElement ? e = p(t.parentElement) : e = !1, B.set(t, e), e;
281
281
  }
282
- function me(t) {
282
+ function Se(t) {
283
283
  return !!(t.getAttribute("aria-hidden") === "true" || t instanceof HTMLElement && (t.hidden || t.style.display === "none"));
284
284
  }
285
285
  function y(t) {
286
- var e, i, n, r;
286
+ var e, i, n, r, o;
287
287
  let a = "";
288
- for (const o of t.childNodes)
289
- if (o.nodeType === 3)
290
- a += o.textContent ?? "";
291
- else if (o.nodeType === 1) {
292
- const s = o;
293
- if (!me(s)) {
294
- const u = (e = s.tagName) == null ? void 0 : e.toLowerCase();
295
- if (u === "img" || u === "area")
296
- a += ((i = s.getAttribute("aria-label")) == null ? void 0 : i.trim()) ?? s.getAttribute("alt") ?? "";
297
- else if (u === "svg") {
298
- const h = (n = s.getAttribute("aria-label")) == null ? void 0 : n.trim();
299
- if (h)
300
- a += h;
288
+ for (const s of t.childNodes)
289
+ if (s.nodeType === 3)
290
+ a += s.textContent ?? "";
291
+ else if (s.nodeType === 1) {
292
+ const c = s;
293
+ if (!Se(c)) {
294
+ const h = (e = c.tagName) == null ? void 0 : e.toLowerCase();
295
+ if (h === "img" || h === "area") {
296
+ const l = c.getAttribute("aria-labelledby");
297
+ if (l) {
298
+ const m = l.split(/\s+/).map((g) => {
299
+ var b, f;
300
+ return ((f = (b = c.ownerDocument.getElementById(g)) == null ? void 0 : b.textContent) == null ? void 0 : f.trim()) ?? "";
301
+ }).filter(Boolean);
302
+ if (m.length) {
303
+ a += m.join(" ");
304
+ continue;
305
+ }
306
+ }
307
+ a += ((i = c.getAttribute("aria-label")) == null ? void 0 : i.trim()) ?? c.getAttribute("alt") ?? ((n = c.getAttribute("title")) == null ? void 0 : n.trim()) ?? "";
308
+ } else if (h === "svg") {
309
+ const l = (r = c.getAttribute("aria-label")) == null ? void 0 : r.trim();
310
+ if (l)
311
+ a += l;
301
312
  else {
302
- const d = s.querySelector("title");
303
- d && (a += d.textContent ?? "");
313
+ const m = c.querySelector("title");
314
+ m && (a += m.textContent ?? "");
304
315
  }
305
- } else (r = s.getAttribute("aria-label")) != null && r.trim() ? a += s.getAttribute("aria-label").trim() : a += y(s);
316
+ } else (o = c.getAttribute("aria-label")) != null && o.trim() ? a += c.getAttribute("aria-label").trim() : a += y(c);
306
317
  }
307
318
  }
308
319
  return a;
309
320
  }
310
- let D = /* @__PURE__ */ new WeakMap();
311
- function pe() {
312
- D = /* @__PURE__ */ new WeakMap();
321
+ let W = /* @__PURE__ */ new WeakMap();
322
+ function xe() {
323
+ W = /* @__PURE__ */ new WeakMap();
313
324
  }
314
- function he(t) {
325
+ function ke(t) {
315
326
  return t.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
316
327
  }
317
- const ge = [
328
+ const Ie = [
318
329
  "data-testid",
319
330
  "data-test-id",
320
331
  "data-cy",
@@ -324,12 +335,12 @@ const ge = [
324
335
  "for",
325
336
  "aria-label"
326
337
  ];
327
- function be(t) {
338
+ function Ee(t) {
328
339
  const a = t.tagName.toLowerCase();
329
- for (const i of ge) {
340
+ for (const i of Ie) {
330
341
  const n = t.getAttribute(i);
331
342
  if (n != null && n.length > 0 && n.length < 100)
332
- return `${a}[${i}="${he(n)}"]`;
343
+ return `${a}[${i}="${ke(n)}"]`;
333
344
  }
334
345
  const e = t.parentElement;
335
346
  if (e) {
@@ -341,7 +352,7 @@ function be(t) {
341
352
  }
342
353
  return a;
343
354
  }
344
- function R(t) {
355
+ function M(t) {
345
356
  if (t.id) return `#${CSS.escape(t.id)}`;
346
357
  const a = t.getRootNode(), e = a instanceof ShadowRoot ? null : a.documentElement, i = [];
347
358
  let n = t;
@@ -350,7 +361,7 @@ function R(t) {
350
361
  i.unshift(`#${CSS.escape(n.id)}`);
351
362
  break;
352
363
  }
353
- if (i.unshift(be(n)), i.length >= 2) {
364
+ if (i.unshift(Ee(n)), i.length >= 2) {
354
365
  const r = i.join(" > ");
355
366
  try {
356
367
  const o = a.querySelectorAll(r);
@@ -362,30 +373,30 @@ function R(t) {
362
373
  }
363
374
  return i.join(" > ");
364
375
  }
365
- function c(t) {
376
+ function d(t) {
366
377
  var r;
367
- const a = D.get(t);
378
+ const a = W.get(t);
368
379
  if (a !== void 0) return a;
369
380
  const e = [];
370
381
  let i = t;
371
382
  for (; i; ) {
372
383
  const o = i.getRootNode();
373
384
  if (o instanceof ShadowRoot)
374
- e.unshift({ selector: R(i), delimiter: " >>> " }), i = o.host;
385
+ e.unshift({ selector: M(i), delimiter: " >>> " }), i = o.host;
375
386
  else {
376
387
  const s = (r = o.defaultView) == null ? void 0 : r.frameElement;
377
388
  if (s)
378
- e.unshift({ selector: R(i), delimiter: " >>>iframe> " }), i = s;
389
+ e.unshift({ selector: M(i), delimiter: " >>>iframe> " }), i = s;
379
390
  else {
380
- e.unshift({ selector: R(i), delimiter: "" });
391
+ e.unshift({ selector: M(i), delimiter: "" });
381
392
  break;
382
393
  }
383
394
  }
384
395
  }
385
396
  const n = e.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
386
- return D.set(t, n), n;
397
+ return W.set(t, n), n;
387
398
  }
388
- function ja(t) {
399
+ function bi(t) {
389
400
  const a = [], e = [];
390
401
  let i = t;
391
402
  for (; i; ) {
@@ -418,11 +429,11 @@ function ja(t) {
418
429
  }
419
430
  return null;
420
431
  }
421
- function l(t) {
432
+ function u(t) {
422
433
  const a = t.outerHTML;
423
434
  return a.length > 200 ? a.slice(0, 200) + "..." : a;
424
435
  }
425
- const fe = /* @__PURE__ */ new Set([
436
+ const Te = /* @__PURE__ */ new Set([
426
437
  "aria-activedescendant",
427
438
  "aria-atomic",
428
439
  "aria-autocomplete",
@@ -476,7 +487,7 @@ const fe = /* @__PURE__ */ new Set([
476
487
  "aria-valuemin",
477
488
  "aria-valuenow",
478
489
  "aria-valuetext"
479
- ]), ve = /* @__PURE__ */ new Set([
490
+ ]), U = /* @__PURE__ */ new Set([
480
491
  "aria-atomic",
481
492
  "aria-busy",
482
493
  "aria-disabled",
@@ -487,7 +498,7 @@ const fe = /* @__PURE__ */ new Set([
487
498
  "aria-multiselectable",
488
499
  "aria-readonly",
489
500
  "aria-required"
490
- ]), we = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), ye = /* @__PURE__ */ new Set([
501
+ ]), G = /* @__PURE__ */ new Set(["aria-checked", "aria-pressed"]), Le = /* @__PURE__ */ new Set([
491
502
  "aria-colcount",
492
503
  "aria-colindex",
493
504
  "aria-colspan",
@@ -497,12 +508,13 @@ const fe = /* @__PURE__ */ new Set([
497
508
  "aria-rowindex",
498
509
  "aria-rowspan",
499
510
  "aria-setsize"
500
- ]), Ae = /* @__PURE__ */ new Set([
511
+ ]), Ce = /* @__PURE__ */ new Set([
501
512
  "aria-valuemax",
502
513
  "aria-valuemin",
503
514
  "aria-valuenow"
504
- ]), V = {
515
+ ]), X = {
505
516
  "aria-autocomplete": /* @__PURE__ */ new Set(["inline", "list", "both", "none"]),
517
+ "aria-expanded": /* @__PURE__ */ new Set(["true", "false", "undefined"]),
506
518
  "aria-current": /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"]),
507
519
  "aria-dropeffect": /* @__PURE__ */ new Set(["copy", "execute", "link", "move", "none", "popup"]),
508
520
  "aria-haspopup": /* @__PURE__ */ new Set(["true", "false", "menu", "listbox", "tree", "grid", "dialog"]),
@@ -511,7 +523,7 @@ const fe = /* @__PURE__ */ new Set([
511
523
  "aria-orientation": /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]),
512
524
  "aria-relevant": /* @__PURE__ */ new Set(["additions", "all", "removals", "text"]),
513
525
  "aria-sort": /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"])
514
- }, U = /* @__PURE__ */ new Set([
526
+ }, Y = /* @__PURE__ */ new Set([
515
527
  "caption",
516
528
  "code",
517
529
  "deletion",
@@ -528,7 +540,7 @@ const fe = /* @__PURE__ */ new Set([
528
540
  "suggestion",
529
541
  "term",
530
542
  "time"
531
- ]), Se = {
543
+ ]), qe = {
532
544
  abbr: !0,
533
545
  bdi: !0,
534
546
  bdo: !0,
@@ -556,7 +568,7 @@ const fe = /* @__PURE__ */ new Set([
556
568
  u: !0,
557
569
  var: !0,
558
570
  wbr: !0
559
- }, xe = {
571
+ }, Re = {
560
572
  alert: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
561
573
  article: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
562
574
  banner: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
@@ -589,183 +601,185 @@ const fe = /* @__PURE__ */ new Set([
589
601
  time: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"]),
590
602
  tooltip: /* @__PURE__ */ new Set(["aria-disabled", "aria-errormessage", "aria-haspopup", "aria-invalid"])
591
603
  };
592
- let q = null, C = null;
593
- function ke() {
594
- q = null, C = null;
604
+ let E = null, T = null;
605
+ function Ne() {
606
+ E = null, T = null;
595
607
  }
596
- function _(t) {
608
+ function V(t) {
597
609
  var n;
598
- if (C && (q == null ? void 0 : q.deref()) === t) return C;
610
+ if (T && (E == null ? void 0 : E.deref()) === t) return T;
599
611
  const a = [], e = [], i = [];
600
612
  for (const r of t.querySelectorAll("*")) {
601
613
  let o = !1;
602
- for (const d of r.attributes)
603
- if (d.name.startsWith("aria-")) {
614
+ for (const l of r.attributes)
615
+ if (l.name.startsWith("aria-")) {
604
616
  o = !0;
605
617
  break;
606
618
  }
607
619
  if (!o) continue;
608
- let s, u;
609
- const h = () => (s === void 0 && (s = c(r), u = l(r)), { selector: s, html: u });
610
- for (const d of r.attributes)
611
- if (d.name.startsWith("aria-") && !fe.has(d.name)) {
612
- const p = h();
620
+ let s, c;
621
+ const h = () => (s === void 0 && (s = d(r), c = u(r)), { selector: s, html: c });
622
+ for (const l of r.attributes)
623
+ if (l.name.startsWith("aria-") && !Te.has(l.name)) {
624
+ const m = h();
613
625
  a.push({
614
626
  ruleId: "aria-valid-attr",
615
- selector: p.selector,
616
- html: p.html,
627
+ selector: m.selector,
628
+ html: m.html,
617
629
  impact: "critical",
618
- message: `Invalid ARIA attribute "${d.name}".`
630
+ message: `Invalid ARIA attribute "${l.name}".`
619
631
  });
620
632
  break;
621
633
  }
622
- for (const d of r.attributes) {
623
- if (!d.name.startsWith("aria-")) continue;
624
- const p = d.value.trim();
625
- if (ve.has(d.name)) {
626
- if (p !== "true" && p !== "false") {
627
- const g = h();
628
- e.push({
629
- ruleId: "aria-valid-attr-value",
630
- selector: g.selector,
631
- html: g.html,
632
- impact: "critical",
633
- message: `${d.name} must be "true" or "false", got "${p}".`
634
- });
635
- }
636
- } else if (we.has(d.name)) {
637
- if (p !== "true" && p !== "false" && p !== "mixed") {
638
- const g = h();
639
- e.push({
640
- ruleId: "aria-valid-attr-value",
641
- selector: g.selector,
642
- html: g.html,
643
- impact: "critical",
644
- message: `${d.name} must be "true", "false", or "mixed", got "${p}".`
645
- });
646
- }
647
- } else if (ye.has(d.name)) {
648
- if (p === "" || !/^-?\d+$/.test(p)) {
649
- const g = h();
650
- e.push({
651
- ruleId: "aria-valid-attr-value",
652
- selector: g.selector,
653
- html: g.html,
654
- impact: "critical",
655
- message: `${d.name} must be an integer, got "${p}".`
656
- });
657
- }
658
- } else if (Ae.has(d.name)) {
659
- if (p === "" || isNaN(Number(p))) {
660
- const g = h();
661
- e.push({
662
- ruleId: "aria-valid-attr-value",
663
- selector: g.selector,
664
- html: g.html,
665
- impact: "critical",
666
- message: `${d.name} must be a number, got "${p}".`
667
- });
668
- }
669
- } else if (V[d.name]) {
670
- const g = p.split(/\s+/);
671
- for (const f of g)
672
- if (!V[d.name].has(f)) {
673
- const v = h();
634
+ for (const l of r.attributes) {
635
+ if (!l.name.startsWith("aria-")) continue;
636
+ const m = l.value.trim();
637
+ if (!(m === "" && !U.has(l.name) && !G.has(l.name))) {
638
+ if (U.has(l.name)) {
639
+ if (m !== "true" && m !== "false") {
640
+ const g = h();
674
641
  e.push({
675
642
  ruleId: "aria-valid-attr-value",
676
- selector: v.selector,
677
- html: v.html,
643
+ selector: g.selector,
644
+ html: g.html,
678
645
  impact: "critical",
679
- message: `Invalid value "${p}" for ${d.name}.`
646
+ message: `${l.name} must be "true" or "false", got "${m}".`
647
+ });
648
+ }
649
+ } else if (G.has(l.name)) {
650
+ if (m !== "true" && m !== "false" && m !== "mixed") {
651
+ const g = h();
652
+ e.push({
653
+ ruleId: "aria-valid-attr-value",
654
+ selector: g.selector,
655
+ html: g.html,
656
+ impact: "critical",
657
+ message: `${l.name} must be "true", "false", or "mixed", got "${m}".`
680
658
  });
681
- break;
682
659
  }
660
+ } else if (Le.has(l.name)) {
661
+ if (m === "" || !/^-?\d+$/.test(m)) {
662
+ const g = h();
663
+ e.push({
664
+ ruleId: "aria-valid-attr-value",
665
+ selector: g.selector,
666
+ html: g.html,
667
+ impact: "critical",
668
+ message: `${l.name} must be an integer, got "${m}".`
669
+ });
670
+ }
671
+ } else if (Ce.has(l.name)) {
672
+ if (m === "" || isNaN(Number(m))) {
673
+ const g = h();
674
+ e.push({
675
+ ruleId: "aria-valid-attr-value",
676
+ selector: g.selector,
677
+ html: g.html,
678
+ impact: "critical",
679
+ message: `${l.name} must be a number, got "${m}".`
680
+ });
681
+ }
682
+ } else if (X[l.name]) {
683
+ const g = m.split(/\s+/);
684
+ for (const b of g)
685
+ if (!X[l.name].has(b)) {
686
+ const f = h();
687
+ e.push({
688
+ ruleId: "aria-valid-attr-value",
689
+ selector: f.selector,
690
+ html: f.html,
691
+ impact: "critical",
692
+ message: `Invalid value "${m}" for ${l.name}.`
693
+ });
694
+ break;
695
+ }
696
+ }
683
697
  }
684
698
  }
685
- if (!m(r)) {
686
- const d = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase(), p = r.tagName.toLowerCase();
687
- if (!d && Se[p]) {
688
- const g = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
689
- if (g || f) {
690
- const v = h();
699
+ if (!p(r)) {
700
+ const l = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase(), m = r.tagName.toLowerCase();
701
+ if (!l && qe[m]) {
702
+ const g = r.hasAttribute("aria-label"), b = r.hasAttribute("aria-labelledby");
703
+ if (g || b) {
704
+ const f = h();
691
705
  i.push({
692
706
  ruleId: "aria-prohibited-attr",
693
- selector: v.selector,
694
- html: v.html,
707
+ selector: f.selector,
708
+ html: f.html,
695
709
  impact: "serious",
696
- message: `aria-label and aria-labelledby are prohibited on <${p}> elements.`
710
+ message: `aria-label and aria-labelledby are prohibited on <${m}> elements.`
697
711
  });
698
712
  }
699
- } else if (d) {
700
- if (U.has(d)) {
701
- const f = r.hasAttribute("aria-label"), v = r.hasAttribute("aria-labelledby");
702
- if (f || v) {
713
+ } else if (l) {
714
+ if (Y.has(l)) {
715
+ const b = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
716
+ if (b || f) {
703
717
  const w = h();
704
718
  i.push({
705
719
  ruleId: "aria-prohibited-attr",
706
720
  selector: w.selector,
707
721
  html: w.html,
708
722
  impact: "serious",
709
- message: `aria-label and aria-labelledby are prohibited on role "${d}".`
723
+ message: `aria-label and aria-labelledby are prohibited on role "${l}".`
710
724
  });
711
725
  }
712
726
  }
713
- const g = xe[d];
727
+ const g = Re[l];
714
728
  if (g) {
715
- for (const f of r.attributes)
716
- if (f.name.startsWith("aria-") && g.has(f.name)) {
717
- if ((f.name === "aria-label" || f.name === "aria-labelledby") && U.has(d))
729
+ for (const b of r.attributes)
730
+ if (b.name.startsWith("aria-") && g.has(b.name)) {
731
+ if ((b.name === "aria-label" || b.name === "aria-labelledby") && Y.has(l))
718
732
  continue;
719
- const v = h();
733
+ const f = h();
720
734
  i.push({
721
735
  ruleId: "aria-prohibited-attr",
722
- selector: v.selector,
723
- html: v.html,
736
+ selector: f.selector,
737
+ html: f.html,
724
738
  impact: "serious",
725
- message: `Attribute "${f.name}" is prohibited on role "${d}".`
739
+ message: `Attribute "${b.name}" is prohibited on role "${l}".`
726
740
  });
727
741
  }
728
742
  }
729
743
  }
730
744
  }
731
745
  }
732
- return q = new WeakRef(t), C = { validAttr: a, validAttrValue: e, prohibitedAttr: i }, C;
746
+ return E = new WeakRef(t), T = { validAttr: a, validAttrValue: e, prohibitedAttr: i }, T;
733
747
  }
734
- let O = /* @__PURE__ */ new WeakMap(), W = /* @__PURE__ */ new WeakMap(), B = /* @__PURE__ */ new WeakMap();
735
- function Ie() {
736
- O = /* @__PURE__ */ new WeakMap(), W = /* @__PURE__ */ new WeakMap(), B = /* @__PURE__ */ new WeakMap();
748
+ let _ = /* @__PURE__ */ new WeakMap(), F = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap();
749
+ function Me() {
750
+ _ = /* @__PURE__ */ new WeakMap(), F = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakMap();
737
751
  }
738
- function x(t) {
739
- let a = O.get(t);
740
- return a || (a = getComputedStyle(t), O.set(t, a), a);
752
+ function A(t) {
753
+ let a = _.get(t);
754
+ return a || (a = getComputedStyle(t), _.set(t, a), a);
741
755
  }
742
- function j(t, a, e) {
756
+ function q(t, a, e) {
743
757
  const [i, n, r] = [t, a, e].map((o) => {
744
758
  const s = o / 255;
745
759
  return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
746
760
  });
747
761
  return 0.2126 * i + 0.7152 * n + 0.0722 * r;
748
762
  }
749
- function qe(t, a) {
763
+ function ce(t, a) {
750
764
  const e = Math.max(t, a), i = Math.min(t, a);
751
765
  return (e + 0.05) / (i + 0.05);
752
766
  }
753
- function Z(t) {
767
+ function R(t) {
754
768
  const a = t.match(
755
769
  /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*[\d.]+)?\s*\)/
756
770
  );
757
771
  return a ? [parseInt(a[1]), parseInt(a[2]), parseInt(a[3])] : null;
758
772
  }
759
- function Ce(t) {
760
- const a = W.get(t);
773
+ function $e(t) {
774
+ const a = F.get(t);
761
775
  if (a !== void 0) return a;
762
- const e = Te(t);
763
- return W.set(t, e), e;
776
+ const e = He(t);
777
+ return F.set(t, e), e;
764
778
  }
765
- function Te(t) {
779
+ function He(t) {
766
780
  let a = t;
767
781
  for (; a; ) {
768
- const e = x(a), i = e.backgroundImage;
782
+ const e = A(a), i = e.backgroundImage;
769
783
  if (i && i !== "none" && i !== "initial") return null;
770
784
  const n = e.backgroundColor;
771
785
  if (n === "transparent" || n === "rgba(0, 0, 0, 0)") {
@@ -777,26 +791,26 @@ function Te(t) {
777
791
  a = a.parentElement;
778
792
  continue;
779
793
  }
780
- return Z(n);
794
+ return R(n);
781
795
  }
782
796
  return [255, 255, 255];
783
797
  }
784
- const Ee = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
785
- function Le(t) {
786
- const a = B.get(t);
798
+ const De = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
799
+ function Oe(t) {
800
+ const a = j.get(t);
787
801
  if (a !== void 0) return a;
788
- const e = Re(t);
789
- return B.set(t, e), e;
802
+ const e = Be(t);
803
+ return j.set(t, e), e;
790
804
  }
791
- function Re(t) {
805
+ function Be(t) {
792
806
  let a = t, e = !1;
793
807
  for (; a; ) {
794
- const i = x(a).position;
808
+ const i = A(a).position;
795
809
  if ((i === "absolute" || i === "fixed") && (e = !0), a !== t && i !== "static") {
796
810
  for (const n of a.children)
797
- if (!(n === t || n.contains(t)) && Ee.has(n.tagName)) {
811
+ if (!(n === t || n.contains(t)) && De.has(n.tagName)) {
798
812
  if (e) return !0;
799
- const r = x(n).position;
813
+ const r = A(n).position;
800
814
  if (r === "absolute" || r === "fixed") return !0;
801
815
  }
802
816
  if (e) break;
@@ -805,11 +819,11 @@ function Re(t) {
805
819
  }
806
820
  return !1;
807
821
  }
808
- function Ne(t) {
809
- const a = x(t), e = parseFloat(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
822
+ function We(t) {
823
+ const a = A(t), e = parseFloat(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
810
824
  return e >= 24 || e >= 18.66 && i >= 700;
811
825
  }
812
- function Me(t) {
826
+ function $(t) {
813
827
  var r, o;
814
828
  const a = [], e = t.closest("a");
815
829
  if (e) {
@@ -823,13 +837,21 @@ function Me(t) {
823
837
  }
824
838
  const n = t.parentElement;
825
839
  if (n && n !== e) {
826
- const s = (o = n.textContent) == null ? void 0 : o.replace(t.alt || "", "").trim().slice(0, 100);
827
- s && a.push(`Adjacent text: ${s}`);
840
+ const s = t instanceof HTMLImageElement && t.alt || "", c = (o = n.textContent) == null ? void 0 : o.replace(s, "").trim().slice(0, 100);
841
+ c && a.push(`Adjacent text: ${c}`);
828
842
  }
829
843
  return a.length > 0 ? a.join(`
830
844
  `) : void 0;
831
845
  }
832
- const $e = {
846
+ function K(t) {
847
+ let a = t;
848
+ for (; a; ) {
849
+ if (a instanceof HTMLElement && a.style.visibility === "hidden") return !0;
850
+ a = a.parentElement;
851
+ }
852
+ return !1;
853
+ }
854
+ const _e = {
833
855
  id: "img-alt",
834
856
  wcag: ["1.1.1"],
835
857
  level: "A",
@@ -838,18 +860,64 @@ const $e = {
838
860
  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.",
839
861
  run(t) {
840
862
  const a = [];
841
- for (const e of t.querySelectorAll("img"))
842
- m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none" || !e.hasAttribute("alt") && !b(e) && a.push({
863
+ for (const e of t.querySelectorAll("img")) {
864
+ if (p(e) || K(e)) continue;
865
+ const i = e.getAttribute("role");
866
+ if (i === "presentation" || i === "none") {
867
+ const r = e.getAttribute("tabindex");
868
+ if (!r || r === "-1") continue;
869
+ }
870
+ const n = e.getAttribute("alt");
871
+ if (n !== null && n.trim() === "" && n !== "") {
872
+ a.push({
873
+ ruleId: "img-alt",
874
+ selector: d(e),
875
+ html: u(e),
876
+ impact: "critical",
877
+ message: 'Image has whitespace-only alt text. Use alt="" for decorative images or provide descriptive text.',
878
+ context: $(e)
879
+ });
880
+ continue;
881
+ }
882
+ !e.hasAttribute("alt") && !v(e) && a.push({
843
883
  ruleId: "img-alt",
844
- selector: c(e),
845
- html: l(e),
884
+ selector: d(e),
885
+ html: u(e),
846
886
  impact: "critical",
847
887
  message: "Image element missing alt attribute.",
848
- context: Me(e)
888
+ context: $(e)
889
+ });
890
+ }
891
+ for (const e of t.querySelectorAll('[role="img"]:not(img):not(svg)'))
892
+ p(e) || K(e) || v(e) || a.push({
893
+ ruleId: "img-alt",
894
+ selector: d(e),
895
+ html: u(e),
896
+ impact: "critical",
897
+ message: 'Element with role="img" has no accessible name. Add aria-label or aria-labelledby.',
898
+ context: $(e)
849
899
  });
850
900
  return a;
851
901
  }
852
- }, He = {
902
+ };
903
+ function Fe(t) {
904
+ var r, o, s;
905
+ const a = t.getAttribute("aria-labelledby");
906
+ if (a) {
907
+ const c = a.split(/\s+/).map((h) => {
908
+ var l, m;
909
+ return ((m = (l = t.ownerDocument.getElementById(h)) == null ? void 0 : l.textContent) == null ? void 0 : m.trim()) ?? "";
910
+ }).filter(Boolean);
911
+ if (c.length) return c.join(" ");
912
+ }
913
+ const e = (r = t.getAttribute("aria-label")) == null ? void 0 : r.trim();
914
+ if (e) return e;
915
+ const i = t.querySelector("title");
916
+ if ((o = i == null ? void 0 : i.textContent) != null && o.trim()) return i.textContent.trim();
917
+ const n = (s = t.getAttribute("title")) == null ? void 0 : s.trim();
918
+ return n || "";
919
+ }
920
+ const je = {
853
921
  id: "svg-img-alt",
854
922
  wcag: ["1.1.1"],
855
923
  level: "A",
@@ -857,20 +925,23 @@ const $e = {
857
925
  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.",
858
926
  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'.",
859
927
  run(t) {
860
- const a = [];
861
- for (const e of t.querySelectorAll('svg[role="img"]')) {
862
- if (m(e)) continue;
863
- b(e) || a.push({
864
- ruleId: "svg-img-alt",
865
- selector: c(e),
866
- html: l(e),
867
- impact: "serious",
868
- message: "SVG with role='img' has no accessible name."
869
- });
928
+ const a = [], e = 'svg[role="img"], [role="graphics-document"], [role="graphics-symbol"]';
929
+ for (const i of t.querySelectorAll(e)) {
930
+ if (p(i)) continue;
931
+ if (!Fe(i)) {
932
+ const r = i.getAttribute("role");
933
+ a.push({
934
+ ruleId: "svg-img-alt",
935
+ selector: d(i),
936
+ html: u(i),
937
+ impact: "serious",
938
+ message: `${i.tagName.toLowerCase()} with role='${r}' has no accessible name.`
939
+ });
940
+ }
870
941
  }
871
942
  return a;
872
943
  }
873
- }, De = {
944
+ }, Pe = {
874
945
  id: "input-image-alt",
875
946
  wcag: ["1.1.1", "4.1.2"],
876
947
  level: "A",
@@ -880,16 +951,16 @@ const $e = {
880
951
  run(t) {
881
952
  const a = [];
882
953
  for (const e of t.querySelectorAll('input[type="image"]'))
883
- m(e) || b(e) || a.push({
954
+ p(e) || v(e) || a.push({
884
955
  ruleId: "input-image-alt",
885
- selector: c(e),
886
- html: l(e),
956
+ selector: d(e),
957
+ html: u(e),
887
958
  impact: "critical",
888
959
  message: "Image input missing alt text."
889
960
  });
890
961
  return a;
891
962
  }
892
- }, Oe = {
963
+ }, Ve = {
893
964
  id: "image-redundant-alt",
894
965
  wcag: [],
895
966
  level: "A",
@@ -908,8 +979,8 @@ const $e = {
908
979
  const o = ((e = r.textContent) == null ? void 0 : e.trim().toLowerCase()) || "";
909
980
  o && o === n && a.push({
910
981
  ruleId: "image-redundant-alt",
911
- selector: c(i),
912
- html: l(i),
982
+ selector: d(i),
983
+ html: u(i),
913
984
  impact: "minor",
914
985
  message: `Alt text "${i.getAttribute("alt")}" duplicates surrounding ${r.tagName.toLowerCase()} text.`
915
986
  });
@@ -917,7 +988,7 @@ const $e = {
917
988
  }
918
989
  return a;
919
990
  }
920
- }, We = ["image", "picture", "photo", "graphic", "icon", "img"], Be = {
991
+ }, ze = ["image", "picture", "photo", "graphic", "icon", "img"], Ue = {
921
992
  id: "image-alt-redundant-words",
922
993
  wcag: [],
923
994
  level: "A",
@@ -929,17 +1000,17 @@ const $e = {
929
1000
  const a = [];
930
1001
  for (const e of t.querySelectorAll("img[alt]")) {
931
1002
  const i = e.getAttribute("alt").toLowerCase();
932
- i && We.some((n) => i.split(/\s+/).includes(n)) && a.push({
1003
+ i && ze.some((n) => i.split(/\s+/).includes(n)) && a.push({
933
1004
  ruleId: "image-alt-redundant-words",
934
- selector: c(e),
935
- html: l(e),
1005
+ selector: d(e),
1006
+ html: u(e),
936
1007
  impact: "minor",
937
1008
  message: `Alt text "${e.getAttribute("alt")}" contains redundant word(s).`
938
1009
  });
939
1010
  }
940
1011
  return a;
941
1012
  }
942
- }, Fe = {
1013
+ }, Ge = {
943
1014
  id: "area-alt",
944
1015
  wcag: ["1.1.1", "4.1.2"],
945
1016
  level: "A",
@@ -949,37 +1020,70 @@ const $e = {
949
1020
  run(t) {
950
1021
  const a = [];
951
1022
  for (const e of t.querySelectorAll("area[href]")) {
952
- if (m(e)) continue;
953
- b(e) || a.push({
1023
+ if (p(e)) continue;
1024
+ v(e) || a.push({
954
1025
  ruleId: "area-alt",
955
- selector: c(e),
956
- html: l(e),
1026
+ selector: d(e),
1027
+ html: u(e),
957
1028
  impact: "critical",
958
1029
  message: "Image map <area> element is missing alternative text."
959
1030
  });
960
1031
  }
961
1032
  return a;
962
1033
  }
963
- }, _e = {
1034
+ };
1035
+ function Xe(t) {
1036
+ var n, r;
1037
+ const a = t.getAttribute("aria-labelledby");
1038
+ if (a) {
1039
+ const o = a.split(/\s+/).map((s) => {
1040
+ var c, h;
1041
+ return ((h = (c = t.ownerDocument.getElementById(s)) == null ? void 0 : c.textContent) == null ? void 0 : h.trim()) ?? "";
1042
+ }).filter(Boolean);
1043
+ if (o.length) return o.join(" ");
1044
+ }
1045
+ const e = (n = t.getAttribute("aria-label")) == null ? void 0 : n.trim();
1046
+ if (e) return e;
1047
+ const i = (r = t.getAttribute("title")) == null ? void 0 : r.trim();
1048
+ return i || "";
1049
+ }
1050
+ const Ye = {
964
1051
  id: "object-alt",
965
1052
  wcag: ["1.1.1"],
966
1053
  level: "A",
967
1054
  description: "<object> elements must have alternative text.",
968
- guidance: "Object elements embed external content that may not be accessible to all users. Provide alternative text via aria-label, aria-labelledby, or fallback content inside the <object> element. The fallback content displays when the object cannot be rendered and should convey the same information.",
969
- prompt: "Based on the data/type attributes, suggest adding aria-label or fallback text content inside the <object> tag describing what the embedded content represents.",
1055
+ 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.",
1056
+ prompt: "Based on the data/type attributes, suggest adding aria-label or a title attribute describing what the embedded content represents.",
970
1057
  run(t) {
1058
+ var e;
971
1059
  const a = [];
972
- for (const e of t.querySelectorAll("object"))
973
- m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none" || b(e) || a.push({
1060
+ for (const i of t.querySelectorAll("object")) {
1061
+ if (p(i) || i instanceof HTMLElement && i.style.visibility === "hidden") continue;
1062
+ let n = i.parentElement, r = !1;
1063
+ for (; n; ) {
1064
+ if (n instanceof HTMLElement && n.style.visibility === "hidden") {
1065
+ r = !0;
1066
+ break;
1067
+ }
1068
+ n = n.parentElement;
1069
+ }
1070
+ if (r || i.getAttribute("role") === "presentation" || i.getAttribute("role") === "none" || Xe(i)) continue;
1071
+ const o = i.getAttribute("data") || "";
1072
+ if (!((i.getAttribute("type") || "").startsWith("image/") || /\.(png|jpg|jpeg|gif|svg|webp|bmp|ico)$/i.test(o))) {
1073
+ const h = i.querySelector("img[alt]");
1074
+ if (h && ((e = h.getAttribute("alt")) != null && e.trim())) continue;
1075
+ }
1076
+ a.push({
974
1077
  ruleId: "object-alt",
975
- selector: c(e),
976
- html: l(e),
1078
+ selector: d(i),
1079
+ html: u(i),
977
1080
  impact: "serious",
978
- message: "<object> element is missing alternative text. Add aria-label, aria-labelledby, or fallback content."
1081
+ message: "<object> element is missing alternative text. Add aria-label, aria-labelledby, or a title attribute."
979
1082
  });
1083
+ }
980
1084
  return a;
981
1085
  }
982
- }, Pe = {
1086
+ }, Ke = {
983
1087
  id: "role-img-alt",
984
1088
  wcag: ["1.1.1"],
985
1089
  level: "A",
@@ -989,11 +1093,11 @@ const $e = {
989
1093
  run(t) {
990
1094
  const a = [];
991
1095
  for (const e of t.querySelectorAll('[role="img"]')) {
992
- if (m(e) || e.tagName.toLowerCase() === "svg" || e.tagName.toLowerCase() === "img") continue;
993
- b(e) || a.push({
1096
+ if (p(e) || e.tagName.toLowerCase() === "svg" || e.tagName.toLowerCase() === "img") continue;
1097
+ v(e) || a.push({
994
1098
  ruleId: "role-img-alt",
995
- selector: c(e),
996
- html: l(e),
1099
+ selector: d(e),
1100
+ html: u(e),
997
1101
  impact: "serious",
998
1102
  message: "Element with role='img' has no accessible name. Add aria-label or aria-labelledby."
999
1103
  });
@@ -1001,7 +1105,7 @@ const $e = {
1001
1105
  return a;
1002
1106
  }
1003
1107
  };
1004
- function za(t) {
1108
+ function fi(t) {
1005
1109
  if (typeof t != "object" || t === null)
1006
1110
  return "Rule spec must be an object";
1007
1111
  const a = t;
@@ -1031,10 +1135,10 @@ function za(t) {
1031
1135
  return "Rule must have a wcag array";
1032
1136
  if (typeof a.level != "string" || !["A", "AA"].includes(a.level))
1033
1137
  return "Rule must have level A or AA";
1034
- const n = Ve(e);
1138
+ const n = Qe(e);
1035
1139
  return n || null;
1036
1140
  }
1037
- function Ve(t) {
1141
+ function Qe(t) {
1038
1142
  switch (t.type) {
1039
1143
  case "selector-exists":
1040
1144
  return null;
@@ -1052,7 +1156,7 @@ function Ve(t) {
1052
1156
  return `Unknown check type: ${String(t.type)}`;
1053
1157
  }
1054
1158
  }
1055
- function S(t, a, e) {
1159
+ function x(t, a, e) {
1056
1160
  let i = t;
1057
1161
  if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
1058
1162
  let n = "";
@@ -1075,12 +1179,12 @@ function k(t) {
1075
1179
  switch (t.check.type) {
1076
1180
  case "selector-exists": {
1077
1181
  for (const n of e.querySelectorAll(t.selector))
1078
- a && m(n) || i.push({
1182
+ a && p(n) || i.push({
1079
1183
  ruleId: t.id,
1080
- selector: c(n),
1081
- html: l(n),
1184
+ selector: d(n),
1185
+ html: u(n),
1082
1186
  impact: t.impact,
1083
- message: S(t.message, n, t.check),
1187
+ message: x(t.message, n, t.check),
1084
1188
  element: n
1085
1189
  });
1086
1190
  break;
@@ -1088,14 +1192,14 @@ function k(t) {
1088
1192
  case "attribute-value": {
1089
1193
  const { attribute: n, operator: r, value: o } = t.check;
1090
1194
  for (const s of e.querySelectorAll(t.selector)) {
1091
- if (a && m(s)) continue;
1092
- const u = s.getAttribute(n);
1093
- u !== null && Ue(u, r, o) && i.push({
1195
+ if (a && p(s)) continue;
1196
+ const c = s.getAttribute(n);
1197
+ c !== null && Je(c, r, o) && i.push({
1094
1198
  ruleId: t.id,
1095
- selector: c(s),
1096
- html: l(s),
1199
+ selector: d(s),
1200
+ html: u(s),
1097
1201
  impact: t.impact,
1098
- message: S(t.message, s, t.check),
1202
+ message: x(t.message, s, t.check),
1099
1203
  element: s
1100
1204
  });
1101
1205
  }
@@ -1104,42 +1208,42 @@ function k(t) {
1104
1208
  case "attribute-missing": {
1105
1209
  const { attribute: n } = t.check;
1106
1210
  for (const r of e.querySelectorAll(t.selector))
1107
- a && m(r) || r.hasAttribute(n) || i.push({
1211
+ a && p(r) || r.hasAttribute(n) || i.push({
1108
1212
  ruleId: t.id,
1109
- selector: c(r),
1110
- html: l(r),
1213
+ selector: d(r),
1214
+ html: u(r),
1111
1215
  impact: t.impact,
1112
- message: S(t.message, r, t.check),
1216
+ message: x(t.message, r, t.check),
1113
1217
  element: r
1114
1218
  });
1115
1219
  break;
1116
1220
  }
1117
1221
  case "attribute-regex": {
1118
1222
  const { attribute: n, pattern: r, flags: o, shouldMatch: s } = t.check;
1119
- let u;
1223
+ let c;
1120
1224
  try {
1121
- u = new RegExp(r, o);
1225
+ c = new RegExp(r, o);
1122
1226
  } catch {
1123
1227
  break;
1124
1228
  }
1125
1229
  for (const h of e.querySelectorAll(t.selector)) {
1126
- if (a && m(h)) continue;
1127
- const d = h.getAttribute(n);
1128
- if (d === null) continue;
1129
- const p = u.test(d);
1130
- s && !p ? i.push({
1230
+ if (a && p(h)) continue;
1231
+ const l = h.getAttribute(n);
1232
+ if (l === null) continue;
1233
+ const m = c.test(l);
1234
+ s && !m ? i.push({
1131
1235
  ruleId: t.id,
1132
- selector: c(h),
1133
- html: l(h),
1236
+ selector: d(h),
1237
+ html: u(h),
1134
1238
  impact: t.impact,
1135
- message: S(t.message, h, t.check),
1239
+ message: x(t.message, h, t.check),
1136
1240
  element: h
1137
- }) : !s && p && i.push({
1241
+ }) : !s && m && i.push({
1138
1242
  ruleId: t.id,
1139
- selector: c(h),
1140
- html: l(h),
1243
+ selector: d(h),
1244
+ html: u(h),
1141
1245
  impact: t.impact,
1142
- message: S(t.message, h, t.check),
1246
+ message: x(t.message, h, t.check),
1143
1247
  element: h
1144
1248
  });
1145
1249
  }
@@ -1148,12 +1252,12 @@ function k(t) {
1148
1252
  case "child-required": {
1149
1253
  const { childSelector: n } = t.check;
1150
1254
  for (const r of e.querySelectorAll(t.selector))
1151
- a && m(r) || r.querySelector(n) || i.push({
1255
+ a && p(r) || r.querySelector(n) || i.push({
1152
1256
  ruleId: t.id,
1153
- selector: c(r),
1154
- html: l(r),
1257
+ selector: d(r),
1258
+ html: u(r),
1155
1259
  impact: t.impact,
1156
- message: S(t.message, r, t.check),
1260
+ message: x(t.message, r, t.check),
1157
1261
  element: r
1158
1262
  });
1159
1263
  break;
@@ -1163,15 +1267,15 @@ function k(t) {
1163
1267
  t.check.allowedChildren.map((r) => r.toLowerCase())
1164
1268
  );
1165
1269
  for (const r of e.querySelectorAll(t.selector))
1166
- if (!(a && m(r))) {
1270
+ if (!(a && p(r))) {
1167
1271
  for (const o of r.children)
1168
1272
  if (!n.has(o.tagName.toLowerCase())) {
1169
1273
  i.push({
1170
1274
  ruleId: t.id,
1171
- selector: c(o),
1172
- html: l(o),
1275
+ selector: d(o),
1276
+ html: u(o),
1173
1277
  impact: t.impact,
1174
- message: S(t.message, o, t.check),
1278
+ message: x(t.message, o, t.check),
1175
1279
  element: o
1176
1280
  });
1177
1281
  break;
@@ -1184,7 +1288,7 @@ function k(t) {
1184
1288
  }
1185
1289
  };
1186
1290
  }
1187
- function Ue(t, a, e) {
1291
+ function Je(t, a, e) {
1188
1292
  switch (a) {
1189
1293
  case ">":
1190
1294
  return parseFloat(t) > e;
@@ -1202,7 +1306,7 @@ function Ue(t, a, e) {
1202
1306
  return !1;
1203
1307
  }
1204
1308
  }
1205
- const je = {
1309
+ const Ze = {
1206
1310
  id: "server-side-image-map",
1207
1311
  selector: "img[ismap], input[type='image'][ismap]",
1208
1312
  check: { type: "selector-exists" },
@@ -1213,7 +1317,70 @@ const je = {
1213
1317
  level: "A",
1214
1318
  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.",
1215
1319
  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."
1216
- }, ze = k(je), Ge = {
1320
+ }, et = k(Ze), tt = [
1321
+ '[role="checkbox"]',
1322
+ '[role="combobox"]',
1323
+ '[role="listbox"]',
1324
+ '[role="menuitemcheckbox"]',
1325
+ '[role="menuitemradio"]',
1326
+ '[role="radio"]',
1327
+ '[role="searchbox"]',
1328
+ '[role="slider"]',
1329
+ '[role="spinbutton"]',
1330
+ '[role="switch"]',
1331
+ '[role="textbox"]'
1332
+ ].join(", "), at = /* @__PURE__ */ new Set([
1333
+ "checkbox",
1334
+ "menuitemcheckbox",
1335
+ "menuitemradio",
1336
+ "radio",
1337
+ "switch"
1338
+ ]), it = /* @__PURE__ */ new Set([
1339
+ "combobox",
1340
+ "listbox",
1341
+ "searchbox",
1342
+ "slider",
1343
+ "spinbutton",
1344
+ "textbox"
1345
+ ]);
1346
+ function nt(t) {
1347
+ var o, s, c, h;
1348
+ const a = (o = t.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
1349
+ if (a && at.has(a) || (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) && !(a && it.has(a)))
1350
+ return v(t);
1351
+ const i = t.getAttribute("aria-labelledby");
1352
+ if (i) {
1353
+ const l = i.split(/\s+/).map((m) => {
1354
+ const g = t.ownerDocument.getElementById(m);
1355
+ return g ? y(g).trim() : "";
1356
+ }).filter(Boolean);
1357
+ if (l.length) return l.join(" ");
1358
+ }
1359
+ const n = (s = t.getAttribute("aria-label")) == null ? void 0 : s.trim();
1360
+ if (n) return n;
1361
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) {
1362
+ if (t.id) {
1363
+ const m = t.ownerDocument.querySelector(`label[for="${CSS.escape(t.id)}"]`);
1364
+ if (m) {
1365
+ const g = y(m).trim();
1366
+ if (g) return g;
1367
+ }
1368
+ }
1369
+ const l = t.closest("label");
1370
+ if (l) {
1371
+ const m = y(l).trim();
1372
+ if (m) return m;
1373
+ }
1374
+ }
1375
+ const r = (c = t.getAttribute("title")) == null ? void 0 : c.trim();
1376
+ if (r) return r;
1377
+ if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement) {
1378
+ const l = (h = t.getAttribute("placeholder")) == null ? void 0 : h.trim();
1379
+ if (l) return l;
1380
+ }
1381
+ return "";
1382
+ }
1383
+ const rt = {
1217
1384
  id: "label",
1218
1385
  wcag: ["4.1.2"],
1219
1386
  level: "A",
@@ -1221,22 +1388,23 @@ const je = {
1221
1388
  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.",
1222
1389
  prompt: "Based on the input type, name attribute, or placeholder, suggest a label element with appropriate text, or an aria-label.",
1223
1390
  run(t) {
1224
- const a = [], e = t.querySelectorAll(
1225
- 'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
1226
- );
1227
- for (const i of e) {
1228
- if (m(i)) continue;
1229
- b(i) || a.push({
1391
+ var n;
1392
+ const a = [], i = t.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select, ${tt}`);
1393
+ for (const r of i) {
1394
+ if (p(r) || r instanceof HTMLElement && (r.hidden || r.style.display === "none")) continue;
1395
+ const o = (n = r.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase();
1396
+ if (o === "presentation" || o === "none") continue;
1397
+ nt(r) || a.push({
1230
1398
  ruleId: "label",
1231
- selector: c(i),
1232
- html: l(i),
1399
+ selector: d(r),
1400
+ html: u(r),
1233
1401
  impact: "critical",
1234
1402
  message: "Form element has no accessible label."
1235
1403
  });
1236
1404
  }
1237
1405
  return a;
1238
1406
  }
1239
- }, Xe = {
1407
+ }, ot = {
1240
1408
  id: "form-field-multiple-labels",
1241
1409
  wcag: [],
1242
1410
  level: "A",
@@ -1247,7 +1415,7 @@ const je = {
1247
1415
  run(t) {
1248
1416
  const a = [], e = t.querySelectorAll('input:not([type="hidden"]), textarea, select');
1249
1417
  for (const i of e) {
1250
- if (m(i) || !i.id) continue;
1418
+ if (p(i) || !i.id) continue;
1251
1419
  const n = t.querySelectorAll(`label[for="${CSS.escape(i.id)}"]`);
1252
1420
  let r = 0, o = i.parentElement;
1253
1421
  for (; o; ) {
@@ -1260,15 +1428,15 @@ const je = {
1260
1428
  const s = n.length + r;
1261
1429
  s > 1 && a.push({
1262
1430
  ruleId: "form-field-multiple-labels",
1263
- selector: c(i),
1264
- html: l(i),
1431
+ selector: d(i),
1432
+ html: u(i),
1265
1433
  impact: "moderate",
1266
1434
  message: `Form field has ${s} labels. Use a single label element.`
1267
1435
  });
1268
1436
  }
1269
1437
  return a;
1270
1438
  }
1271
- }, Ke = {
1439
+ }, st = {
1272
1440
  id: "select-name",
1273
1441
  wcag: ["4.1.2"],
1274
1442
  level: "A",
@@ -1278,16 +1446,16 @@ const je = {
1278
1446
  run(t) {
1279
1447
  const a = [];
1280
1448
  for (const e of t.querySelectorAll("select"))
1281
- m(e) || b(e) || a.push({
1449
+ p(e) || v(e) || a.push({
1282
1450
  ruleId: "select-name",
1283
- selector: c(e),
1284
- html: l(e),
1451
+ selector: d(e),
1452
+ html: u(e),
1285
1453
  impact: "critical",
1286
1454
  message: "Select element has no accessible name."
1287
1455
  });
1288
1456
  return a;
1289
1457
  }
1290
- }, Ye = {
1458
+ }, lt = {
1291
1459
  id: "input-button-name",
1292
1460
  wcag: ["4.1.2"],
1293
1461
  level: "A",
@@ -1300,19 +1468,19 @@ const je = {
1300
1468
  for (const n of t.querySelectorAll(
1301
1469
  'input[type="submit"], input[type="button"], input[type="reset"]'
1302
1470
  )) {
1303
- if (m(n)) continue;
1471
+ if (p(n)) continue;
1304
1472
  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");
1305
- !r && !s && !b(n) && a.push({
1473
+ !r && !s && !v(n) && a.push({
1306
1474
  ruleId: "input-button-name",
1307
- selector: c(n),
1308
- html: l(n),
1475
+ selector: d(n),
1476
+ html: u(n),
1309
1477
  impact: "critical",
1310
1478
  message: "Input button has no discernible text."
1311
1479
  });
1312
1480
  }
1313
1481
  return a;
1314
1482
  }
1315
- }, Qe = /* @__PURE__ */ new Set([
1483
+ }, ct = /* @__PURE__ */ new Set([
1316
1484
  "off",
1317
1485
  "on",
1318
1486
  "name",
@@ -1367,7 +1535,27 @@ const je = {
1367
1535
  "impp",
1368
1536
  "url",
1369
1537
  "photo"
1370
- ]), Je = {
1538
+ ]), ut = /* @__PURE__ */ new Set([
1539
+ "tel",
1540
+ "tel-country-code",
1541
+ "tel-national",
1542
+ "tel-area-code",
1543
+ "tel-local",
1544
+ "tel-extension",
1545
+ "email",
1546
+ "impp"
1547
+ ]), dt = /* @__PURE__ */ new Set(["home", "work", "mobile", "fax", "pager"]), mt = /* @__PURE__ */ new Set(["shipping", "billing"]), ht = /* @__PURE__ */ new Set(["webauthn"]);
1548
+ function pt(t) {
1549
+ const a = t.toLowerCase().split(/\s+/).filter(Boolean);
1550
+ if (a.length === 0) return !0;
1551
+ let e = 0;
1552
+ a[e].startsWith("section-") && e++, e < a.length && mt.has(a[e]) && e++;
1553
+ let i = !1;
1554
+ if (e < a.length && dt.has(a[e]) && (i = !0, e++), e >= a.length) return !1;
1555
+ const n = a[e];
1556
+ return !ct.has(n) || i && !ut.has(n) ? !1 : (e++, e < a.length && ht.has(a[e]) && e++, e === a.length);
1557
+ }
1558
+ const gt = {
1371
1559
  id: "autocomplete-valid",
1372
1560
  wcag: ["1.3.5"],
1373
1561
  level: "AA",
@@ -1377,30 +1565,29 @@ const je = {
1377
1565
  run(t) {
1378
1566
  const a = [];
1379
1567
  for (const e of t.querySelectorAll("[autocomplete]")) {
1568
+ if (p(e) || e instanceof HTMLElement && e.style.display === "none" || e.disabled || e.getAttribute("aria-disabled") === "true") continue;
1380
1569
  const i = e.getAttribute("autocomplete").trim();
1381
- if (!i) continue;
1382
- const n = i.split(/\s+/), r = n[n.length - 1];
1383
- Qe.has(r) || a.push({
1570
+ i && (pt(i) || a.push({
1384
1571
  ruleId: "autocomplete-valid",
1385
- selector: c(e),
1386
- html: l(e),
1572
+ selector: d(e),
1573
+ html: u(e),
1387
1574
  impact: "serious",
1388
1575
  message: `Invalid autocomplete value "${i}".`
1389
- });
1576
+ }));
1390
1577
  }
1391
1578
  return a;
1392
1579
  }
1393
1580
  };
1394
- function z(t) {
1581
+ function Q(t) {
1395
1582
  return t.toLowerCase().replace(/\s+/g, " ").trim();
1396
1583
  }
1397
- function G(t, a) {
1398
- const e = z(t), i = z(a);
1584
+ function J(t, a) {
1585
+ const e = Q(t), i = Q(a);
1399
1586
  if (!e || !i || e.includes(i) || i.includes(e)) return !0;
1400
1587
  const n = i.split(/\s+/).map((r) => r.replace(/[.,;:!?\u2026]+$/g, "")).filter((r) => r.length > 2);
1401
1588
  return n.length >= 2 && n.filter((o) => e.includes(o)).length / n.length > 0.5;
1402
1589
  }
1403
- function F(t) {
1590
+ function P(t) {
1404
1591
  let a = "";
1405
1592
  for (const e of t.childNodes)
1406
1593
  if (e.nodeType === 3)
@@ -1410,11 +1597,11 @@ function F(t) {
1410
1597
  if (n === "style" || n === "script" || n === "svg" || i.getAttribute("aria-hidden") === "true" || i instanceof HTMLElement && i.style.display === "none") continue;
1411
1598
  const r = i.getAttribute("role");
1412
1599
  if (r === "img" || r === "presentation" || r === "none") continue;
1413
- a += F(i);
1600
+ a += P(i);
1414
1601
  }
1415
1602
  return a;
1416
1603
  }
1417
- const Ze = {
1604
+ const bt = {
1418
1605
  id: "label-content-name-mismatch",
1419
1606
  wcag: ["2.5.3"],
1420
1607
  level: "A",
@@ -1424,43 +1611,43 @@ const Ze = {
1424
1611
  run(t) {
1425
1612
  const a = [];
1426
1613
  for (const e of t.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
1427
- if (m(e)) continue;
1428
- const i = b(e);
1614
+ if (p(e)) continue;
1615
+ const i = v(e);
1429
1616
  if (!i) continue;
1430
1617
  let n = "";
1431
- e instanceof HTMLInputElement ? n = e.value || "" : n = F(e);
1618
+ e instanceof HTMLInputElement ? n = e.value || "" : n = P(e);
1432
1619
  const r = n.trim();
1433
1620
  if (!r || r.length <= 2) continue;
1434
1621
  const o = e.hasAttribute("aria-label"), s = e.hasAttribute("aria-labelledby");
1435
- !o && !s || G(i, n) || a.push({
1622
+ !o && !s || J(i, n) || a.push({
1436
1623
  ruleId: "label-content-name-mismatch",
1437
- selector: c(e),
1438
- html: l(e),
1624
+ selector: d(e),
1625
+ html: u(e),
1439
1626
  impact: "serious",
1440
1627
  message: `Accessible name "${i}" does not contain visible text "${n.trim()}".`
1441
1628
  });
1442
1629
  }
1443
1630
  for (const e of t.querySelectorAll("input, select, textarea")) {
1444
- if (m(e) || e instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(e.type)) continue;
1445
- const i = b(e);
1631
+ if (p(e) || e instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(e.type)) continue;
1632
+ const i = v(e);
1446
1633
  if (!i || !e.hasAttribute("aria-label")) continue;
1447
1634
  const r = e.id;
1448
1635
  let o = "";
1449
1636
  if (r) {
1450
1637
  const s = t.querySelector(`label[for="${CSS.escape(r)}"]`);
1451
- s && (o = F(s));
1638
+ s && (o = P(s));
1452
1639
  }
1453
- o.trim() && (G(i, o) || a.push({
1640
+ o.trim() && (J(i, o) || a.push({
1454
1641
  ruleId: "label-content-name-mismatch",
1455
- selector: c(e),
1456
- html: l(e),
1642
+ selector: d(e),
1643
+ html: u(e),
1457
1644
  impact: "serious",
1458
1645
  message: `Accessible name "${i}" does not contain visible label "${o.trim()}".`
1459
1646
  }));
1460
1647
  }
1461
1648
  return a;
1462
1649
  }
1463
- }, et = {
1650
+ }, ft = {
1464
1651
  id: "label-title-only",
1465
1652
  wcag: [],
1466
1653
  level: "A",
@@ -1474,26 +1661,26 @@ const Ze = {
1474
1661
  'input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]), textarea, select'
1475
1662
  );
1476
1663
  for (const s of e) {
1477
- if (m(s)) continue;
1478
- const u = 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()), d = s.hasAttribute("aria-labelledby");
1479
- let p = !1;
1664
+ if (p(s)) continue;
1665
+ const c = 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()), l = s.hasAttribute("aria-labelledby");
1666
+ let m = !1;
1480
1667
  const g = s.id;
1481
1668
  if (g) {
1482
- const v = s.ownerDocument.querySelector(`label[for="${CSS.escape(g)}"]`);
1483
- (r = v == null ? void 0 : v.textContent) != null && r.trim() && (p = !0);
1669
+ const f = s.ownerDocument.querySelector(`label[for="${CSS.escape(g)}"]`);
1670
+ (r = f == null ? void 0 : f.textContent) != null && r.trim() && (m = !0);
1484
1671
  }
1485
- const f = s.closest("label");
1486
- (o = f == null ? void 0 : f.textContent) != null && o.trim() && (p = !0), u && !h && !d && !p && a.push({
1672
+ const b = s.closest("label");
1673
+ (o = b == null ? void 0 : b.textContent) != null && o.trim() && (m = !0), c && !h && !l && !m && a.push({
1487
1674
  ruleId: "label-title-only",
1488
- selector: c(s),
1489
- html: l(s),
1675
+ selector: d(s),
1676
+ html: u(s),
1490
1677
  impact: "serious",
1491
1678
  message: "Form element uses title attribute as only label. Use <label>, aria-label, or aria-labelledby instead."
1492
1679
  });
1493
1680
  }
1494
1681
  return a;
1495
1682
  }
1496
- }, tt = {
1683
+ }, vt = {
1497
1684
  id: "tabindex",
1498
1685
  selector: "[tabindex]",
1499
1686
  check: { type: "attribute-value", attribute: "tabindex", operator: ">", value: 0 },
@@ -1505,7 +1692,7 @@ const Ze = {
1505
1692
  tags: ["best-practice"],
1506
1693
  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.",
1507
1694
  prompt: "Change the positive tabindex value to tabindex='0' and rely on DOM order for tab sequence instead."
1508
- }, at = k(tt), it = /* @__PURE__ */ new Set([
1695
+ }, wt = k(vt), yt = /* @__PURE__ */ new Set([
1509
1696
  "div",
1510
1697
  "span",
1511
1698
  "p",
@@ -1532,7 +1719,7 @@ const Ze = {
1532
1719
  "tr",
1533
1720
  "td",
1534
1721
  "th"
1535
- ]), nt = {
1722
+ ]), At = {
1536
1723
  id: "focus-order-semantics",
1537
1724
  wcag: [],
1538
1725
  tags: ["best-practice"],
@@ -1544,18 +1731,18 @@ const Ze = {
1544
1731
  const a = [];
1545
1732
  for (const e of t.querySelectorAll('[tabindex="0"]')) {
1546
1733
  const i = e.tagName.toLowerCase();
1547
- if (!it.has(i)) continue;
1734
+ if (!yt.has(i)) continue;
1548
1735
  e.getAttribute("role") || a.push({
1549
1736
  ruleId: "focus-order-semantics",
1550
- selector: c(e),
1551
- html: l(e),
1737
+ selector: d(e),
1738
+ html: u(e),
1552
1739
  impact: "moderate",
1553
1740
  message: `Non-interactive <${i}> with tabindex="0" has no interactive role.`
1554
1741
  });
1555
1742
  }
1556
1743
  return a;
1557
1744
  }
1558
- }, rt = /* @__PURE__ */ new Set([
1745
+ }, St = /* @__PURE__ */ new Set([
1559
1746
  "a",
1560
1747
  "audio",
1561
1748
  "button",
@@ -1564,7 +1751,7 @@ const Ze = {
1564
1751
  "select",
1565
1752
  "textarea",
1566
1753
  "video"
1567
- ]), ot = /* @__PURE__ */ new Set([
1754
+ ]), xt = /* @__PURE__ */ new Set([
1568
1755
  "button",
1569
1756
  "checkbox",
1570
1757
  "combobox",
@@ -1588,7 +1775,7 @@ const Ze = {
1588
1775
  "tabpanel",
1589
1776
  "textbox",
1590
1777
  "treeitem"
1591
- ]), st = {
1778
+ ]), kt = {
1592
1779
  grid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader"]),
1593
1780
  listbox: /* @__PURE__ */ new Set(["option"]),
1594
1781
  menu: /* @__PURE__ */ new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]),
@@ -1598,26 +1785,26 @@ const Ze = {
1598
1785
  tree: /* @__PURE__ */ new Set(["treeitem"]),
1599
1786
  treegrid: /* @__PURE__ */ new Set(["gridcell", "row", "columnheader", "rowheader", "treeitem"])
1600
1787
  };
1601
- function lt(t, a) {
1788
+ function It(t, a) {
1602
1789
  var n, r, o;
1603
1790
  const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase(), i = (r = a.getAttribute("role")) == null ? void 0 : r.toLowerCase();
1604
- return !e || !i ? !1 : ((o = st[e]) == null ? void 0 : o.has(i)) ?? !1;
1791
+ return !e || !i ? !1 : ((o = kt[e]) == null ? void 0 : o.has(i)) ?? !1;
1605
1792
  }
1606
- function ct(t) {
1793
+ function Et(t) {
1607
1794
  var n;
1608
1795
  const a = t.tagName.toLowerCase();
1609
- if (rt.has(a))
1796
+ if (St.has(a))
1610
1797
  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);
1611
1798
  const e = (n = t.getAttribute("role")) == null ? void 0 : n.toLowerCase();
1612
- if (e && ot.has(e)) return !0;
1799
+ if (e && xt.has(e)) return !0;
1613
1800
  const i = t.getAttribute("tabindex");
1614
1801
  return i !== null && i !== "-1" || t.getAttribute("contenteditable") === "true";
1615
1802
  }
1616
- function dt(t) {
1803
+ function Tt(t) {
1617
1804
  const a = t.tagName.toLowerCase();
1618
1805
  return !!(a === "a" && t.hasAttribute("href") || a === "button" && !t.disabled);
1619
1806
  }
1620
- const ut = {
1807
+ const Lt = {
1621
1808
  id: "nested-interactive",
1622
1809
  wcag: ["4.1.2"],
1623
1810
  level: "A",
@@ -1632,24 +1819,24 @@ const ut = {
1632
1819
  for (; o; ) {
1633
1820
  for (; r.length > 0 && !r[r.length - 1].contains(o); )
1634
1821
  r.pop();
1635
- if (!m(o) && ct(o)) {
1822
+ if (!p(o) && Et(o)) {
1636
1823
  if (r.length > 0) {
1637
1824
  const s = r[r.length - 1];
1638
- lt(s, o) || a.push({
1825
+ It(s, o) || a.push({
1639
1826
  ruleId: "nested-interactive",
1640
- selector: c(o),
1641
- html: l(o),
1827
+ selector: d(o),
1828
+ html: u(o),
1642
1829
  impact: "serious",
1643
1830
  message: `Interactive element <${o.tagName.toLowerCase()}> is nested inside <${s.tagName.toLowerCase()}>.`
1644
1831
  });
1645
1832
  }
1646
- dt(o) && r.push(o);
1833
+ Tt(o) && r.push(o);
1647
1834
  }
1648
1835
  o = n.nextNode();
1649
1836
  }
1650
1837
  return a;
1651
1838
  }
1652
- }, mt = {
1839
+ }, Ct = {
1653
1840
  id: "scrollable-region-focusable",
1654
1841
  wcag: ["2.1.1"],
1655
1842
  level: "A",
@@ -1659,23 +1846,23 @@ const ut = {
1659
1846
  run(t) {
1660
1847
  const a = [];
1661
1848
  for (const e of t.querySelectorAll("*")) {
1662
- if (m(e) || !(e instanceof HTMLElement)) continue;
1663
- const i = x(e), n = i.overflowX, r = i.overflowY;
1849
+ if (p(e) || !(e instanceof HTMLElement)) continue;
1850
+ const i = A(e), n = i.overflowX, r = i.overflowY;
1664
1851
  if (!(n === "scroll" || n === "auto" || r === "scroll" || r === "auto") || !(e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth)) continue;
1665
- const u = e.getAttribute("tabindex");
1666
- u !== null && u !== "-1" || e.querySelector(
1852
+ const c = e.getAttribute("tabindex");
1853
+ c !== null && c !== "-1" || e.querySelector(
1667
1854
  'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
1668
1855
  ) || a.push({
1669
1856
  ruleId: "scrollable-region-focusable",
1670
- selector: c(e),
1671
- html: l(e),
1857
+ selector: d(e),
1858
+ html: u(e),
1672
1859
  impact: "serious",
1673
1860
  message: "Scrollable region is not keyboard accessible. Add tabindex='0' or include focusable elements."
1674
1861
  });
1675
1862
  }
1676
1863
  return a;
1677
1864
  }
1678
- }, pt = {
1865
+ }, qt = {
1679
1866
  id: "accesskeys",
1680
1867
  wcag: [],
1681
1868
  level: "A",
@@ -1687,7 +1874,7 @@ const ut = {
1687
1874
  var i;
1688
1875
  const a = [], e = /* @__PURE__ */ new Map();
1689
1876
  for (const n of t.querySelectorAll("[accesskey]")) {
1690
- if (m(n)) continue;
1877
+ if (p(n)) continue;
1691
1878
  const r = (i = n.getAttribute("accesskey")) == null ? void 0 : i.trim().toLowerCase();
1692
1879
  if (!r) continue;
1693
1880
  const o = e.get(r) || [];
@@ -1698,14 +1885,14 @@ const ut = {
1698
1885
  for (const o of r.slice(1))
1699
1886
  a.push({
1700
1887
  ruleId: "accesskeys",
1701
- selector: c(o),
1702
- html: l(o),
1888
+ selector: d(o),
1889
+ html: u(o),
1703
1890
  impact: "serious",
1704
1891
  message: `Duplicate accesskey "${n}". Each accesskey must be unique.`
1705
1892
  });
1706
1893
  return a;
1707
1894
  }
1708
- }, ht = {
1895
+ }, Rt = {
1709
1896
  id: "heading-order",
1710
1897
  wcag: [],
1711
1898
  level: "A",
@@ -1717,20 +1904,20 @@ const ut = {
1717
1904
  const a = [], e = t.querySelectorAll("h1, h2, h3, h4, h5, h6, [role='heading']");
1718
1905
  let i = 0, n = null;
1719
1906
  for (const r of e) {
1720
- if (m(r)) continue;
1907
+ if (p(r)) continue;
1721
1908
  let o;
1722
1909
  r.hasAttribute("aria-level") ? o = parseInt(r.getAttribute("aria-level"), 10) : o = parseInt(r.tagName[1], 10), i > 0 && o > i + 1 && a.push({
1723
1910
  ruleId: "heading-order",
1724
- selector: c(r),
1725
- html: l(r),
1911
+ selector: d(r),
1912
+ html: u(r),
1726
1913
  impact: "moderate",
1727
1914
  message: `Heading level ${o} skipped from level ${i}.`,
1728
- context: n ? `Previous heading: ${l(n)}` : void 0
1915
+ context: n ? `Previous heading: ${u(n)}` : void 0
1729
1916
  }), i = o, n = r;
1730
1917
  }
1731
1918
  return a;
1732
1919
  }
1733
- }, L = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', X = '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"]', gt = {
1920
+ }, N = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', Z = '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"]', Nt = {
1734
1921
  id: "landmark-one-main",
1735
1922
  wcag: [],
1736
1923
  level: "A",
@@ -1748,13 +1935,13 @@ const ut = {
1748
1935
  message: "Page has no main landmark."
1749
1936
  }] : a.length > 1 ? Array.from(a).slice(1).map((e) => ({
1750
1937
  ruleId: "landmark-one-main",
1751
- selector: c(e),
1752
- html: l(e),
1938
+ selector: d(e),
1939
+ html: u(e),
1753
1940
  impact: "moderate",
1754
1941
  message: "Page has multiple main landmarks."
1755
1942
  })) : [];
1756
1943
  }
1757
- }, bt = {
1944
+ }, Mt = {
1758
1945
  id: "landmark-no-duplicate-banner",
1759
1946
  wcag: [],
1760
1947
  level: "A",
@@ -1763,18 +1950,18 @@ const ut = {
1763
1950
  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.",
1764
1951
  prompt: "Explain whether to remove this duplicate banner or nest it inside a sectioning element.",
1765
1952
  run(t) {
1766
- const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest(L));
1953
+ const a = [], e = t.querySelectorAll('header, [role="banner"]'), i = Array.from(e).filter((n) => !n.closest(N));
1767
1954
  return i.length > 1 && i.slice(1).forEach(
1768
1955
  (n) => a.push({
1769
1956
  ruleId: "landmark-no-duplicate-banner",
1770
- selector: c(n),
1771
- html: l(n),
1957
+ selector: d(n),
1958
+ html: u(n),
1772
1959
  impact: "moderate",
1773
1960
  message: "Page has multiple banner landmarks."
1774
1961
  })
1775
1962
  ), a;
1776
1963
  }
1777
- }, ft = {
1964
+ }, $t = {
1778
1965
  id: "landmark-no-duplicate-contentinfo",
1779
1966
  wcag: [],
1780
1967
  level: "A",
@@ -1783,18 +1970,18 @@ const ut = {
1783
1970
  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.",
1784
1971
  prompt: "Explain whether to remove this duplicate footer or nest it inside a sectioning element.",
1785
1972
  run(t) {
1786
- const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest(L));
1973
+ const a = [], e = t.querySelectorAll('footer, [role="contentinfo"]'), i = Array.from(e).filter((n) => !n.closest(N));
1787
1974
  return i.length > 1 && i.slice(1).forEach(
1788
1975
  (n) => a.push({
1789
1976
  ruleId: "landmark-no-duplicate-contentinfo",
1790
- selector: c(n),
1791
- html: l(n),
1977
+ selector: d(n),
1978
+ html: u(n),
1792
1979
  impact: "moderate",
1793
1980
  message: "Page has multiple contentinfo landmarks."
1794
1981
  })
1795
1982
  ), a;
1796
1983
  }
1797
- }, vt = {
1984
+ }, Ht = {
1798
1985
  id: "landmark-no-duplicate-main",
1799
1986
  wcag: [],
1800
1987
  level: "A",
@@ -1807,14 +1994,14 @@ const ut = {
1807
1994
  return e.length > 1 && Array.from(e).slice(1).forEach(
1808
1995
  (i) => a.push({
1809
1996
  ruleId: "landmark-no-duplicate-main",
1810
- selector: c(i),
1811
- html: l(i),
1997
+ selector: d(i),
1998
+ html: u(i),
1812
1999
  impact: "moderate",
1813
2000
  message: "Page has multiple main landmarks."
1814
2001
  })
1815
2002
  ), a;
1816
2003
  }
1817
- }, wt = {
2004
+ }, Dt = {
1818
2005
  id: "landmark-banner-is-top-level",
1819
2006
  wcag: [],
1820
2007
  level: "A",
@@ -1825,16 +2012,16 @@ const ut = {
1825
2012
  run(t) {
1826
2013
  const a = [], e = t.querySelectorAll('[role="banner"]');
1827
2014
  for (const i of e)
1828
- i.closest(L) && a.push({
2015
+ i.closest(N) && a.push({
1829
2016
  ruleId: "landmark-banner-is-top-level",
1830
- selector: c(i),
1831
- html: l(i),
2017
+ selector: d(i),
2018
+ html: u(i),
1832
2019
  impact: "moderate",
1833
2020
  message: "Banner landmark is nested within another landmark."
1834
2021
  });
1835
2022
  return a;
1836
2023
  }
1837
- }, yt = {
2024
+ }, Ot = {
1838
2025
  id: "landmark-contentinfo-is-top-level",
1839
2026
  wcag: [],
1840
2027
  level: "A",
@@ -1845,16 +2032,16 @@ const ut = {
1845
2032
  run(t) {
1846
2033
  const a = [], e = t.querySelectorAll('[role="contentinfo"]');
1847
2034
  for (const i of e)
1848
- i.closest(L) && a.push({
2035
+ i.closest(N) && a.push({
1849
2036
  ruleId: "landmark-contentinfo-is-top-level",
1850
- selector: c(i),
1851
- html: l(i),
2037
+ selector: d(i),
2038
+ html: u(i),
1852
2039
  impact: "moderate",
1853
2040
  message: "Contentinfo landmark is nested within another landmark."
1854
2041
  });
1855
2042
  return a;
1856
2043
  }
1857
- }, At = {
2044
+ }, Bt = {
1858
2045
  id: "landmark-main-is-top-level",
1859
2046
  wcag: [],
1860
2047
  level: "A",
@@ -1868,15 +2055,15 @@ const ut = {
1868
2055
  const n = i.parentElement;
1869
2056
  n != null && n.closest('article, aside, nav, section, [role="article"], [role="complementary"], [role="navigation"], [role="region"]') && a.push({
1870
2057
  ruleId: "landmark-main-is-top-level",
1871
- selector: c(i),
1872
- html: l(i),
2058
+ selector: d(i),
2059
+ html: u(i),
1873
2060
  impact: "moderate",
1874
2061
  message: "Main landmark is nested within another landmark."
1875
2062
  });
1876
2063
  }
1877
2064
  return a;
1878
2065
  }
1879
- }, St = {
2066
+ }, Wt = {
1880
2067
  id: "landmark-complementary-is-top-level",
1881
2068
  wcag: [],
1882
2069
  level: "A",
@@ -1890,15 +2077,15 @@ const ut = {
1890
2077
  const n = i.parentElement;
1891
2078
  n && !n.matches('body, main, [role="main"]') && i.closest('article, nav, section, [role="article"], [role="navigation"], [role="region"]') && a.push({
1892
2079
  ruleId: "landmark-complementary-is-top-level",
1893
- selector: c(i),
1894
- html: l(i),
2080
+ selector: d(i),
2081
+ html: u(i),
1895
2082
  impact: "moderate",
1896
2083
  message: "Complementary landmark should be top-level."
1897
2084
  });
1898
2085
  }
1899
2086
  return a;
1900
2087
  }
1901
- }, xt = {
2088
+ }, _t = {
1902
2089
  id: "landmark-unique",
1903
2090
  wcag: [],
1904
2091
  level: "A",
@@ -1914,27 +2101,27 @@ const ut = {
1914
2101
  { selector: 'form[aria-label], form[aria-labelledby], [role="form"], [role="search"]', type: "form" }
1915
2102
  ];
1916
2103
  for (const { selector: i, type: n } of e) {
1917
- const r = Array.from(t.querySelectorAll(i)).filter((s) => !m(s));
2104
+ const r = Array.from(t.querySelectorAll(i)).filter((s) => !p(s));
1918
2105
  if (r.length <= 1) continue;
1919
2106
  const o = /* @__PURE__ */ new Map();
1920
2107
  for (const s of r) {
1921
- const u = b(s).toLowerCase() || "", h = o.get(u) || [];
1922
- h.push(s), o.set(u, h);
2108
+ const c = v(s).toLowerCase() || "", h = o.get(c) || [];
2109
+ h.push(s), o.set(c, h);
1923
2110
  }
1924
- for (const [s, u] of o)
1925
- if (u.length > 1)
1926
- for (const h of u.slice(1))
2111
+ for (const [s, c] of o)
2112
+ if (c.length > 1)
2113
+ for (const h of c.slice(1))
1927
2114
  a.push({
1928
2115
  ruleId: "landmark-unique",
1929
- selector: c(h),
1930
- html: l(h),
2116
+ selector: d(h),
2117
+ html: u(h),
1931
2118
  impact: "moderate",
1932
2119
  message: s ? `Multiple ${n} landmarks have the same label "${s}".` : `Multiple ${n} landmarks have no label. Add unique aria-label attributes.`
1933
2120
  });
1934
2121
  }
1935
2122
  return a;
1936
2123
  }
1937
- }, kt = {
2124
+ }, Ft = {
1938
2125
  id: "region",
1939
2126
  wcag: [],
1940
2127
  level: "A",
@@ -1947,19 +2134,19 @@ const ut = {
1947
2134
  const a = [], e = t.body;
1948
2135
  if (!e) return [];
1949
2136
  for (const n of e.children) {
1950
- if (m(n) || n instanceof HTMLScriptElement || n instanceof HTMLStyleElement || n.tagName === "NOSCRIPT" || n instanceof HTMLElement && n.hidden || n.matches('a[href^="#"]')) continue;
1951
- const r = n.matches(X), o = (i = n.textContent) == null ? void 0 : i.trim();
1952
- !r && o && (n.querySelector(X) || a.push({
2137
+ if (p(n) || n instanceof HTMLScriptElement || n instanceof HTMLStyleElement || n.tagName === "NOSCRIPT" || n instanceof HTMLElement && n.hidden || n.matches('a[href^="#"]')) continue;
2138
+ const r = n.matches(Z), o = (i = n.textContent) == null ? void 0 : i.trim();
2139
+ !r && o && (n.querySelector(Z) || a.push({
1953
2140
  ruleId: "region",
1954
- selector: c(n),
1955
- html: l(n),
2141
+ selector: d(n),
2142
+ html: u(n),
1956
2143
  impact: "moderate",
1957
2144
  message: "Content is not contained within a landmark region."
1958
2145
  }));
1959
2146
  }
1960
2147
  return a;
1961
2148
  }
1962
- }, It = {
2149
+ }, jt = {
1963
2150
  id: "list",
1964
2151
  selector: "ul, ol",
1965
2152
  check: { type: "child-invalid", allowedChildren: ["li", "script", "template"] },
@@ -1970,7 +2157,7 @@ const ut = {
1970
2157
  level: "A",
1971
2158
  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.",
1972
2159
  prompt: "Explain how to restructure this element within the list properly."
1973
- }, qt = k(It), Ct = {
2160
+ }, Pt = k(jt), Vt = {
1974
2161
  id: "dlitem",
1975
2162
  wcag: ["1.3.1"],
1976
2163
  level: "A",
@@ -1982,14 +2169,14 @@ const ut = {
1982
2169
  for (const e of t.querySelectorAll("dt, dd"))
1983
2170
  (!e.parentElement || e.parentElement.tagName.toLowerCase() !== "dl") && a.push({
1984
2171
  ruleId: "dlitem",
1985
- selector: c(e),
1986
- html: l(e),
2172
+ selector: d(e),
2173
+ html: u(e),
1987
2174
  impact: "serious",
1988
2175
  message: `<${e.tagName.toLowerCase()}> is not contained in a <dl>.`
1989
2176
  });
1990
2177
  return a;
1991
2178
  }
1992
- }, Tt = {
2179
+ }, zt = {
1993
2180
  id: "definition-list",
1994
2181
  selector: "dl",
1995
2182
  check: { type: "child-invalid", allowedChildren: ["dt", "dd", "div", "script", "template"] },
@@ -2000,7 +2187,7 @@ const ut = {
2000
2187
  level: "A",
2001
2188
  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.",
2002
2189
  prompt: "Explain whether to move this element outside the <dl> or convert it to dt/dd."
2003
- }, Et = k(Tt), Lt = {
2190
+ }, Ut = k(zt), Gt = {
2004
2191
  id: "document-title",
2005
2192
  wcag: ["2.4.2"],
2006
2193
  level: "A",
@@ -2018,7 +2205,7 @@ const ut = {
2018
2205
  message: a ? "Document <title> element is empty." : "Document is missing a <title> element."
2019
2206
  }] : [];
2020
2207
  }
2021
- }, Rt = {
2208
+ }, Xt = {
2022
2209
  id: "bypass",
2023
2210
  wcag: ["2.4.1"],
2024
2211
  level: "A",
@@ -2045,7 +2232,7 @@ const ut = {
2045
2232
  message: "Page has no mechanism to bypass repeated content. Add a <main> landmark or skip link."
2046
2233
  }];
2047
2234
  }
2048
- }, Nt = {
2235
+ }, Yt = {
2049
2236
  id: "page-has-heading-one",
2050
2237
  wcag: [],
2051
2238
  level: "A",
@@ -2055,10 +2242,10 @@ const ut = {
2055
2242
  prompt: "Suggest appropriate h1 text based on the page's visible content.",
2056
2243
  run(t) {
2057
2244
  const a = t.querySelector("h1");
2058
- if (a && b(a)) return [];
2245
+ if (a && v(a)) return [];
2059
2246
  const e = t.querySelectorAll('[role="heading"][aria-level="1"]');
2060
2247
  for (const i of e)
2061
- if (b(i)) return [];
2248
+ if (v(i)) return [];
2062
2249
  return [{
2063
2250
  ruleId: "page-has-heading-one",
2064
2251
  selector: "html",
@@ -2067,7 +2254,7 @@ const ut = {
2067
2254
  message: "Page does not contain a level-one heading."
2068
2255
  }];
2069
2256
  }
2070
- }, Mt = {
2257
+ }, Kt = {
2071
2258
  id: "frame-title",
2072
2259
  wcag: ["4.1.2"],
2073
2260
  level: "A",
@@ -2077,18 +2264,18 @@ const ut = {
2077
2264
  run(t) {
2078
2265
  const a = [];
2079
2266
  for (const e of t.querySelectorAll("iframe, frame")) {
2080
- if (m(e)) continue;
2081
- b(e) || a.push({
2267
+ if (p(e)) continue;
2268
+ v(e) || a.push({
2082
2269
  ruleId: "frame-title",
2083
- selector: c(e),
2084
- html: l(e),
2270
+ selector: d(e),
2271
+ html: u(e),
2085
2272
  impact: "serious",
2086
2273
  message: "Frame is missing an accessible name. Add a title attribute."
2087
2274
  });
2088
2275
  }
2089
2276
  return a;
2090
2277
  }
2091
- }, $t = {
2278
+ }, Qt = {
2092
2279
  id: "frame-title-unique",
2093
2280
  wcag: ["4.1.2"],
2094
2281
  level: "A",
@@ -2100,13 +2287,13 @@ const ut = {
2100
2287
  var n;
2101
2288
  const a = [], e = Array.from(t.querySelectorAll("iframe[title], frame[title]")), i = /* @__PURE__ */ new Map();
2102
2289
  for (const r of e) {
2103
- if (m(r)) continue;
2290
+ if (p(r)) continue;
2104
2291
  const o = r.getAttribute("width"), s = r.getAttribute("height");
2105
2292
  if (o === "0" || s === "0" || r instanceof HTMLElement && r.style.display === "none" || r instanceof HTMLElement && r.style.visibility === "hidden") continue;
2106
- const u = (n = r.getAttribute("title")) == null ? void 0 : n.trim().toLowerCase();
2107
- if (u) {
2108
- const h = i.get(u) || [];
2109
- h.push(r), i.set(u, h);
2293
+ const c = (n = r.getAttribute("title")) == null ? void 0 : n.trim().toLowerCase();
2294
+ if (c) {
2295
+ const h = i.get(c) || [];
2296
+ h.push(r), i.set(c, h);
2110
2297
  }
2111
2298
  }
2112
2299
  for (const [, r] of i)
@@ -2114,14 +2301,14 @@ const ut = {
2114
2301
  for (const o of r.slice(1))
2115
2302
  a.push({
2116
2303
  ruleId: "frame-title-unique",
2117
- selector: c(o),
2118
- html: l(o),
2304
+ selector: d(o),
2305
+ html: u(o),
2119
2306
  impact: "moderate",
2120
2307
  message: "Frame title is not unique. Use a distinct title for each frame."
2121
2308
  });
2122
2309
  return a;
2123
2310
  }
2124
- }, Ht = {
2311
+ }, Jt = {
2125
2312
  id: "empty-heading",
2126
2313
  wcag: [],
2127
2314
  level: "A",
@@ -2132,16 +2319,16 @@ const ut = {
2132
2319
  run(t) {
2133
2320
  const a = [], e = t.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
2134
2321
  for (const i of e)
2135
- m(i) || b(i) || a.push({
2322
+ p(i) || v(i) || a.push({
2136
2323
  ruleId: "empty-heading",
2137
- selector: c(i),
2138
- html: l(i),
2324
+ selector: d(i),
2325
+ html: u(i),
2139
2326
  impact: "minor",
2140
2327
  message: "Heading is empty. Add text content or remove the heading element."
2141
2328
  });
2142
2329
  return a;
2143
2330
  }
2144
- }, Dt = {
2331
+ }, Zt = {
2145
2332
  id: "meta-viewport",
2146
2333
  wcag: ["1.4.4"],
2147
2334
  level: "AA",
@@ -2155,25 +2342,25 @@ const ut = {
2155
2342
  const i = ((r = e.getAttribute("content")) == null ? void 0 : r.toLowerCase()) || "";
2156
2343
  (/user-scalable\s*=\s*no/i.test(i) || /user-scalable\s*=\s*0/i.test(i)) && a.push({
2157
2344
  ruleId: "meta-viewport",
2158
- selector: c(e),
2159
- html: l(e),
2345
+ selector: d(e),
2346
+ html: u(e),
2160
2347
  impact: "critical",
2161
2348
  message: "Viewport disables user scaling. Remove user-scalable=no."
2162
2349
  });
2163
- const n = i.match(/maximum-scale\s*=\s*([\d.]+)/i);
2350
+ const n = i.match(/maximum-scale\s*=\s*([\d.]+|yes)/i);
2164
2351
  if (n) {
2165
- const o = parseFloat(n[1]);
2166
- o < 2 && a.push({
2352
+ const o = n[1], s = o.toLowerCase() === "yes" ? 1 : parseFloat(o);
2353
+ s < 2 && a.push({
2167
2354
  ruleId: "meta-viewport",
2168
- selector: c(e),
2169
- html: l(e),
2355
+ selector: d(e),
2356
+ html: u(e),
2170
2357
  impact: "critical",
2171
- message: `Viewport maximum-scale=${o} restricts zooming. Set to at least 2 or remove.`
2358
+ message: `Viewport maximum-scale=${s} restricts zooming. Set to at least 2 or remove.`
2172
2359
  });
2173
2360
  }
2174
2361
  return a;
2175
2362
  }
2176
- }, Ot = {
2363
+ }, ea = {
2177
2364
  id: "meta-refresh",
2178
2365
  wcag: ["2.2.1", "2.2.4", "3.2.5"],
2179
2366
  level: "A",
@@ -2181,34 +2368,30 @@ const ut = {
2181
2368
  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.",
2182
2369
  prompt: "Explain why meta refresh is problematic and suggest server-side alternatives.",
2183
2370
  run(t) {
2184
- const a = [], e = t.querySelector('meta[http-equiv="refresh"]');
2185
- if (!e) return [];
2186
- const i = e.getAttribute("content") || "", n = i.match(/^(\d+)/);
2187
- if (n) {
2188
- const r = parseInt(n[1], 10);
2189
- i.includes("url=") ? r <= 0 ? a.push({
2190
- ruleId: "meta-refresh",
2191
- selector: c(e),
2192
- html: l(e),
2193
- impact: "moderate",
2194
- message: "Page uses meta refresh for redirect. Use server-side redirect instead."
2195
- }) : a.push({
2196
- ruleId: "meta-refresh",
2197
- selector: c(e),
2198
- html: l(e),
2199
- impact: "critical",
2200
- message: `Page redirects after ${r} seconds without warning. Use server-side redirect.`
2201
- }) : r > 0 && r <= 72e3 && a.push({
2202
- ruleId: "meta-refresh",
2203
- selector: c(e),
2204
- html: l(e),
2205
- impact: "critical",
2206
- message: `Page auto-refreshes after ${r} seconds. Provide user control over refresh.`
2207
- });
2371
+ for (const a of t.querySelectorAll('meta[http-equiv="refresh"]')) {
2372
+ const e = a.getAttribute("content") || "", i = e.match(/^(\d+)/);
2373
+ if (!i) continue;
2374
+ const n = parseInt(i[1], 10);
2375
+ if (/^\d+\s*[;,]\s*url\s*=/i.test(e) || /^\d+\s*[;,]\s*['"]?\s*https?:/i.test(e))
2376
+ return n > 0 && n <= 72e3 ? [{
2377
+ ruleId: "meta-refresh",
2378
+ selector: d(a),
2379
+ html: u(a),
2380
+ impact: "critical",
2381
+ message: `Page redirects after ${n} seconds without warning. Use server-side redirect.`
2382
+ }] : [];
2383
+ if (n > 0 && n <= 72e3)
2384
+ return [{
2385
+ ruleId: "meta-refresh",
2386
+ selector: d(a),
2387
+ html: u(a),
2388
+ impact: "critical",
2389
+ message: `Page auto-refreshes after ${n} seconds. Provide user control over refresh.`
2390
+ }];
2208
2391
  }
2209
- return a;
2392
+ return [];
2210
2393
  }
2211
- }, Wt = {
2394
+ }, ta = {
2212
2395
  id: "blink",
2213
2396
  selector: "blink",
2214
2397
  check: { type: "selector-exists" },
@@ -2219,7 +2402,7 @@ const ut = {
2219
2402
  level: "A",
2220
2403
  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.",
2221
2404
  prompt: "Suggest static alternatives to the blinking effect."
2222
- }, Bt = k(Wt), Ft = {
2405
+ }, aa = k(ta), ia = {
2223
2406
  id: "marquee",
2224
2407
  selector: "marquee",
2225
2408
  check: { type: "selector-exists" },
@@ -2230,7 +2413,7 @@ const ut = {
2230
2413
  level: "A",
2231
2414
  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.",
2232
2415
  prompt: "Suggest static alternatives or accessible carousel patterns."
2233
- }, _t = k(Ft), Pt = {
2416
+ }, na = k(ia), ra = {
2234
2417
  id: "p-as-heading",
2235
2418
  wcag: [],
2236
2419
  level: "A",
@@ -2242,14 +2425,14 @@ const ut = {
2242
2425
  var e, i;
2243
2426
  const a = [];
2244
2427
  for (const n of t.querySelectorAll("p")) {
2245
- if (m(n)) continue;
2246
- 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), u = ((e = n.className) == null ? void 0 : e.toLowerCase()) || "", h = /\bh[1-6]\b|\bheading\b/.test(u), d = ((i = n.textContent) == null ? void 0 : i.trim()) || "", p = d.length > 0 && d.length < 50, g = !d.match(/[.!?,;:]$/);
2247
- if ((o && s || o && h) && p && g) {
2428
+ if (p(n)) continue;
2429
+ 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), c = ((e = n.className) == null ? void 0 : e.toLowerCase()) || "", h = /\bh[1-6]\b|\bheading\b/.test(c), l = ((i = n.textContent) == null ? void 0 : i.trim()) || "", m = l.length > 0 && l.length < 50, g = !l.match(/[.!?,;:]$/);
2430
+ if ((o && s || o && h) && m && g) {
2248
2431
  const w = n.nextElementSibling;
2249
2432
  w && (w.tagName === "P" || w.tagName === "DIV" || w.tagName === "UL") && a.push({
2250
2433
  ruleId: "p-as-heading",
2251
- selector: c(n),
2252
- html: l(n),
2434
+ selector: d(n),
2435
+ html: u(n),
2253
2436
  impact: "serious",
2254
2437
  message: "Paragraph appears to be styled as a heading. Use an h1-h6 element instead."
2255
2438
  });
@@ -2257,7 +2440,7 @@ const ut = {
2257
2440
  }
2258
2441
  return a;
2259
2442
  }
2260
- }, Vt = {
2443
+ }, oa = {
2261
2444
  id: "aria-roles",
2262
2445
  wcag: ["4.1.2"],
2263
2446
  level: "A",
@@ -2267,22 +2450,18 @@ const ut = {
2267
2450
  run(t) {
2268
2451
  const a = [];
2269
2452
  for (const e of t.querySelectorAll("[role]")) {
2270
- const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/);
2271
- for (const o of r)
2272
- if (o && !de(o)) {
2273
- a.push({
2274
- ruleId: "aria-roles",
2275
- selector: c(e),
2276
- html: l(e),
2277
- impact: "critical",
2278
- message: `Invalid ARIA role "${o}".`
2279
- });
2280
- break;
2281
- }
2453
+ const r = e.getAttribute("role").replace(/[\u201C\u201D\u2018\u2019\u00AB\u00BB]/g, "").split(/\s+/).filter(Boolean);
2454
+ !r.some((s) => ye(s)) && r.length > 0 && a.push({
2455
+ ruleId: "aria-roles",
2456
+ selector: d(e),
2457
+ html: u(e),
2458
+ impact: "critical",
2459
+ message: `Invalid ARIA role "${r[0]}".`
2460
+ });
2282
2461
  }
2283
2462
  return a;
2284
2463
  }
2285
- }, Ut = {
2464
+ }, sa = {
2286
2465
  id: "aria-valid-attr",
2287
2466
  wcag: ["4.1.2"],
2288
2467
  level: "A",
@@ -2290,9 +2469,9 @@ const ut = {
2290
2469
  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+).",
2291
2470
  prompt: "Identify the misspelled attribute and provide the correct spelling.",
2292
2471
  run(t) {
2293
- return _(t).validAttr;
2472
+ return V(t).validAttr;
2294
2473
  }
2295
- }, jt = {
2474
+ }, la = {
2296
2475
  id: "aria-valid-attr-value",
2297
2476
  wcag: ["4.1.2"],
2298
2477
  level: "A",
@@ -2300,16 +2479,15 @@ const ut = {
2300
2479
  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.",
2301
2480
  prompt: "Show the invalid value and list the valid values for this specific attribute.",
2302
2481
  run(t) {
2303
- return _(t).validAttrValue;
2482
+ return V(t).validAttrValue;
2304
2483
  }
2305
- }, zt = {
2484
+ }, ca = {
2306
2485
  checkbox: ["aria-checked"],
2307
2486
  combobox: ["aria-expanded"],
2308
2487
  heading: ["aria-level"],
2309
2488
  menuitemcheckbox: ["aria-checked"],
2310
2489
  menuitemradio: ["aria-checked"],
2311
2490
  meter: ["aria-valuenow"],
2312
- option: ["aria-selected"],
2313
2491
  radio: ["aria-checked"],
2314
2492
  scrollbar: ["aria-controls", "aria-valuenow"],
2315
2493
  separator: ["aria-valuenow"],
@@ -2317,7 +2495,7 @@ const ut = {
2317
2495
  slider: ["aria-valuenow"],
2318
2496
  spinbutton: ["aria-valuenow"],
2319
2497
  switch: ["aria-checked"]
2320
- }, Gt = {
2498
+ }, ua = {
2321
2499
  id: "aria-required-attr",
2322
2500
  wcag: ["4.1.2"],
2323
2501
  level: "A",
@@ -2327,7 +2505,8 @@ const ut = {
2327
2505
  run(t) {
2328
2506
  const a = [];
2329
2507
  for (const e of t.querySelectorAll("[role]")) {
2330
- const i = e.getAttribute("role").trim().toLowerCase(), n = zt[i];
2508
+ if (p(e) || e instanceof HTMLElement && e.style.display === "none") continue;
2509
+ const i = e.getAttribute("role").trim().toLowerCase(), n = ca[i];
2331
2510
  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))) {
2332
2511
  if (i === "separator") {
2333
2512
  const r = e.getAttribute("tabindex");
@@ -2338,8 +2517,8 @@ const ut = {
2338
2517
  if (!e.hasAttribute(r)) {
2339
2518
  a.push({
2340
2519
  ruleId: "aria-required-attr",
2341
- selector: c(e),
2342
- html: l(e),
2520
+ selector: d(e),
2521
+ html: u(e),
2343
2522
  impact: "critical",
2344
2523
  message: `Role "${i}" requires attribute "${r}".`
2345
2524
  });
@@ -2351,24 +2530,24 @@ const ut = {
2351
2530
  return a;
2352
2531
  }
2353
2532
  };
2354
- function Xt(t) {
2533
+ function da(t) {
2355
2534
  var r, o, s;
2356
2535
  const a = [], e = t.className;
2357
2536
  e && typeof e == "string" && e.trim() && a.push(`Classes: ${e.trim().slice(0, 100)}`);
2358
2537
  const i = t.closest("form");
2359
2538
  if (i) {
2360
- const u = i.getAttribute("aria-label") || ((o = (r = i.querySelector("legend")) == null ? void 0 : r.textContent) == null ? void 0 : o.trim());
2361
- u && a.push(`Form: ${u.slice(0, 60)}`);
2539
+ const c = i.getAttribute("aria-label") || ((o = (r = i.querySelector("legend")) == null ? void 0 : r.textContent) == null ? void 0 : o.trim());
2540
+ c && a.push(`Form: ${c.slice(0, 60)}`);
2362
2541
  }
2363
2542
  const n = t.parentElement;
2364
2543
  if (n) {
2365
- const u = n.closest("h1, h2, h3, h4, h5, h6") || n.querySelector("h1, h2, h3, h4, h5, h6");
2366
- (s = u == null ? void 0 : u.textContent) != null && s.trim() && a.push(`Nearby heading: ${u.textContent.trim().slice(0, 60)}`);
2544
+ const c = n.closest("h1, h2, h3, h4, h5, h6") || n.querySelector("h1, h2, h3, h4, h5, h6");
2545
+ (s = c == null ? void 0 : c.textContent) != null && s.trim() && a.push(`Nearby heading: ${c.textContent.trim().slice(0, 60)}`);
2367
2546
  }
2368
2547
  return a.length > 0 ? a.join(`
2369
2548
  `) : void 0;
2370
2549
  }
2371
- const Kt = {
2550
+ const ma = {
2372
2551
  id: "button-name",
2373
2552
  wcag: ["4.1.2"],
2374
2553
  level: "A",
@@ -2378,19 +2557,21 @@ const Kt = {
2378
2557
  run(t) {
2379
2558
  const a = [];
2380
2559
  for (const e of t.querySelectorAll('button, [role="button"]')) {
2381
- if (m(e) || e.getRootNode() instanceof ShadowRoot) continue;
2382
- b(e) || a.push({
2560
+ if (p(e)) continue;
2561
+ const i = e.getAttribute("role");
2562
+ 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;
2563
+ v(e) || a.push({
2383
2564
  ruleId: "button-name",
2384
- selector: c(e),
2385
- html: l(e),
2565
+ selector: d(e),
2566
+ html: u(e),
2386
2567
  impact: "critical",
2387
2568
  message: "Button has no discernible text.",
2388
- context: Xt(e)
2569
+ context: da(e)
2389
2570
  });
2390
2571
  }
2391
2572
  return a;
2392
2573
  }
2393
- }, Yt = {
2574
+ }, ha = {
2394
2575
  alert: /* @__PURE__ */ new Set(["aria-atomic", "aria-busy", "aria-live", "aria-relevant"]),
2395
2576
  alertdialog: /* @__PURE__ */ new Set(["aria-describedby", "aria-modal"]),
2396
2577
  application: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-expanded", "aria-haspopup", "aria-invalid"]),
@@ -2462,7 +2643,7 @@ const Kt = {
2462
2643
  tree: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-required"]),
2463
2644
  treegrid: /* @__PURE__ */ new Set(["aria-activedescendant", "aria-colcount", "aria-disabled", "aria-errormessage", "aria-invalid", "aria-multiselectable", "aria-orientation", "aria-readonly", "aria-required", "aria-rowcount"]),
2464
2645
  treeitem: /* @__PURE__ */ new Set(["aria-checked", "aria-disabled", "aria-expanded", "aria-haspopup", "aria-level", "aria-posinset", "aria-selected", "aria-setsize"])
2465
- }, Qt = /* @__PURE__ */ new Set([
2646
+ }, pa = /* @__PURE__ */ new Set([
2466
2647
  "aria-atomic",
2467
2648
  "aria-busy",
2468
2649
  "aria-controls",
@@ -2486,7 +2667,7 @@ const Kt = {
2486
2667
  "aria-roledescription",
2487
2668
  "aria-braillelabel",
2488
2669
  "aria-brailleroledescription"
2489
- ]), Jt = {
2670
+ ]), ga = {
2490
2671
  id: "aria-allowed-attr",
2491
2672
  wcag: ["4.1.2"],
2492
2673
  level: "A",
@@ -2496,23 +2677,23 @@ const Kt = {
2496
2677
  run(t) {
2497
2678
  const a = [];
2498
2679
  for (const e of t.querySelectorAll("[role], [aria-*]")) {
2499
- if (m(e)) continue;
2500
- const i = E(e);
2680
+ if (p(e)) continue;
2681
+ const i = C(e);
2501
2682
  if (!i) continue;
2502
- const n = Yt[i];
2683
+ const n = ha[i];
2503
2684
  if (n)
2504
2685
  for (const r of e.attributes)
2505
- r.name.startsWith("aria-") && (Qt.has(r.name) || n.has(r.name) || a.push({
2686
+ r.name.startsWith("aria-") && (pa.has(r.name) || n.has(r.name) || a.push({
2506
2687
  ruleId: "aria-allowed-attr",
2507
- selector: c(e),
2508
- html: l(e),
2688
+ selector: d(e),
2689
+ html: u(e),
2509
2690
  impact: "critical",
2510
2691
  message: `ARIA attribute "${r.name}" is not allowed on role "${i}".`
2511
2692
  }));
2512
2693
  }
2513
2694
  return a;
2514
2695
  }
2515
- }, Zt = /* @__PURE__ */ new Set([
2696
+ }, ba = /* @__PURE__ */ new Set([
2516
2697
  "base",
2517
2698
  "col",
2518
2699
  "colgroup",
@@ -2634,10 +2815,10 @@ const Kt = {
2634
2815
  video: /* @__PURE__ */ new Set(["application"]),
2635
2816
  wbr: /* @__PURE__ */ new Set(["none", "presentation"])
2636
2817
  };
2637
- function ea(t) {
2818
+ function fa(t) {
2638
2819
  var e;
2639
2820
  const a = t.tagName.toLowerCase();
2640
- if (Zt.has(a))
2821
+ if (ba.has(a))
2641
2822
  return "none";
2642
2823
  if (a === "a" && t.hasAttribute("href"))
2643
2824
  return I["a[href]"];
@@ -2649,7 +2830,7 @@ function ea(t) {
2649
2830
  }
2650
2831
  return I[a] || "any";
2651
2832
  }
2652
- const ta = {
2833
+ const va = {
2653
2834
  id: "aria-allowed-role",
2654
2835
  wcag: ["4.1.2"],
2655
2836
  level: "A",
@@ -2660,29 +2841,29 @@ const ta = {
2660
2841
  var e;
2661
2842
  const a = [];
2662
2843
  for (const i of t.querySelectorAll("[role]")) {
2663
- if (m(i)) continue;
2844
+ if (p(i)) continue;
2664
2845
  const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
2665
2846
  if (!n) continue;
2666
- const r = J(i);
2847
+ const r = le(i);
2667
2848
  if (r && n === r) continue;
2668
- const o = ea(i);
2849
+ const o = fa(i);
2669
2850
  o === "none" ? a.push({
2670
2851
  ruleId: "aria-allowed-role",
2671
- selector: c(i),
2672
- html: l(i),
2852
+ selector: d(i),
2853
+ html: u(i),
2673
2854
  impact: "minor",
2674
2855
  message: `Element <${i.tagName.toLowerCase()}> should not have an explicit role.`
2675
2856
  }) : o !== "any" && !o.has(n) && a.push({
2676
2857
  ruleId: "aria-allowed-role",
2677
- selector: c(i),
2678
- html: l(i),
2858
+ selector: d(i),
2859
+ html: u(i),
2679
2860
  impact: "minor",
2680
2861
  message: `Role "${n}" is not allowed on element <${i.tagName.toLowerCase()}>.`
2681
2862
  });
2682
2863
  }
2683
2864
  return a;
2684
2865
  }
2685
- }, K = {
2866
+ }, ee = {
2686
2867
  // Each array is an OR group - at least one of each inner array must be present
2687
2868
  combobox: [["listbox", "tree", "grid", "dialog", "textbox"]],
2688
2869
  // Must own/contain one of these
@@ -2699,7 +2880,7 @@ const ta = {
2699
2880
  tablist: [["tab"]],
2700
2881
  tree: [["treeitem", "group"]],
2701
2882
  treegrid: [["row", "rowgroup"]]
2702
- }, Y = {
2883
+ }, te = {
2703
2884
  caption: ["figure", "table", "grid", "treegrid"],
2704
2885
  // cell/gridcell/columnheader/rowheader must be in a row
2705
2886
  // but we skip checking native td/th since they're handled by HTML semantics
@@ -2713,25 +2894,25 @@ const ta = {
2713
2894
  tab: ["tablist"],
2714
2895
  treeitem: ["tree", "group"]
2715
2896
  };
2716
- function aa(t, a) {
2897
+ function wa(t, a) {
2717
2898
  var r;
2718
2899
  const e = ((r = t.getAttribute("aria-owns")) == null ? void 0 : r.split(/\s+/)) || [], i = t.ownerDocument, n = /* @__PURE__ */ new Set();
2719
2900
  for (const o of t.querySelectorAll("*")) {
2720
- const s = E(o);
2721
- s && !m(o) && n.add(s);
2901
+ const s = C(o);
2902
+ s && !p(o) && n.add(s);
2722
2903
  }
2723
2904
  for (const o of e) {
2724
2905
  const s = i.getElementById(o);
2725
2906
  if (s) {
2726
- const u = E(s);
2727
- u && !m(s) && n.add(u);
2907
+ const c = C(s);
2908
+ c && !p(s) && n.add(c);
2728
2909
  }
2729
2910
  }
2730
2911
  for (const o of a)
2731
- if (!o.some((u) => n.has(u))) return !1;
2912
+ if (!o.some((c) => n.has(c))) return !1;
2732
2913
  return !0;
2733
2914
  }
2734
- const ia = {
2915
+ const ya = {
2735
2916
  id: "aria-required-children",
2736
2917
  wcag: ["4.1.2"],
2737
2918
  level: "A",
@@ -2742,16 +2923,16 @@ const ia = {
2742
2923
  var e;
2743
2924
  const a = [];
2744
2925
  for (const i of t.querySelectorAll("[role]")) {
2745
- if (m(i)) continue;
2926
+ if (p(i)) continue;
2746
2927
  const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
2747
- if (!n || !(n in K)) continue;
2748
- const r = K[n];
2749
- if (!aa(i, r)) {
2928
+ if (!n || !(n in ee)) continue;
2929
+ const r = ee[n];
2930
+ if (!wa(i, r)) {
2750
2931
  const o = r.map((s) => s.join(" or ")).join(", ");
2751
2932
  a.push({
2752
2933
  ruleId: "aria-required-children",
2753
- selector: c(i),
2754
- html: l(i),
2934
+ selector: d(i),
2935
+ html: u(i),
2755
2936
  impact: "critical",
2756
2937
  message: `Role "${n}" requires children with role: ${o}.`
2757
2938
  });
@@ -2759,7 +2940,7 @@ const ia = {
2759
2940
  }
2760
2941
  return a;
2761
2942
  }
2762
- }, na = {
2943
+ }, Aa = {
2763
2944
  id: "aria-required-parent",
2764
2945
  wcag: ["4.1.2"],
2765
2946
  level: "A",
@@ -2770,14 +2951,14 @@ const ia = {
2770
2951
  var e;
2771
2952
  const a = [];
2772
2953
  for (const i of t.querySelectorAll("[role]")) {
2773
- if (m(i)) continue;
2954
+ if (p(i)) continue;
2774
2955
  const n = (e = i.getAttribute("role")) == null ? void 0 : e.trim().toLowerCase();
2775
- if (!n || !(n in Y)) continue;
2776
- const r = Y[n];
2956
+ if (!n || !(n in te)) continue;
2957
+ const r = te[n];
2777
2958
  let o = i.parentElement, s = !1;
2778
2959
  for (; o && o !== t.documentElement; ) {
2779
- const u = E(o);
2780
- if (u && r.includes(u)) {
2960
+ const c = C(o);
2961
+ if (c && r.includes(c)) {
2781
2962
  s = !0;
2782
2963
  break;
2783
2964
  }
@@ -2785,15 +2966,15 @@ const ia = {
2785
2966
  }
2786
2967
  s || a.push({
2787
2968
  ruleId: "aria-required-parent",
2788
- selector: c(i),
2789
- html: l(i),
2969
+ selector: d(i),
2970
+ html: u(i),
2790
2971
  impact: "critical",
2791
2972
  message: `Role "${n}" must be contained within: ${r.join(", ")}.`
2792
2973
  });
2793
2974
  }
2794
2975
  return a;
2795
2976
  }
2796
- }, ra = [
2977
+ }, ae = [
2797
2978
  "a[href]",
2798
2979
  "button:not([disabled])",
2799
2980
  'input:not([disabled]):not([type="hidden"])',
@@ -2809,7 +2990,7 @@ const ia = {
2809
2990
  "embed",
2810
2991
  "area[href]"
2811
2992
  ].join(", ");
2812
- function oa(t) {
2993
+ function Sa(t) {
2813
2994
  let a = t;
2814
2995
  const e = t.ownerDocument, i = e.defaultView;
2815
2996
  for (; a && a !== e.body; ) {
@@ -2822,7 +3003,7 @@ function oa(t) {
2822
3003
  }
2823
3004
  return !0;
2824
3005
  }
2825
- const sa = {
3006
+ const xa = {
2826
3007
  id: "aria-hidden-body",
2827
3008
  selector: 'body[aria-hidden="true"]',
2828
3009
  check: { type: "selector-exists" },
@@ -2834,7 +3015,7 @@ const sa = {
2834
3015
  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.",
2835
3016
  prompt: "Instruct to remove aria-hidden='true' from the body element.",
2836
3017
  skipAriaHidden: !1
2837
- }, la = k(sa), ca = {
3018
+ }, ka = k(xa), Ia = {
2838
3019
  id: "aria-hidden-focus",
2839
3020
  wcag: ["4.1.2"],
2840
3021
  level: "A",
@@ -2845,14 +3026,15 @@ const sa = {
2845
3026
  const a = [];
2846
3027
  for (const e of t.querySelectorAll('[aria-hidden="true"]')) {
2847
3028
  if (e === t.body) continue;
2848
- const i = e.querySelectorAll(ra);
3029
+ const i = [...e.querySelectorAll(ae)];
3030
+ e.matches(ae) && i.push(e);
2849
3031
  for (const n of i)
2850
3032
  if (n instanceof HTMLElement) {
2851
- if (n.getAttribute("tabindex") === "-1" || n.disabled || n instanceof HTMLInputElement && n.type === "hidden" || !oa(n)) continue;
3033
+ if (n.getAttribute("tabindex") === "-1" || n.disabled || n instanceof HTMLInputElement && n.type === "hidden" || !Sa(n)) continue;
2852
3034
  a.push({
2853
3035
  ruleId: "aria-hidden-focus",
2854
- selector: c(n),
2855
- html: l(n),
3036
+ selector: d(n),
3037
+ html: u(n),
2856
3038
  impact: "serious",
2857
3039
  message: "Focusable element is inside an aria-hidden region."
2858
3040
  });
@@ -2860,7 +3042,7 @@ const sa = {
2860
3042
  }
2861
3043
  return a;
2862
3044
  }
2863
- }, da = {
3045
+ }, Ea = {
2864
3046
  id: "aria-command-name",
2865
3047
  wcag: ["4.1.2"],
2866
3048
  level: "A",
@@ -2871,14 +3053,14 @@ const sa = {
2871
3053
  var e;
2872
3054
  const a = [];
2873
3055
  for (const i of t.querySelectorAll('[role="button"], [role="link"], [role="menuitem"]')) {
2874
- if (m(i) || i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") continue;
2875
- if (!b(i)) {
3056
+ if (p(i) || i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") continue;
3057
+ if (!v(i)) {
2876
3058
  const r = i.querySelector("img[alt]");
2877
3059
  if ((e = r == null ? void 0 : r.getAttribute("alt")) != null && e.trim()) continue;
2878
3060
  a.push({
2879
3061
  ruleId: "aria-command-name",
2880
- selector: c(i),
2881
- html: l(i),
3062
+ selector: d(i),
3063
+ html: u(i),
2882
3064
  impact: "serious",
2883
3065
  message: "ARIA command has no accessible name."
2884
3066
  });
@@ -2886,7 +3068,7 @@ const sa = {
2886
3068
  }
2887
3069
  return a;
2888
3070
  }
2889
- }, ua = {
3071
+ }, Ta = {
2890
3072
  id: "aria-input-field-name",
2891
3073
  wcag: ["4.1.2"],
2892
3074
  level: "A",
@@ -2896,18 +3078,18 @@ const sa = {
2896
3078
  run(t) {
2897
3079
  const a = [], e = '[role="combobox"], [role="listbox"], [role="searchbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
2898
3080
  for (const i of t.querySelectorAll(e)) {
2899
- if (m(i) || i.matches("input, select, textarea")) continue;
2900
- b(i) || a.push({
3081
+ if (p(i) || i.matches("input, select, textarea")) continue;
3082
+ v(i) || a.push({
2901
3083
  ruleId: "aria-input-field-name",
2902
- selector: c(i),
2903
- html: l(i),
3084
+ selector: d(i),
3085
+ html: u(i),
2904
3086
  impact: "serious",
2905
3087
  message: "ARIA input field has no accessible name."
2906
3088
  });
2907
3089
  }
2908
3090
  return a;
2909
3091
  }
2910
- }, ma = {
3092
+ }, La = {
2911
3093
  id: "aria-toggle-field-name",
2912
3094
  wcag: ["4.1.2"],
2913
3095
  level: "A",
@@ -2917,18 +3099,18 @@ const sa = {
2917
3099
  run(t) {
2918
3100
  const a = [], e = '[role="checkbox"], [role="switch"], [role="radio"], [role="menuitemcheckbox"], [role="menuitemradio"]';
2919
3101
  for (const i of t.querySelectorAll(e)) {
2920
- if (m(i) || i.matches('input[type="checkbox"], input[type="radio"]')) continue;
2921
- b(i) || a.push({
3102
+ if (p(i) || i.matches('input[type="checkbox"], input[type="radio"]')) continue;
3103
+ v(i) || a.push({
2922
3104
  ruleId: "aria-toggle-field-name",
2923
- selector: c(i),
2924
- html: l(i),
3105
+ selector: d(i),
3106
+ html: u(i),
2925
3107
  impact: "serious",
2926
3108
  message: "ARIA toggle field has no accessible name."
2927
3109
  });
2928
3110
  }
2929
3111
  return a;
2930
3112
  }
2931
- }, pa = {
3113
+ }, Ca = {
2932
3114
  id: "aria-meter-name",
2933
3115
  wcag: ["4.1.2"],
2934
3116
  level: "A",
@@ -2938,18 +3120,18 @@ const sa = {
2938
3120
  run(t) {
2939
3121
  const a = [];
2940
3122
  for (const e of t.querySelectorAll('[role="meter"], meter')) {
2941
- if (m(e)) continue;
2942
- b(e) || a.push({
3123
+ if (p(e)) continue;
3124
+ v(e) || a.push({
2943
3125
  ruleId: "aria-meter-name",
2944
- selector: c(e),
2945
- html: l(e),
3126
+ selector: d(e),
3127
+ html: u(e),
2946
3128
  impact: "serious",
2947
3129
  message: "Meter has no accessible name."
2948
3130
  });
2949
3131
  }
2950
3132
  return a;
2951
3133
  }
2952
- }, ha = {
3134
+ }, qa = {
2953
3135
  id: "aria-progressbar-name",
2954
3136
  wcag: ["4.1.2"],
2955
3137
  level: "A",
@@ -2959,18 +3141,18 @@ const sa = {
2959
3141
  run(t) {
2960
3142
  const a = [];
2961
3143
  for (const e of t.querySelectorAll('[role="progressbar"], progress')) {
2962
- if (m(e)) continue;
2963
- b(e) || a.push({
3144
+ if (p(e)) continue;
3145
+ v(e) || a.push({
2964
3146
  ruleId: "aria-progressbar-name",
2965
- selector: c(e),
2966
- html: l(e),
3147
+ selector: d(e),
3148
+ html: u(e),
2967
3149
  impact: "serious",
2968
3150
  message: "Progressbar has no accessible name."
2969
3151
  });
2970
3152
  }
2971
3153
  return a;
2972
3154
  }
2973
- }, ga = {
3155
+ }, Ra = {
2974
3156
  id: "aria-dialog-name",
2975
3157
  wcag: ["4.1.2"],
2976
3158
  level: "A",
@@ -2980,18 +3162,18 @@ const sa = {
2980
3162
  run(t) {
2981
3163
  const a = [];
2982
3164
  for (const e of t.querySelectorAll('[role="dialog"], [role="alertdialog"], dialog')) {
2983
- if (m(e)) continue;
2984
- b(e) || a.push({
3165
+ if (p(e)) continue;
3166
+ v(e) || a.push({
2985
3167
  ruleId: "aria-dialog-name",
2986
- selector: c(e),
2987
- html: l(e),
3168
+ selector: d(e),
3169
+ html: u(e),
2988
3170
  impact: "serious",
2989
3171
  message: "Dialog has no accessible name."
2990
3172
  });
2991
3173
  }
2992
3174
  return a;
2993
3175
  }
2994
- }, ba = {
3176
+ }, Na = {
2995
3177
  id: "aria-tooltip-name",
2996
3178
  wcag: ["4.1.2"],
2997
3179
  level: "A",
@@ -3001,18 +3183,18 @@ const sa = {
3001
3183
  run(t) {
3002
3184
  const a = [];
3003
3185
  for (const e of t.querySelectorAll('[role="tooltip"]')) {
3004
- if (m(e)) continue;
3005
- b(e) || a.push({
3186
+ if (p(e)) continue;
3187
+ v(e) || a.push({
3006
3188
  ruleId: "aria-tooltip-name",
3007
- selector: c(e),
3008
- html: l(e),
3189
+ selector: d(e),
3190
+ html: u(e),
3009
3191
  impact: "serious",
3010
3192
  message: "Tooltip has no accessible name."
3011
3193
  });
3012
3194
  }
3013
3195
  return a;
3014
3196
  }
3015
- }, fa = {
3197
+ }, Ma = {
3016
3198
  id: "aria-treeitem-name",
3017
3199
  wcag: ["4.1.2"],
3018
3200
  level: "A",
@@ -3022,18 +3204,18 @@ const sa = {
3022
3204
  run(t) {
3023
3205
  const a = [];
3024
3206
  for (const e of t.querySelectorAll('[role="treeitem"]')) {
3025
- if (m(e)) continue;
3026
- b(e) || a.push({
3207
+ if (p(e)) continue;
3208
+ v(e) || a.push({
3027
3209
  ruleId: "aria-treeitem-name",
3028
- selector: c(e),
3029
- html: l(e),
3210
+ selector: d(e),
3211
+ html: u(e),
3030
3212
  impact: "serious",
3031
3213
  message: "Treeitem has no accessible name."
3032
3214
  });
3033
3215
  }
3034
3216
  return a;
3035
3217
  }
3036
- }, va = {
3218
+ }, $a = {
3037
3219
  id: "aria-prohibited-attr",
3038
3220
  wcag: ["4.1.2"],
3039
3221
  level: "A",
@@ -3041,16 +3223,16 @@ const sa = {
3041
3223
  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.",
3042
3224
  prompt: "Identify the prohibited attribute and recommend removing it from this element.",
3043
3225
  run(t) {
3044
- return _(t).prohibitedAttr;
3226
+ return V(t).prohibitedAttr;
3045
3227
  }
3046
- }, wa = [
3228
+ }, Ha = [
3047
3229
  "a[href]",
3048
3230
  "button:not([disabled])",
3049
3231
  'input:not([disabled]):not([type="hidden"])',
3050
3232
  "select:not([disabled])",
3051
3233
  "textarea:not([disabled])",
3052
3234
  '[tabindex]:not([tabindex="-1"])'
3053
- ].join(", "), ya = [
3235
+ ].join(", "), Da = [
3054
3236
  "aria-atomic",
3055
3237
  "aria-busy",
3056
3238
  "aria-controls",
@@ -3064,7 +3246,18 @@ const sa = {
3064
3246
  "aria-live",
3065
3247
  "aria-owns",
3066
3248
  "aria-relevant"
3067
- ], Aa = {
3249
+ ];
3250
+ function ie(t) {
3251
+ const a = [];
3252
+ t.matches(Ha) && a.push("element is focusable");
3253
+ for (const e of Da)
3254
+ if (t.hasAttribute(e)) {
3255
+ a.push(`has ${e}`);
3256
+ break;
3257
+ }
3258
+ return (t.hasAttribute("aria-label") || t.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
3259
+ }
3260
+ const Oa = {
3068
3261
  id: "presentation-role-conflict",
3069
3262
  wcag: ["4.1.2"],
3070
3263
  level: "A",
@@ -3074,25 +3267,30 @@ const sa = {
3074
3267
  run(t) {
3075
3268
  const a = [];
3076
3269
  for (const e of t.querySelectorAll('[role="presentation"], [role="none"]')) {
3077
- if (m(e)) continue;
3078
- const i = [];
3079
- e.matches(wa) && i.push("element is focusable");
3080
- for (const n of ya)
3081
- if (e.hasAttribute(n)) {
3082
- i.push(`has ${n}`);
3083
- break;
3084
- }
3085
- (e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && i.push("has accessible name"), i.length > 0 && a.push({
3270
+ if (p(e)) continue;
3271
+ const i = ie(e);
3272
+ i.length > 0 && a.push({
3086
3273
  ruleId: "presentation-role-conflict",
3087
- selector: c(e),
3088
- html: l(e),
3274
+ selector: d(e),
3275
+ html: u(e),
3089
3276
  impact: "serious",
3090
3277
  message: `Presentation role conflicts with: ${i.join(", ")}. The role will be ignored.`
3091
3278
  });
3092
3279
  }
3280
+ for (const e of t.querySelectorAll('img[alt=""]')) {
3281
+ if (p(e) || e.hasAttribute("role")) continue;
3282
+ const i = ie(e);
3283
+ i.length > 0 && a.push({
3284
+ ruleId: "presentation-role-conflict",
3285
+ selector: d(e),
3286
+ html: u(e),
3287
+ impact: "serious",
3288
+ message: `Element with implicit presentation role (alt="") conflicts with: ${i.join(", ")}. The decorative role will be ignored.`
3289
+ });
3290
+ }
3093
3291
  return a;
3094
3292
  }
3095
- }, Sa = {
3293
+ }, Ba = {
3096
3294
  id: "summary-name",
3097
3295
  wcag: ["4.1.2"],
3098
3296
  level: "A",
@@ -3101,12 +3299,12 @@ const sa = {
3101
3299
  prompt: "Based on the surrounding context or details content, suggest text to add inside the <summary> element.",
3102
3300
  run(t) {
3103
3301
  const a = [];
3104
- for (const e of t.querySelectorAll("summary")) {
3105
- if (m(e)) continue;
3106
- b(e) || a.push({
3302
+ for (const e of t.querySelectorAll("details > summary:first-of-type")) {
3303
+ if (p(e)) continue;
3304
+ v(e) || a.push({
3107
3305
  ruleId: "summary-name",
3108
- selector: c(e),
3109
- html: l(e),
3306
+ selector: d(e),
3307
+ html: u(e),
3110
3308
  impact: "serious",
3111
3309
  message: "<summary> element has no accessible name. Add descriptive text."
3112
3310
  });
@@ -3114,7 +3312,7 @@ const sa = {
3114
3312
  return a;
3115
3313
  }
3116
3314
  };
3117
- function xa(t) {
3315
+ function Wa(t) {
3118
3316
  var n, r;
3119
3317
  const a = [], e = t.getAttribute("href");
3120
3318
  e && a.push(`href: ${e}`);
@@ -3131,7 +3329,7 @@ function xa(t) {
3131
3329
  return a.length > 0 ? a.join(`
3132
3330
  `) : void 0;
3133
3331
  }
3134
- const ka = {
3332
+ const _a = {
3135
3333
  id: "link-name",
3136
3334
  wcag: ["2.4.4", "4.1.2"],
3137
3335
  level: "A",
@@ -3140,20 +3338,20 @@ const ka = {
3140
3338
  prompt: "Based on the href or surrounding context, suggest descriptive link text or an aria-label.",
3141
3339
  run(t) {
3142
3340
  const a = [];
3143
- for (const e of t.querySelectorAll('a[href], [role="link"]')) {
3144
- if (m(e)) continue;
3145
- b(e) || a.push({
3341
+ for (const e of t.querySelectorAll('a[href], area[href], [role="link"]')) {
3342
+ if (p(e)) continue;
3343
+ v(e) || a.push({
3146
3344
  ruleId: "link-name",
3147
- selector: c(e),
3148
- html: l(e),
3345
+ selector: d(e),
3346
+ html: u(e),
3149
3347
  impact: "serious",
3150
3348
  message: "Link has no discernible text.",
3151
- context: xa(e)
3349
+ context: Wa(e)
3152
3350
  });
3153
3351
  }
3154
3352
  return a;
3155
3353
  }
3156
- }, Ia = {
3354
+ }, Fa = {
3157
3355
  id: "skip-link",
3158
3356
  wcag: ["2.4.1"],
3159
3357
  level: "A",
@@ -3171,15 +3369,105 @@ const ka = {
3171
3369
  const s = n.slice(1);
3172
3370
  t.getElementById(s) || a.push({
3173
3371
  ruleId: "skip-link",
3174
- selector: c(i),
3175
- html: l(i),
3372
+ selector: d(i),
3373
+ html: u(i),
3176
3374
  impact: "moderate",
3177
3375
  message: `Skip link points to "#${s}" which does not exist on the page.`
3178
3376
  });
3179
3377
  }
3180
3378
  return a;
3181
3379
  }
3182
- }, qa = {
3380
+ }, ja = /* @__PURE__ */ new Set([
3381
+ "block",
3382
+ "flex",
3383
+ "grid",
3384
+ "table",
3385
+ "table-cell",
3386
+ "list-item",
3387
+ "flow-root"
3388
+ ]), Pa = /* @__PURE__ */ new Set([
3389
+ "inline",
3390
+ "inline-block",
3391
+ "inline-flex",
3392
+ "inline-grid"
3393
+ ]);
3394
+ function Va(t) {
3395
+ let a = t.parentElement;
3396
+ for (; a; ) {
3397
+ const e = A(a).display;
3398
+ if (ja.has(e) && za(a))
3399
+ return a;
3400
+ a = a.parentElement;
3401
+ }
3402
+ return null;
3403
+ }
3404
+ function za(t) {
3405
+ const a = t.ownerDocument.createTreeWalker(
3406
+ t,
3407
+ NodeFilter.SHOW_TEXT
3408
+ );
3409
+ let e;
3410
+ for (; e = a.nextNode(); ) {
3411
+ if (!e.data.trim()) continue;
3412
+ let i = e.parentElement, n = !1;
3413
+ for (; i && i !== t; ) {
3414
+ if (i.tagName === "A") {
3415
+ n = !0;
3416
+ break;
3417
+ }
3418
+ i = i.parentElement;
3419
+ }
3420
+ if (!n) return !0;
3421
+ }
3422
+ return !1;
3423
+ }
3424
+ function Ua(t, a) {
3425
+ const e = t.ownerDocument.createTreeWalker(
3426
+ t,
3427
+ NodeFilter.SHOW_TEXT
3428
+ );
3429
+ let i;
3430
+ for (; i = e.nextNode(); ) {
3431
+ if (!i.data.trim()) continue;
3432
+ let n = i.parentElement, r = !1, o = n;
3433
+ for (; o && o !== t; ) {
3434
+ if (o.tagName === "A") {
3435
+ r = !0;
3436
+ break;
3437
+ }
3438
+ o = o.parentElement;
3439
+ }
3440
+ if (!r && n)
3441
+ return R(A(n).color);
3442
+ }
3443
+ return null;
3444
+ }
3445
+ function Ga(t, a) {
3446
+ const e = t.textDecorationLine || t.textDecoration || "", i = a.textDecorationLine || a.textDecoration || "";
3447
+ if ((e.includes("underline") || e.includes("line-through")) && e !== i)
3448
+ return !0;
3449
+ const n = parseFloat(t.borderBottomWidth) || 0, r = t.borderBottomStyle || "";
3450
+ if (n > 0 && r !== "none" && r !== "hidden")
3451
+ return !0;
3452
+ const o = parseFloat(t.outlineWidth) || 0, s = t.outlineStyle || "";
3453
+ if (o > 0 && s !== "none")
3454
+ return !0;
3455
+ const c = t.backgroundImage || "";
3456
+ if (c && c !== "none" && c !== "initial")
3457
+ return !0;
3458
+ const h = ne(t.fontWeight), l = ne(a.fontWeight);
3459
+ if (Math.abs(h - l) >= 300 || t.fontStyle !== a.fontStyle)
3460
+ return !0;
3461
+ const m = parseFloat(t.fontSize) || 16, g = parseFloat(a.fontSize) || 16;
3462
+ return g > 0 && m / g >= 1.2;
3463
+ }
3464
+ function ne(t) {
3465
+ return t === "bold" ? 700 : t === "normal" ? 400 : parseInt(t) || 400;
3466
+ }
3467
+ function re(t, a, e) {
3468
+ return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
3469
+ }
3470
+ const Xa = {
3183
3471
  id: "link-in-text-block",
3184
3472
  wcag: ["1.4.1"],
3185
3473
  level: "A",
@@ -3189,24 +3477,30 @@ const ka = {
3189
3477
  run(t) {
3190
3478
  const a = [];
3191
3479
  for (const e of t.querySelectorAll("a[href]")) {
3192
- if (m(e)) continue;
3193
- const i = e.parentElement;
3194
- if (!i) continue;
3195
- const n = i.textContent || "", r = e.textContent || "";
3196
- if (n.length > r.length + 20) {
3197
- const o = e.getAttribute("style") || "";
3198
- o.includes("text-decoration") && o.includes("none") && a.push({
3199
- ruleId: "link-in-text-block",
3200
- selector: c(e),
3201
- html: l(e),
3202
- impact: "serious",
3203
- message: "Link in text block has no underline. Add text-decoration or other non-color indicator."
3204
- });
3205
- }
3480
+ if (p(e) || !y(e).trim()) continue;
3481
+ const i = A(e), n = i.display || "inline";
3482
+ if (!Pa.has(n)) continue;
3483
+ const r = Va(e);
3484
+ if (!r) continue;
3485
+ const o = A(r);
3486
+ if (Ga(i, o)) continue;
3487
+ const s = R(i.color), c = Ua(r);
3488
+ if (!s || !c) continue;
3489
+ const h = q(...s), l = q(...c), m = ce(h, l);
3490
+ if (m >= 3) continue;
3491
+ const g = re(...s), b = re(...c), f = `link color: ${g} rgb(${s.join(", ")}), surrounding text: ${b} rgb(${c.join(", ")}), ratio: ${m.toFixed(2)}:1`;
3492
+ a.push({
3493
+ ruleId: "link-in-text-block",
3494
+ selector: d(e),
3495
+ html: u(e),
3496
+ impact: "serious",
3497
+ 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.",
3498
+ context: f
3499
+ });
3206
3500
  }
3207
3501
  return a;
3208
3502
  }
3209
- }, Ca = {
3503
+ }, Ya = {
3210
3504
  id: "html-has-lang",
3211
3505
  wcag: ["3.1.1"],
3212
3506
  level: "A",
@@ -3216,15 +3510,32 @@ const ka = {
3216
3510
  run(t) {
3217
3511
  var e;
3218
3512
  const a = t.documentElement;
3513
+ if (a.tagName.toLowerCase() !== "html") return [];
3514
+ if (!t.doctype && t.body) {
3515
+ const i = t.body.children;
3516
+ if (i.length > 0 && Array.from(i).every(
3517
+ (n) => n.tagName.toLowerCase() === "svg" || n.tagName.toLowerCase() === "math"
3518
+ )) return [];
3519
+ }
3219
3520
  return (e = a.getAttribute("lang")) != null && e.trim() ? [] : [{
3220
3521
  ruleId: "html-has-lang",
3221
- selector: c(a),
3222
- html: l(a),
3522
+ selector: d(a),
3523
+ html: u(a),
3223
3524
  impact: "serious",
3224
3525
  message: "<html> element missing lang attribute."
3225
3526
  }];
3226
3527
  }
3227
- }, ee = /^[a-z]{2,3}(-[a-z0-9]{2,8})*$/i, Ta = {
3528
+ }, Ka = new Set(
3529
+ "aa ab ae af ak am an ar as av ay az ba be bg bh bi bm bn bo br bs ca ce ch co cr cs cu cv cy da de dv dz ee el en eo es et eu fa ff fi fj fo fr fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pi pl ps pt qu rm rn ro ru rw sa sc sd se sg si sk sl sm sn so sq sr ss st su sv sw ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zu".split(" ")
3530
+ ), Qa = new Set(
3531
+ "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(" ")
3532
+ ), Ja = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
3533
+ function ue(t) {
3534
+ if (!Ja.test(t)) return !1;
3535
+ const a = t.split("-")[0].toLowerCase();
3536
+ return a.length === 2 ? Ka.has(a) : a.length === 3 ? !Qa.has(a) : !1;
3537
+ }
3538
+ const Za = {
3228
3539
  id: "html-lang-valid",
3229
3540
  wcag: ["3.1.1"],
3230
3541
  level: "A",
@@ -3234,15 +3545,48 @@ const ka = {
3234
3545
  run(t) {
3235
3546
  var e;
3236
3547
  const a = (e = t.documentElement.getAttribute("lang")) == null ? void 0 : e.trim();
3237
- return a && !ee.test(a) ? [{
3548
+ return a && !ue(a) ? [{
3238
3549
  ruleId: "html-lang-valid",
3239
3550
  selector: "html",
3240
- html: l(t.documentElement),
3551
+ html: u(t.documentElement),
3241
3552
  impact: "serious",
3242
3553
  message: `Invalid lang attribute value "${a}".`
3243
3554
  }] : [];
3244
3555
  }
3245
- }, Ea = {
3556
+ };
3557
+ function oe(t) {
3558
+ var i;
3559
+ const a = t.ownerDocument.createTreeWalker(t, NodeFilter.SHOW_TEXT);
3560
+ let e;
3561
+ for (; e = a.nextNode(); ) {
3562
+ if (!e.data.trim()) continue;
3563
+ const n = e.parentElement;
3564
+ if (!n || n instanceof HTMLElement && (n.hidden || n.style.display === "none")) continue;
3565
+ let r = n, o = !1;
3566
+ for (; r && r !== t; ) {
3567
+ if (r.hasAttribute("lang")) {
3568
+ o = !0;
3569
+ break;
3570
+ }
3571
+ r = r.parentElement;
3572
+ }
3573
+ if (!o) return !0;
3574
+ }
3575
+ for (const n of t.querySelectorAll("img[alt]")) {
3576
+ if (!((i = n.getAttribute("alt")) == null ? void 0 : i.trim())) continue;
3577
+ let o = n.parentElement, s = !1;
3578
+ for (; o && o !== t; ) {
3579
+ if (o.hasAttribute("lang")) {
3580
+ s = !0;
3581
+ break;
3582
+ }
3583
+ o = o.parentElement;
3584
+ }
3585
+ if (!s) return !0;
3586
+ }
3587
+ return !1;
3588
+ }
3589
+ const ei = {
3246
3590
  id: "valid-lang",
3247
3591
  wcag: ["3.1.2"],
3248
3592
  level: "AA",
@@ -3250,22 +3594,31 @@ const ka = {
3250
3594
  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.",
3251
3595
  prompt: "Identify the content's language and suggest the correct BCP 47 tag.",
3252
3596
  run(t) {
3253
- var e;
3254
3597
  const a = [];
3255
- for (const i of t.querySelectorAll("[lang]")) {
3256
- if (m(i) || i === t.documentElement) continue;
3257
- const n = (e = i.getAttribute("lang")) == null ? void 0 : e.trim();
3258
- n && !ee.test(n) && a.push({
3598
+ for (const e of t.querySelectorAll("[lang]")) {
3599
+ if (p(e) || e === t.documentElement) continue;
3600
+ const i = e.getAttribute("lang"), n = i == null ? void 0 : i.trim();
3601
+ if (i && !n) {
3602
+ oe(e) && a.push({
3603
+ ruleId: "valid-lang",
3604
+ selector: d(e),
3605
+ html: u(e),
3606
+ impact: "serious",
3607
+ message: "Empty lang attribute value."
3608
+ });
3609
+ continue;
3610
+ }
3611
+ n && oe(e) && (ue(n) || a.push({
3259
3612
  ruleId: "valid-lang",
3260
- selector: c(i),
3261
- html: l(i),
3613
+ selector: d(e),
3614
+ html: u(e),
3262
3615
  impact: "serious",
3263
3616
  message: `Invalid lang attribute value "${n}".`
3264
- });
3617
+ }));
3265
3618
  }
3266
3619
  return a;
3267
3620
  }
3268
- }, La = {
3621
+ }, ti = {
3269
3622
  id: "html-xml-lang-mismatch",
3270
3623
  wcag: ["3.1.1"],
3271
3624
  level: "A",
@@ -3281,14 +3634,14 @@ const ka = {
3281
3634
  return [{
3282
3635
  ruleId: "html-xml-lang-mismatch",
3283
3636
  selector: "html",
3284
- html: l(a),
3637
+ html: u(a),
3285
3638
  impact: "moderate",
3286
3639
  message: `lang="${e}" and xml:lang="${i}" do not match.`
3287
3640
  }];
3288
3641
  }
3289
3642
  return [];
3290
3643
  }
3291
- }, Ra = {
3644
+ }, ai = {
3292
3645
  id: "td-headers-attr",
3293
3646
  wcag: ["1.3.1"],
3294
3647
  level: "A",
@@ -3298,25 +3651,36 @@ const ka = {
3298
3651
  run(t) {
3299
3652
  const a = [];
3300
3653
  for (const e of t.querySelectorAll("td[headers]")) {
3301
- if (m(e)) continue;
3654
+ if (p(e)) continue;
3302
3655
  const i = e.closest("table");
3303
3656
  if (!i) continue;
3304
- const n = e.getAttribute("headers").split(/\s+/);
3305
- for (const r of n)
3306
- if (!i.querySelector(`th#${CSS.escape(r)}, td#${CSS.escape(r)}`)) {
3657
+ const n = e.getAttribute("id"), r = e.getAttribute("headers").split(/\s+/);
3658
+ for (const o of r) {
3659
+ if (o === n) {
3660
+ a.push({
3661
+ ruleId: "td-headers-attr",
3662
+ selector: d(e),
3663
+ html: u(e),
3664
+ impact: "serious",
3665
+ message: `Headers attribute references the cell itself ("${o}").`
3666
+ });
3667
+ break;
3668
+ }
3669
+ if (!i.querySelector(`th#${CSS.escape(o)}, td#${CSS.escape(o)}`)) {
3307
3670
  a.push({
3308
3671
  ruleId: "td-headers-attr",
3309
- selector: c(e),
3310
- html: l(e),
3672
+ selector: d(e),
3673
+ html: u(e),
3311
3674
  impact: "serious",
3312
- message: `Headers attribute references non-existent ID "${r}".`
3675
+ message: `Headers attribute references non-existent ID "${o}".`
3313
3676
  });
3314
3677
  break;
3315
3678
  }
3679
+ }
3316
3680
  }
3317
3681
  return a;
3318
3682
  }
3319
- }, Na = {
3683
+ }, ii = {
3320
3684
  id: "th-has-data-cells",
3321
3685
  wcag: ["1.3.1"],
3322
3686
  level: "A",
@@ -3326,19 +3690,19 @@ const ka = {
3326
3690
  run(t) {
3327
3691
  const a = [];
3328
3692
  for (const e of t.querySelectorAll("table")) {
3329
- if (m(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none") continue;
3693
+ if (p(e) || e.getAttribute("role") === "presentation" || e.getAttribute("role") === "none") continue;
3330
3694
  const i = e.querySelectorAll("th"), n = e.querySelectorAll("td");
3331
3695
  i.length > 0 && n.length === 0 && a.push({
3332
3696
  ruleId: "th-has-data-cells",
3333
- selector: c(e),
3334
- html: l(e),
3697
+ selector: d(e),
3698
+ html: u(e),
3335
3699
  impact: "serious",
3336
3700
  message: "Table has header cells but no data cells."
3337
3701
  });
3338
3702
  }
3339
3703
  return a;
3340
3704
  }
3341
- }, Ma = {
3705
+ }, ni = {
3342
3706
  id: "td-has-header",
3343
3707
  wcag: ["1.3.1"],
3344
3708
  level: "A",
@@ -3349,39 +3713,39 @@ const ka = {
3349
3713
  var e, i;
3350
3714
  const a = [];
3351
3715
  for (const n of t.querySelectorAll("table")) {
3352
- if (m(n) || n.getAttribute("role") === "presentation" || n.getAttribute("role") === "none") continue;
3716
+ if (p(n) || n.getAttribute("role") === "presentation" || n.getAttribute("role") === "none") continue;
3353
3717
  const r = n.querySelectorAll("tr"), o = r.length;
3354
3718
  let s = 0;
3355
- for (const p of r) {
3356
- const g = p.querySelectorAll("td, th");
3357
- let f = 0;
3358
- for (const v of g)
3359
- f += parseInt(v.getAttribute("colspan") || "1", 10);
3360
- s = Math.max(s, f);
3719
+ for (const m of r) {
3720
+ const g = m.querySelectorAll("td, th");
3721
+ let b = 0;
3722
+ for (const f of g)
3723
+ b += parseInt(f.getAttribute("colspan") || "1", 10);
3724
+ s = Math.max(s, b);
3361
3725
  }
3362
3726
  if (o <= 3 && s <= 3) continue;
3363
- const u = n.querySelector("th") !== null, h = n.querySelector("th[scope]") !== null, d = n.querySelector("td[headers]") !== null;
3364
- if (u)
3365
- for (const p of n.querySelectorAll("td")) {
3366
- if (m(p) || p.hasAttribute("headers")) continue;
3367
- const g = p.closest("tr");
3727
+ const c = n.querySelector("th") !== null, h = n.querySelector("th[scope]") !== null, l = n.querySelector("td[headers]") !== null;
3728
+ if (c)
3729
+ for (const m of n.querySelectorAll("td")) {
3730
+ if (p(m) || m.hasAttribute("headers")) continue;
3731
+ const g = m.closest("tr");
3368
3732
  if (!g) continue;
3369
- const f = g.querySelector("th") !== null, v = Array.from(g.children).indexOf(p);
3733
+ const b = g.querySelector("th") !== null, f = Array.from(g.children).indexOf(m);
3370
3734
  let w = !1;
3371
- const T = n.querySelector("thead");
3372
- if (T) {
3373
- const A = T.querySelector("tr");
3374
- A && ((e = A.querySelectorAll("th, td")[v]) == null ? void 0 : e.tagName.toLowerCase()) === "th" && (w = !0);
3735
+ const L = n.querySelector("thead");
3736
+ if (L) {
3737
+ const S = L.querySelector("tr");
3738
+ S && ((e = S.querySelectorAll("th, td")[f]) == null ? void 0 : e.tagName.toLowerCase()) === "th" && (w = !0);
3375
3739
  }
3376
3740
  if (!w) {
3377
- const A = n.querySelector("tbody > tr, tr");
3378
- A && ((i = A.querySelectorAll("th, td")[v]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (w = !0);
3741
+ const S = n.querySelector("tbody > tr, tr");
3742
+ S && ((i = S.querySelectorAll("th, td")[f]) == null ? void 0 : i.tagName.toLowerCase()) === "th" && (w = !0);
3379
3743
  }
3380
- if (!f && !w && !h && !d) {
3744
+ if (!b && !w && !h && !l) {
3381
3745
  a.push({
3382
3746
  ruleId: "td-has-header",
3383
- selector: c(p),
3384
- html: l(p),
3747
+ selector: d(m),
3748
+ html: u(m),
3385
3749
  impact: "serious",
3386
3750
  message: "Data cell has no associated header. Add th elements with scope, or headers attribute."
3387
3751
  });
@@ -3391,7 +3755,7 @@ const ka = {
3391
3755
  }
3392
3756
  return a;
3393
3757
  }
3394
- }, $a = {
3758
+ }, ri = {
3395
3759
  id: "scope-attr-valid",
3396
3760
  wcag: ["1.3.1"],
3397
3761
  level: "A",
@@ -3402,19 +3766,19 @@ const ka = {
3402
3766
  var i;
3403
3767
  const a = [], e = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
3404
3768
  for (const n of t.querySelectorAll("th[scope]")) {
3405
- if (m(n)) continue;
3769
+ if (p(n)) continue;
3406
3770
  const r = (i = n.getAttribute("scope")) == null ? void 0 : i.toLowerCase();
3407
3771
  r && !e.has(r) && a.push({
3408
3772
  ruleId: "scope-attr-valid",
3409
- selector: c(n),
3410
- html: l(n),
3773
+ selector: d(n),
3774
+ html: u(n),
3411
3775
  impact: "moderate",
3412
3776
  message: `Invalid scope value "${r}". Use row, col, rowgroup, or colgroup.`
3413
3777
  });
3414
3778
  }
3415
3779
  return a;
3416
3780
  }
3417
- }, Ha = {
3781
+ }, oi = {
3418
3782
  id: "empty-table-header",
3419
3783
  wcag: [],
3420
3784
  level: "A",
@@ -3425,19 +3789,19 @@ const ka = {
3425
3789
  run(t) {
3426
3790
  const a = [];
3427
3791
  for (const e of t.querySelectorAll("th")) {
3428
- if (m(e)) continue;
3792
+ if (p(e)) continue;
3429
3793
  const i = e.closest("table");
3430
- (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || b(e) || a.push({
3794
+ (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || v(e) || a.push({
3431
3795
  ruleId: "empty-table-header",
3432
- selector: c(e),
3433
- html: l(e),
3796
+ selector: d(e),
3797
+ html: u(e),
3434
3798
  impact: "minor",
3435
3799
  message: "Table header cell is empty. Add text or use aria-label."
3436
3800
  });
3437
3801
  }
3438
3802
  return a;
3439
3803
  }
3440
- }, N = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], Da = {
3804
+ }, H = ["aria-labelledby", "aria-describedby", "aria-controls", "aria-owns", "aria-flowto"], si = {
3441
3805
  id: "duplicate-id-aria",
3442
3806
  wcag: ["4.1.2"],
3443
3807
  level: "A",
@@ -3447,7 +3811,7 @@ const ka = {
3447
3811
  run(t) {
3448
3812
  const a = [], e = /* @__PURE__ */ new Set();
3449
3813
  for (const n of t.querySelectorAll("[aria-labelledby], [aria-describedby], [aria-controls], [aria-owns], [aria-flowto]"))
3450
- for (const r of N) {
3814
+ for (const r of H) {
3451
3815
  const o = n.getAttribute(r);
3452
3816
  o && o.split(/\s+/).forEach((s) => e.add(s));
3453
3817
  }
@@ -3461,31 +3825,31 @@ const ka = {
3461
3825
  for (const [n, r] of i) {
3462
3826
  if (r <= 1) continue;
3463
3827
  const o = t.querySelectorAll(`#${CSS.escape(n)}`), s = t.querySelector(
3464
- N.map((d) => `[${d}~="${CSS.escape(n)}"]`).join(", ")
3465
- ), u = t.querySelector(`label[for="${CSS.escape(n)}"]`);
3828
+ H.map((l) => `[${l}~="${CSS.escape(n)}"]`).join(", ")
3829
+ ), c = t.querySelector(`label[for="${CSS.escape(n)}"]`);
3466
3830
  let h;
3467
3831
  if (s) {
3468
- const d = N.find(
3469
- (p) => {
3832
+ const l = H.find(
3833
+ (m) => {
3470
3834
  var g;
3471
- return (g = s.getAttribute(p)) == null ? void 0 : g.split(/\s+/).includes(n);
3835
+ return (g = s.getAttribute(m)) == null ? void 0 : g.split(/\s+/).includes(n);
3472
3836
  }
3473
3837
  );
3474
- d && (h = d);
3475
- } else u && (h = "label[for]");
3838
+ l && (h = l);
3839
+ } else c && (h = "label[for]");
3476
3840
  a.push({
3477
3841
  ruleId: "duplicate-id-aria",
3478
- selector: c(o[1]),
3479
- html: l(o[1]),
3842
+ selector: d(o[1]),
3843
+ html: u(o[1]),
3480
3844
  impact: "critical",
3481
3845
  message: `Duplicate ID "${n}" referenced by ${h ?? "an accessibility attribute"}.`,
3482
- context: `First element: ${l(o[0])}${h ? `
3846
+ context: `First element: ${u(o[0])}${h ? `
3483
3847
  Referenced by: ${h}` : ""}`
3484
3848
  });
3485
3849
  }
3486
3850
  return a;
3487
3851
  }
3488
- }, Oa = {
3852
+ }, li = {
3489
3853
  id: "video-caption",
3490
3854
  wcag: ["1.2.2"],
3491
3855
  level: "A",
@@ -3495,18 +3859,18 @@ Referenced by: ${h}` : ""}`
3495
3859
  run(t) {
3496
3860
  const a = [];
3497
3861
  for (const e of t.querySelectorAll("video")) {
3498
- if (m(e) || e.hasAttribute("muted") || e.hasAttribute("autoplay")) continue;
3862
+ if (p(e) || e.hasAttribute("muted") || e.hasAttribute("autoplay")) continue;
3499
3863
  e.querySelector('track[kind="captions"], track[kind="subtitles"]') || a.push({
3500
3864
  ruleId: "video-caption",
3501
- selector: c(e),
3502
- html: l(e),
3865
+ selector: d(e),
3866
+ html: u(e),
3503
3867
  impact: "critical",
3504
3868
  message: "Video element has no captions track."
3505
3869
  });
3506
3870
  }
3507
3871
  return a;
3508
3872
  }
3509
- }, Wa = {
3873
+ }, ci = {
3510
3874
  id: "audio-caption",
3511
3875
  wcag: ["1.2.1"],
3512
3876
  level: "A",
@@ -3516,19 +3880,19 @@ Referenced by: ${h}` : ""}`
3516
3880
  run(t) {
3517
3881
  const a = [];
3518
3882
  for (const e of t.querySelectorAll("audio")) {
3519
- if (m(e) || e.querySelector('track[kind="captions"], track[kind="descriptions"]') || e.hasAttribute("aria-describedby")) continue;
3883
+ if (p(e) || e.querySelector('track[kind="captions"], track[kind="descriptions"]') || e.hasAttribute("aria-describedby")) continue;
3520
3884
  const n = e.parentElement;
3521
3885
  n && n.querySelector('a[href*="transcript"], a[href*="text"]') || a.push({
3522
3886
  ruleId: "audio-caption",
3523
- selector: c(e),
3524
- html: l(e),
3887
+ selector: d(e),
3888
+ html: u(e),
3525
3889
  impact: "critical",
3526
3890
  message: "Audio element has no transcript or text alternative. Add a transcript or track element."
3527
3891
  });
3528
3892
  }
3529
3893
  return a;
3530
3894
  }
3531
- }, Ba = /* @__PURE__ */ new Set([
3895
+ }, ui = /* @__PURE__ */ new Set([
3532
3896
  "SCRIPT",
3533
3897
  "STYLE",
3534
3898
  "NOSCRIPT",
@@ -3544,13 +3908,13 @@ Referenced by: ${h}` : ""}`
3544
3908
  "BR",
3545
3909
  "HR"
3546
3910
  ]);
3547
- function Q([t, a, e]) {
3911
+ function se([t, a, e]) {
3548
3912
  return "#" + [t, a, e].map((i) => i.toString(16).padStart(2, "0")).join("");
3549
3913
  }
3550
- function Fa(t) {
3914
+ function di(t) {
3551
3915
  return t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t instanceof HTMLButtonElement ? t.disabled : !!t.closest("fieldset[disabled]");
3552
3916
  }
3553
- function _a(t) {
3917
+ function mi(t) {
3554
3918
  const a = t.clip;
3555
3919
  if (a && a.startsWith("rect(")) {
3556
3920
  const i = a.match(/[\d.]+/g);
@@ -3564,17 +3928,17 @@ function _a(t) {
3564
3928
  }
3565
3929
  return !1;
3566
3930
  }
3567
- function Pa(t) {
3568
- if (m(t)) return !0;
3931
+ function hi(t) {
3932
+ if (p(t)) return !0;
3569
3933
  let a = t;
3570
3934
  for (; a; ) {
3571
- const e = x(a);
3572
- if (e.display === "none" || e.visibility === "hidden" || _a(e)) return !0;
3935
+ const e = A(a);
3936
+ if (e.display === "none" || e.visibility === "hidden" || mi(e)) return !0;
3573
3937
  a = a.parentElement;
3574
3938
  }
3575
3939
  return !1;
3576
3940
  }
3577
- const Va = {
3941
+ const pi = {
3578
3942
  id: "color-contrast",
3579
3943
  wcag: ["1.4.3"],
3580
3944
  level: "AA",
@@ -3589,138 +3953,138 @@ const Va = {
3589
3953
  for (; r = i.nextNode(); ) {
3590
3954
  if (!r.textContent || !r.textContent.trim()) continue;
3591
3955
  const o = r.parentElement;
3592
- if (!o || n.has(o) || (n.add(o), Ba.has(o.tagName)) || Fa(o) || Pa(o)) continue;
3593
- const s = x(o);
3956
+ if (!o || n.has(o) || (n.add(o), ui.has(o.tagName)) || di(o) || hi(o)) continue;
3957
+ const s = A(o);
3594
3958
  if (parseFloat(s.opacity) === 0) continue;
3595
- const u = Z(s.color);
3596
- if (!u) continue;
3959
+ const c = R(s.color);
3960
+ if (!c) continue;
3597
3961
  const h = s.color.match(/rgba\(.+?,\s*([\d.]+)\s*\)/);
3598
- if (h && parseFloat(h[1]) === 0 || Le(o)) continue;
3599
- const d = Ce(o);
3600
- if (!d) continue;
3601
- const p = j(u[0], u[1], u[2]), g = j(d[0], d[1], d[2]), f = qe(p, g), v = Ne(o) ? 3 : 4.5;
3602
- if (f < v) {
3603
- const w = Math.round(f * 100) / 100, T = Q(u), A = Q(d);
3962
+ if (h && parseFloat(h[1]) === 0 || Oe(o)) continue;
3963
+ const l = $e(o);
3964
+ if (!l) continue;
3965
+ const m = q(c[0], c[1], c[2]), g = q(l[0], l[1], l[2]), b = ce(m, g), f = We(o) ? 3 : 4.5;
3966
+ if (b < f) {
3967
+ const w = Math.round(b * 100) / 100, L = se(c), S = se(l);
3604
3968
  a.push({
3605
3969
  ruleId: "color-contrast",
3606
- selector: c(o),
3607
- html: l(o),
3970
+ selector: d(o),
3971
+ html: u(o),
3608
3972
  impact: "serious",
3609
- message: `Insufficient color contrast ratio of ${w}:1 (required ${v}:1).`,
3610
- context: `foreground: ${T} rgb(${u.join(", ")}), background: ${A} rgb(${d.join(", ")}), ratio: ${w}:1, required: ${v}:1`
3973
+ message: `Insufficient color contrast ratio of ${w}:1 (required ${f}:1).`,
3974
+ context: `foreground: ${L} rgb(${c.join(", ")}), background: ${S} rgb(${l.join(", ")}), ratio: ${w}:1, required: ${f}:1`
3611
3975
  });
3612
3976
  }
3613
3977
  }
3614
3978
  return a;
3615
3979
  }
3616
- }, te = [
3980
+ }, de = [
3617
3981
  // Document Structure
3618
- Lt,
3619
- Rt,
3620
- Nt,
3621
- Mt,
3622
- $t,
3623
- Dt,
3624
- Ot,
3625
- Bt,
3626
- _t,
3982
+ Gt,
3983
+ Xt,
3984
+ Yt,
3985
+ Kt,
3986
+ Qt,
3987
+ Zt,
3988
+ ea,
3989
+ aa,
3990
+ na,
3627
3991
  // Images
3628
- $e,
3629
- He,
3630
- De,
3631
- Oe,
3632
- Be,
3633
- Fe,
3634
3992
  _e,
3993
+ je,
3635
3994
  Pe,
3636
- ze,
3637
- // Forms
3995
+ Ve,
3996
+ Ue,
3638
3997
  Ge,
3639
- Xe,
3640
- Ke,
3641
3998
  Ye,
3642
- Je,
3643
- Ze,
3999
+ Ke,
3644
4000
  et,
3645
- // Keyboard
3646
- at,
3647
- nt,
3648
- ut,
3649
- mt,
3650
- pt,
3651
- // Structure
3652
- ht,
3653
- Ht,
3654
- Pt,
4001
+ // Forms
4002
+ rt,
4003
+ ot,
4004
+ st,
4005
+ lt,
3655
4006
  gt,
3656
4007
  bt,
3657
4008
  ft,
3658
- vt,
4009
+ // Keyboard
3659
4010
  wt,
3660
- yt,
3661
4011
  At,
3662
- St,
3663
- xt,
3664
- kt,
3665
- qt,
4012
+ Lt,
3666
4013
  Ct,
3667
- Et,
3668
- // ARIA
4014
+ qt,
4015
+ // Structure
4016
+ Rt,
4017
+ Jt,
4018
+ ra,
4019
+ Nt,
4020
+ Mt,
4021
+ $t,
4022
+ Ht,
4023
+ Dt,
4024
+ Ot,
4025
+ Bt,
4026
+ Wt,
4027
+ _t,
4028
+ Ft,
4029
+ Pt,
3669
4030
  Vt,
3670
4031
  Ut,
3671
- jt,
3672
- Gt,
3673
- Jt,
3674
- ta,
3675
- ia,
3676
- na,
4032
+ // ARIA
4033
+ oa,
4034
+ sa,
3677
4035
  la,
3678
- ca,
3679
- da,
3680
4036
  ua,
3681
- ma,
3682
- pa,
3683
- ha,
3684
4037
  ga,
3685
- ba,
3686
- fa,
3687
4038
  va,
4039
+ ya,
3688
4040
  Aa,
3689
- Kt,
3690
- Sa,
3691
- // Links
3692
4041
  ka,
3693
4042
  Ia,
3694
- qa,
3695
- // Language
3696
- Ca,
3697
- Ta,
3698
4043
  Ea,
4044
+ Ta,
3699
4045
  La,
3700
- // Tables
4046
+ Ca,
4047
+ qa,
3701
4048
  Ra,
3702
4049
  Na,
3703
4050
  Ma,
3704
4051
  $a,
3705
- Ha,
4052
+ Oa,
4053
+ ma,
4054
+ Ba,
4055
+ // Links
4056
+ _a,
4057
+ Fa,
4058
+ Xa,
4059
+ // Language
4060
+ Ya,
4061
+ Za,
4062
+ ei,
4063
+ ti,
4064
+ // Tables
4065
+ ai,
4066
+ ii,
4067
+ ni,
4068
+ ri,
4069
+ oi,
3706
4070
  // Parsing
3707
- Da,
4071
+ si,
3708
4072
  // Media
3709
- Oa,
3710
- Wa,
4073
+ li,
4074
+ ci,
3711
4075
  // Color
3712
- Va
4076
+ pi
3713
4077
  ];
3714
- let P = [], ae = /* @__PURE__ */ new Set();
3715
- function Ga(t) {
3716
- t.additionalRules && (P = t.additionalRules), t.disabledRules && (ae = new Set(t.disabledRules));
4078
+ let z = [], me = /* @__PURE__ */ new Set();
4079
+ function vi(t) {
4080
+ t.additionalRules && (z = t.additionalRules), t.disabledRules && (me = new Set(t.disabledRules));
3717
4081
  }
3718
- function ie() {
3719
- return te.filter((a) => !ae.has(a.id)).concat(P);
4082
+ function he() {
4083
+ return de.filter((a) => !me.has(a.id)).concat(z);
3720
4084
  }
3721
- function Xa(t) {
3722
- ne();
3723
- const a = ie(), e = [];
4085
+ function wi(t) {
4086
+ pe();
4087
+ const a = he(), e = [];
3724
4088
  let i = 0;
3725
4089
  return {
3726
4090
  processChunk(n) {
@@ -3739,13 +4103,13 @@ function Xa(t) {
3739
4103
  }
3740
4104
  };
3741
4105
  }
3742
- function ne() {
3743
- ue(), oe(), se(), Ie(), ke(), pe();
4106
+ function pe() {
4107
+ Ae(), be(), fe(), Me(), Ne(), xe();
3744
4108
  }
3745
- function Ka(t) {
4109
+ function yi(t) {
3746
4110
  var i;
3747
- ne();
3748
- const a = ie(), e = [];
4111
+ pe();
4112
+ const a = he(), e = [];
3749
4113
  for (const n of a)
3750
4114
  try {
3751
4115
  e.push(...n.run(t));
@@ -3758,32 +4122,32 @@ function Ka(t) {
3758
4122
  ruleCount: a.length
3759
4123
  };
3760
4124
  }
3761
- const Ua = new Map(te.map((t) => [t.id, t]));
3762
- function Ya(t) {
3763
- const a = Ua.get(t);
3764
- return a || P.find((e) => e.id === t);
4125
+ const gi = new Map(de.map((t) => [t.id, t]));
4126
+ function Ai(t) {
4127
+ const a = gi.get(t);
4128
+ return a || z.find((e) => e.id === t);
3765
4129
  }
3766
4130
  export {
3767
- ne as clearAllCaches,
3768
- ke as clearAriaAttrAuditCache,
3769
- ue as clearAriaHiddenCache,
3770
- Ie as clearColorCaches,
3771
- oe as clearComputedRoleCache,
4131
+ pe as clearAllCaches,
4132
+ Ne as clearAriaAttrAuditCache,
4133
+ Ae as clearAriaHiddenCache,
4134
+ Me as clearColorCaches,
4135
+ be as clearComputedRoleCache,
3772
4136
  k as compileDeclarativeRule,
3773
- Ga as configureRules,
3774
- Xa as createChunkedAudit,
3775
- b as getAccessibleName,
4137
+ vi as configureRules,
4138
+ wi as createChunkedAudit,
4139
+ v as getAccessibleName,
3776
4140
  y as getAccessibleTextContent,
3777
- ie as getActiveRules,
3778
- E as getComputedRole,
3779
- l as getHtmlSnippet,
3780
- J as getImplicitRole,
3781
- Ya as getRuleById,
3782
- c as getSelector,
3783
- m as isAriaHidden,
3784
- de as isValidRole,
3785
- ja as querySelectorShadowAware,
3786
- te as rules,
3787
- Ka as runAudit,
3788
- za as validateDeclarativeRule
4141
+ he as getActiveRules,
4142
+ C as getComputedRole,
4143
+ u as getHtmlSnippet,
4144
+ le as getImplicitRole,
4145
+ Ai as getRuleById,
4146
+ d as getSelector,
4147
+ p as isAriaHidden,
4148
+ ye as isValidRole,
4149
+ bi as querySelectorShadowAware,
4150
+ de as rules,
4151
+ yi as runAudit,
4152
+ fi as validateDeclarativeRule
3789
4153
  };