@accesslint/core 0.8.1 → 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 (36) hide show
  1. package/dist/index.cjs +5 -5
  2. package/dist/index.iife.js +5 -5
  3. package/dist/index.js +280 -243
  4. package/dist/rules/adaptable/empty-table-header.d.ts.map +1 -1
  5. package/dist/rules/adaptable/td-has-header.d.ts.map +1 -1
  6. package/dist/rules/distinguishable/color-contrast-enhanced.d.ts.map +1 -1
  7. package/dist/rules/distinguishable/color-contrast-helpers.d.ts +4 -0
  8. package/dist/rules/distinguishable/color-contrast-helpers.d.ts.map +1 -1
  9. package/dist/rules/distinguishable/color-contrast.d.ts.map +1 -1
  10. package/dist/rules/distinguishable/link-in-text-block.d.ts.map +1 -1
  11. package/dist/rules/distinguishable/meta-viewport.d.ts.map +1 -1
  12. package/dist/rules/engine.d.ts.map +1 -1
  13. package/dist/rules/index.d.ts +5 -0
  14. package/dist/rules/index.d.ts.map +1 -1
  15. package/dist/rules/keyboard-accessible/focus-visible.d.ts.map +1 -1
  16. package/dist/rules/keyboard-accessible/scrollable-region.d.ts.map +1 -1
  17. package/dist/rules/labels-and-names/button-name.d.ts.map +1 -1
  18. package/dist/rules/labels-and-names/form-label.d.ts.map +1 -1
  19. package/dist/rules/labels-and-names/frame-title.d.ts.map +1 -1
  20. package/dist/rules/labels-and-names/input-button-name.d.ts.map +1 -1
  21. package/dist/rules/labels-and-names/label-content-mismatch.d.ts.map +1 -1
  22. package/dist/rules/navigable/empty-heading.d.ts.map +1 -1
  23. package/dist/rules/navigable/heading-order.d.ts.map +1 -1
  24. package/dist/rules/navigable/link-name.d.ts.map +1 -1
  25. package/dist/rules/navigable/p-as-heading.d.ts.map +1 -1
  26. package/dist/rules/text-alternatives/image-alt-words.d.ts.map +1 -1
  27. package/dist/rules/text-alternatives/img-alt.d.ts.map +1 -1
  28. package/dist/rules/text-alternatives/input-image-alt.d.ts.map +1 -1
  29. package/dist/rules/text-alternatives/object-alt.d.ts.map +1 -1
  30. package/dist/rules/text-alternatives/role-img-alt.d.ts.map +1 -1
  31. package/dist/rules/text-alternatives/svg-img-alt.d.ts.map +1 -1
  32. package/dist/rules/time-based-media/audio-transcript.d.ts.map +1 -1
  33. package/dist/rules/time-based-media/video-captions.d.ts.map +1 -1
  34. package/dist/rules/types.d.ts +8 -1
  35. package/dist/rules/types.d.ts.map +1 -1
  36. 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]");
@@ -1405,13 +1410,14 @@ const Wt = {
1405
1410
  wcag: ["1.1.1"],
1406
1411
  level: "A",
1407
1412
  fixability: "contextual",
1413
+ browserHint: "Screenshot the element to see its visual appearance, then provide an aria-label describing what it represents.",
1408
1414
  description: "Elements with role='img' must have an accessible name.",
1409
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.",
1410
1416
  run(e) {
1411
1417
  const a = [];
1412
1418
  for (const t of e.querySelectorAll('[role="img"]')) {
1413
1419
  if (h(t) || t.tagName.toLowerCase() === "svg" || t.tagName.toLowerCase() === "img") continue;
1414
- x(t) || a.push({
1420
+ w(t) || a.push({
1415
1421
  ruleId: "text-alternatives/role-img-alt",
1416
1422
  selector: p(t),
1417
1423
  html: m(t),
@@ -1422,13 +1428,14 @@ const Wt = {
1422
1428
  }
1423
1429
  return a;
1424
1430
  }
1425
- }, Kt = {
1431
+ }, Jt = {
1426
1432
  id: "time-based-media/video-captions",
1427
1433
  category: "time-based-media",
1428
1434
  actRuleIds: ["eac66b"],
1429
1435
  wcag: ["1.2.2"],
1430
1436
  level: "A",
1431
1437
  fixability: "contextual",
1438
+ browserHint: "Screenshot the video element to see its poster or content for context when writing captions.",
1432
1439
  description: "Video elements must have captions via <track kind='captions'> or <track kind='subtitles'>.",
1433
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.",
1434
1441
  run(e) {
@@ -1445,13 +1452,14 @@ const Wt = {
1445
1452
  }
1446
1453
  return a;
1447
1454
  }
1448
- }, Jt = {
1455
+ }, Kt = {
1449
1456
  id: "time-based-media/audio-transcript",
1450
1457
  category: "time-based-media",
1451
1458
  actRuleIds: ["e7aa44"],
1452
1459
  wcag: ["1.2.1"],
1453
1460
  level: "A",
1454
1461
  fixability: "contextual",
1462
+ browserHint: "Inspect the page around the audio element for existing transcript links or associated text content.",
1455
1463
  description: "Audio elements should have a text alternative or transcript.",
1456
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.",
1457
1465
  run(e) {
@@ -1620,7 +1628,7 @@ function ra(e) {
1620
1628
  return `Unknown check type: ${String(e.type)}`;
1621
1629
  }
1622
1630
  }
1623
- function E(e, a, t) {
1631
+ function L(e, a, t) {
1624
1632
  let i = e;
1625
1633
  if (i.includes("{{tag}}") && (i = i.replace(/\{\{tag\}\}/g, a.tagName.toLowerCase())), i.includes("{{value}}")) {
1626
1634
  let n = "";
@@ -1638,6 +1646,7 @@ function N(e) {
1638
1646
  level: e.level,
1639
1647
  tags: e.tags,
1640
1648
  fixability: e.fixability,
1649
+ browserHint: e.browserHint,
1641
1650
  description: e.description,
1642
1651
  guidance: e.guidance,
1643
1652
  run(t) {
@@ -1651,7 +1660,7 @@ function N(e) {
1651
1660
  selector: p(o),
1652
1661
  html: m(o),
1653
1662
  impact: e.impact,
1654
- message: E(e.message, o, e.check),
1663
+ message: L(e.message, o, e.check),
1655
1664
  ...e.fix ? { fix: e.fix } : {},
1656
1665
  element: o
1657
1666
  });
@@ -1667,7 +1676,7 @@ function N(e) {
1667
1676
  selector: p(d),
1668
1677
  html: m(d),
1669
1678
  impact: e.impact,
1670
- message: E(e.message, d, e.check),
1679
+ message: L(e.message, d, e.check),
1671
1680
  ...e.fix ? { fix: e.fix } : {},
1672
1681
  element: d
1673
1682
  });
@@ -1682,7 +1691,7 @@ function N(e) {
1682
1691
  selector: p(s),
1683
1692
  html: m(s),
1684
1693
  impact: e.impact,
1685
- message: E(e.message, s, e.check),
1694
+ message: L(e.message, s, e.check),
1686
1695
  ...e.fix ? { fix: e.fix } : {},
1687
1696
  element: s
1688
1697
  });
@@ -1706,7 +1715,7 @@ function N(e) {
1706
1715
  selector: p(u),
1707
1716
  html: m(u),
1708
1717
  impact: e.impact,
1709
- message: E(e.message, u, e.check),
1718
+ message: L(e.message, u, e.check),
1710
1719
  ...e.fix ? { fix: e.fix } : {},
1711
1720
  element: u
1712
1721
  }) : !d && g && i.push({
@@ -1714,7 +1723,7 @@ function N(e) {
1714
1723
  selector: p(u),
1715
1724
  html: m(u),
1716
1725
  impact: e.impact,
1717
- message: E(e.message, u, e.check),
1726
+ message: L(e.message, u, e.check),
1718
1727
  ...e.fix ? { fix: e.fix } : {},
1719
1728
  element: u
1720
1729
  });
@@ -1729,7 +1738,7 @@ function N(e) {
1729
1738
  selector: p(s),
1730
1739
  html: m(s),
1731
1740
  impact: e.impact,
1732
- message: E(e.message, s, e.check),
1741
+ message: L(e.message, s, e.check),
1733
1742
  ...e.fix ? { fix: e.fix } : {},
1734
1743
  element: s
1735
1744
  });
@@ -1771,7 +1780,7 @@ function N(e) {
1771
1780
  selector: p(b),
1772
1781
  html: m(b),
1773
1782
  impact: e.impact,
1774
- message: E(e.message, b, e.check),
1783
+ message: L(e.message, b, e.check),
1775
1784
  ...e.fix ? { fix: e.fix } : {},
1776
1785
  element: b
1777
1786
  });
@@ -1890,7 +1899,7 @@ function je(e, a) {
1890
1899
  return NaN;
1891
1900
  }
1892
1901
  }
1893
- function V(e) {
1902
+ function B(e) {
1894
1903
  return isNaN(e) ? !1 : (e = (e % 360 + 360) % 360, e >= 85 && e <= 95 || e >= 265 && e <= 275);
1895
1904
  }
1896
1905
  function pa(e) {
@@ -1899,21 +1908,21 @@ function pa(e) {
1899
1908
  );
1900
1909
  if (a) {
1901
1910
  const n = je(parseFloat(a[1]), a[2]);
1902
- if (V(n)) return !0;
1911
+ if (B(n)) return !0;
1903
1912
  }
1904
1913
  const t = e.match(
1905
1914
  /matrix\(\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)\s*,\s*(-?[\d.e]+)/i
1906
1915
  );
1907
1916
  if (t) {
1908
1917
  const n = parseFloat(t[1]), r = parseFloat(t[2]), o = Math.atan2(r, n) * (180 / Math.PI);
1909
- if (V(o)) return !0;
1918
+ if (B(o)) return !0;
1910
1919
  }
1911
1920
  const i = e.match(
1912
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
1913
1922
  );
1914
1923
  if (i) {
1915
1924
  const n = parseFloat(i[1]), r = parseFloat(i[2]), o = Math.atan2(r, n) * (180 / Math.PI);
1916
- if (V(o)) return !0;
1925
+ if (B(o)) return !0;
1917
1926
  }
1918
1927
  return !1;
1919
1928
  }
@@ -1921,7 +1930,7 @@ function ba(e) {
1921
1930
  const a = e.match(/(-?[\d.]+)(deg|rad|turn|grad)/i);
1922
1931
  if (!a) return !1;
1923
1932
  const t = je(parseFloat(a[1]), a[2]);
1924
- return V(t);
1933
+ return B(t);
1925
1934
  }
1926
1935
  const ha = {
1927
1936
  id: "adaptable/orientation-lock",
@@ -1998,14 +2007,14 @@ function fa(e, a) {
1998
2007
  for (const s of e.querySelectorAll("*")) {
1999
2008
  if (h(s)) continue;
2000
2009
  r = !0;
2001
- const l = j(s);
2010
+ const l = U(s);
2002
2011
  l && n.add(l);
2003
2012
  }
2004
2013
  for (const s of t) {
2005
2014
  const l = i.getElementById(s);
2006
2015
  if (l && !h(l)) {
2007
2016
  r = !0;
2008
- const d = j(l);
2017
+ const d = U(l);
2009
2018
  d && n.add(d);
2010
2019
  }
2011
2020
  }
@@ -2082,7 +2091,7 @@ const va = {
2082
2091
  const r = Se[n];
2083
2092
  let o = i.parentElement, s = !1;
2084
2093
  for (; o && o !== e.documentElement; ) {
2085
- const l = j(o);
2094
+ const l = U(o);
2086
2095
  if (l && r.includes(l)) {
2087
2096
  s = !0;
2088
2097
  break;
@@ -2188,6 +2197,7 @@ const ka = {
2188
2197
  wcag: ["1.3.1"],
2189
2198
  level: "A",
2190
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.",
2191
2201
  description: "Data cells in tables larger than 3x3 should have associated headers.",
2192
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.",
2193
2203
  run(e) {
@@ -2214,9 +2224,9 @@ const ka = {
2214
2224
  let g = !1;
2215
2225
  const f = i.querySelector("thead"), v = (f == null ? void 0 : f.querySelector("tr")) ?? i.querySelector("tbody > tr, tr");
2216
2226
  if (v)
2217
- for (const w of v.querySelectorAll("th, td")) {
2218
- const A = Ie(w), S = parseInt(w.getAttribute("colspan") || "1", 10);
2219
- 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) {
2220
2230
  g = !0;
2221
2231
  break;
2222
2232
  }
@@ -2266,6 +2276,7 @@ const ka = {
2266
2276
  level: "A",
2267
2277
  tags: ["best-practice"],
2268
2278
  fixability: "contextual",
2279
+ browserHint: "Screenshot the table to see which header cells are visually empty, then add text content or aria-label.",
2269
2280
  description: "Table header cells should have visible text.",
2270
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.",
2271
2282
  run(e) {
@@ -2273,7 +2284,7 @@ const ka = {
2273
2284
  for (const t of e.querySelectorAll("th")) {
2274
2285
  if (h(t)) continue;
2275
2286
  const i = t.closest("table");
2276
- (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({
2277
2288
  ruleId: "adaptable/empty-table-header",
2278
2289
  selector: p(t),
2279
2290
  html: m(t),
@@ -2291,6 +2302,7 @@ const ka = {
2291
2302
  level: "AA",
2292
2303
  tags: ["page-level"],
2293
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.",
2294
2306
  description: "Viewport meta tag must not disable user scaling.",
2295
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.",
2296
2308
  run(e) {
@@ -2387,7 +2399,7 @@ function We(e, a, t, i) {
2387
2399
  }
2388
2400
  for (const s of r.childNodes)
2389
2401
  if (s.nodeType === 3 && ((o = s.textContent) != null && o.trim())) {
2390
- const l = parseFloat(y(r).fontSize);
2402
+ const l = parseFloat(x(r).fontSize);
2391
2403
  if (l > 0 && t / l < i) return !0;
2392
2404
  break;
2393
2405
  }
@@ -2397,7 +2409,7 @@ function We(e, a, t, i) {
2397
2409
  }
2398
2410
  return n(e);
2399
2411
  }
2400
- function La(e) {
2412
+ function Ea(e) {
2401
2413
  var a;
2402
2414
  for (const t of e.childNodes)
2403
2415
  if (t.nodeType === 3 && ((a = t.textContent) != null && a.trim()))
@@ -2419,7 +2431,7 @@ function Ve(e) {
2419
2431
  return !1;
2420
2432
  }
2421
2433
  function de(e, a) {
2422
- if (La(e)) return !0;
2434
+ if (Ea(e)) return !0;
2423
2435
  for (const t of e.children) {
2424
2436
  const i = t.getAttribute("style") || "";
2425
2437
  if (!new RegExp(
@@ -2450,10 +2462,10 @@ function Be(e, a, t, i) {
2450
2462
  }
2451
2463
  return n;
2452
2464
  }
2453
- function Ea(e) {
2465
+ function La(e) {
2454
2466
  let a = e, t = !1;
2455
2467
  for (; a; ) {
2456
- const i = y(a);
2468
+ const i = x(a);
2457
2469
  parseFloat(i.width) > 500 && (t = !0), (i.whiteSpace === "nowrap" || i.whiteSpace === "pre") && (t = !0);
2458
2470
  const r = i.overflowX, o = i.overflowY;
2459
2471
  if ((r === "scroll" || r === "auto") && o !== "scroll" && o !== "auto")
@@ -2486,9 +2498,9 @@ const Ra = {
2486
2498
  run(e) {
2487
2499
  const a = [];
2488
2500
  for (const t of e.querySelectorAll("[style]")) {
2489
- 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;
2490
2502
  if (t instanceof HTMLElement && t.scrollHeight > 0) {
2491
- const r = parseFloat(y(t).lineHeight);
2503
+ const r = parseFloat(x(t).lineHeight);
2492
2504
  if (r > 0 && t.scrollHeight <= r * 1.5) continue;
2493
2505
  }
2494
2506
  const i = Ue(t, "line-height");
@@ -2535,7 +2547,7 @@ const Ra = {
2535
2547
  ]);
2536
2548
  function $a(e) {
2537
2549
  let a = e.parentElement;
2538
- for (; a && !Na.has(y(a).display); )
2550
+ for (; a && !Na.has(x(a).display); )
2539
2551
  a = a.parentElement;
2540
2552
  if (!a) return null;
2541
2553
  const t = a.ownerDocument.createTreeWalker(a, NodeFilter.SHOW_TEXT);
@@ -2550,7 +2562,7 @@ function $a(e) {
2550
2562
  }
2551
2563
  s = s.parentElement;
2552
2564
  }
2553
- 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)));
2554
2566
  }
2555
2567
  const o = i.match(new RegExp("\\p{L}{3,}", "gu"));
2556
2568
  return !n || !o || o.length < 2 ? null : { block: a, textColor: n };
@@ -2559,40 +2571,41 @@ function qe(e, a) {
2559
2571
  const t = e.textDecorationLine || e.textDecoration || "";
2560
2572
  return (t.includes("underline") || t.includes("line-through")) && t !== a;
2561
2573
  }
2562
- function O(e) {
2574
+ function V(e) {
2563
2575
  return e === "bold" ? 700 : e === "normal" ? 400 : parseInt(e) || 400;
2564
2576
  }
2565
- function Da(e) {
2577
+ function Ha(e) {
2566
2578
  const a = e.ownerDocument.createTreeWalker(e, NodeFilter.SHOW_TEXT);
2567
2579
  let t;
2568
2580
  for (; t = a.nextNode(); )
2569
2581
  if (t.data.trim()) return !1;
2570
2582
  return !0;
2571
2583
  }
2572
- const Pa = {
2584
+ const Da = {
2573
2585
  id: "distinguishable/link-in-text-block",
2574
2586
  category: "distinguishable",
2575
2587
  wcag: ["1.4.1"],
2576
2588
  level: "A",
2577
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.",
2578
2591
  description: "Links within text blocks must be distinguishable by more than color alone.",
2579
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.",
2580
2593
  run(e) {
2581
2594
  const a = [];
2582
2595
  for (const t of e.querySelectorAll("a[href]")) {
2583
- if (h(t) || !k(t).trim() || Da(t) || t.closest('nav, header, footer, aside, [role="navigation"], [role="banner"], [role="contentinfo"], [role="complementary"]')) continue;
2584
- 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);
2585
2598
  if (!Ma.has(i.display || "inline")) continue;
2586
2599
  const n = $a(t);
2587
2600
  if (!n) continue;
2588
- const r = y(n.block), o = r.textDecorationLine || r.textDecoration || "";
2589
- 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;
2590
2603
  const l = parseFloat(i.fontSize) || 16, d = parseFloat(r.fontSize) || 16;
2591
2604
  if (d > 0 && l / d >= 1.2) continue;
2592
2605
  let c = !1;
2593
- for (const w of t.querySelectorAll("*")) {
2594
- const A = y(w);
2595
- 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) {
2596
2609
  c = !0;
2597
2610
  break;
2598
2611
  }
@@ -2602,19 +2615,20 @@ const Pa = {
2602
2615
  if (!u) continue;
2603
2616
  const b = I(...u), g = I(...n.textColor), f = $(b, g);
2604
2617
  if (f < 1.1 || f >= 3) continue;
2605
- 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("");
2606
2619
  a.push({
2607
2620
  ruleId: "distinguishable/link-in-text-block",
2608
2621
  selector: p(t),
2609
2622
  html: m(t),
2610
2623
  impact: "serious",
2611
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.",
2612
- 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." }
2613
2627
  });
2614
2628
  }
2615
2629
  return a;
2616
2630
  }
2617
- }, Fa = /* @__PURE__ */ new Set([
2631
+ }, Pa = /* @__PURE__ */ new Set([
2618
2632
  "SCRIPT",
2619
2633
  "STYLE",
2620
2634
  "NOSCRIPT",
@@ -2630,7 +2644,7 @@ const Pa = {
2630
2644
  "BR",
2631
2645
  "HR"
2632
2646
  ]);
2633
- function Ha(e) {
2647
+ function Fa(e) {
2634
2648
  const a = e.clip;
2635
2649
  if (a && a.startsWith("rect(")) {
2636
2650
  const i = a.match(/[\d.]+/g);
@@ -2648,8 +2662,8 @@ function za(e) {
2648
2662
  if (h(e)) return !0;
2649
2663
  let a = e;
2650
2664
  for (; a; ) {
2651
- const t = y(a);
2652
- 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;
2653
2667
  a = a.parentElement;
2654
2668
  }
2655
2669
  return !1;
@@ -2694,10 +2708,10 @@ function _a(e) {
2694
2708
  const a = parseFloat(e);
2695
2709
  return isNaN(a) ? NaN : e.trim().endsWith("%") ? a / 100 : a;
2696
2710
  }
2697
- const Le = /([a-z-]+)\(([^)]*)\)/g;
2698
- function Ee(e) {
2711
+ const Ee = /([a-z-]+)\(([^)]*)\)/g;
2712
+ function Le(e) {
2699
2713
  let a, t = !1;
2700
- for (Le.lastIndex = 0; a = Le.exec(e); ) {
2714
+ for (Ee.lastIndex = 0; a = Ee.exec(e); ) {
2701
2715
  t = !0;
2702
2716
  const i = Ba[a[1]];
2703
2717
  if (i === void 0 || _a(a[2]) !== i) return !1;
@@ -2707,12 +2721,12 @@ function Ee(e) {
2707
2721
  function Ga(e) {
2708
2722
  let a = e;
2709
2723
  for (; a; ) {
2710
- const t = y(a), i = t.filter;
2711
- 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;
2712
2726
  const n = t.mixBlendMode;
2713
2727
  if (n && n !== "normal" && n !== "initial") return !0;
2714
2728
  const r = t.backdropFilter;
2715
- if (r && r !== "none" && r !== "initial" && !Ee(r)) return !0;
2729
+ if (r && r !== "none" && r !== "initial" && !Le(r)) return !0;
2716
2730
  a = a.parentElement;
2717
2731
  }
2718
2732
  return !1;
@@ -2720,7 +2734,7 @@ function Ga(e) {
2720
2734
  function Ya(e) {
2721
2735
  let a = e;
2722
2736
  for (; a; ) {
2723
- const t = y(a), i = t.backgroundImage;
2737
+ const t = x(a), i = t.backgroundImage;
2724
2738
  if (i && i !== "none" && i !== "initial")
2725
2739
  return i.includes("gradient(") ? { bgImage: i, gradientEl: a } : null;
2726
2740
  const n = t.backgroundColor;
@@ -2728,7 +2742,7 @@ function Ya(e) {
2728
2742
  a = a.parentElement;
2729
2743
  continue;
2730
2744
  }
2731
- if (U(n) < 0.01) {
2745
+ if (W(n) < 0.01) {
2732
2746
  a = a.parentElement;
2733
2747
  continue;
2734
2748
  }
@@ -2743,11 +2757,11 @@ function Xa(e, a, t, i, n, r, o, s, l) {
2743
2757
  for (const f of d) {
2744
2758
  let v = a;
2745
2759
  t < 1 && (v = R(a, f, t)), i < 1 && (v = R(v, f, i));
2746
- const w = $(
2760
+ const y = $(
2747
2761
  I(v[0], v[1], v[2]),
2748
2762
  I(f[0], f[1], f[2])
2749
2763
  );
2750
- w > c && (c = w, u = f);
2764
+ y > c && (c = y, u = f);
2751
2765
  }
2752
2766
  if (c >= n) return null;
2753
2767
  let b = a;
@@ -2759,7 +2773,8 @@ function Xa(e, a, t, i, n, r, o, s, l) {
2759
2773
  html: m(e),
2760
2774
  impact: "serious",
2761
2775
  message: `Insufficient${o === "AAA" ? " enhanced" : ""} color contrast ratio of ${g}:1 (required ${n}:1).`,
2762
- 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)}.` }
2763
2778
  };
2764
2779
  }
2765
2780
  function _e(e, a, t) {
@@ -2770,10 +2785,10 @@ function _e(e, a, t) {
2770
2785
  for (; s = r.nextNode(); ) {
2771
2786
  if (!s.textContent || !s.textContent.trim() || Oa(s.textContent)) continue;
2772
2787
  const l = s.parentElement;
2773
- 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;
2774
2789
  const d = l.tagName;
2775
2790
  if (d === "BODY" || d === "HTML" || Wa(l) || ja(l) || Ua(l, e) || Va(l) || za(l)) continue;
2776
- const c = y(l);
2791
+ const c = x(l);
2777
2792
  if (parseFloat(c.opacity) === 0) continue;
2778
2793
  const u = Mt(l);
2779
2794
  if (u < 0.1) continue;
@@ -2782,47 +2797,48 @@ function _e(e, a, t) {
2782
2797
  if (b && b !== "none" && b !== "initial" && (g = Tt(b), !g) || Ga(l) || $t(l)) continue;
2783
2798
  const f = C(c.color);
2784
2799
  if (!f) continue;
2785
- const v = U(c.color);
2786
- if (v === 0 || Lt(l)) continue;
2787
- 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;
2788
2803
  let A = ye(l);
2789
2804
  if (!A) {
2790
2805
  if (g) continue;
2791
- const L = Ya(l);
2792
- if (L) {
2793
- 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(
2794
2809
  l,
2795
2810
  f,
2796
2811
  v,
2797
2812
  u,
2798
- w,
2813
+ y,
2799
2814
  a,
2800
2815
  t,
2801
- L.bgImage,
2802
- _ ?? [255, 255, 255]
2816
+ E.bgImage,
2817
+ O ?? [255, 255, 255]
2803
2818
  );
2804
- W && i.push(W);
2819
+ H && i.push(H);
2805
2820
  }
2806
2821
  continue;
2807
2822
  }
2808
2823
  let S = f;
2809
2824
  v < 1 && (S = R(f, A, v)), u < 1 && (S = R(S, A, u));
2810
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);
2811
- if (be < w) {
2812
- 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);
2813
2828
  i.push({
2814
2829
  ruleId: a,
2815
2830
  selector: p(l),
2816
2831
  html: m(l),
2817
2832
  impact: "serious",
2818
- message: `Insufficient${t === "AAA" ? " enhanced" : ""} color contrast ratio of ${L}:1 (required ${w}:1).`,
2819
- 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}.` }
2820
2836
  });
2821
2837
  }
2822
2838
  }
2823
2839
  return i;
2824
2840
  }
2825
- const Ka = {
2841
+ const Ja = {
2826
2842
  id: "distinguishable/color-contrast",
2827
2843
  category: "distinguishable",
2828
2844
  actRuleIds: ["afw4f7"],
@@ -2830,11 +2846,12 @@ const Ka = {
2830
2846
  level: "AA",
2831
2847
  fixability: "visual",
2832
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.",
2833
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.",
2834
2851
  run(e) {
2835
2852
  return _e(e, "distinguishable/color-contrast", "AA");
2836
2853
  }
2837
- }, Ja = {
2854
+ }, Ka = {
2838
2855
  id: "distinguishable/color-contrast-enhanced",
2839
2856
  category: "distinguishable",
2840
2857
  actRuleIds: ["09o5cg"],
@@ -2842,6 +2859,7 @@ const Ka = {
2842
2859
  level: "AAA",
2843
2860
  fixability: "visual",
2844
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.",
2845
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.",
2846
2864
  run(e) {
2847
2865
  return _e(e, "distinguishable/color-contrast-enhanced", "AAA");
@@ -3025,6 +3043,7 @@ const di = {
3025
3043
  wcag: ["2.1.1"],
3026
3044
  level: "A",
3027
3045
  fixability: "contextual",
3046
+ browserHint: "Tab to the scrollable region and verify keyboard scrolling works with arrow keys.",
3028
3047
  description: "Scrollable regions must be keyboard accessible.",
3029
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.",
3030
3049
  run(e) {
@@ -3036,17 +3055,17 @@ const di = {
3036
3055
  if (n === "body" || n === "html") continue;
3037
3056
  const r = i.getAttribute("role");
3038
3057
  if (r === "presentation" || r === "none" || r === "listbox" || r === "menu" || r === "tree" || r === "tabpanel") continue;
3039
- const o = y(i), s = o.overflowX, l = o.overflowY;
3058
+ const o = x(i), s = o.overflowX, l = o.overflowY;
3040
3059
  if (!(s === "scroll" || s === "auto" || l === "scroll" || l === "auto")) continue;
3041
3060
  if (i.scrollHeight > 0 || i.clientHeight > 0) {
3042
3061
  const g = i.scrollHeight - i.clientHeight, f = i.scrollWidth - i.clientWidth;
3043
3062
  if (g <= 0 && f <= 0 || g < 14 && f < 14 || i.clientWidth < 64 && i.clientHeight < 64) continue;
3044
- const v = ((t = i.textContent) == null ? void 0 : t.trim().length) ?? 0, w = i.querySelector("img, svg, video, canvas, picture") !== null;
3045
- 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;
3046
3065
  } else
3047
3066
  continue;
3048
3067
  const u = i.getAttribute("tabindex");
3049
- u !== null && u !== "-1" || i.querySelector(z) || a.push({
3068
+ u !== null && u !== "-1" || i.querySelector(j) || a.push({
3050
3069
  ruleId: "keyboard-accessible/scrollable-region",
3051
3070
  selector: p(i),
3052
3071
  html: m(i),
@@ -3094,11 +3113,12 @@ const di = {
3094
3113
  wcag: ["2.4.7"],
3095
3114
  level: "AA",
3096
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.",
3097
3117
  description: "Elements in sequential focus order must have a visible focus indicator.",
3098
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.",
3099
3119
  run(e) {
3100
3120
  const a = [];
3101
- for (const t of e.querySelectorAll(z)) {
3121
+ for (const t of e.querySelectorAll(j)) {
3102
3122
  if (h(t) || !(t instanceof HTMLElement)) continue;
3103
3123
  const i = t.getAttribute("style") || "";
3104
3124
  if (/outline\s*:\s*(none|0)\s*(;|$|!)/i.test(i)) {
@@ -3128,7 +3148,7 @@ function Ye(e) {
3128
3148
  return { seconds: t, hasValidUrl: i };
3129
3149
  }
3130
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"]';
3131
- function Ke(e) {
3151
+ function Je(e) {
3132
3152
  return {
3133
3153
  id: e.id,
3134
3154
  category: e.id.split("/")[0],
@@ -3351,10 +3371,10 @@ const bi = {
3351
3371
  run(e) {
3352
3372
  var o, s, l;
3353
3373
  const a = e.querySelector("h1");
3354
- if (a && x(a)) return [];
3374
+ if (a && w(a)) return [];
3355
3375
  const t = e.querySelectorAll('[role="heading"][aria-level="1"]');
3356
3376
  for (const d of t)
3357
- if (x(d)) return [];
3377
+ if (w(d)) return [];
3358
3378
  const i = [], n = (s = (o = e.querySelector("title")) == null ? void 0 : o.textContent) == null ? void 0 : s.trim();
3359
3379
  n && i.push(`Page title: "${n}"`);
3360
3380
  const r = e.querySelector("main");
@@ -3378,6 +3398,7 @@ const bi = {
3378
3398
  level: "A",
3379
3399
  tags: ["best-practice"],
3380
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.",
3381
3402
  description: "Heading levels should increase by one; skipping levels (e.g. h2 to h4) makes navigation harder.",
3382
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.",
3383
3404
  run(e) {
@@ -3406,13 +3427,14 @@ const bi = {
3406
3427
  level: "A",
3407
3428
  tags: ["best-practice"],
3408
3429
  fixability: "contextual",
3430
+ browserHint: "Screenshot the heading area to verify it's visually empty, then add meaningful text or remove the heading element.",
3409
3431
  description: "Headings must have discernible text.",
3410
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.",
3411
3433
  run(e) {
3412
3434
  var i;
3413
3435
  const a = [], t = e.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"]');
3414
3436
  for (const n of t)
3415
- if (!h(n) && !x(n)) {
3437
+ if (!h(n) && !w(n)) {
3416
3438
  let r;
3417
3439
  const o = n.nextElementSibling;
3418
3440
  if (o) {
@@ -3437,7 +3459,8 @@ const bi = {
3437
3459
  wcag: ["1.3.1"],
3438
3460
  level: "A",
3439
3461
  tags: ["best-practice"],
3440
- 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.",
3441
3464
  description: "Paragraphs should not be styled to look like headings.",
3442
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.",
3443
3466
  run(e) {
@@ -3453,7 +3476,8 @@ const bi = {
3453
3476
  selector: p(n),
3454
3477
  html: m(n),
3455
3478
  impact: "serious",
3456
- 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." }
3457
3481
  });
3458
3482
  }
3459
3483
  }
@@ -3477,20 +3501,21 @@ function qi(e) {
3477
3501
  return a.length > 0 ? a.join(`
3478
3502
  `) : void 0;
3479
3503
  }
3480
- const Li = {
3504
+ const Ei = {
3481
3505
  id: "navigable/link-name",
3482
3506
  category: "navigable",
3483
3507
  actRuleIds: ["c487ae"],
3484
3508
  wcag: ["2.4.4", "4.1.2"],
3485
3509
  level: "A",
3486
3510
  fixability: "contextual",
3511
+ browserHint: "Screenshot the link in context to understand its destination, then write descriptive link text.",
3487
3512
  description: "Links must have discernible text via content, aria-label, or aria-labelledby.",
3488
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.",
3489
3514
  run(e) {
3490
3515
  const a = [];
3491
3516
  for (const t of e.querySelectorAll('a[href], area[href], [role="link"]')) {
3492
3517
  if (h(t) || q(t) || t.getRootNode() instanceof ShadowRoot) continue;
3493
- x(t) || a.push({
3518
+ w(t) || a.push({
3494
3519
  ruleId: "navigable/link-name",
3495
3520
  selector: p(t),
3496
3521
  html: m(t),
@@ -3502,7 +3527,7 @@ const Li = {
3502
3527
  }
3503
3528
  return a;
3504
3529
  }
3505
- }, Ei = {
3530
+ }, Li = {
3506
3531
  id: "navigable/skip-link",
3507
3532
  category: "navigable",
3508
3533
  wcag: ["2.4.1"],
@@ -3575,19 +3600,19 @@ const Li = {
3575
3600
  description: "Page should not have more than one main landmark.",
3576
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.",
3577
3602
  filterTopLevel: !1
3578
- }), Mi = Ke({
3603
+ }), Mi = Je({
3579
3604
  id: "landmarks/banner-is-top-level",
3580
3605
  selector: '[role="banner"]',
3581
3606
  landmarkName: "Banner",
3582
3607
  description: "Banner landmark should not be nested within another landmark.",
3583
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."
3584
- }), $i = Ke({
3609
+ }), $i = Je({
3585
3610
  id: "landmarks/contentinfo-is-top-level",
3586
3611
  selector: '[role="contentinfo"]',
3587
3612
  landmarkName: "Contentinfo",
3588
3613
  description: "Contentinfo landmark should not be nested within another landmark.",
3589
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."
3590
- }), Di = {
3615
+ }), Hi = {
3591
3616
  id: "landmarks/main-is-top-level",
3592
3617
  category: "landmarks",
3593
3618
  wcag: [],
@@ -3610,7 +3635,7 @@ const Li = {
3610
3635
  }
3611
3636
  return a;
3612
3637
  }
3613
- }, Pi = {
3638
+ }, Di = {
3614
3639
  id: "landmarks/complementary-is-top-level",
3615
3640
  category: "landmarks",
3616
3641
  wcag: [],
@@ -3633,7 +3658,7 @@ const Li = {
3633
3658
  }
3634
3659
  return a;
3635
3660
  }
3636
- }, Fi = {
3661
+ }, Pi = {
3637
3662
  id: "landmarks/landmark-unique",
3638
3663
  category: "landmarks",
3639
3664
  wcag: [],
@@ -3654,7 +3679,7 @@ const Li = {
3654
3679
  if (r.length <= 1) continue;
3655
3680
  const o = /* @__PURE__ */ new Map();
3656
3681
  for (const s of r) {
3657
- const l = x(s).toLowerCase() || "", d = o.get(l) || [];
3682
+ const l = w(s).toLowerCase() || "", d = o.get(l) || [];
3658
3683
  d.push(s), o.set(l, d);
3659
3684
  }
3660
3685
  for (const [s, l] of o)
@@ -3670,7 +3695,7 @@ const Li = {
3670
3695
  }
3671
3696
  return a;
3672
3697
  }
3673
- }, Hi = {
3698
+ }, Fi = {
3674
3699
  id: "landmarks/region",
3675
3700
  category: "landmarks",
3676
3701
  wcag: [],
@@ -3739,7 +3764,7 @@ const Li = {
3739
3764
  ), Ui = new Set(
3740
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(" ")
3741
3766
  ), Wi = /^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i;
3742
- function Je(e) {
3767
+ function Ke(e) {
3743
3768
  if (!Wi.test(e)) return !1;
3744
3769
  const a = e.split("-")[0].toLowerCase();
3745
3770
  return a.length === 2 ? ji.has(a) : a.length === 3 ? !Ui.has(a) : !1;
@@ -3789,7 +3814,7 @@ const Oi = {
3789
3814
  run(e) {
3790
3815
  var t;
3791
3816
  const a = (t = e.documentElement.getAttribute("lang")) == null ? void 0 : t.trim();
3792
- return a && !Je(a) ? [{
3817
+ return a && !Ke(a) ? [{
3793
3818
  ruleId: "readable/html-lang-valid",
3794
3819
  selector: "html",
3795
3820
  html: m(e.documentElement),
@@ -3822,7 +3847,7 @@ const Oi = {
3822
3847
  });
3823
3848
  continue;
3824
3849
  }
3825
- n && Ce(t) && (Je(n) || a.push({
3850
+ n && Ce(t) && (Ke(n) || a.push({
3826
3851
  ruleId: "readable/valid-lang",
3827
3852
  selector: p(t),
3828
3853
  html: m(t),
@@ -3865,13 +3890,14 @@ const Oi = {
3865
3890
  wcag: ["4.1.2"],
3866
3891
  level: "A",
3867
3892
  fixability: "contextual",
3893
+ browserHint: "Screenshot the iframe to see what content it displays, then add a title describing its purpose.",
3868
3894
  description: "Frames must have an accessible name.",
3869
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'.",
3870
3896
  run(e) {
3871
3897
  const a = [];
3872
3898
  for (const t of e.querySelectorAll("iframe, frame")) {
3873
3899
  if (h(t) || Ge(t)) continue;
3874
- if (!x(t)) {
3900
+ if (!w(t)) {
3875
3901
  const n = t.getAttribute("src");
3876
3902
  a.push({
3877
3903
  ruleId: "labels-and-names/frame-title",
@@ -3941,7 +3967,7 @@ function Xi(e) {
3941
3967
  }
3942
3968
  return "";
3943
3969
  }
3944
- const Ki = [
3970
+ const Ji = [
3945
3971
  '[role="checkbox"]',
3946
3972
  '[role="combobox"]',
3947
3973
  '[role="listbox"]',
@@ -3953,7 +3979,7 @@ const Ki = [
3953
3979
  '[role="spinbutton"]',
3954
3980
  '[role="switch"]',
3955
3981
  '[role="textbox"]'
3956
- ].join(", "), Ji = /* @__PURE__ */ new Set([
3982
+ ].join(", "), Ki = /* @__PURE__ */ new Set([
3957
3983
  "checkbox",
3958
3984
  "menuitemcheckbox",
3959
3985
  "menuitemradio",
@@ -3970,8 +3996,8 @@ const Ki = [
3970
3996
  function Zi(e) {
3971
3997
  var o, s, l, d;
3972
3998
  const a = (o = e.getAttribute("role")) == null ? void 0 : o.trim().toLowerCase();
3973
- if (a && Ji.has(a) || (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && !(a && Qi.has(a)))
3974
- return x(e);
3999
+ if (a && Ki.has(a) || (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && !(a && Qi.has(a)))
4000
+ return w(e);
3975
4001
  const i = e.getAttribute("aria-labelledby");
3976
4002
  if (i) {
3977
4003
  const c = i.split(/\s+/).map((u) => {
@@ -4001,11 +4027,12 @@ const en = {
4001
4027
  wcag: ["4.1.2"],
4002
4028
  level: "A",
4003
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.",
4004
4031
  description: "Form elements must have labels. Use <label>, aria-label, or aria-labelledby.",
4005
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').",
4006
4033
  run(e) {
4007
4034
  var i;
4008
- const a = [], t = e.querySelectorAll(`${Qe}, ${Ki}`);
4035
+ const a = [], t = e.querySelectorAll(`${Qe}, ${Ji}`);
4009
4036
  for (const n of t) {
4010
4037
  if (h(n) || q(n)) continue;
4011
4038
  const r = (i = n.getAttribute("role")) == null ? void 0 : i.trim().toLowerCase();
@@ -4071,6 +4098,7 @@ const en = {
4071
4098
  wcag: ["4.1.2"],
4072
4099
  level: "A",
4073
4100
  fixability: "contextual",
4101
+ browserHint: "Screenshot the button to see its visual purpose, then set value or aria-label to describe the action.",
4074
4102
  description: "Input buttons must have discernible text via value, aria-label, or aria-labelledby.",
4075
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.",
4076
4104
  run(e) {
@@ -4081,7 +4109,7 @@ const en = {
4081
4109
  )) {
4082
4110
  if (h(n) || q(n)) continue;
4083
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");
4084
- !r && !s && !x(n) && a.push({
4112
+ !r && !s && !w(n) && a.push({
4085
4113
  ruleId: "labels-and-names/input-button-name",
4086
4114
  selector: p(n),
4087
4115
  html: m(n),
@@ -4110,16 +4138,17 @@ const nn = {
4110
4138
  level: "A",
4111
4139
  tags: ["best-practice"],
4112
4140
  fixability: "contextual",
4141
+ browserHint: "Screenshot the control to see its visible label, then ensure aria-label starts with that visible text.",
4113
4142
  description: "Interactive elements with visible text must have accessible names that contain that text.",
4114
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.",
4115
4144
  run(e) {
4116
4145
  const a = [];
4117
4146
  for (const t of e.querySelectorAll('button, [role="button"], a[href], input[type="submit"], input[type="button"]')) {
4118
4147
  if (h(t)) continue;
4119
- const i = x(t);
4148
+ const i = w(t);
4120
4149
  if (!i) continue;
4121
4150
  let n = "";
4122
- t instanceof HTMLInputElement ? n = t.value || "" : n = Z(t);
4151
+ t instanceof HTMLInputElement ? n = t.value || "" : n = ee(t);
4123
4152
  const r = n.trim();
4124
4153
  if (!r || r.length <= 2) continue;
4125
4154
  const o = t.hasAttribute("aria-label"), s = t.hasAttribute("aria-labelledby");
@@ -4134,13 +4163,13 @@ const nn = {
4134
4163
  }
4135
4164
  for (const t of e.querySelectorAll("input, select, textarea")) {
4136
4165
  if (h(t) || t instanceof HTMLInputElement && ["hidden", "submit", "button", "image"].includes(t.type)) continue;
4137
- const i = x(t);
4166
+ const i = w(t);
4138
4167
  if (!i || !t.hasAttribute("aria-label")) continue;
4139
4168
  const r = t.id;
4140
4169
  let o = "";
4141
4170
  if (r) {
4142
4171
  const s = e.querySelector(`label[for="${CSS.escape(r)}"]`);
4143
- s && (o = Z(s));
4172
+ s && (o = ee(s));
4144
4173
  }
4145
4174
  o.trim() && (Ne(i, o) || a.push({
4146
4175
  ruleId: "labels-and-names/label-content-mismatch",
@@ -4195,7 +4224,7 @@ const nn = {
4195
4224
  if (h(i) || q(i) || se(i)) continue;
4196
4225
  const n = i.getAttribute("role");
4197
4226
  if ((i.tagName.toLowerCase() === "button" || i.tagName.toLowerCase() === "a") && n !== "menuitem") continue;
4198
- if (!x(i)) {
4227
+ if (!w(i)) {
4199
4228
  const o = i.querySelector("img[alt]");
4200
4229
  if ((t = o == null ? void 0 : o.getAttribute("alt")) != null && t.trim()) continue;
4201
4230
  a.push({
@@ -4231,7 +4260,7 @@ function M(e) {
4231
4260
  if (!o || !e.roleSet.has(o)) continue;
4232
4261
  }
4233
4262
  if (e.skipNative && n.matches(e.skipNative)) continue;
4234
- x(n) || t.push({
4263
+ w(n) || t.push({
4235
4264
  ruleId: e.id,
4236
4265
  selector: p(n),
4237
4266
  html: m(n),
@@ -4331,6 +4360,7 @@ const hn = {
4331
4360
  wcag: ["4.1.2"],
4332
4361
  level: "A",
4333
4362
  fixability: "contextual",
4363
+ browserHint: "Screenshot the button to identify its icon or visual label, then add a matching aria-label.",
4334
4364
  description: "Buttons must have discernible text.",
4335
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.",
4336
4366
  run(e) {
@@ -4339,7 +4369,7 @@ const hn = {
4339
4369
  if (h(t) || q(t)) continue;
4340
4370
  const i = t.getAttribute("role");
4341
4371
  if ((i === "none" || i === "presentation") && !(t.matches('button:not([disabled]), [tabindex]:not([tabindex="-1"])') || t.tagName.toLowerCase() === "button" && !t.disabled) || se(t)) continue;
4342
- x(t) || a.push({
4372
+ w(t) || a.push({
4343
4373
  ruleId: "labels-and-names/button-name",
4344
4374
  selector: p(t),
4345
4375
  html: m(t),
@@ -4364,7 +4394,7 @@ const hn = {
4364
4394
  const a = [];
4365
4395
  for (const t of e.querySelectorAll("details > summary:first-of-type")) {
4366
4396
  if (h(t)) continue;
4367
- x(t) || a.push({
4397
+ w(t) || a.push({
4368
4398
  ruleId: "labels-and-names/summary-name",
4369
4399
  selector: p(t),
4370
4400
  html: m(t),
@@ -4615,7 +4645,7 @@ Referenced by: ${d}` : ""}`,
4615
4645
  const a = [];
4616
4646
  for (const t of e.querySelectorAll("[role], [aria-*]")) {
4617
4647
  if (h(t)) continue;
4618
- const i = j(t);
4648
+ const i = U(t);
4619
4649
  if (!i) continue;
4620
4650
  const n = Sn[i];
4621
4651
  if (n)
@@ -4757,7 +4787,7 @@ Referenced by: ${d}` : ""}`,
4757
4787
  video: /* @__PURE__ */ new Set(["application"]),
4758
4788
  wbr: /* @__PURE__ */ new Set(["none", "presentation"])
4759
4789
  };
4760
- function Ln(e) {
4790
+ function En(e) {
4761
4791
  var t;
4762
4792
  const a = e.tagName.toLowerCase();
4763
4793
  if (qn.has(a))
@@ -4772,7 +4802,7 @@ function Ln(e) {
4772
4802
  }
4773
4803
  return D[a] || "any";
4774
4804
  }
4775
- const En = {
4805
+ const Ln = {
4776
4806
  id: "aria/aria-allowed-role",
4777
4807
  category: "aria",
4778
4808
  wcag: ["4.1.2"],
@@ -4789,7 +4819,7 @@ const En = {
4789
4819
  if (!n) continue;
4790
4820
  const r = $e(i);
4791
4821
  if (r && n === r) continue;
4792
- const o = Ln(i);
4822
+ const o = En(i);
4793
4823
  o === "none" ? a.push({
4794
4824
  ruleId: "aria/aria-allowed-role",
4795
4825
  selector: p(i),
@@ -4864,8 +4894,8 @@ const Mn = {
4864
4894
  const a = [];
4865
4895
  for (const t of e.querySelectorAll('[aria-hidden="true"]')) {
4866
4896
  if (t === e.body) continue;
4867
- const i = [...t.querySelectorAll(z)];
4868
- t.matches(z) && i.push(t);
4897
+ const i = [...t.querySelectorAll(j)];
4898
+ t.matches(j) && i.push(t);
4869
4899
  for (const n of i)
4870
4900
  if (n instanceof HTMLElement) {
4871
4901
  const r = n.getAttribute("tabindex");
@@ -4901,14 +4931,14 @@ const Mn = {
4901
4931
  run(e) {
4902
4932
  return le(e).prohibitedAttr;
4903
4933
  }
4904
- }, Dn = [
4934
+ }, Hn = [
4905
4935
  "a[href]",
4906
4936
  "button:not([disabled])",
4907
4937
  'input:not([disabled]):not([type="hidden"])',
4908
4938
  "select:not([disabled])",
4909
4939
  "textarea:not([disabled])",
4910
4940
  '[tabindex]:not([tabindex="-1"])'
4911
- ].join(", "), Pn = [
4941
+ ].join(", "), Dn = [
4912
4942
  "aria-atomic",
4913
4943
  "aria-busy",
4914
4944
  "aria-controls",
@@ -4925,15 +4955,15 @@ const Mn = {
4925
4955
  ];
4926
4956
  function Me(e) {
4927
4957
  const a = [];
4928
- e.matches(Dn) && a.push("element is focusable");
4929
- for (const t of Pn)
4958
+ e.matches(Hn) && a.push("element is focusable");
4959
+ for (const t of Dn)
4930
4960
  if (e.hasAttribute(t)) {
4931
4961
  a.push(`has ${t}`);
4932
4962
  break;
4933
4963
  }
4934
4964
  return (e.hasAttribute("aria-label") || e.hasAttribute("aria-labelledby")) && a.push("has accessible name"), a;
4935
4965
  }
4936
- const Fn = {
4966
+ const Pn = {
4937
4967
  id: "aria/presentation-role-conflict",
4938
4968
  category: "aria",
4939
4969
  actRuleIds: ["46ca7f"],
@@ -4970,7 +5000,7 @@ const Fn = {
4970
5000
  }
4971
5001
  return a;
4972
5002
  }
4973
- }, Hn = /* @__PURE__ */ new Set([
5003
+ }, Fn = /* @__PURE__ */ new Set([
4974
5004
  "button",
4975
5005
  "checkbox",
4976
5006
  "img",
@@ -5001,9 +5031,9 @@ const Fn = {
5001
5031
  const a = [];
5002
5032
  for (const t of e.querySelectorAll("*")) {
5003
5033
  if (h(t)) continue;
5004
- const i = j(t);
5005
- if (!(!i || !Hn.has(i))) {
5006
- 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))
5007
5037
  if (n !== t && !n.disabled) {
5008
5038
  a.push({
5009
5039
  ruleId: "aria/presentational-children-focusable",
@@ -5029,8 +5059,8 @@ const Fn = {
5029
5059
  Yt,
5030
5060
  Xt,
5031
5061
  // Time-based Media
5032
- Kt,
5033
5062
  Jt,
5063
+ Kt,
5034
5064
  // Adaptable
5035
5065
  na,
5036
5066
  la,
@@ -5050,9 +5080,9 @@ const Fn = {
5050
5080
  Ra,
5051
5081
  Ca,
5052
5082
  Ta,
5053
- Pa,
5054
- Ka,
5083
+ Da,
5055
5084
  Ja,
5085
+ Ka,
5056
5086
  // Keyboard Accessible
5057
5087
  Za,
5058
5088
  ti,
@@ -5073,8 +5103,8 @@ const Fn = {
5073
5103
  ki,
5074
5104
  Si,
5075
5105
  Ii,
5076
- Li,
5077
5106
  Ei,
5107
+ Li,
5078
5108
  // Landmarks
5079
5109
  Ri,
5080
5110
  Ci,
@@ -5082,10 +5112,10 @@ const Fn = {
5082
5112
  Ni,
5083
5113
  Mi,
5084
5114
  $i,
5115
+ Hi,
5085
5116
  Di,
5086
5117
  Pi,
5087
5118
  Fi,
5088
- Hi,
5089
5119
  // Readable
5090
5120
  zi,
5091
5121
  Oi,
@@ -5116,43 +5146,48 @@ const Fn = {
5116
5146
  wn,
5117
5147
  kn,
5118
5148
  In,
5119
- En,
5149
+ Ln,
5120
5150
  Cn,
5121
5151
  Mn,
5122
5152
  $n,
5123
- Fn,
5153
+ Pn,
5124
5154
  zn
5125
5155
  ];
5126
- 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;
5127
5157
  function Vn(e) {
5128
- 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;
5129
5159
  }
5130
5160
  function pe() {
5131
- if (H) return H;
5161
+ if (z) return z;
5132
5162
  const a = Ze.filter((t) => {
5133
5163
  var i;
5134
5164
  return !(et.has(t.id) || t.level === "AAA" && !tt || at && ((i = t.tags) != null && i.includes("page-level")));
5135
5165
  }).concat(me);
5136
- return T ? (H = Dt(a, T), H) : a;
5166
+ return T ? (z = Ht(a, T), z) : a;
5137
5167
  }
5138
5168
  function Bn(e) {
5139
5169
  it();
5140
- const a = pe(), t = T, i = [];
5141
- let n = 0;
5170
+ const a = pe(), t = T, i = [], n = [];
5171
+ let r = 0;
5142
5172
  return {
5143
- processChunk(r) {
5144
- const o = performance.now();
5145
- for (; n < a.length; ) {
5173
+ processChunk(o) {
5174
+ const s = performance.now();
5175
+ for (; r < a.length; ) {
5176
+ const l = a[r];
5146
5177
  try {
5147
- i.push(...a[n].run(e));
5148
- } catch {
5178
+ i.push(...l.run(e));
5179
+ } catch (d) {
5180
+ n.push({ ruleId: l.id, error: d instanceof Error ? d.message : String(d) });
5149
5181
  }
5150
- if (n++, performance.now() - o >= r) break;
5182
+ if (r++, performance.now() - s >= o) break;
5151
5183
  }
5152
- return n < a.length;
5184
+ return r < a.length;
5153
5185
  },
5154
5186
  getViolations() {
5155
5187
  return t ? ze(i, t) : i;
5188
+ },
5189
+ getSkippedRules() {
5190
+ return n;
5156
5191
  }
5157
5192
  };
5158
5193
  }
@@ -5160,19 +5195,21 @@ function it() {
5160
5195
  mt(), ot(), st(), kt(), At(), pt();
5161
5196
  }
5162
5197
  function _n(e) {
5163
- var i;
5198
+ var n;
5164
5199
  it();
5165
- const a = pe(), t = [];
5166
- for (const n of a)
5200
+ const a = pe(), t = [], i = [];
5201
+ for (const r of a)
5167
5202
  try {
5168
- t.push(...n.run(e));
5169
- } catch {
5203
+ t.push(...r.run(e));
5204
+ } catch (o) {
5205
+ i.push({ ruleId: r.id, error: o instanceof Error ? o.message : String(o) });
5170
5206
  }
5171
5207
  return {
5172
- url: ((i = e.location) == null ? void 0 : i.href) ?? "",
5208
+ url: ((n = e.location) == null ? void 0 : n.href) ?? "",
5173
5209
  timestamp: Date.now(),
5174
5210
  violations: T ? ze(t, T) : t,
5175
- ruleCount: a.length
5211
+ ruleCount: a.length,
5212
+ skippedRules: i
5176
5213
  };
5177
5214
  }
5178
5215
  function Gn(e, a) {
@@ -5290,7 +5327,7 @@ const Xn = {
5290
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." } },
5291
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.' } },
5292
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." } }
5293
- }, Kn = {
5330
+ }, Jn = {
5294
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>." } },
5295
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." } },
5296
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." } },
@@ -5394,10 +5431,10 @@ export {
5394
5431
  Vn as configureRules,
5395
5432
  Bn as createChunkedAudit,
5396
5433
  Gn as diffAudit,
5397
- x as getAccessibleName,
5434
+ w as getAccessibleName,
5398
5435
  k as getAccessibleTextContent,
5399
5436
  pe as getActiveRules,
5400
- j as getComputedRole,
5437
+ U as getComputedRole,
5401
5438
  m as getHtmlSnippet,
5402
5439
  $e as getImplicitRole,
5403
5440
  Yn as getRuleById,
@@ -5405,7 +5442,7 @@ export {
5405
5442
  h as isAriaHidden,
5406
5443
  dt as isValidRole,
5407
5444
  Xn as localeEn,
5408
- Kn as localeEs,
5445
+ Jn as localeEs,
5409
5446
  Un as querySelectorShadowAware,
5410
5447
  Wn as registerLocale,
5411
5448
  Ze as rules,