@accesslint/core 0.8.0 → 0.8.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.
Files changed (37) hide show
  1. package/README.md +0 -2
  2. package/dist/index.cjs +5 -5
  3. package/dist/index.iife.js +5 -5
  4. package/dist/index.js +281 -243
  5. package/dist/rules/adaptable/empty-table-header.d.ts.map +1 -1
  6. package/dist/rules/adaptable/td-has-header.d.ts.map +1 -1
  7. package/dist/rules/distinguishable/color-contrast-enhanced.d.ts.map +1 -1
  8. package/dist/rules/distinguishable/color-contrast-helpers.d.ts +4 -0
  9. package/dist/rules/distinguishable/color-contrast-helpers.d.ts.map +1 -1
  10. package/dist/rules/distinguishable/color-contrast.d.ts.map +1 -1
  11. package/dist/rules/distinguishable/link-in-text-block.d.ts.map +1 -1
  12. package/dist/rules/distinguishable/meta-viewport.d.ts.map +1 -1
  13. package/dist/rules/engine.d.ts.map +1 -1
  14. package/dist/rules/index.d.ts +5 -0
  15. package/dist/rules/index.d.ts.map +1 -1
  16. package/dist/rules/keyboard-accessible/focus-visible.d.ts.map +1 -1
  17. package/dist/rules/keyboard-accessible/scrollable-region.d.ts.map +1 -1
  18. package/dist/rules/labels-and-names/button-name.d.ts.map +1 -1
  19. package/dist/rules/labels-and-names/form-label.d.ts.map +1 -1
  20. package/dist/rules/labels-and-names/frame-title.d.ts.map +1 -1
  21. package/dist/rules/labels-and-names/input-button-name.d.ts.map +1 -1
  22. package/dist/rules/labels-and-names/label-content-mismatch.d.ts.map +1 -1
  23. package/dist/rules/navigable/empty-heading.d.ts.map +1 -1
  24. package/dist/rules/navigable/heading-order.d.ts.map +1 -1
  25. package/dist/rules/navigable/link-name.d.ts.map +1 -1
  26. package/dist/rules/navigable/p-as-heading.d.ts.map +1 -1
  27. package/dist/rules/text-alternatives/image-alt-words.d.ts.map +1 -1
  28. package/dist/rules/text-alternatives/img-alt.d.ts.map +1 -1
  29. package/dist/rules/text-alternatives/input-image-alt.d.ts.map +1 -1
  30. package/dist/rules/text-alternatives/object-alt.d.ts.map +1 -1
  31. package/dist/rules/text-alternatives/role-img-alt.d.ts.map +1 -1
  32. package/dist/rules/text-alternatives/svg-img-alt.d.ts.map +1 -1
  33. package/dist/rules/time-based-media/audio-transcript.d.ts.map +1 -1
  34. package/dist/rules/time-based-media/video-captions.d.ts.map +1 -1
  35. package/dist/rules/types.d.ts +8 -1
  36. package/dist/rules/types.d.ts.map +1 -1
  37. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const z = [
1
+ const j = [
2
2
  "a[href]",
3
3
  "button:not([disabled])",
4
4
  'input:not([disabled]):not([type="hidden"])',
@@ -133,22 +133,22 @@ function $e(e) {
133
133
  return null;
134
134
  }
135
135
  }
136
- function j(e) {
136
+ function U(e) {
137
137
  var n;
138
138
  const a = K.get(e);
139
139
  if (a !== void 0) return a;
140
140
  const i = ((n = e.getAttribute("role")) == null ? void 0 : n.trim().toLowerCase()) || null || $e(e);
141
141
  return K.set(e, i), i;
142
142
  }
143
- let J = /* @__PURE__ */ new WeakMap();
143
+ let Q = /* @__PURE__ */ new WeakMap();
144
144
  function st() {
145
- J = /* @__PURE__ */ new WeakMap();
145
+ Q = /* @__PURE__ */ new WeakMap();
146
146
  }
147
- function x(e) {
148
- const a = J.get(e);
147
+ function w(e) {
148
+ const a = Q.get(e);
149
149
  if (a !== void 0) return a;
150
150
  const t = lt(e);
151
- return J.set(e, t), t;
151
+ return Q.set(e, t), t;
152
152
  }
153
153
  function lt(e) {
154
154
  var r, o, s, l, d;
@@ -313,22 +313,22 @@ const ut = /* @__PURE__ */ new Set([
313
313
  function q(e) {
314
314
  let a = e;
315
315
  for (; a; ) {
316
- if (De(a)) return !0;
316
+ if (He(a)) return !0;
317
317
  a = a.parentElement;
318
318
  }
319
319
  return !1;
320
320
  }
321
- let Q = /* @__PURE__ */ new WeakMap();
321
+ let Z = /* @__PURE__ */ new WeakMap();
322
322
  function mt() {
323
- Q = /* @__PURE__ */ new WeakMap();
323
+ Z = /* @__PURE__ */ new WeakMap();
324
324
  }
325
325
  function h(e) {
326
- const a = Q.get(e);
326
+ const a = Z.get(e);
327
327
  if (a !== void 0) return a;
328
328
  let t;
329
- return e.getAttribute("aria-hidden") === "true" || e instanceof HTMLElement && (e.hidden || e.style.display === "none") ? t = !0 : e.parentElement ? t = h(e.parentElement) : t = !1, Q.set(e, t), t;
329
+ return e.getAttribute("aria-hidden") === "true" || e instanceof HTMLElement && (e.hidden || e.style.display === "none") ? t = !0 : e.parentElement ? t = h(e.parentElement) : t = !1, Z.set(e, t), t;
330
330
  }
331
- function De(e) {
331
+ function He(e) {
332
332
  if (e.getAttribute("aria-hidden") === "true" || e instanceof HTMLElement && e.hidden) return !0;
333
333
  if (typeof getComputedStyle == "function") {
334
334
  const a = getComputedStyle(e);
@@ -345,7 +345,7 @@ function k(e) {
345
345
  a += s.textContent ?? "";
346
346
  else if (s.nodeType === 1) {
347
347
  const l = s;
348
- if (!De(l)) {
348
+ if (!He(l)) {
349
349
  const d = (t = l.tagName) == null ? void 0 : t.toLowerCase();
350
350
  if (d === "img" || d === "area") {
351
351
  const c = l.getAttribute("aria-labelledby");
@@ -373,7 +373,7 @@ function k(e) {
373
373
  }
374
374
  return a;
375
375
  }
376
- function Z(e) {
376
+ function ee(e) {
377
377
  let a = "";
378
378
  for (const t of e.childNodes)
379
379
  if (t.nodeType === 3)
@@ -383,11 +383,11 @@ function Z(e) {
383
383
  if (n === "style" || n === "script" || n === "svg" || i.getAttribute("aria-hidden") === "true" || i instanceof HTMLElement && i.style.display === "none") continue;
384
384
  const r = i.getAttribute("role");
385
385
  if (r === "img" || r === "presentation" || r === "none") continue;
386
- a += Z(i);
386
+ a += ee(i);
387
387
  }
388
388
  return a;
389
389
  }
390
- function Pe(e) {
390
+ function De(e) {
391
391
  let a = e;
392
392
  for (; a; ) {
393
393
  if (a instanceof HTMLElement && a.style.visibility === "hidden") return !0;
@@ -395,7 +395,7 @@ function Pe(e) {
395
395
  }
396
396
  return !1;
397
397
  }
398
- function Fe(e) {
398
+ function Pe(e) {
399
399
  var n, r;
400
400
  const a = e.getAttribute("aria-labelledby");
401
401
  if (a) {
@@ -413,9 +413,9 @@ function Fe(e) {
413
413
  function se(e) {
414
414
  return e.getRootNode() instanceof ShadowRoot;
415
415
  }
416
- let ee = /* @__PURE__ */ new WeakMap();
416
+ let te = /* @__PURE__ */ new WeakMap();
417
417
  function pt() {
418
- ee = /* @__PURE__ */ new WeakMap();
418
+ te = /* @__PURE__ */ new WeakMap();
419
419
  }
420
420
  function bt(e) {
421
421
  return e.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -447,7 +447,7 @@ function gt(e) {
447
447
  }
448
448
  return a;
449
449
  }
450
- function G(e) {
450
+ function Y(e) {
451
451
  if (e.id) return `#${CSS.escape(e.id)}`;
452
452
  const a = e.getRootNode(), t = a instanceof ShadowRoot ? null : a.documentElement;
453
453
  if (e === t) return e.tagName.toLowerCase();
@@ -472,26 +472,26 @@ function G(e) {
472
472
  }
473
473
  function p(e) {
474
474
  var r;
475
- const a = ee.get(e);
475
+ const a = te.get(e);
476
476
  if (a !== void 0) return a;
477
477
  const t = [];
478
478
  let i = e;
479
479
  for (; i; ) {
480
480
  const o = i.getRootNode();
481
481
  if (o instanceof ShadowRoot)
482
- t.unshift({ selector: G(i), delimiter: " >>> " }), i = o.host;
482
+ t.unshift({ selector: Y(i), delimiter: " >>> " }), i = o.host;
483
483
  else {
484
484
  const s = (r = o.defaultView) == null ? void 0 : r.frameElement;
485
485
  if (s)
486
- t.unshift({ selector: G(i), delimiter: " >>>iframe> " }), i = s;
486
+ t.unshift({ selector: Y(i), delimiter: " >>>iframe> " }), i = s;
487
487
  else {
488
- t.unshift({ selector: G(i), delimiter: "" });
488
+ t.unshift({ selector: Y(i), delimiter: "" });
489
489
  break;
490
490
  }
491
491
  }
492
492
  }
493
493
  const n = t.map((o, s) => (s === 0 ? "" : o.delimiter) + o.selector).join("");
494
- return ee.set(e, n), n;
494
+ return te.set(e, n), n;
495
495
  }
496
496
  function Un(e) {
497
497
  const a = [], t = [];
@@ -609,7 +609,7 @@ const ft = /* @__PURE__ */ new Set([
609
609
  "aria-valuemax",
610
610
  "aria-valuemin",
611
611
  "aria-valuenow"
612
- ]), Y = {
612
+ ]), X = {
613
613
  "aria-autocomplete": /* @__PURE__ */ new Set(["inline", "list", "both", "none"]),
614
614
  "aria-expanded": /* @__PURE__ */ new Set(["true", "false", "undefined"]),
615
615
  "aria-current": /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"]),
@@ -781,10 +781,10 @@ function le(e) {
781
781
  fix: { type: "suggest", suggestion: `Set ${c.name} to a valid number value` }
782
782
  });
783
783
  }
784
- } else if (Y[c.name]) {
784
+ } else if (X[c.name]) {
785
785
  const b = u.split(/\s+/);
786
786
  for (const g of b)
787
- if (!Y[c.name].has(g)) {
787
+ if (!X[c.name].has(g)) {
788
788
  const f = d();
789
789
  t.push({
790
790
  ruleId: "aria/aria-valid-attr-value",
@@ -792,7 +792,7 @@ function le(e) {
792
792
  html: f.html,
793
793
  impact: "critical",
794
794
  message: `Invalid value "${u}" for ${c.name}.`,
795
- fix: { type: "suggest", suggestion: `Set ${c.name} to one of: ${[...Y[c.name]].join(", ")}` }
795
+ fix: { type: "suggest", suggestion: `Set ${c.name} to one of: ${[...X[c.name]].join(", ")}` }
796
796
  });
797
797
  break;
798
798
  }
@@ -818,14 +818,14 @@ function le(e) {
818
818
  if (fe.has(c)) {
819
819
  const g = r.hasAttribute("aria-label"), f = r.hasAttribute("aria-labelledby");
820
820
  if (g || f) {
821
- const v = d(), w = g ? "aria-label" : "aria-labelledby";
821
+ const v = d(), y = g ? "aria-label" : "aria-labelledby";
822
822
  i.push({
823
823
  ruleId: "aria/aria-prohibited-attr",
824
824
  selector: v.selector,
825
825
  html: v.html,
826
826
  impact: "serious",
827
827
  message: `aria-label and aria-labelledby are prohibited on role "${c}".`,
828
- fix: { type: "remove-attribute", attribute: w }
828
+ fix: { type: "remove-attribute", attribute: y }
829
829
  });
830
830
  }
831
831
  }
@@ -851,13 +851,13 @@ function le(e) {
851
851
  }
852
852
  return P = new WeakRef(e), F = { validAttr: a, validAttrValue: t, prohibitedAttr: i }, F;
853
853
  }
854
- let te = /* @__PURE__ */ new WeakMap(), ae = /* @__PURE__ */ new WeakMap(), ie = /* @__PURE__ */ new WeakMap();
854
+ let ae = /* @__PURE__ */ new WeakMap(), ie = /* @__PURE__ */ new WeakMap(), ne = /* @__PURE__ */ new WeakMap();
855
855
  function kt() {
856
- te = /* @__PURE__ */ new WeakMap(), ae = /* @__PURE__ */ new WeakMap(), ie = /* @__PURE__ */ new WeakMap();
856
+ ae = /* @__PURE__ */ new WeakMap(), ie = /* @__PURE__ */ new WeakMap(), ne = /* @__PURE__ */ new WeakMap();
857
857
  }
858
- function y(e) {
859
- let a = te.get(e);
860
- return a || (a = getComputedStyle(e), te.set(e, a), a);
858
+ function x(e) {
859
+ let a = ae.get(e);
860
+ return a || (a = getComputedStyle(e), ae.set(e, a), a);
861
861
  }
862
862
  function I(e, a, t) {
863
863
  const [i, n, r] = [e, a, t].map((o) => {
@@ -909,7 +909,7 @@ function C(e) {
909
909
  );
910
910
  return r ? [parseInt(r[1]), parseInt(r[2]), parseInt(r[3])] : null;
911
911
  }
912
- function U(e) {
912
+ function W(e) {
913
913
  const a = e.match(/rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*([\d.]+)\s*\)/);
914
914
  if (a) return parseFloat(a[1]);
915
915
  const t = e.match(/rgba?\([^)]+\/\s*([\d.]+%?)\s*\)/);
@@ -927,12 +927,12 @@ function R(e, a, t) {
927
927
  ];
928
928
  }
929
929
  function ye(e) {
930
- const a = ae.get(e);
930
+ const a = ie.get(e);
931
931
  if (a !== void 0) return a;
932
932
  const t = St(e);
933
- return ae.set(e, t), t;
933
+ return ie.set(e, t), t;
934
934
  }
935
- function X(e, a) {
935
+ function J(e, a) {
936
936
  let t = a;
937
937
  for (let i = e.length - 1; i >= 0; i--)
938
938
  t = R(e[i].color, t, e[i].alpha);
@@ -942,13 +942,13 @@ function St(e) {
942
942
  const a = [];
943
943
  let t = e;
944
944
  for (; t; ) {
945
- const n = y(t), r = n.backgroundImage;
945
+ const n = x(t), r = n.backgroundImage;
946
946
  if (r && r !== "none" && r !== "initial") {
947
947
  const d = n.backgroundColor;
948
948
  if (d && d !== "transparent" && d !== "rgba(0, 0, 0, 0)" && d !== "rgba(0 0 0 / 0)") {
949
949
  const c = C(d);
950
950
  if (c)
951
- return a.length > 0 ? X(a, c) : c;
951
+ return a.length > 0 ? J(a, c) : c;
952
952
  }
953
953
  return null;
954
954
  }
@@ -957,7 +957,7 @@ function St(e) {
957
957
  t = t.parentElement;
958
958
  continue;
959
959
  }
960
- const s = U(o);
960
+ const s = W(o);
961
961
  if (s < 0.01) {
962
962
  t = t.parentElement;
963
963
  continue;
@@ -968,13 +968,13 @@ function St(e) {
968
968
  continue;
969
969
  }
970
970
  if (s >= 1)
971
- return a.length > 0 ? X(a, l) : l;
971
+ return a.length > 0 ? J(a, l) : l;
972
972
  a.push({ color: l, alpha: s }), t = t.parentElement;
973
973
  }
974
974
  const i = [255, 255, 255];
975
- return a.length > 0 ? X(a, i) : i;
975
+ return a.length > 0 ? J(a, i) : i;
976
976
  }
977
- function He(e) {
977
+ function Fe(e) {
978
978
  const a = [];
979
979
  let t = 0, i = 0;
980
980
  for (let n = 0; n < e.length; n++)
@@ -989,7 +989,7 @@ function It(e, a = [255, 255, 255]) {
989
989
  let r = 1, o = n + 1;
990
990
  for (; o < e.length && r > 0; o++)
991
991
  e[o] === "(" ? r++ : e[o] === ")" && r--;
992
- const s = e.slice(n + 1, o - 1), l = He(s);
992
+ const s = e.slice(n + 1, o - 1), l = Fe(s);
993
993
  for (const d of l) {
994
994
  const c = d.trim();
995
995
  if (/^(to\s|[\d.]+deg|[\d.]+turn|[\d.]+rad)/i.test(c)) continue;
@@ -1003,28 +1003,28 @@ function It(e, a = [255, 255, 255]) {
1003
1003
  return t;
1004
1004
  }
1005
1005
  const qt = /* @__PURE__ */ new Set(["IMG", "PICTURE", "VIDEO", "SVG"]);
1006
- function Lt(e) {
1007
- const a = ie.get(e);
1006
+ function Et(e) {
1007
+ const a = ne.get(e);
1008
1008
  if (a !== void 0) return a;
1009
1009
  const t = Rt(e);
1010
- return ie.set(e, t), t;
1010
+ return ne.set(e, t), t;
1011
1011
  }
1012
- function Et(e) {
1012
+ function Lt(e) {
1013
1013
  return qt.has(e.tagName) ? !0 : !!e.querySelector("img, picture, video, svg");
1014
1014
  }
1015
1015
  function Rt(e) {
1016
1016
  let a = e, t = !1;
1017
1017
  for (; a; ) {
1018
- const i = y(a).position;
1018
+ const i = x(a).position;
1019
1019
  if ((i === "absolute" || i === "fixed") && (t = !0), a !== e && i !== "static") {
1020
1020
  for (const n of a.children) {
1021
1021
  if (n === e || n.contains(e)) continue;
1022
- if (Et(n)) {
1022
+ if (Lt(n)) {
1023
1023
  if (t) return !0;
1024
- const o = y(n).position;
1024
+ const o = x(n).position;
1025
1025
  if (o === "absolute" || o === "fixed") return !0;
1026
1026
  }
1027
- const r = y(n);
1027
+ const r = x(n);
1028
1028
  if (r.position === "absolute" || r.position === "fixed") {
1029
1029
  const o = r.backgroundImage;
1030
1030
  if (o && o !== "none" && o !== "initial") return !0;
@@ -1041,11 +1041,11 @@ function Ct(e) {
1041
1041
  return e.endsWith("pt") ? a * (4 / 3) : a;
1042
1042
  }
1043
1043
  function xe(e) {
1044
- const a = y(e), t = Ct(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
1044
+ const a = x(e), t = Ct(a.fontSize), i = parseInt(a.fontWeight) || (a.fontWeight === "bold" ? 700 : 400);
1045
1045
  return t >= 23.5 || t >= 18.5 && i >= 700;
1046
1046
  }
1047
1047
  function Tt(e) {
1048
- const a = He(e), t = [];
1048
+ const a = Fe(e), t = [];
1049
1049
  for (const i of a) {
1050
1050
  const n = i.trim();
1051
1051
  if (!n) continue;
@@ -1059,7 +1059,7 @@ function Tt(e) {
1059
1059
  function we(e) {
1060
1060
  return e === "transparent" || e === "rgba(0, 0, 0, 0)" || e === "rgba(0 0 0 / 0)";
1061
1061
  }
1062
- function ne([e, a, t]) {
1062
+ function _([e, a, t]) {
1063
1063
  return "#" + [e, a, t].map((i) => i.toString(16).padStart(2, "0")).join("");
1064
1064
  }
1065
1065
  function Nt(e, a, t) {
@@ -1074,7 +1074,7 @@ function Nt(e, a, t) {
1074
1074
  function Mt(e) {
1075
1075
  let a = 1, t = e;
1076
1076
  for (; t; ) {
1077
- const i = y(t), n = parseFloat(i.opacity);
1077
+ const i = x(t), n = parseFloat(i.opacity);
1078
1078
  isNaN(n) || (a *= n), t = t.parentElement;
1079
1079
  }
1080
1080
  return a;
@@ -1087,7 +1087,7 @@ function $t(e) {
1087
1087
  const r = getComputedStyle(a, n), o = r.content;
1088
1088
  if (!o || o === "none" || o === "normal" || o === '""') continue;
1089
1089
  const s = r.backgroundColor;
1090
- if (s && !we(s) && U(s) >= 0.1) return !0;
1090
+ if (s && !we(s) && W(s) >= 0.1) return !0;
1091
1091
  const l = r.backgroundImage;
1092
1092
  if (l && l !== "none" && l !== "initial") return !0;
1093
1093
  const d = r.position;
@@ -1097,18 +1097,18 @@ function $t(e) {
1097
1097
  }
1098
1098
  } catch {
1099
1099
  }
1100
- const i = y(a).backgroundColor;
1101
- if (i && !we(i) && U(i) >= 1) break;
1100
+ const i = x(a).backgroundColor;
1101
+ if (i && !we(i) && W(i) >= 1) break;
1102
1102
  a = a.parentElement;
1103
1103
  }
1104
1104
  return !1;
1105
1105
  }
1106
- const B = /* @__PURE__ */ new Map();
1106
+ const G = /* @__PURE__ */ new Map();
1107
1107
  function Wn(e, a) {
1108
- B.set(e, a), re.delete(e);
1108
+ G.set(e, a), re.delete(e);
1109
1109
  }
1110
- function Dt(e, a) {
1111
- const t = B.get(a);
1110
+ function Ht(e, a) {
1111
+ const t = G.get(a);
1112
1112
  return t ? e.map((i) => {
1113
1113
  const n = t[i.id];
1114
1114
  return n ? {
@@ -1119,20 +1119,20 @@ function Dt(e, a) {
1119
1119
  }) : e;
1120
1120
  }
1121
1121
  const re = /* @__PURE__ */ new Map();
1122
- function Pt(e) {
1122
+ function Dt(e) {
1123
1123
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1124
1124
  }
1125
- function Ft(e) {
1125
+ function Pt(e) {
1126
1126
  const a = e.split(/\{(\d+)\}/);
1127
1127
  let t = "^";
1128
1128
  for (let i = 0; i < a.length; i++)
1129
- i % 2 === 0 ? t += Pt(a[i]) : t += "(.+?)";
1129
+ i % 2 === 0 ? t += Dt(a[i]) : t += "(.+?)";
1130
1130
  return t += "$", new RegExp(t);
1131
1131
  }
1132
- function Ht(e, a) {
1132
+ function Ft(e, a) {
1133
1133
  let t = re.get(e);
1134
1134
  if (t || (t = /* @__PURE__ */ new Map(), re.set(e, t)), t.has(a)) return t.get(a);
1135
- const i = B.get(e);
1135
+ const i = G.get(e);
1136
1136
  if (!i) return;
1137
1137
  const n = i[a];
1138
1138
  if (!(n != null && n.messages))
@@ -1140,13 +1140,13 @@ function Ht(e, a) {
1140
1140
  const r = [];
1141
1141
  for (const [o, s] of Object.entries(n.messages))
1142
1142
  r.push({
1143
- regex: Ft(o),
1143
+ regex: Pt(o),
1144
1144
  translated: s
1145
1145
  });
1146
1146
  return t.set(a, r), r;
1147
1147
  }
1148
1148
  function zt(e, a, t) {
1149
- const i = Ht(t, e);
1149
+ const i = Ft(t, e);
1150
1150
  if (!i) return a;
1151
1151
  for (const { regex: n, translated: r } of i) {
1152
1152
  const o = a.match(n);
@@ -1159,7 +1159,7 @@ function zt(e, a, t) {
1159
1159
  return a;
1160
1160
  }
1161
1161
  function ze(e, a) {
1162
- return B.has(a) ? e.map((t) => {
1162
+ return G.has(a) ? e.map((t) => {
1163
1163
  const i = zt(t.ruleId, t.message, a);
1164
1164
  return i === t.message ? t : { ...t, message: i };
1165
1165
  }) : e;
@@ -1191,12 +1191,13 @@ const jt = {
1191
1191
  wcag: ["1.1.1"],
1192
1192
  level: "A",
1193
1193
  fixability: "contextual",
1194
+ browserHint: "Screenshot the image to describe its visual content for alt text.",
1194
1195
  description: `Images must have alternate text. Add an alt attribute to <img> elements. Decorative images may use an empty alt attribute (alt=""), role='none', or role='presentation'.`,
1195
1196
  guidance: "Every image needs an alt attribute. For informative images, describe the content or function concisely. For decorative images (backgrounds, spacers, purely visual flourishes), use alt='' to hide them from screen readers. Never omit alt entirely—screen readers may read the filename instead.",
1196
1197
  run(e) {
1197
1198
  const a = [];
1198
1199
  for (const t of e.querySelectorAll("img")) {
1199
- if (h(t) || Pe(t)) continue;
1200
+ if (h(t) || De(t)) continue;
1200
1201
  const i = t.getAttribute("role");
1201
1202
  if (i === "presentation" || i === "none") {
1202
1203
  const r = t.getAttribute("tabindex");
@@ -1215,7 +1216,7 @@ const jt = {
1215
1216
  });
1216
1217
  continue;
1217
1218
  }
1218
- !t.hasAttribute("alt") && !x(t) && a.push({
1219
+ !t.hasAttribute("alt") && !w(t) && a.push({
1219
1220
  ruleId: "text-alternatives/img-alt",
1220
1221
  selector: p(t),
1221
1222
  html: m(t),
@@ -1230,7 +1231,7 @@ const jt = {
1230
1231
  };
1231
1232
  function Ut(e) {
1232
1233
  var i;
1233
- const a = Fe(e);
1234
+ const a = Pe(e);
1234
1235
  if (a) return a;
1235
1236
  const t = e.querySelector("title");
1236
1237
  return (i = t == null ? void 0 : t.textContent) != null && i.trim() ? t.textContent.trim() : "";
@@ -1242,6 +1243,7 @@ const Wt = {
1242
1243
  wcag: ["1.1.1"],
1243
1244
  level: "A",
1244
1245
  fixability: "contextual",
1246
+ browserHint: "Screenshot the SVG to understand its content, then add a title element or aria-label.",
1245
1247
  description: "SVG elements with an img, graphics-document, or graphics-symbol role must have an accessible name via a <title> element, aria-label, or aria-labelledby.",
1246
1248
  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.",
1247
1249
  run(e) {
@@ -1269,12 +1271,13 @@ const Wt = {
1269
1271
  wcag: ["1.1.1", "4.1.2"],
1270
1272
  level: "A",
1271
1273
  fixability: "contextual",
1274
+ browserHint: "Screenshot the image button to see its icon, then set alt to describe the action (e.g., 'Search', 'Submit').",
1272
1275
  description: 'Image inputs (<input type="image">) must have alternate text describing the button action.',
1273
1276
  guidance: "Image buttons (<input type='image'>) act as submit buttons with a custom image. Add alt text via alt, aria-label, or aria-labelledby that describes the action (e.g. alt='Search' or alt='Submit order'), not the image itself. Without it, screen readers announce only 'image' or the filename, giving no clue what the button does.",
1274
1277
  run(e) {
1275
1278
  const a = [];
1276
1279
  for (const t of e.querySelectorAll('input[type="image"]'))
1277
- h(t) || x(t) || a.push({
1280
+ h(t) || w(t) || a.push({
1278
1281
  ruleId: "text-alternatives/input-image-alt",
1279
1282
  selector: p(t),
1280
1283
  html: m(t),
@@ -1325,6 +1328,7 @@ const Wt = {
1325
1328
  level: "A",
1326
1329
  tags: ["best-practice"],
1327
1330
  fixability: "contextual",
1331
+ browserHint: "Screenshot the image to verify the alt text accurately describes it without filler words like 'image of'.",
1328
1332
  description: "Image alt text should not contain words like 'image', 'photo', or 'picture' — screen readers already announce the element type.",
1329
1333
  guidance: "Screen readers already announce 'image' or 'graphic' before reading alt text, so phrases like 'image of', 'photo of', or 'picture of' are redundant. Remove these words and describe what the image shows. For example, change 'image of a dog' to 'golden retriever playing fetch'.",
1330
1334
  run(e) {
@@ -1357,7 +1361,7 @@ const Wt = {
1357
1361
  const a = [];
1358
1362
  for (const t of e.querySelectorAll("area[href]")) {
1359
1363
  if (h(t)) continue;
1360
- x(t) || a.push({
1364
+ w(t) || a.push({
1361
1365
  ruleId: "text-alternatives/area-alt",
1362
1366
  selector: p(t),
1363
1367
  html: m(t),
@@ -1375,13 +1379,14 @@ const Wt = {
1375
1379
  wcag: ["1.1.1"],
1376
1380
  level: "A",
1377
1381
  fixability: "contextual",
1382
+ browserHint: "Screenshot the embedded object to see its content, then add aria-label or title describing it.",
1378
1383
  description: "<object> elements must have alternative text.",
1379
1384
  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.",
1380
1385
  run(e) {
1381
1386
  var t;
1382
1387
  const a = [];
1383
1388
  for (const i of e.querySelectorAll("object")) {
1384
- if (h(i) || Pe(i) || i.getAttribute("role") === "presentation" || i.getAttribute("role") === "none" || Fe(i)) continue;
1389
+ if (h(i) || De(i) || i.getAttribute("role") === "presentation" || i.getAttribute("role") === "none" || Pe(i)) continue;
1385
1390
  const n = i.getAttribute("data") || "";
1386
1391
  if (!((i.getAttribute("type") || "").startsWith("image/") || /\.(png|jpg|jpeg|gif|svg|webp|bmp|ico)$/i.test(n))) {
1387
1392
  const s = i.querySelector("img[alt]");
@@ -1401,16 +1406,18 @@ const Wt = {
1401
1406
  }, Xt = {
1402
1407
  id: "text-alternatives/role-img-alt",
1403
1408
  category: "text-alternatives",
1409
+ actRuleIds: ["23a2a8"],
1404
1410
  wcag: ["1.1.1"],
1405
1411
  level: "A",
1406
1412
  fixability: "contextual",
1413
+ browserHint: "Screenshot the element to see its visual appearance, then provide an aria-label describing what it represents.",
1407
1414
  description: "Elements with role='img' must have an accessible name.",
1408
1415
  guidance: "When you assign role='img' to an element (like a div containing icon fonts or CSS backgrounds), you must provide an accessible name via aria-label or aria-labelledby. Without this, screen reader users have no way to understand what the image represents. If the image is decorative, use role='presentation' or role='none' instead.",
1409
1416
  run(e) {
1410
1417
  const a = [];
1411
1418
  for (const t of e.querySelectorAll('[role="img"]')) {
1412
1419
  if (h(t) || t.tagName.toLowerCase() === "svg" || t.tagName.toLowerCase() === "img") continue;
1413
- x(t) || a.push({
1420
+ w(t) || a.push({
1414
1421
  ruleId: "text-alternatives/role-img-alt",
1415
1422
  selector: p(t),
1416
1423
  html: m(t),
@@ -1421,13 +1428,14 @@ const Wt = {
1421
1428
  }
1422
1429
  return a;
1423
1430
  }
1424
- }, Kt = {
1431
+ }, Jt = {
1425
1432
  id: "time-based-media/video-captions",
1426
1433
  category: "time-based-media",
1427
1434
  actRuleIds: ["eac66b"],
1428
1435
  wcag: ["1.2.2"],
1429
1436
  level: "A",
1430
1437
  fixability: "contextual",
1438
+ browserHint: "Screenshot the video element to see its poster or content for context when writing captions.",
1431
1439
  description: "Video elements must have captions via <track kind='captions'> or <track kind='subtitles'>.",
1432
1440
  guidance: "Captions provide text alternatives for audio content in videos, benefiting deaf users and those who cannot hear audio. Add a <track> element with kind='captions' pointing to a WebVTT caption file. Captions should include both dialogue and important sound effects.",
1433
1441
  run(e) {
@@ -1444,13 +1452,14 @@ const Wt = {
1444
1452
  }
1445
1453
  return a;
1446
1454
  }
1447
- }, Jt = {
1455
+ }, Kt = {
1448
1456
  id: "time-based-media/audio-transcript",
1449
1457
  category: "time-based-media",
1450
1458
  actRuleIds: ["e7aa44"],
1451
1459
  wcag: ["1.2.1"],
1452
1460
  level: "A",
1453
1461
  fixability: "contextual",
1462
+ browserHint: "Inspect the page around the audio element for existing transcript links or associated text content.",
1454
1463
  description: "Audio elements should have a text alternative or transcript.",
1455
1464
  guidance: "Audio-only content like podcasts or recordings needs a text alternative for deaf users. Provide a transcript either on the same page or linked nearby. The transcript should include all spoken content and descriptions of relevant sounds.",
1456
1465
  run(e) {
@@ -1619,7 +1628,7 @@ function ra(e) {
1619
1628
  return `Unknown check type: ${String(e.type)}`;
1620
1629
  }
1621
1630
  }
1622
- function E(e, a, t) {
1631
+ function L(e, a, t) {
1623
1632
  let i = e;
1624
1633
  if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
1625
1634
  let n = "";
@@ -1637,6 +1646,7 @@ function N(e) {
1637
1646
  level: e.level,
1638
1647
  tags: e.tags,
1639
1648
  fixability: e.fixability,
1649
+ browserHint: e.browserHint,
1640
1650
  description: e.description,
1641
1651
  guidance: e.guidance,
1642
1652
  run(t) {
@@ -1650,7 +1660,7 @@ function N(e) {
1650
1660
  selector: p(o),
1651
1661
  html: m(o),
1652
1662
  impact: e.impact,
1653
- message: E(e.message, o, e.check),
1663
+ message: L(e.message, o, e.check),
1654
1664
  ...e.fix ? { fix: e.fix } : {},
1655
1665
  element: o
1656
1666
  });
@@ -1666,7 +1676,7 @@ function N(e) {
1666
1676
  selector: p(d),
1667
1677
  html: m(d),
1668
1678
  impact: e.impact,
1669
- message: E(e.message, d, e.check),
1679
+ message: L(e.message, d, e.check),
1670
1680
  ...e.fix ? { fix: e.fix } : {},
1671
1681
  element: d
1672
1682
  });
@@ -1681,7 +1691,7 @@ function N(e) {
1681
1691
  selector: p(s),
1682
1692
  html: m(s),
1683
1693
  impact: e.impact,
1684
- message: E(e.message, s, e.check),
1694
+ message: L(e.message, s, e.check),
1685
1695
  ...e.fix ? { fix: e.fix } : {},
1686
1696
  element: s
1687
1697
  });
@@ -1705,7 +1715,7 @@ function N(e) {
1705
1715
  selector: p(u),
1706
1716
  html: m(u),
1707
1717
  impact: e.impact,
1708
- message: E(e.message, u, e.check),
1718
+ message: L(e.message, u, e.check),
1709
1719
  ...e.fix ? { fix: e.fix } : {},
1710
1720
  element: u
1711
1721
  }) : !d && g && i.push({
@@ -1713,7 +1723,7 @@ function N(e) {
1713
1723
  selector: p(u),
1714
1724
  html: m(u),
1715
1725
  impact: e.impact,
1716
- message: E(e.message, u, e.check),
1726
+ message: L(e.message, u, e.check),
1717
1727
  ...e.fix ? { fix: e.fix } : {},
1718
1728
  element: u
1719
1729
  });
@@ -1728,7 +1738,7 @@ function N(e) {
1728
1738
  selector: p(s),
1729
1739
  html: m(s),
1730
1740
  impact: e.impact,
1731
- message: E(e.message, s, e.check),
1741
+ message: L(e.message, s, e.check),
1732
1742
  ...e.fix ? { fix: e.fix } : {},
1733
1743
  element: s
1734
1744
  });
@@ -1770,7 +1780,7 @@ function N(e) {
1770
1780
  selector: p(b),
1771
1781
  html: m(b),
1772
1782
  impact: e.impact,
1773
- message: E(e.message, b, e.check),
1783
+ message: L(e.message, b, e.check),
1774
1784
  ...e.fix ? { fix: e.fix } : {},
1775
1785
  element: b
1776
1786
  });
@@ -1889,7 +1899,7 @@ function je(e, a) {
1889
1899
  return NaN;
1890
1900
  }
1891
1901
  }
1892
- function V(e) {
1902
+ function B(e) {
1893
1903
  return isNaN(e) ? !1 : (e = (e % 360 + 360) % 360, e >= 85 && e <= 95 || e >= 265 && e <= 275);
1894
1904
  }
1895
1905
  function pa(e) {
@@ -1898,21 +1908,21 @@ function pa(e) {
1898
1908
  );
1899
1909
  if (a) {
1900
1910
  const n = je(parseFloat(a[1]), a[2]);
1901
- if (V(n)) return !0;
1911
+ if (B(n)) return !0;
1902
1912
  }
1903
1913
  const t = e.match(
1904
1914
  /matrix\(\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)/i
1905
1915
  );
1906
1916
  if (t) {
1907
1917
  const n = parseFloat(t[1]), r = parseFloat(t[2]), o = Math.atan2(r, n) * (180 / Math.PI);
1908
- if (V(o)) return !0;
1918
+ if (B(o)) return !0;
1909
1919
  }
1910
1920
  const i = e.match(
1911
1921
  /matrix3d\(\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)/i
1912
1922
  );
1913
1923
  if (i) {
1914
1924
  const n = parseFloat(i[1]), r = parseFloat(i[2]), o = Math.atan2(r, n) * (180 / Math.PI);
1915
- if (V(o)) return !0;
1925
+ if (B(o)) return !0;
1916
1926
  }
1917
1927
  return !1;
1918
1928
  }
@@ -1920,7 +1930,7 @@ function ba(e) {
1920
1930
  const a = e.match(/(-?[\d.]+)(deg|rad|turn|grad)/i);
1921
1931
  if (!a) return !1;
1922
1932
  const t = je(parseFloat(a[1]), a[2]);
1923
- return V(t);
1933
+ return B(t);
1924
1934
  }
1925
1935
  const ha = {
1926
1936
  id: "adaptable/orientation-lock",
@@ -1997,14 +2007,14 @@ function fa(e, a) {
1997
2007
  for (const s of e.querySelectorAll("*")) {
1998
2008
  if (h(s)) continue;
1999
2009
  r = !0;
2000
- const l = j(s);
2010
+ const l = U(s);
2001
2011
  l && n.add(l);
2002
2012
  }
2003
2013
  for (const s of t) {
2004
2014
  const l = i.getElementById(s);
2005
2015
  if (l && !h(l)) {
2006
2016
  r = !0;
2007
- const d = j(l);
2017
+ const d = U(l);
2008
2018
  d && n.add(d);
2009
2019
  }
2010
2020
  }
@@ -2081,7 +2091,7 @@ const va = {
2081
2091
  const r = Se[n];
2082
2092
  let o = i.parentElement, s = !1;
2083
2093
  for (; o && o !== e.documentElement; ) {
2084
- const l = j(o);
2094
+ const l = U(o);
2085
2095
  if (l && r.includes(l)) {
2086
2096
  s = !0;
2087
2097
  break;
@@ -2187,6 +2197,7 @@ const ka = {
2187
2197
  wcag: ["1.3.1"],
2188
2198
  level: "A",
2189
2199
  fixability: "contextual",
2200
+ browserHint: "Screenshot the table to understand its visual layout, then add scope or headers attributes to associate data cells with headers.",
2190
2201
  description: "Data cells in tables larger than 3x3 should have associated headers.",
2191
2202
  guidance: "In complex tables, screen reader users need header associations to understand data cells. Use th elements with scope attribute, or the headers attribute on td elements. For simple tables (≤3x3), this is less critical as context is usually clear.",
2192
2203
  run(e) {
@@ -2213,9 +2224,9 @@ const ka = {
2213
2224
  let g = !1;
2214
2225
  const f = i.querySelector("thead"), v = (f == null ? void 0 : f.querySelector("tr")) ?? i.querySelector("tbody > tr, tr");
2215
2226
  if (v)
2216
- for (const w of v.querySelectorAll("th, td")) {
2217
- const A = Ie(w), S = parseInt(w.getAttribute("colspan") || "1", 10);
2218
- if (w.tagName.toLowerCase() === "th" && b >= A && b < A + S) {
2227
+ for (const y of v.querySelectorAll("th, td")) {
2228
+ const A = Ie(y), S = parseInt(y.getAttribute("colspan") || "1", 10);
2229
+ if (y.tagName.toLowerCase() === "th" && b >= A && b < A + S) {
2219
2230
  g = !0;
2220
2231
  break;
2221
2232
  }
@@ -2265,6 +2276,7 @@ const ka = {
2265
2276
  level: "A",
2266
2277
  tags: ["best-practice"],
2267
2278
  fixability: "contextual",
2279
+ browserHint: "Screenshot the table to see which header cells are visually empty, then add text content or aria-label.",
2268
2280
  description: "Table header cells should have visible text.",
2269
2281
  guidance: "Empty table headers provide no information to screen reader users. Either add descriptive text to the header, or if the header is intentionally empty (like a corner cell), consider using a td element instead or adding a visually hidden label.",
2270
2282
  run(e) {
@@ -2272,7 +2284,7 @@ const ka = {
2272
2284
  for (const t of e.querySelectorAll("th")) {
2273
2285
  if (h(t)) continue;
2274
2286
  const i = t.closest("table");
2275
- (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || x(t) || a.push({
2287
+ (i == null ? void 0 : i.getAttribute("role")) === "presentation" || (i == null ? void 0 : i.getAttribute("role")) === "none" || w(t) || a.push({
2276
2288
  ruleId: "adaptable/empty-table-header",
2277
2289
  selector: p(t),
2278
2290
  html: m(t),
@@ -2290,6 +2302,7 @@ const ka = {
2290
2302
  level: "AA",
2291
2303
  tags: ["page-level"],
2292
2304
  fixability: "mechanical",
2305
+ browserHint: "After fixing the viewport meta tag, resize the viewport to 320px wide and screenshot to verify content remains readable and usable.",
2293
2306
  description: "Viewport meta tag must not disable user scaling.",
2294
2307
  guidance: "Users with low vision need to zoom content up to 200% or more. Setting user-scalable=no or maximum-scale=1 prevents zooming and fails WCAG. Remove these restrictions. If your layout breaks at high zoom, fix the responsive design rather than preventing zoom.",
2295
2308
  run(e) {
@@ -2386,7 +2399,7 @@ function We(e, a, t, i) {
2386
2399
  }
2387
2400
  for (const s of r.childNodes)
2388
2401
  if (s.nodeType === 3 && ((o = s.textContent) != null && o.trim())) {
2389
- const l = parseFloat(y(r).fontSize);
2402
+ const l = parseFloat(x(r).fontSize);
2390
2403
  if (l > 0 && t / l < i) return !0;
2391
2404
  break;
2392
2405
  }
@@ -2396,7 +2409,7 @@ function We(e, a, t, i) {
2396
2409
  }
2397
2410
  return n(e);
2398
2411
  }
2399
- function La(e) {
2412
+ function Ea(e) {
2400
2413
  var a;
2401
2414
  for (const t of e.childNodes)
2402
2415
  if (t.nodeType === 3 && ((a = t.textContent) != null && a.trim()))
@@ -2418,7 +2431,7 @@ function Ve(e) {
2418
2431
  return !1;
2419
2432
  }
2420
2433
  function de(e, a) {
2421
- if (La(e)) return !0;
2434
+ if (Ea(e)) return !0;
2422
2435
  for (const t of e.children) {
2423
2436
  const i = t.getAttribute("style") || "";
2424
2437
  if (!new RegExp(
@@ -2449,10 +2462,10 @@ function Be(e, a, t, i) {
2449
2462
  }
2450
2463
  return n;
2451
2464
  }
2452
- function Ea(e) {
2465
+ function La(e) {
2453
2466
  let a = e, t = !1;
2454
2467
  for (; a; ) {
2455
- const i = y(a);
2468
+ const i = x(a);
2456
2469
  parseFloat(i.width) > 500 && (t = !0), (i.whiteSpace === "nowrap" || i.whiteSpace === "pre") && (t = !0);
2457
2470
  const r = i.overflowX, o = i.overflowY;
2458
2471
  if ((r === "scroll" || r === "auto") && o !== "scroll" && o !== "auto")
@@ -2485,9 +2498,9 @@ const Ra = {
2485
2498
  run(e) {
2486
2499
  const a = [];
2487
2500
  for (const t of e.querySelectorAll("[style]")) {
2488
- if (h(t) || !Oe(t) || Ve(t) || !de(t, "line-height") || Ea(t)) continue;
2501
+ if (h(t) || !Oe(t) || Ve(t) || !de(t, "line-height") || La(t)) continue;
2489
2502
  if (t instanceof HTMLElement && t.scrollHeight > 0) {
2490
- const r = parseFloat(y(t).lineHeight);
2503
+ const r = parseFloat(x(t).lineHeight);
2491
2504
  if (r > 0 && t.scrollHeight <= r * 1.5) continue;
2492
2505
  }
2493
2506
  const i = Ue(t, "line-height");
@@ -2534,7 +2547,7 @@ const Ra = {
2534
2547
  ]);
2535
2548
  function $a(e) {
2536
2549
  let a = e.parentElement;
2537
- for (; a && !Na.has(y(a).display); )
2550
+ for (; a && !Na.has(x(a).display); )
2538
2551
  a = a.parentElement;
2539
2552
  if (!a) return null;
2540
2553
  const t = a.ownerDocument.createTreeWalker(a, NodeFilter.SHOW_TEXT);
@@ -2549,7 +2562,7 @@ function $a(e) {
2549
2562
  }
2550
2563
  s = s.parentElement;
2551
2564
  }
2552
- l || (i += r.data, !n && r.parentElement && (n = C(y(r.parentElement).color)));
2565
+ l || (i += r.data, !n && r.parentElement && (n = C(x(r.parentElement).color)));
2553
2566
  }
2554
2567
  const o = i.match(new RegExp("\\p{L}{3,}", "gu"));
2555
2568
  return !n || !o || o.length < 2 ? null : { block: a, textColor: n };
@@ -2558,40 +2571,41 @@ function qe(e, a) {
2558
2571
  const t = e.textDecorationLine || e.textDecoration || "";
2559
2572
  return (t.includes("underline") || t.includes("line-through")) && t !== a;
2560
2573
  }
2561
- function O(e) {
2574
+ function V(e) {
2562
2575
  return e === "bold" ? 700 : e === "normal" ? 400 : parseInt(e) || 400;
2563
2576
  }
2564
- function Da(e) {
2577
+ function Ha(e) {
2565
2578
  const a = e.ownerDocument.createTreeWalker(e, NodeFilter.SHOW_TEXT);
2566
2579
  let t;
2567
2580
  for (; t = a.nextNode(); )
2568
2581
  if (t.data.trim()) return !1;
2569
2582
  return !0;
2570
2583
  }
2571
- const Pa = {
2584
+ const Da = {
2572
2585
  id: "distinguishable/link-in-text-block",
2573
2586
  category: "distinguishable",
2574
2587
  wcag: ["1.4.1"],
2575
2588
  level: "A",
2576
2589
  fixability: "visual",
2590
+ browserHint: "Screenshot the text block to see how the link blends with surrounding text, then verify your fix (e.g., underline or border) makes the link visually distinct.",
2577
2591
  description: "Links within text blocks must be distinguishable by more than color alone.",
2578
2592
  guidance: "Users who cannot perceive color differences need other visual cues to identify links. Links in text should have underlines or other non-color indicators. If using color alone, ensure 3:1 contrast with surrounding text AND provide additional indication on focus/hover.",
2579
2593
  run(e) {
2580
2594
  const a = [];
2581
2595
  for (const t of e.querySelectorAll("a[href]")) {
2582
- if (h(t) || !k(t).trim() || Da(t) || t.closest('nav, header, footer, aside, [role="navigation"], [role="banner"], [role="contentinfo"], [role="complementary"]')) continue;
2583
- const i = y(t);
2596
+ if (h(t) || !k(t).trim() || Ha(t) || t.closest('nav, header, footer, aside, [role="navigation"], [role="banner"], [role="contentinfo"], [role="complementary"]')) continue;
2597
+ const i = x(t);
2584
2598
  if (!Ma.has(i.display || "inline")) continue;
2585
2599
  const n = $a(t);
2586
2600
  if (!n) continue;
2587
- const r = y(n.block), o = r.textDecorationLine || r.textDecoration || "";
2588
- if (qe(i, o) || (parseFloat(i.borderBottomWidth) || 0) > 0 && i.borderBottomStyle !== "none" && i.borderBottomStyle !== "hidden" || Math.abs(O(i.fontWeight) - O(r.fontWeight)) >= 300 || i.fontStyle !== r.fontStyle) continue;
2601
+ const r = x(n.block), o = r.textDecorationLine || r.textDecoration || "";
2602
+ if (qe(i, o) || (parseFloat(i.borderBottomWidth) || 0) > 0 && i.borderBottomStyle !== "none" && i.borderBottomStyle !== "hidden" || Math.abs(V(i.fontWeight) - V(r.fontWeight)) >= 300 || i.fontStyle !== r.fontStyle) continue;
2589
2603
  const l = parseFloat(i.fontSize) || 16, d = parseFloat(r.fontSize) || 16;
2590
2604
  if (d > 0 && l / d >= 1.2) continue;
2591
2605
  let c = !1;
2592
- for (const w of t.querySelectorAll("*")) {
2593
- const A = y(w);
2594
- if (qe(A, o) || Math.abs(O(A.fontWeight) - O(r.fontWeight)) >= 300) {
2606
+ for (const y of t.querySelectorAll("*")) {
2607
+ const A = x(y);
2608
+ if (qe(A, o) || Math.abs(V(A.fontWeight) - V(r.fontWeight)) >= 300) {
2595
2609
  c = !0;
2596
2610
  break;
2597
2611
  }
@@ -2601,19 +2615,20 @@ const Pa = {
2601
2615
  if (!u) continue;
2602
2616
  const b = I(...u), g = I(...n.textColor), f = $(b, g);
2603
2617
  if (f < 1.1 || f >= 3) continue;
2604
- const v = (w) => "#" + w.map((A) => A.toString(16).padStart(2, "0")).join("");
2618
+ const v = (y) => "#" + y.map((A) => A.toString(16).padStart(2, "0")).join("");
2605
2619
  a.push({
2606
2620
  ruleId: "distinguishable/link-in-text-block",
2607
2621
  selector: p(t),
2608
2622
  html: m(t),
2609
2623
  impact: "serious",
2610
2624
  message: "Link in text block is not visually distinguishable from surrounding text. Add a non-color visual indicator such as an underline or border.",
2611
- context: `link color: ${v(u)} rgb(${u.join(", ")}), surrounding text: ${v(n.textColor)} rgb(${n.textColor.join(", ")}), ratio: ${f.toFixed(2)}:1`
2625
+ context: `link color: ${v(u)} rgb(${u.join(", ")}), surrounding text: ${v(n.textColor)} rgb(${n.textColor.join(", ")}), ratio: ${f.toFixed(2)}:1`,
2626
+ fix: { type: "suggest", suggestion: "Add text-decoration: underline to the link, or add a visible border-bottom. If relying on color contrast alone, ensure at least 3:1 ratio between the link color and surrounding text color." }
2612
2627
  });
2613
2628
  }
2614
2629
  return a;
2615
2630
  }
2616
- }, Fa = /* @__PURE__ */ new Set([
2631
+ }, Pa = /* @__PURE__ */ new Set([
2617
2632
  "SCRIPT",
2618
2633
  "STYLE",
2619
2634
  "NOSCRIPT",
@@ -2629,7 +2644,7 @@ const Pa = {
2629
2644
  "BR",
2630
2645
  "HR"
2631
2646
  ]);
2632
- function Ha(e) {
2647
+ function Fa(e) {
2633
2648
  const a = e.clip;
2634
2649
  if (a && a.startsWith("rect(")) {
2635
2650
  const i = a.match(/[\d.]+/g);
@@ -2647,8 +2662,8 @@ function za(e) {
2647
2662
  if (h(e)) return !0;
2648
2663
  let a = e;
2649
2664
  for (; a; ) {
2650
- const t = y(a);
2651
- if (t.display === "none" || t.visibility === "hidden" || Ha(t)) return !0;
2665
+ const t = x(a);
2666
+ if (t.display === "none" || t.visibility === "hidden" || Fa(t)) return !0;
2652
2667
  a = a.parentElement;
2653
2668
  }
2654
2669
  return !1;
@@ -2693,10 +2708,10 @@ function _a(e) {
2693
2708
  const a = parseFloat(e);
2694
2709
  return isNaN(a) ? NaN : e.trim().endsWith("%") ? a / 100 : a;
2695
2710
  }
2696
- const Le = /([a-z-]+)\(([^)]*)\)/g;
2697
- function Ee(e) {
2711
+ const Ee = /([a-z-]+)\(([^)]*)\)/g;
2712
+ function Le(e) {
2698
2713
  let a, t = !1;
2699
- for (Le.lastIndex = 0; a = Le.exec(e); ) {
2714
+ for (Ee.lastIndex = 0; a = Ee.exec(e); ) {
2700
2715
  t = !0;
2701
2716
  const i = Ba[a[1]];
2702
2717
  if (i === void 0 || _a(a[2]) !== i) return !1;
@@ -2706,12 +2721,12 @@ function Ee(e) {
2706
2721
  function Ga(e) {
2707
2722
  let a = e;
2708
2723
  for (; a; ) {
2709
- const t = y(a), i = t.filter;
2710
- if (i && i !== "none" && i !== "initial" && !Ee(i)) return !0;
2724
+ const t = x(a), i = t.filter;
2725
+ if (i && i !== "none" && i !== "initial" && !Le(i)) return !0;
2711
2726
  const n = t.mixBlendMode;
2712
2727
  if (n && n !== "normal" && n !== "initial") return !0;
2713
2728
  const r = t.backdropFilter;
2714
- if (r && r !== "none" && r !== "initial" && !Ee(r)) return !0;
2729
+ if (r && r !== "none" && r !== "initial" && !Le(r)) return !0;
2715
2730
  a = a.parentElement;
2716
2731
  }
2717
2732
  return !1;
@@ -2719,7 +2734,7 @@ function Ga(e) {
2719
2734
  function Ya(e) {
2720
2735
  let a = e;
2721
2736
  for (; a; ) {
2722
- const t = y(a), i = t.backgroundImage;
2737
+ const t = x(a), i = t.backgroundImage;
2723
2738
  if (i && i !== "none" && i !== "initial")
2724
2739
  return i.includes("gradient(") ? { bgImage: i, gradientEl: a } : null;
2725
2740
  const n = t.backgroundColor;
@@ -2727,7 +2742,7 @@ function Ya(e) {
2727
2742
  a = a.parentElement;
2728
2743
  continue;
2729
2744
  }
2730
- if (U(n) < 0.01) {
2745
+ if (W(n) < 0.01) {
2731
2746
  a = a.parentElement;
2732
2747
  continue;
2733
2748
  }
@@ -2742,11 +2757,11 @@ function Xa(e, a, t, i, n, r, o, s, l) {
2742
2757
  for (const f of d) {
2743
2758
  let v = a;
2744
2759
  t < 1 && (v = R(a, f, t)), i < 1 && (v = R(v, f, i));
2745
- const w = $(
2760
+ const y = $(
2746
2761
  I(v[0], v[1], v[2]),
2747
2762
  I(f[0], f[1], f[2])
2748
2763
  );
2749
- w > c && (c = w, u = f);
2764
+ y > c && (c = y, u = f);
2750
2765
  }
2751
2766
  if (c >= n) return null;
2752
2767
  let b = a;
@@ -2758,7 +2773,8 @@ function Xa(e, a, t, i, n, r, o, s, l) {
2758
2773
  html: m(e),
2759
2774
  impact: "serious",
2760
2775
  message: `Insufficient${o === "AAA" ? " enhanced" : ""} color contrast ratio of ${g}:1 (required ${n}:1).`,
2761
- context: `foreground: ${ne(b)} rgb(${b.join(", ")}), background: gradient, ratio: ${g}:1, required: ${n}:1`
2776
+ context: `foreground: ${_(b)} rgb(${b.join(", ")}), background: gradient, ratio: ${g}:1, required: ${n}:1`,
2777
+ fix: { type: "suggest", suggestion: `Change the text color or gradient background so the contrast ratio meets ${n}:1. The current foreground is ${_(b)}.` }
2762
2778
  };
2763
2779
  }
2764
2780
  function _e(e, a, t) {
@@ -2769,10 +2785,10 @@ function _e(e, a, t) {
2769
2785
  for (; s = r.nextNode(); ) {
2770
2786
  if (!s.textContent || !s.textContent.trim() || Oa(s.textContent)) continue;
2771
2787
  const l = s.parentElement;
2772
- if (!l || o.has(l) || (o.add(l), Fa.has(l.tagName))) continue;
2788
+ if (!l || o.has(l) || (o.add(l), Pa.has(l.tagName))) continue;
2773
2789
  const d = l.tagName;
2774
2790
  if (d === "BODY" || d === "HTML" || Wa(l) || ja(l) || Ua(l, e) || Va(l) || za(l)) continue;
2775
- const c = y(l);
2791
+ const c = x(l);
2776
2792
  if (parseFloat(c.opacity) === 0) continue;
2777
2793
  const u = Mt(l);
2778
2794
  if (u < 0.1) continue;
@@ -2781,47 +2797,48 @@ function _e(e, a, t) {
2781
2797
  if (b && b !== "none" && b !== "initial" && (g = Tt(b), !g) || Ga(l) || $t(l)) continue;
2782
2798
  const f = C(c.color);
2783
2799
  if (!f) continue;
2784
- const v = U(c.color);
2785
- if (v === 0 || Lt(l)) continue;
2786
- const w = t === "AAA" ? xe(l) ? 4.5 : 7 : xe(l) ? 3 : 4.5;
2800
+ const v = W(c.color);
2801
+ if (v === 0 || Et(l)) continue;
2802
+ const y = t === "AAA" ? xe(l) ? 4.5 : 7 : xe(l) ? 3 : 4.5;
2787
2803
  let A = ye(l);
2788
2804
  if (!A) {
2789
2805
  if (g) continue;
2790
- const L = Ya(l);
2791
- if (L) {
2792
- const _ = L.gradientEl.parentElement ? ye(L.gradientEl.parentElement) : null, W = Xa(
2806
+ const E = Ya(l);
2807
+ if (E) {
2808
+ const O = E.gradientEl.parentElement ? ye(E.gradientEl.parentElement) : null, H = Xa(
2793
2809
  l,
2794
2810
  f,
2795
2811
  v,
2796
2812
  u,
2797
- w,
2813
+ y,
2798
2814
  a,
2799
2815
  t,
2800
- L.bgImage,
2801
- _ ?? [255, 255, 255]
2816
+ E.bgImage,
2817
+ O ?? [255, 255, 255]
2802
2818
  );
2803
- W && i.push(W);
2819
+ H && i.push(H);
2804
2820
  }
2805
2821
  continue;
2806
2822
  }
2807
2823
  let S = f;
2808
2824
  v < 1 && (S = R(f, A, v)), u < 1 && (S = R(S, A, u));
2809
2825
  const nt = I(S[0], S[1], S[2]), rt = I(A[0], A[1], A[2]), be = g ? Nt(S, A, g) : $(nt, rt);
2810
- if (be < w) {
2811
- const L = Math.round(be * 100) / 100, _ = ne(S), W = ne(A);
2826
+ if (be < y) {
2827
+ const E = Math.round(be * 100) / 100, O = _(S), H = _(A);
2812
2828
  i.push({
2813
2829
  ruleId: a,
2814
2830
  selector: p(l),
2815
2831
  html: m(l),
2816
2832
  impact: "serious",
2817
- message: `Insufficient${t === "AAA" ? " enhanced" : ""} color contrast ratio of ${L}:1 (required ${w}:1).`,
2818
- context: `foreground: ${_} rgb(${S.join(", ")}), background: ${W} rgb(${A.join(", ")}), ratio: ${L}:1, required: ${w}:1`
2833
+ message: `Insufficient${t === "AAA" ? " enhanced" : ""} color contrast ratio of ${E}:1 (required ${y}:1).`,
2834
+ context: `foreground: ${O} rgb(${S.join(", ")}), background: ${H} rgb(${A.join(", ")}), ratio: ${E}:1, required: ${y}:1`,
2835
+ fix: { type: "suggest", suggestion: `Change the text color or background color so the contrast ratio meets ${y}:1. Current foreground is ${O}, background is ${H}.` }
2819
2836
  });
2820
2837
  }
2821
2838
  }
2822
2839
  return i;
2823
2840
  }
2824
- const Ka = {
2841
+ const Ja = {
2825
2842
  id: "distinguishable/color-contrast",
2826
2843
  category: "distinguishable",
2827
2844
  actRuleIds: ["afw4f7"],
@@ -2829,11 +2846,12 @@ const Ka = {
2829
2846
  level: "AA",
2830
2847
  fixability: "visual",
2831
2848
  description: "Text elements must have sufficient color contrast against the background.",
2849
+ browserHint: "Violation context includes computed colors and ratio. After changing colors, use JavaScript to read getComputedStyle() on the element and recalculate the contrast ratio. Screenshot the element to verify the fix looks correct in context.",
2832
2850
  guidance: "WCAG SC 1.4.3 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (>=24px or >=18.66px bold). Increase the contrast by darkening the text or lightening the background, or vice versa.",
2833
2851
  run(e) {
2834
2852
  return _e(e, "distinguishable/color-contrast", "AA");
2835
2853
  }
2836
- }, Ja = {
2854
+ }, Ka = {
2837
2855
  id: "distinguishable/color-contrast-enhanced",
2838
2856
  category: "distinguishable",
2839
2857
  actRuleIds: ["09o5cg"],
@@ -2841,6 +2859,7 @@ const Ka = {
2841
2859
  level: "AAA",
2842
2860
  fixability: "visual",
2843
2861
  description: "Text elements must have enhanced color contrast against the background (WCAG AAA).",
2862
+ browserHint: "Violation context includes computed colors and ratio. After changing colors, use JavaScript to read getComputedStyle() on the element and recalculate the contrast ratio. Screenshot the element to verify the fix looks correct in context.",
2844
2863
  guidance: "WCAG SC 1.4.6 (AAA) requires a contrast ratio of at least 7:1 for normal text and 4.5:1 for large text (>=24px or >=18.66px bold). Higher contrast benefits users with low vision, aging eyes, or poor screen conditions. Increase the contrast by darkening the text or lightening the background, or vice versa.",
2845
2864
  run(e) {
2846
2865
  return _e(e, "distinguishable/color-contrast-enhanced", "AAA");
@@ -3024,6 +3043,7 @@ const di = {
3024
3043
  wcag: ["2.1.1"],
3025
3044
  level: "A",
3026
3045
  fixability: "contextual",
3046
+ browserHint: "Tab to the scrollable region and verify keyboard scrolling works with arrow keys.",
3027
3047
  description: "Scrollable regions must be keyboard accessible.",
3028
3048
  guidance: "Content that scrolls must be accessible to keyboard users. If a region has overflow:scroll or overflow:auto and contains scrollable content, it needs either tabindex='0' to be focusable, or it must contain focusable elements. Without this, keyboard users cannot scroll the content.",
3029
3049
  run(e) {
@@ -3035,17 +3055,17 @@ const di = {
3035
3055
  if (n === "body" || n === "html") continue;
3036
3056
  const r = i.getAttribute("role");
3037
3057
  if (r === "presentation" || r === "none" || r === "listbox" || r === "menu" || r === "tree" || r === "tabpanel") continue;
3038
- const o = y(i), s = o.overflowX, l = o.overflowY;
3058
+ const o = x(i), s = o.overflowX, l = o.overflowY;
3039
3059
  if (!(s === "scroll" || s === "auto" || l === "scroll" || l === "auto")) continue;
3040
3060
  if (i.scrollHeight > 0 || i.clientHeight > 0) {
3041
3061
  const g = i.scrollHeight - i.clientHeight, f = i.scrollWidth - i.clientWidth;
3042
3062
  if (g <= 0 && f <= 0 || g < 14 && f < 14 || i.clientWidth < 64 && i.clientHeight < 64) continue;
3043
- const v = ((t = i.textContent) == null ? void 0 : t.trim().length) ?? 0, w = i.querySelector("img, svg, video, canvas, picture") !== null;
3044
- if (v === 0 && !w) continue;
3063
+ const v = ((t = i.textContent) == null ? void 0 : t.trim().length) ?? 0, y = i.querySelector("img, svg, video, canvas, picture") !== null;
3064
+ if (v === 0 && !y) continue;
3045
3065
  } else
3046
3066
  continue;
3047
3067
  const u = i.getAttribute("tabindex");
3048
- u !== null && u !== "-1" || i.querySelector(z) || a.push({
3068
+ u !== null && u !== "-1" || i.querySelector(j) || a.push({
3049
3069
  ruleId: "keyboard-accessible/scrollable-region",
3050
3070
  selector: p(i),
3051
3071
  html: m(i),
@@ -3093,11 +3113,12 @@ const di = {
3093
3113
  wcag: ["2.4.7"],
3094
3114
  level: "AA",
3095
3115
  fixability: "visual",
3116
+ browserHint: "Tab to the element and screenshot to verify a visible focus indicator appears. Check that the indicator has sufficient contrast against the background.",
3096
3117
  description: "Elements in sequential focus order must have a visible focus indicator.",
3097
3118
  guidance: "Keyboard users need to see which element has focus. Do not remove the default focus outline (outline: none) without providing an alternative visible indicator. Use :focus-visible or :focus styles to ensure focus is always perceivable.",
3098
3119
  run(e) {
3099
3120
  const a = [];
3100
- for (const t of e.querySelectorAll(z)) {
3121
+ for (const t of e.querySelectorAll(j)) {
3101
3122
  if (h(t) || !(t instanceof HTMLElement)) continue;
3102
3123
  const i = t.getAttribute("style") || "";
3103
3124
  if (/outline\s*:\s*(none|0)\s*(;|$|!)/i.test(i)) {
@@ -3127,7 +3148,7 @@ function Ye(e) {
3127
3148
  return { seconds: t, hasValidUrl: i };
3128
3149
  }
3129
3150
  const Xe = 'article, aside, main, nav, section, [role="article"], [role="complementary"], [role="main"], [role="navigation"], [role="region"]', Re = '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"]';
3130
- function Ke(e) {
3151
+ function Je(e) {
3131
3152
  return {
3132
3153
  id: e.id,
3133
3154
  category: e.id.split("/")[0],
@@ -3350,10 +3371,10 @@ const bi = {
3350
3371
  run(e) {
3351
3372
  var o, s, l;
3352
3373
  const a = e.querySelector("h1");
3353
- if (a && x(a)) return [];
3374
+ if (a && w(a)) return [];
3354
3375
  const t = e.querySelectorAll('[role="heading"][aria-level="1"]');
3355
3376
  for (const d of t)
3356
- if (x(d)) return [];
3377
+ if (w(d)) return [];
3357
3378
  const i = [], n = (s = (o = e.querySelector("title")) == null ? void 0 : o.textContent) == null ? void 0 : s.trim();
3358
3379
  n && i.push(`Page title: "${n}"`);
3359
3380
  const r = e.querySelector("main");
@@ -3377,6 +3398,7 @@ const bi = {
3377
3398
  level: "A",
3378
3399
  tags: ["best-practice"],
3379
3400
  fixability: "contextual",
3401
+ browserHint: "Screenshot the page to see the visual hierarchy, then take an accessibility tree snapshot to map heading levels to visual sections.",
3380
3402
  description: "Heading levels should increase by one; skipping levels (e.g. h2 to h4) makes navigation harder.",
3381
3403
  guidance: "Screen reader users navigate by headings to understand page structure. Skipping levels (h2 to h4) suggests missing content and creates confusion. Start with h1 for the page title, then use h2 for main sections, h3 for subsections, etc. You can go back up (h3 to h2) when starting a new section.",
3382
3404
  run(e) {
@@ -3405,13 +3427,14 @@ const bi = {
3405
3427
  level: "A",
3406
3428
  tags: ["best-practice"],
3407
3429
  fixability: "contextual",
3430
+ browserHint: "Screenshot the heading area to verify it's visually empty, then add meaningful text or remove the heading element.",
3408
3431
  description: "Headings must have discernible text.",
3409
3432
  guidance: "Screen reader users navigate pages by headings, so empty headings create confusing navigation points. Ensure all headings contain visible text or accessible names. If a heading is used purely for visual styling, use CSS instead of heading elements.",
3410
3433
  run(e) {
3411
3434
  var i;
3412
3435
  const a = [], t = e.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
3413
3436
  for (const n of t)
3414
- if (!h(n) && !x(n)) {
3437
+ if (!h(n) && !w(n)) {
3415
3438
  let r;
3416
3439
  const o = n.nextElementSibling;
3417
3440
  if (o) {
@@ -3436,7 +3459,8 @@ const bi = {
3436
3459
  wcag: ["1.3.1"],
3437
3460
  level: "A",
3438
3461
  tags: ["best-practice"],
3439
- fixability: "visual",
3462
+ fixability: "contextual",
3463
+ browserHint: "Screenshot the page to verify the paragraph visually functions as a heading and choose the correct heading level.",
3440
3464
  description: "Paragraphs should not be styled to look like headings.",
3441
3465
  guidance: "When paragraphs are styled with bold, large fonts to look like headings, screen reader users miss the semantic structure. Use proper heading elements (h1-h6) instead of styled paragraphs. If you need specific styling, apply CSS to the heading elements while maintaining proper heading hierarchy.",
3442
3466
  run(e) {
@@ -3452,7 +3476,8 @@ const bi = {
3452
3476
  selector: p(n),
3453
3477
  html: m(n),
3454
3478
  impact: "serious",
3455
- message: "Paragraph appears to be styled as a heading. Use an h1-h6 element instead."
3479
+ message: "Paragraph appears to be styled as a heading. Use an h1-h6 element instead.",
3480
+ fix: { type: "suggest", suggestion: "Replace the <p> element with the appropriate heading level (h1-h6) based on the document outline. Preserve the text content and move any inline styles to a CSS class on the new heading element." }
3456
3481
  });
3457
3482
  }
3458
3483
  }
@@ -3476,20 +3501,21 @@ function qi(e) {
3476
3501
  return a.length > 0 ? a.join(`
3477
3502
  `) : void 0;
3478
3503
  }
3479
- const Li = {
3504
+ const Ei = {
3480
3505
  id: "navigable/link-name",
3481
3506
  category: "navigable",
3482
3507
  actRuleIds: ["c487ae"],
3483
3508
  wcag: ["2.4.4", "4.1.2"],
3484
3509
  level: "A",
3485
3510
  fixability: "contextual",
3511
+ browserHint: "Screenshot the link in context to understand its destination, then write descriptive link text.",
3486
3512
  description: "Links must have discernible text via content, aria-label, or aria-labelledby.",
3487
3513
  guidance: "Screen reader users need to know where a link goes. Add descriptive text content, aria-label, or use aria-labelledby. For image links, ensure the image has alt text describing the link destination. Avoid generic text like 'click here' or 'read more'—link text should make sense out of context.",
3488
3514
  run(e) {
3489
3515
  const a = [];
3490
3516
  for (const t of e.querySelectorAll('a[href], area[href], [role="link"]')) {
3491
3517
  if (h(t) || q(t) || t.getRootNode() instanceof ShadowRoot) continue;
3492
- x(t) || a.push({
3518
+ w(t) || a.push({
3493
3519
  ruleId: "navigable/link-name",
3494
3520
  selector: p(t),
3495
3521
  html: m(t),
@@ -3501,7 +3527,7 @@ const Li = {
3501
3527
  }
3502
3528
  return a;
3503
3529
  }
3504
- }, Ei = {
3530
+ }, Li = {
3505
3531
  id: "navigable/skip-link",
3506
3532
  category: "navigable",
3507
3533
  wcag: ["2.4.1"],
@@ -3574,19 +3600,19 @@ const Li = {
3574
3600
  description: "Page should not have more than one main landmark.",
3575
3601
  guidance: "Only one main landmark should exist per page. The main landmark identifies the primary content area. If you have multiple content sections, use <section> with appropriate headings instead of multiple main elements.",
3576
3602
  filterTopLevel: !1
3577
- }), Mi = Ke({
3603
+ }), Mi = Je({
3578
3604
  id: "landmarks/banner-is-top-level",
3579
3605
  selector: '[role="banner"]',
3580
3606
  landmarkName: "Banner",
3581
3607
  description: "Banner landmark should not be nested within another landmark.",
3582
3608
  guidance: "The banner landmark should be a top-level landmark, not nested inside article, aside, main, nav, or section. If a header is inside these elements, it automatically becomes a generic header rather than a banner. Remove explicit role='banner' from nested headers or restructure the page."
3583
- }), $i = Ke({
3609
+ }), $i = Je({
3584
3610
  id: "landmarks/contentinfo-is-top-level",
3585
3611
  selector: '[role="contentinfo"]',
3586
3612
  landmarkName: "Contentinfo",
3587
3613
  description: "Contentinfo landmark should not be nested within another landmark.",
3588
3614
  guidance: "The contentinfo landmark should be a top-level landmark. A footer inside article, aside, main, nav, or section becomes a scoped footer, not a contentinfo landmark. Remove explicit role='contentinfo' from nested footers or move the footer outside sectioning elements."
3589
- }), Di = {
3615
+ }), Hi = {
3590
3616
  id: "landmarks/main-is-top-level",
3591
3617
  category: "landmarks",
3592
3618
  wcag: [],
@@ -3609,7 +3635,7 @@ const Li = {
3609
3635
  }
3610
3636
  return a;
3611
3637
  }
3612
- }, Pi = {
3638
+ }, Di = {
3613
3639
  id: "landmarks/complementary-is-top-level",
3614
3640
  category: "landmarks",
3615
3641
  wcag: [],
@@ -3632,7 +3658,7 @@ const Li = {
3632
3658
  }
3633
3659
  return a;
3634
3660
  }
3635
- }, Fi = {
3661
+ }, Pi = {
3636
3662
  id: "landmarks/landmark-unique",
3637
3663
  category: "landmarks",
3638
3664
  wcag: [],
@@ -3653,7 +3679,7 @@ const Li = {
3653
3679
  if (r.length <= 1) continue;
3654
3680
  const o = /* @__PURE__ */ new Map();
3655
3681
  for (const s of r) {
3656
- const l = x(s).toLowerCase() || "", d = o.get(l) || [];
3682
+ const l = w(s).toLowerCase() || "", d = o.get(l) || [];
3657
3683
  d.push(s), o.set(l, d);
3658
3684
  }
3659
3685
  for (const [s, l] of o)
@@ -3669,7 +3695,7 @@ const Li = {
3669
3695
  }
3670
3696
  return a;
3671
3697
  }
3672
- }, Hi = {
3698
+ }, Fi = {
3673
3699
  id: "landmarks/region",
3674
3700
  category: "landmarks",
3675
3701
  wcag: [],
@@ -3738,7 +3764,7 @@ const Li = {
3738
3764
  ), Ui = new Set(
3739
3765
  "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(" ")
3740
3766
  ), Wi = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
3741
- function Je(e) {
3767
+ function Ke(e) {
3742
3768
  if (!Wi.test(e)) return !1;
3743
3769
  const a = e.split("-")[0].toLowerCase();
3744
3770
  return a.length === 2 ? ji.has(a) : a.length === 3 ? !Ui.has(a) : !1;
@@ -3788,7 +3814,7 @@ const Oi = {
3788
3814
  run(e) {
3789
3815
  var t;
3790
3816
  const a = (t = e.documentElement.getAttribute("lang")) == null ? void 0 : t.trim();
3791
- return a && !Je(a) ? [{
3817
+ return a && !Ke(a) ? [{
3792
3818
  ruleId: "readable/html-lang-valid",
3793
3819
  selector: "html",
3794
3820
  html: m(e.documentElement),
@@ -3821,7 +3847,7 @@ const Oi = {
3821
3847
  });
3822
3848
  continue;
3823
3849
  }
3824
- n && Ce(t) && (Je(n) || a.push({
3850
+ n && Ce(t) && (Ke(n) || a.push({
3825
3851
  ruleId: "readable/valid-lang",
3826
3852
  selector: p(t),
3827
3853
  html: m(t),
@@ -3864,13 +3890,14 @@ const Oi = {
3864
3890
  wcag: ["4.1.2"],
3865
3891
  level: "A",
3866
3892
  fixability: "contextual",
3893
+ browserHint: "Screenshot the iframe to see what content it displays, then add a title describing its purpose.",
3867
3894
  description: "Frames must have an accessible name.",
3868
3895
  guidance: "Screen readers announce frame titles when users navigate frames. Add a title attribute to <iframe> and <frame> elements that describes the frame's purpose (e.g., <iframe title='Video player'>). Avoid generic titles like 'frame' or 'iframe'. If the frame is decorative, use aria-hidden='true'.",
3869
3896
  run(e) {
3870
3897
  const a = [];
3871
3898
  for (const t of e.querySelectorAll("iframe, frame")) {
3872
3899
  if (h(t) || Ge(t)) continue;
3873
- if (!x(t)) {
3900
+ if (!w(t)) {
3874
3901
  const n = t.getAttribute("src");
3875
3902
  a.push({
3876
3903
  ruleId: "labels-and-names/frame-title",
@@ -3940,7 +3967,7 @@ function Xi(e) {
3940
3967
  }
3941
3968
  return "";
3942
3969
  }
3943
- const Ki = [
3970
+ const Ji = [
3944
3971
  '[role="checkbox"]',
3945
3972
  '[role="combobox"]',
3946
3973
  '[role="listbox"]',
@@ -3952,7 +3979,7 @@ const Ki = [
3952
3979
  '[role="spinbutton"]',
3953
3980
  '[role="switch"]',
3954
3981
  '[role="textbox"]'
3955
- ].join(", "), Ji = /* @__PURE__ */ new Set([
3982
+ ].join(", "), Ki = /* @__PURE__ */ new Set([
3956
3983
  "checkbox",
3957
3984
  "menuitemcheckbox",
3958
3985
  "menuitemradio",
@@ -3969,8 +3996,8 @@ const Ki = [
3969
3996
  function Zi(e) {
3970
3997
  var o, s, l, d;
3971
3998
  const a = (o = e.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
3972
- if (a && Ji.has(a) || (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && !(a && Qi.has(a)))
3973
- return x(e);
3999
+ if (a && Ki.has(a) || (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && !(a && Qi.has(a)))
4000
+ return w(e);
3974
4001
  const i = e.getAttribute("aria-labelledby");
3975
4002
  if (i) {
3976
4003
  const c = i.split(/\s+/).map((u) => {
@@ -4000,11 +4027,12 @@ const en = {
4000
4027
  wcag: ["4.1.2"],
4001
4028
  level: "A",
4002
4029
  fixability: "contextual",
4030
+ browserHint: "Screenshot the form to see visual label placement relative to the input, then associate them with a label element or aria-labelledby.",
4003
4031
  description: "Form elements must have labels. Use <label>, aria-label, or aria-labelledby.",
4004
4032
  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. Labels should describe the information requested, not the field type (e.g., 'Email address', 'Search', 'Phone number').",
4005
4033
  run(e) {
4006
4034
  var i;
4007
- const a = [], t = e.querySelectorAll(`${Qe}, ${Ki}`);
4035
+ const a = [], t = e.querySelectorAll(`${Qe}, ${Ji}`);
4008
4036
  for (const n of t) {
4009
4037
  if (h(n) || q(n)) continue;
4010
4038
  const r = (i = n.getAttribute("role")) == null ? void 0 : i.trim().toLowerCase();
@@ -4070,6 +4098,7 @@ const en = {
4070
4098
  wcag: ["4.1.2"],
4071
4099
  level: "A",
4072
4100
  fixability: "contextual",
4101
+ browserHint: "Screenshot the button to see its visual purpose, then set value or aria-label to describe the action.",
4073
4102
  description: "Input buttons must have discernible text via value, aria-label, or aria-labelledby.",
4074
4103
  guidance: "Input buttons (<input type='submit'>, type='button', type='reset'>) need accessible names so users know what action the button performs. Add a value attribute with descriptive text (e.g., value='Submit Form'), or use aria-label if the value must differ from the accessible name.",
4075
4104
  run(e) {
@@ -4080,7 +4109,7 @@ const en = {
4080
4109
  )) {
4081
4110
  if (h(n) || q(n)) continue;
4082
4111
  const r = (t = n.getAttribute("value")) == null ? void 0 : t.trim(), o = (i = n.getAttribute("type")) == null ? void 0 : i.toLowerCase(), s = (o === "submit" || o === "reset") && !n.hasAttribute("value");
4083
- !r && !s && !x(n) && a.push({
4112
+ !r && !s && !w(n) && a.push({
4084
4113
  ruleId: "labels-and-names/input-button-name",
4085
4114
  selector: p(n),
4086
4115
  html: m(n),
@@ -4109,16 +4138,17 @@ const nn = {
4109
4138
  level: "A",
4110
4139
  tags: ["best-practice"],
4111
4140
  fixability: "contextual",
4141
+ browserHint: "Screenshot the control to see its visible label, then ensure aria-label starts with that visible text.",
4112
4142
  description: "Interactive elements with visible text must have accessible names that contain that text.",
4113
4143
  guidance: "For voice control users who activate controls by speaking their visible label, the accessible name must include the visible text. If aria-label is 'Submit form' but the button shows 'Send', voice users saying 'click Send' won't activate it. Ensure aria-label/aria-labelledby contains or matches the visible text.",
4114
4144
  run(e) {
4115
4145
  const a = [];
4116
4146
  for (const t of e.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
4117
4147
  if (h(t)) continue;
4118
- const i = x(t);
4148
+ const i = w(t);
4119
4149
  if (!i) continue;
4120
4150
  let n = "";
4121
- t instanceof HTMLInputElement ? n = t.value || "" : n = Z(t);
4151
+ t instanceof HTMLInputElement ? n = t.value || "" : n = ee(t);
4122
4152
  const r = n.trim();
4123
4153
  if (!r || r.length <= 2) continue;
4124
4154
  const o = t.hasAttribute("aria-label"), s = t.hasAttribute("aria-labelledby");
@@ -4133,13 +4163,13 @@ const nn = {
4133
4163
  }
4134
4164
  for (const t of e.querySelectorAll("input, select, textarea")) {
4135
4165
  if (h(t) || t instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(t.type)) continue;
4136
- const i = x(t);
4166
+ const i = w(t);
4137
4167
  if (!i || !t.hasAttribute("aria-label")) continue;
4138
4168
  const r = t.id;
4139
4169
  let o = "";
4140
4170
  if (r) {
4141
4171
  const s = e.querySelector(`label[for="${CSS.escape(r)}"]`);
4142
- s && (o = Z(s));
4172
+ s && (o = ee(s));
4143
4173
  }
4144
4174
  o.trim() && (Ne(i, o) || a.push({
4145
4175
  ruleId: "labels-and-names/label-content-mismatch",
@@ -4194,7 +4224,7 @@ const nn = {
4194
4224
  if (h(i) || q(i) || se(i)) continue;
4195
4225
  const n = i.getAttribute("role");
4196
4226
  if ((i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") && n !== "menuitem") continue;
4197
- if (!x(i)) {
4227
+ if (!w(i)) {
4198
4228
  const o = i.querySelector("img[alt]");
4199
4229
  if ((t = o == null ? void 0 : o.getAttribute("alt")) != null && t.trim()) continue;
4200
4230
  a.push({
@@ -4230,7 +4260,7 @@ function M(e) {
4230
4260
  if (!o || !e.roleSet.has(o)) continue;
4231
4261
  }
4232
4262
  if (e.skipNative && n.matches(e.skipNative)) continue;
4233
- x(n) || t.push({
4263
+ w(n) || t.push({
4234
4264
  ruleId: e.id,
4235
4265
  selector: p(n),
4236
4266
  html: m(n),
@@ -4330,6 +4360,7 @@ const hn = {
4330
4360
  wcag: ["4.1.2"],
4331
4361
  level: "A",
4332
4362
  fixability: "contextual",
4363
+ browserHint: "Screenshot the button to identify its icon or visual label, then add a matching aria-label.",
4333
4364
  description: "Buttons must have discernible text.",
4334
4365
  guidance: "Screen reader users need to know what a button does. Add visible text content, aria-label, or aria-labelledby. For icon buttons, use aria-label describing the action (e.g., aria-label='Close'). If the button contains an image, ensure the image has alt text describing the button's action.",
4335
4366
  run(e) {
@@ -4338,7 +4369,7 @@ const hn = {
4338
4369
  if (h(t) || q(t)) continue;
4339
4370
  const i = t.getAttribute("role");
4340
4371
  if ((i === "none" || i === "presentation") && !(t.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || t.tagName.toLowerCase() === "button" && !t.disabled) || se(t)) continue;
4341
- x(t) || a.push({
4372
+ w(t) || a.push({
4342
4373
  ruleId: "labels-and-names/button-name",
4343
4374
  selector: p(t),
4344
4375
  html: m(t),
@@ -4363,7 +4394,7 @@ const hn = {
4363
4394
  const a = [];
4364
4395
  for (const t of e.querySelectorAll("details > summary:first-of-type")) {
4365
4396
  if (h(t)) continue;
4366
- x(t) || a.push({
4397
+ w(t) || a.push({
4367
4398
  ruleId: "labels-and-names/summary-name",
4368
4399
  selector: p(t),
4369
4400
  html: m(t),
@@ -4614,7 +4645,7 @@ Referenced by: ${d}` : ""}`,
4614
4645
  const a = [];
4615
4646
  for (const t of e.querySelectorAll("[role], [aria-*]")) {
4616
4647
  if (h(t)) continue;
4617
- const i = j(t);
4648
+ const i = U(t);
4618
4649
  if (!i) continue;
4619
4650
  const n = Sn[i];
4620
4651
  if (n)
@@ -4756,7 +4787,7 @@ Referenced by: ${d}` : ""}`,
4756
4787
  video: /* @__PURE__ */ new Set(["application"]),
4757
4788
  wbr: /* @__PURE__ */ new Set(["none", "presentation"])
4758
4789
  };
4759
- function Ln(e) {
4790
+ function En(e) {
4760
4791
  var t;
4761
4792
  const a = e.tagName.toLowerCase();
4762
4793
  if (qn.has(a))
@@ -4771,7 +4802,7 @@ function Ln(e) {
4771
4802
  }
4772
4803
  return D[a] || "any";
4773
4804
  }
4774
- const En = {
4805
+ const Ln = {
4775
4806
  id: "aria/aria-allowed-role",
4776
4807
  category: "aria",
4777
4808
  wcag: ["4.1.2"],
@@ -4788,7 +4819,7 @@ const En = {
4788
4819
  if (!n) continue;
4789
4820
  const r = $e(i);
4790
4821
  if (r && n === r) continue;
4791
- const o = Ln(i);
4822
+ const o = En(i);
4792
4823
  o === "none" ? a.push({
4793
4824
  ruleId: "aria/aria-allowed-role",
4794
4825
  selector: p(i),
@@ -4863,8 +4894,8 @@ const Mn = {
4863
4894
  const a = [];
4864
4895
  for (const t of e.querySelectorAll('[aria-hidden="true"]')) {
4865
4896
  if (t === e.body) continue;
4866
- const i = [...t.querySelectorAll(z)];
4867
- t.matches(z) && i.push(t);
4897
+ const i = [...t.querySelectorAll(j)];
4898
+ t.matches(j) && i.push(t);
4868
4899
  for (const n of i)
4869
4900
  if (n instanceof HTMLElement) {
4870
4901
  const r = n.getAttribute("tabindex");
@@ -4900,14 +4931,14 @@ const Mn = {
4900
4931
  run(e) {
4901
4932
  return le(e).prohibitedAttr;
4902
4933
  }
4903
- }, Dn = [
4934
+ }, Hn = [
4904
4935
  "a[href]",
4905
4936
  "button:not([disabled])",
4906
4937
  'input:not([disabled]):not([type="hidden"])',
4907
4938
  "select:not([disabled])",
4908
4939
  "textarea:not([disabled])",
4909
4940
  '[tabindex]:not([tabindex="-1"])'
4910
- ].join(", "), Pn = [
4941
+ ].join(", "), Dn = [
4911
4942
  "aria-atomic",
4912
4943
  "aria-busy",
4913
4944
  "aria-controls",
@@ -4924,15 +4955,15 @@ const Mn = {
4924
4955
  ];
4925
4956
  function Me(e) {
4926
4957
  const a = [];
4927
- e.matches(Dn) && a.push("element is focusable");
4928
- for (const t of Pn)
4958
+ e.matches(Hn) && a.push("element is focusable");
4959
+ for (const t of Dn)
4929
4960
  if (e.hasAttribute(t)) {
4930
4961
  a.push(`has ${t}`);
4931
4962
  break;
4932
4963
  }
4933
4964
  return (e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
4934
4965
  }
4935
- const Fn = {
4966
+ const Pn = {
4936
4967
  id: "aria/presentation-role-conflict",
4937
4968
  category: "aria",
4938
4969
  actRuleIds: ["46ca7f"],
@@ -4969,7 +5000,7 @@ const Fn = {
4969
5000
  }
4970
5001
  return a;
4971
5002
  }
4972
- }, Hn = /* @__PURE__ */ new Set([
5003
+ }, Fn = /* @__PURE__ */ new Set([
4973
5004
  "button",
4974
5005
  "checkbox",
4975
5006
  "img",
@@ -5000,9 +5031,9 @@ const Fn = {
5000
5031
  const a = [];
5001
5032
  for (const t of e.querySelectorAll("*")) {
5002
5033
  if (h(t)) continue;
5003
- const i = j(t);
5004
- if (!(!i || !Hn.has(i))) {
5005
- for (const n of t.querySelectorAll(z))
5034
+ const i = U(t);
5035
+ if (!(!i || !Fn.has(i))) {
5036
+ for (const n of t.querySelectorAll(j))
5006
5037
  if (n !== t && !n.disabled) {
5007
5038
  a.push({
5008
5039
  ruleId: "aria/presentational-children-focusable",
@@ -5028,8 +5059,8 @@ const Fn = {
5028
5059
  Yt,
5029
5060
  Xt,
5030
5061
  // Time-based Media
5031
- Kt,
5032
5062
  Jt,
5063
+ Kt,
5033
5064
  // Adaptable
5034
5065
  na,
5035
5066
  la,
@@ -5049,9 +5080,9 @@ const Fn = {
5049
5080
  Ra,
5050
5081
  Ca,
5051
5082
  Ta,
5052
- Pa,
5053
- Ka,
5083
+ Da,
5054
5084
  Ja,
5085
+ Ka,
5055
5086
  // Keyboard Accessible
5056
5087
  Za,
5057
5088
  ti,
@@ -5072,8 +5103,8 @@ const Fn = {
5072
5103
  ki,
5073
5104
  Si,
5074
5105
  Ii,
5075
- Li,
5076
5106
  Ei,
5107
+ Li,
5077
5108
  // Landmarks
5078
5109
  Ri,
5079
5110
  Ci,
@@ -5081,10 +5112,10 @@ const Fn = {
5081
5112
  Ni,
5082
5113
  Mi,
5083
5114
  $i,
5115
+ Hi,
5084
5116
  Di,
5085
5117
  Pi,
5086
5118
  Fi,
5087
- Hi,
5088
5119
  // Readable
5089
5120
  zi,
5090
5121
  Oi,
@@ -5115,43 +5146,48 @@ const Fn = {
5115
5146
  wn,
5116
5147
  kn,
5117
5148
  In,
5118
- En,
5149
+ Ln,
5119
5150
  Cn,
5120
5151
  Mn,
5121
5152
  $n,
5122
- Fn,
5153
+ Pn,
5123
5154
  zn
5124
5155
  ];
5125
- let me = [], et = /* @__PURE__ */ new Set(), tt = !1, at = !1, T, H;
5156
+ let me = [], et = /* @__PURE__ */ new Set(), tt = !1, at = !1, T, z;
5126
5157
  function Vn(e) {
5127
- e.additionalRules && (me = e.additionalRules), e.disabledRules && (et = new Set(e.disabledRules)), "includeAAA" in e && (tt = !!e.includeAAA), "componentMode" in e && (at = !!e.componentMode), "locale" in e && (T = e.locale || void 0), H = void 0;
5158
+ e.additionalRules && (me = e.additionalRules), e.disabledRules && (et = new Set(e.disabledRules)), "includeAAA" in e && (tt = !!e.includeAAA), "componentMode" in e && (at = !!e.componentMode), "locale" in e && (T = e.locale || void 0), z = void 0;
5128
5159
  }
5129
5160
  function pe() {
5130
- if (H) return H;
5161
+ if (z) return z;
5131
5162
  const a = Ze.filter((t) => {
5132
5163
  var i;
5133
5164
  return !(et.has(t.id) || t.level === "AAA" && !tt || at && ((i = t.tags) != null && i.includes("page-level")));
5134
5165
  }).concat(me);
5135
- return T ? (H = Dt(a, T), H) : a;
5166
+ return T ? (z = Ht(a, T), z) : a;
5136
5167
  }
5137
5168
  function Bn(e) {
5138
5169
  it();
5139
- const a = pe(), t = T, i = [];
5140
- let n = 0;
5170
+ const a = pe(), t = T, i = [], n = [];
5171
+ let r = 0;
5141
5172
  return {
5142
- processChunk(r) {
5143
- const o = performance.now();
5144
- for (; n < a.length; ) {
5173
+ processChunk(o) {
5174
+ const s = performance.now();
5175
+ for (; r < a.length; ) {
5176
+ const l = a[r];
5145
5177
  try {
5146
- i.push(...a[n].run(e));
5147
- } catch {
5178
+ i.push(...l.run(e));
5179
+ } catch (d) {
5180
+ n.push({ ruleId: l.id, error: d instanceof Error ? d.message : String(d) });
5148
5181
  }
5149
- if (n++, performance.now() - o >= r) break;
5182
+ if (r++, performance.now() - s >= o) break;
5150
5183
  }
5151
- return n < a.length;
5184
+ return r < a.length;
5152
5185
  },
5153
5186
  getViolations() {
5154
5187
  return t ? ze(i, t) : i;
5188
+ },
5189
+ getSkippedRules() {
5190
+ return n;
5155
5191
  }
5156
5192
  };
5157
5193
  }
@@ -5159,19 +5195,21 @@ function it() {
5159
5195
  mt(), ot(), st(), kt(), At(), pt();
5160
5196
  }
5161
5197
  function _n(e) {
5162
- var i;
5198
+ var n;
5163
5199
  it();
5164
- const a = pe(), t = [];
5165
- for (const n of a)
5200
+ const a = pe(), t = [], i = [];
5201
+ for (const r of a)
5166
5202
  try {
5167
- t.push(...n.run(e));
5168
- } catch {
5203
+ t.push(...r.run(e));
5204
+ } catch (o) {
5205
+ i.push({ ruleId: r.id, error: o instanceof Error ? o.message : String(o) });
5169
5206
  }
5170
5207
  return {
5171
- url: ((i = e.location) == null ? void 0 : i.href) ?? "",
5208
+ url: ((n = e.location) == null ? void 0 : n.href) ?? "",
5172
5209
  timestamp: Date.now(),
5173
5210
  violations: T ? ze(t, T) : t,
5174
- ruleCount: a.length
5211
+ ruleCount: a.length,
5212
+ skippedRules: i
5175
5213
  };
5176
5214
  }
5177
5215
  function Gn(e, a) {
@@ -5289,7 +5327,7 @@ const Xn = {
5289
5327
  "adaptable/orientation-lock": { description: "Page orientation must not be restricted using CSS transforms.", guidance: "Users with motor disabilities may mount their device in a fixed orientation. Using CSS transforms with @media (orientation: portrait/landscape) to rotate content 90° effectively locks the page to one orientation. Remove the orientation-dependent transform and use responsive design instead.", messages: { "CSS locks page orientation via @media (orientation: {0}) with a 90° transform.": "CSS locks page orientation via @media (orientation: {0}) with a 90° transform." } },
5290
5328
  "aria/presentational-children-focusable": { description: "Elements with a role that makes children presentational must not contain focusable content.", guidance: "Roles like button, checkbox, img, tab, and others make their children presentational — hidden from assistive technologies. If those children are focusable, keyboard users can reach elements that screen reader users cannot perceive. Move focusable content outside the parent or remove the focusability.", messages: { 'Focusable element inside a "{0}" role whose children are presentational.': 'Focusable element inside a "{0}" role whose children are presentational.' } },
5291
5329
  "keyboard-accessible/focus-visible": { description: "Elements in sequential focus order must have a visible focus indicator.", guidance: "Keyboard users need to see which element has focus. Do not remove the default focus outline (outline: none) without providing an alternative visible indicator. Use :focus-visible or :focus styles to ensure focus is always perceivable.", messages: { "Focusable element has outline removed without a visible focus alternative.": "Focusable element has outline removed without a visible focus alternative." } }
5292
- }, Kn = {
5330
+ }, Jn = {
5293
5331
  "navigable/document-title": { description: "Los documentos deben tener un elemento <title> para proporcionar a los usuarios una vista general del contenido.", guidance: "Los usuarios de lectores de pantalla dependen de los títulos de página para identificar y navegar entre pestañas/ventanas. Agregue un elemento <title> descriptivo en <head> que resuma el propósito de la página. Mantenga los títulos únicos en todo el sitio, colocando el contenido específico antes del nombre del sitio (por ejemplo, 'Contáctenos - Acme Corp').", messages: { "Document <title> element is empty.": "El elemento <title> del documento está vacío.", "Document is missing a <title> element.": "Al documento le falta un elemento <title>." } },
5294
5332
  "navigable/bypass": { description: "La página debe tener un mecanismo para omitir bloques de contenido repetidos.", guidance: 'Los usuarios de teclado deben poder omitir contenido repetitivo como la navegación. Proporcione un enlace de salto en la parte superior de la página que enlace al contenido principal (por ejemplo, <a href="#main">Saltar al contenido principal</a>), o use un landmark <main>. Los lectores de pantalla pueden saltar directamente a los landmarks, por lo que un elemento <main> correctamente marcado satisface este requisito.', messages: { "Page has no mechanism to bypass repeated content. Add a <main> landmark or skip link.": "La página no tiene un mecanismo para omitir contenido repetido. Agregue un landmark <main> o un enlace de salto." } },
5295
5333
  "navigable/page-has-heading-one": { description: "La página debe contener un encabezado de nivel uno.", guidance: "Un encabezado de nivel uno (<h1> o role='heading' con aria-level='1') ayuda a los usuarios a comprender el tema de la página y proporciona un punto de referencia para la navegación con lector de pantalla. Cada página debe tener exactamente un h1 que describa el contenido principal, típicamente coincidiendo o similar al título de la página.", messages: { "Page does not contain a level-one heading.": "La página no contiene un encabezado de nivel uno." } },
@@ -5393,10 +5431,10 @@ export {
5393
5431
  Vn as configureRules,
5394
5432
  Bn as createChunkedAudit,
5395
5433
  Gn as diffAudit,
5396
- x as getAccessibleName,
5434
+ w as getAccessibleName,
5397
5435
  k as getAccessibleTextContent,
5398
5436
  pe as getActiveRules,
5399
- j as getComputedRole,
5437
+ U as getComputedRole,
5400
5438
  m as getHtmlSnippet,
5401
5439
  $e as getImplicitRole,
5402
5440
  Yn as getRuleById,
@@ -5404,7 +5442,7 @@ export {
5404
5442
  h as isAriaHidden,
5405
5443
  dt as isValidRole,
5406
5444
  Xn as localeEn,
5407
- Kn as localeEs,
5445
+ Jn as localeEs,
5408
5446
  Un as querySelectorShadowAware,
5409
5447
  Wn as registerLocale,
5410
5448
  Ze as rules,