[{"data":1,"prerenderedAt":2397},["ShallowReactive",2],{"site-header-nav":3,"page-\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Faccessibility-regression-testing-in-github-actions\u002F":314,"content-navigation":2245},[4,84,88,216],{"title":5,"path":6,"stem":7,"children":8},"Core Accessibility Principles For Modern Frameworks","\u002Fcore-accessibility-principles-for-modern-frameworks","core-accessibility-principles-for-modern-frameworks",[9,12,18,24,36,48,66,78],{"title":10,"path":6,"stem":11},"Core Accessibility Principles for Modern Frameworks","core-accessibility-principles-for-modern-frameworks\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Accessible Color Contrast & Theming","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Faccessible-color-contrast-theming","core-accessibility-principles-for-modern-frameworks\u002Faccessible-color-contrast-theming\u002Findex",[17],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Accessible Form Validation & Error States","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Faccessible-form-validation-error-states","core-accessibility-principles-for-modern-frameworks\u002Faccessible-form-validation-error-states\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Focus Management Strategies for SPAs","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas","core-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Findex",[29,30],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Handling Focus Restoration After Dynamic Route Changes","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Fhandling-focus-restoration-after-dynamic-route-changes","core-accessibility-principles-for-modern-frameworks\u002Ffocus-management-strategies-for-spas\u002Fhandling-focus-restoration-after-dynamic-route-changes\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Keyboard Navigation Patterns for Modals","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals","core-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Findex",[41,42],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Building Accessible Dropdowns Without External UI Kits","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Fbuilding-accessible-dropdowns-without-external-ui-kits","core-accessibility-principles-for-modern-frameworks\u002Fkeyboard-navigation-patterns-for-modals\u002Fbuilding-accessible-dropdowns-without-external-ui-kits\u002Findex",[47],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Reduced Motion & Animation Accessibility","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility","core-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility\u002Findex",[53,54,60],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Accessible Loading Skeletons and Spinners","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility\u002Faccessible-loading-skeletons-and-spinners","core-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility\u002Faccessible-loading-skeletons-and-spinners\u002Findex",[59],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Respecting prefers-reduced-motion in React and CSS","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility\u002Frespecting-prefers-reduced-motion-in-react-and-css","core-accessibility-principles-for-modern-frameworks\u002Freduced-motion-and-animation-accessibility\u002Frespecting-prefers-reduced-motion-in-react-and-css\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Screen Reader Compatibility Testing","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing","core-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Findex",[71,72],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Testing ARIA Live Regions with Jest and Testing Library","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Ftesting-aria-live-regions-with-jest-and-testing-library","core-accessibility-principles-for-modern-frameworks\u002Fscreen-reader-compatibility-testing\u002Ftesting-aria-live-regions-with-jest-and-testing-library\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Semantic HTML vs ARIA in Component Trees","\u002Fcore-accessibility-principles-for-modern-frameworks\u002Fsemantic-html-vs-aria-in-component-trees","core-accessibility-principles-for-modern-frameworks\u002Fsemantic-html-vs-aria-in-component-trees\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87},"Modern Framework Accessibility","\u002F","index",{"title":89,"path":90,"stem":91,"children":92},"React Nextjs Accessibility Patterns","\u002Freact-nextjs-accessibility-patterns","react-nextjs-accessibility-patterns",[93,96,108,132,156,162,180,204],{"title":94,"path":90,"stem":95},"React & Next.js Accessibility Patterns","react-nextjs-accessibility-patterns\u002Findex",{"title":97,"path":98,"stem":99,"children":100},"Accessible Component Libraries in React","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react","react-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Findex",[101,102],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":106},"Building Accessible Tabs in React Without Radix UI","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Fbuilding-accessible-tabs-in-react-without-radix-ui","react-nextjs-accessibility-patterns\u002Faccessible-component-libraries-in-react\u002Fbuilding-accessible-tabs-in-react-without-radix-ui\u002Findex",[107],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":112},"Accessible Data Tables & Grids in React","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids","react-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Findex",[113,114,120,126],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":118},"Accessible Pagination for React Data Tables","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Faccessible-pagination-for-react-data-tables","react-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Faccessible-pagination-for-react-data-tables\u002Findex",[119],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":124},"Building a Sortable Accessible Data Table in React","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Fbuilding-a-sortable-accessible-data-table-in-react","react-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Fbuilding-a-sortable-accessible-data-table-in-react\u002Findex",[125],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":130},"Virtualizing Long Lists Accessibly in React","\u002Freact-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Fvirtualizing-long-lists-accessibly-in-react","react-nextjs-accessibility-patterns\u002Faccessible-data-tables-and-grids\u002Fvirtualizing-long-lists-accessibly-in-react\u002Findex",[131],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":136},"Dynamic Content & State Announcements","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Findex",[137,138,144,150],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":142},"Accessible Toast Notifications in React","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Faccessible-toast-notifications-in-react","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Faccessible-toast-notifications-in-react\u002Findex",[143],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":148},"Announcing Client-Side Route Changes in React","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Fannouncing-client-side-route-changes-in-react","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Fannouncing-client-side-route-changes-in-react\u002Findex",[149],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":154},"React Context for Accessibility Preferences","\u002Freact-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Freact-context-for-global-accessibility-preferences","react-nextjs-accessibility-patterns\u002Fdynamic-content-state-announcements\u002Freact-context-for-global-accessibility-preferences\u002Findex",[155],{"title":151,"path":152,"stem":153},{"title":157,"path":158,"stem":159,"children":160},"Form Handling with React Hook Form & A11y","\u002Freact-nextjs-accessibility-patterns\u002Fform-handling-with-react-hook-form-a11y","react-nextjs-accessibility-patterns\u002Fform-handling-with-react-hook-form-a11y\u002Findex",[161],{"title":157,"path":158,"stem":159},{"title":163,"path":164,"stem":165,"children":166},"Next.js App Router Accessibility","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Findex",[167,168,174],{"title":163,"path":164,"stem":165},{"title":169,"path":170,"stem":171,"children":172},"Skip Links in Next.js App Router","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fimplementing-skip-links-in-nextjs-app-router","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fimplementing-skip-links-in-nextjs-app-router\u002Findex",[173],{"title":169,"path":170,"stem":171},{"title":175,"path":176,"stem":177,"children":178},"Next.js Dynamic Imports & Keyboard Navigation","\u002Freact-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fnextjs-dynamic-imports-and-keyboard-navigation","react-nextjs-accessibility-patterns\u002Fnextjs-app-router-a11y\u002Fnextjs-dynamic-imports-and-keyboard-navigation\u002Findex",[179],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183,"children":184},"React Hooks for Accessibility","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Findex",[185,186,192,198],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189,"children":190},"Building a useAnnouncer Hook for Live Regions","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fbuilding-a-useannouncer-hook-for-live-regions","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fbuilding-a-useannouncer-hook-for-live-regions\u002Findex",[191],{"title":187,"path":188,"stem":189},{"title":193,"path":194,"stem":195,"children":196},"Fixing Focus Trap Issues in React Portals","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Ffixing-focus-trap-issues-in-react-portals","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Ffixing-focus-trap-issues-in-react-portals\u002Findex",[197],{"title":193,"path":194,"stem":195},{"title":199,"path":200,"stem":201,"children":202},"Making React useEffect Accessible for Screen Readers","\u002Freact-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers","react-nextjs-accessibility-patterns\u002Freact-hooks-for-accessibility\u002Fmaking-react-useeffect-accessible-for-screen-readers\u002Findex",[203],{"title":199,"path":200,"stem":201},{"title":205,"path":206,"stem":207,"children":208},"Server Components & Client-Side Interactivity","\u002Freact-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity","react-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Findex",[209,210],{"title":205,"path":206,"stem":207},{"title":211,"path":212,"stem":213,"children":214},"Accessible Modals in Next.js 14 Server Components","\u002Freact-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Fhandling-accessible-modals-in-nextjs-14-server-components","react-nextjs-accessibility-patterns\u002Fserver-components-client-side-interactivity\u002Fhandling-accessible-modals-in-nextjs-14-server-components\u002Findex",[215],{"title":211,"path":212,"stem":213},{"title":217,"path":218,"stem":219,"children":220},"Testing And Automating Accessibility","\u002Ftesting-and-automating-accessibility","testing-and-automating-accessibility",[221,224,242,260,278,296],{"title":222,"path":218,"stem":223},"Testing & Automating Accessibility","testing-and-automating-accessibility\u002Findex",{"title":225,"path":226,"stem":227,"children":228},"Accessibility Audits with Lighthouse","\u002Ftesting-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse","testing-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Findex",[229,230,236],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":234},"Interpreting Lighthouse Accessibility Scores","\u002Ftesting-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Finterpreting-lighthouse-accessibility-scores","testing-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Finterpreting-lighthouse-accessibility-scores\u002Findex",[235],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":240},"Setting Lighthouse CI Accessibility Budgets","\u002Ftesting-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Fsetting-lighthouse-ci-accessibility-budgets","testing-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Fsetting-lighthouse-ci-accessibility-budgets\u002Findex",[241],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":246},"Automated Accessibility Testing with axe-core","\u002Ftesting-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core","testing-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core\u002Findex",[247,248,254],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":252},"Catching Color Contrast Failures with axe-core","\u002Ftesting-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core\u002Fcatching-color-contrast-failures-with-axe-core","testing-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core\u002Fcatching-color-contrast-failures-with-axe-core\u002Findex",[253],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":258},"Writing Custom axe-core Rules","\u002Ftesting-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core\u002Fwriting-custom-axe-core-rules","testing-and-automating-accessibility\u002Fautomated-accessibility-testing-with-axe-core\u002Fwriting-custom-axe-core-rules\u002Findex",[259],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":264},"Component Testing with jest-axe","\u002Ftesting-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe","testing-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe\u002Findex",[265,266,272],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":270},"Debugging jest-axe Violations in CI","\u002Ftesting-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe\u002Fdebugging-jest-axe-violations-in-ci","testing-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe\u002Fdebugging-jest-axe-violations-in-ci\u002Findex",[271],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":276},"Testing React Components with jest-axe","\u002Ftesting-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe\u002Ftesting-react-components-with-jest-axe","testing-and-automating-accessibility\u002Fcomponent-testing-with-jest-axe\u002Ftesting-react-components-with-jest-axe\u002Findex",[277],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":282},"End-to-End Accessibility Testing with Playwright","\u002Ftesting-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright","testing-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright\u002Findex",[283,284,290],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":288},"Asserting Focus Order in Playwright","\u002Ftesting-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright\u002Fasserting-focus-order-in-playwright","testing-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright\u002Fasserting-focus-order-in-playwright\u002Findex",[289],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":294},"Keyboard Navigation Tests in Playwright","\u002Ftesting-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright\u002Fkeyboard-navigation-tests-in-playwright","testing-and-automating-accessibility\u002Fend-to-end-accessibility-testing-with-playwright\u002Fkeyboard-navigation-tests-in-playwright\u002Findex",[295],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":300},"Gating Accessibility in CI\u002FCD Pipelines","\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines","testing-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Findex",[301,302,308],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":306},"Accessibility Regression Testing in GitHub Actions","\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Faccessibility-regression-testing-in-github-actions","testing-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Faccessibility-regression-testing-in-github-actions\u002Findex",[307],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":312},"Failing Pull Requests on axe Violations","\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Ffailing-pull-requests-on-axe-violations","testing-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Ffailing-pull-requests-on-axe-violations\u002Findex",[313],{"title":309,"path":310,"stem":311},{"id":315,"title":303,"body":316,"date":2238,"description":2239,"extension":2240,"image":2238,"meta":2241,"modifiedAt":2238,"navigation":466,"noindex":2242,"path":304,"publishedAt":2238,"seo":2243,"stem":305,"updatedAt":2238,"__hash__":2244},"content\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Faccessibility-regression-testing-in-github-actions\u002Findex.md",{"type":317,"value":318,"toc":2227},"minimark",[319,323,351,356,375,380,399,402,407,414,647,855,865,874,876,880,890,1344,1528,1535,1545,1547,1551,1560,1770,1776,1778,1782,1785,1976,1986,1988,1992,1999,2077,2080,2082,2086,2089,2141,2143,2147,2153,2155,2159,2172,2178,2184,2193,2203,2205,2209,2223],[320,321,303],"h1",{"id":322},"accessibility-regression-testing-in-github-actions",[324,325,326,327,331,332,336,337,341,342,346,347,350],"p",{},"A clean gate on a clean codebase is easy; the hard problem is a real app that already carries accessibility debt. You cannot fail every PR on hundreds of pre-existing violations, but you also cannot let new ones slip through. The answer is ",[328,329,330],"strong",{},"regression testing",": snapshot the currently accepted violations into a baseline, then fail a pull request only when it introduces something ",[333,334,335],"em",{},"new",". This guide—part of ",[338,339,297],"a",{"href":340},"\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002F","—shows how to baseline, diff, and run scheduled full audits in GitHub Actions, so a regression in ",[343,344,345],"code",{},"4.1.2 Name, Role, Value"," or ",[343,348,349],{},"1.4.3 Contrast (Minimum)"," fails the build while legacy debt is tracked, not blocking.",[324,352,353],{},[328,354,355],{},"WCAG Coverage Mapping",[357,358,359,365,370],"ul",{},[360,361,362,364],"li",{},[343,363,345],{}," (Level A)",[360,366,367,369],{},[343,368,349],{}," (Level AA)",[360,371,372,364],{},[343,373,374],{},"1.3.1 Info and Relationships",[324,376,377],{},[328,378,379],{},"Prerequisites",[357,381,382,389,396],{},[360,383,384,385,388],{},"An axe-based suite (jest-axe or ",[343,386,387],{},"@axe-core\u002Fplaywright",") that can emit machine-readable JSON.",[360,390,391,392,395],{},"A GitHub Actions workflow running on ",[343,393,394],{},"pull_request",", already a required check.",[360,397,398],{},"A writable location for the baseline file, committed to the repository.",[400,401],"hr",{},[403,404,406],"h2",{"id":405},"snapshotting-a-baseline-of-accepted-violations","Snapshotting a Baseline of Accepted Violations",[324,408,409,410,413],{},"The baseline is a committed record of every violation you currently tolerate, keyed so that an entry survives unrelated DOM churn. A raw axe report is too volatile to diff directly—node order and attribute values shift between runs—so reduce each violation to a stable ",[328,411,412],{},"fingerprint"," of rule id plus a normalized selector.",[415,416,421],"pre",{"className":417,"code":418,"language":419,"meta":420,"style":420},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F scripts\u002Ffingerprint.js — stable identity for one violation node\nconst crypto = require('node:crypto');\n\nfunction fingerprint(ruleId, node) {\n  \u002F\u002F Normalize the selector so trivial DOM reordering doesn't churn the baseline.\n  const selector = node.target.join(' ').replace(\u002F:nth-child\\(\\d+\\)\u002Fg, ':nth-child(n)');\n  return crypto.createHash('sha1').update(`${ruleId}::${selector}`).digest('hex').slice(0, 12);\n}\nmodule.exports = { fingerprint };\n","js","",[343,422,423,432,461,468,492,498,559,624,630],{"__ignoreMap":420},[424,425,428],"span",{"class":426,"line":427},"line",1,[424,429,431],{"class":430},"sJ8bj","\u002F\u002F scripts\u002Ffingerprint.js — stable identity for one violation node\n",[424,433,435,439,443,446,450,454,458],{"class":426,"line":434},2,[424,436,438],{"class":437},"szBVR","const",[424,440,442],{"class":441},"sj4cs"," crypto",[424,444,445],{"class":437}," =",[424,447,449],{"class":448},"sScJk"," require",[424,451,453],{"class":452},"sVt8B","(",[424,455,457],{"class":456},"sZZnC","'node:crypto'",[424,459,460],{"class":452},");\n",[424,462,464],{"class":426,"line":463},3,[424,465,467],{"emptyLinePlaceholder":466},true,"\n",[424,469,471,474,477,479,483,486,489],{"class":426,"line":470},4,[424,472,473],{"class":437},"function",[424,475,476],{"class":448}," fingerprint",[424,478,453],{"class":452},[424,480,482],{"class":481},"s4XuR","ruleId",[424,484,485],{"class":452},", ",[424,487,488],{"class":481},"node",[424,490,491],{"class":452},") {\n",[424,493,495],{"class":426,"line":494},5,[424,496,497],{"class":430},"  \u002F\u002F Normalize the selector so trivial DOM reordering doesn't churn the baseline.\n",[424,499,501,504,507,509,512,515,517,520,523,526,528,530,534,538,541,544,547,549,552,554,557],{"class":426,"line":500},6,[424,502,503],{"class":437},"  const",[424,505,506],{"class":441}," selector",[424,508,445],{"class":437},[424,510,511],{"class":452}," node.target.",[424,513,514],{"class":448},"join",[424,516,453],{"class":452},[424,518,519],{"class":456},"' '",[424,521,522],{"class":452},").",[424,524,525],{"class":448},"replace",[424,527,453],{"class":452},[424,529,86],{"class":456},[424,531,533],{"class":532},"sA_wV",":nth-child",[424,535,537],{"class":536},"snhLl","\\(",[424,539,540],{"class":441},"\\d",[424,542,543],{"class":437},"+",[424,545,546],{"class":536},"\\)",[424,548,86],{"class":456},[424,550,551],{"class":437},"g",[424,553,485],{"class":452},[424,555,556],{"class":456},"':nth-child(n)'",[424,558,460],{"class":452},[424,560,562,565,568,571,573,576,578,581,583,586,588,591,594,597,599,602,604,607,609,612,614,617,619,622],{"class":426,"line":561},7,[424,563,564],{"class":437},"  return",[424,566,567],{"class":452}," crypto.",[424,569,570],{"class":448},"createHash",[424,572,453],{"class":452},[424,574,575],{"class":456},"'sha1'",[424,577,522],{"class":452},[424,579,580],{"class":448},"update",[424,582,453],{"class":452},[424,584,585],{"class":456},"`${",[424,587,482],{"class":452},[424,589,590],{"class":456},"}::${",[424,592,593],{"class":452},"selector",[424,595,596],{"class":456},"}`",[424,598,522],{"class":452},[424,600,601],{"class":448},"digest",[424,603,453],{"class":452},[424,605,606],{"class":456},"'hex'",[424,608,522],{"class":452},[424,610,611],{"class":448},"slice",[424,613,453],{"class":452},[424,615,616],{"class":441},"0",[424,618,485],{"class":452},[424,620,621],{"class":441},"12",[424,623,460],{"class":452},[424,625,627],{"class":426,"line":626},8,[424,628,629],{"class":452},"}\n",[424,631,633,636,639,642,644],{"class":426,"line":632},9,[424,634,635],{"class":441},"module",[424,637,638],{"class":452},".",[424,640,641],{"class":441},"exports",[424,643,445],{"class":437},[424,645,646],{"class":452}," { fingerprint };\n",[415,648,650],{"className":417,"code":649,"language":419,"meta":420,"style":420},"\u002F\u002F scripts\u002Fwrite-baseline.js — generate the accepted-debt snapshot\nconst fs = require('node:fs');\nconst { fingerprint } = require('.\u002Ffingerprint');\nconst report = require('..\u002Fa11y-report.json');\n\nconst baseline = {};\nfor (const v of report.violations) {\n  for (const node of v.nodes) {\n    baseline[fingerprint(v.id, node)] = { rule: v.id, impact: v.impact, selector: node.target.join(' ') };\n  }\n}\nfs.writeFileSync('a11y-baseline.json', JSON.stringify(baseline, null, 2) + '\\n');\n",[343,651,652,657,675,699,717,721,733,752,769,793,799,804],{"__ignoreMap":420},[424,653,654],{"class":426,"line":427},[424,655,656],{"class":430},"\u002F\u002F scripts\u002Fwrite-baseline.js — generate the accepted-debt snapshot\n",[424,658,659,661,664,666,668,670,673],{"class":426,"line":434},[424,660,438],{"class":437},[424,662,663],{"class":441}," fs",[424,665,445],{"class":437},[424,667,449],{"class":448},[424,669,453],{"class":452},[424,671,672],{"class":456},"'node:fs'",[424,674,460],{"class":452},[424,676,677,679,682,684,687,690,692,694,697],{"class":426,"line":463},[424,678,438],{"class":437},[424,680,681],{"class":452}," { ",[424,683,412],{"class":441},[424,685,686],{"class":452}," } ",[424,688,689],{"class":437},"=",[424,691,449],{"class":448},[424,693,453],{"class":452},[424,695,696],{"class":456},"'.\u002Ffingerprint'",[424,698,460],{"class":452},[424,700,701,703,706,708,710,712,715],{"class":426,"line":470},[424,702,438],{"class":437},[424,704,705],{"class":441}," report",[424,707,445],{"class":437},[424,709,449],{"class":448},[424,711,453],{"class":452},[424,713,714],{"class":456},"'..\u002Fa11y-report.json'",[424,716,460],{"class":452},[424,718,719],{"class":426,"line":494},[424,720,467],{"emptyLinePlaceholder":466},[424,722,723,725,728,730],{"class":426,"line":500},[424,724,438],{"class":437},[424,726,727],{"class":441}," baseline",[424,729,445],{"class":437},[424,731,732],{"class":452}," {};\n",[424,734,735,738,741,743,746,749],{"class":426,"line":561},[424,736,737],{"class":437},"for",[424,739,740],{"class":452}," (",[424,742,438],{"class":437},[424,744,745],{"class":441}," v",[424,747,748],{"class":437}," of",[424,750,751],{"class":452}," report.violations) {\n",[424,753,754,757,759,761,764,766],{"class":426,"line":626},[424,755,756],{"class":437},"  for",[424,758,740],{"class":452},[424,760,438],{"class":437},[424,762,763],{"class":441}," node",[424,765,748],{"class":437},[424,767,768],{"class":452}," v.nodes) {\n",[424,770,771,774,776,779,781,784,786,788,790],{"class":426,"line":632},[424,772,773],{"class":452},"    baseline[",[424,775,412],{"class":448},[424,777,778],{"class":452},"(v.id, node)] ",[424,780,689],{"class":437},[424,782,783],{"class":452}," { rule: v.id, impact: v.impact, selector: node.target.",[424,785,514],{"class":448},[424,787,453],{"class":452},[424,789,519],{"class":456},[424,791,792],{"class":452},") };\n",[424,794,796],{"class":426,"line":795},10,[424,797,798],{"class":452},"  }\n",[424,800,802],{"class":426,"line":801},11,[424,803,629],{"class":452},[424,805,807,810,813,815,818,820,823,825,828,831,834,836,839,842,844,847,850,853],{"class":426,"line":806},12,[424,808,809],{"class":452},"fs.",[424,811,812],{"class":448},"writeFileSync",[424,814,453],{"class":452},[424,816,817],{"class":456},"'a11y-baseline.json'",[424,819,485],{"class":452},[424,821,822],{"class":441},"JSON",[424,824,638],{"class":452},[424,826,827],{"class":448},"stringify",[424,829,830],{"class":452},"(baseline, ",[424,832,833],{"class":441},"null",[424,835,485],{"class":452},[424,837,838],{"class":441},"2",[424,840,841],{"class":452},") ",[424,843,543],{"class":437},[424,845,846],{"class":456}," '",[424,848,849],{"class":441},"\\n",[424,851,852],{"class":456},"'",[424,854,460],{"class":452},[324,856,857,858,861,862,638],{},"Commit ",[343,859,860],{},"a11y-baseline.json"," to the repository. It is the source of truth for \"violations we have agreed to fix later,\" and every PR diffs against it. The narrower, selector-scoped form of this idea for a single rule is covered in ",[338,863,309],{"href":864},"\u002Ftesting-and-automating-accessibility\u002Fgating-accessibility-in-ci-cd-pipelines\u002Ffailing-pull-requests-on-axe-violations\u002F",[866,867,868],"blockquote",{},[324,869,870,873],{},[328,871,872],{},"Gate Hook:"," Regenerate the baseline only on an intentional, reviewed commit—never automatically in CI. An auto-updating baseline launders new regressions into accepted debt, defeating the entire gate.",[400,875],{},[403,877,879],{"id":878},"diffing-a-new-run-against-the-baseline","Diffing a New Run Against the Baseline",[324,881,882,883,885,886,889],{},"On each pull request the workflow runs axe, fingerprints the fresh violations, and subtracts the baseline. Anything left is ",[333,884,335],{}," and fails the build; anything in the baseline that disappeared is a ",[333,887,888],{},"fixed"," item you can prune.",[415,891,893],{"className":417,"code":892,"language":419,"meta":420,"style":420},"\u002F\u002F scripts\u002Fdiff-baseline.js — only NEW violations fail the gate\nconst fs = require('node:fs');\nconst { fingerprint } = require('.\u002Ffingerprint');\nconst baseline = require('..\u002Fa11y-baseline.json');\nconst report = require('..\u002Fa11y-report.json');\n\nconst seen = new Set();\nconst fresh = [];\nfor (const v of report.violations) {\n  for (const node of v.nodes) {\n    const fp = fingerprint(v.id, node);\n    seen.add(fp);\n    if (!baseline[fp]) fresh.push({ rule: v.id, impact: v.impact, selector: node.target.join(' ') });\n  }\n}\nconst fixed = Object.keys(baseline).filter((fp) => !seen.has(fp));\n\nconsole.log(`### Accessibility regression check\\n`);\nconsole.log(`New: **${fresh.length}** · Fixed (prunable): **${fixed.length}**\\n`);\nif (fresh.length) {\n  console.log('| Rule | Impact | Selector |\\n| --- | --- | --- |');\n  for (const f of fresh) console.log(`| ${f.rule} | ${f.impact} | \\`${f.selector}\\` |`);\n}\n\u002F\u002F Non-zero ONLY on new violations -> red required check on regressions.\nprocess.exit(fresh.length ? 1 : 0);\n",[343,894,895,900,916,936,953,969,973,991,1003,1017,1031,1046,1057,1086,1091,1096,1141,1146,1167,1205,1218,1238,1305,1310,1316],{"__ignoreMap":420},[424,896,897],{"class":426,"line":427},[424,898,899],{"class":430},"\u002F\u002F scripts\u002Fdiff-baseline.js — only NEW violations fail the gate\n",[424,901,902,904,906,908,910,912,914],{"class":426,"line":434},[424,903,438],{"class":437},[424,905,663],{"class":441},[424,907,445],{"class":437},[424,909,449],{"class":448},[424,911,453],{"class":452},[424,913,672],{"class":456},[424,915,460],{"class":452},[424,917,918,920,922,924,926,928,930,932,934],{"class":426,"line":463},[424,919,438],{"class":437},[424,921,681],{"class":452},[424,923,412],{"class":441},[424,925,686],{"class":452},[424,927,689],{"class":437},[424,929,449],{"class":448},[424,931,453],{"class":452},[424,933,696],{"class":456},[424,935,460],{"class":452},[424,937,938,940,942,944,946,948,951],{"class":426,"line":470},[424,939,438],{"class":437},[424,941,727],{"class":441},[424,943,445],{"class":437},[424,945,449],{"class":448},[424,947,453],{"class":452},[424,949,950],{"class":456},"'..\u002Fa11y-baseline.json'",[424,952,460],{"class":452},[424,954,955,957,959,961,963,965,967],{"class":426,"line":494},[424,956,438],{"class":437},[424,958,705],{"class":441},[424,960,445],{"class":437},[424,962,449],{"class":448},[424,964,453],{"class":452},[424,966,714],{"class":456},[424,968,460],{"class":452},[424,970,971],{"class":426,"line":500},[424,972,467],{"emptyLinePlaceholder":466},[424,974,975,977,980,982,985,988],{"class":426,"line":561},[424,976,438],{"class":437},[424,978,979],{"class":441}," seen",[424,981,445],{"class":437},[424,983,984],{"class":437}," new",[424,986,987],{"class":448}," Set",[424,989,990],{"class":452},"();\n",[424,992,993,995,998,1000],{"class":426,"line":626},[424,994,438],{"class":437},[424,996,997],{"class":441}," fresh",[424,999,445],{"class":437},[424,1001,1002],{"class":452}," [];\n",[424,1004,1005,1007,1009,1011,1013,1015],{"class":426,"line":632},[424,1006,737],{"class":437},[424,1008,740],{"class":452},[424,1010,438],{"class":437},[424,1012,745],{"class":441},[424,1014,748],{"class":437},[424,1016,751],{"class":452},[424,1018,1019,1021,1023,1025,1027,1029],{"class":426,"line":795},[424,1020,756],{"class":437},[424,1022,740],{"class":452},[424,1024,438],{"class":437},[424,1026,763],{"class":441},[424,1028,748],{"class":437},[424,1030,768],{"class":452},[424,1032,1033,1036,1039,1041,1043],{"class":426,"line":801},[424,1034,1035],{"class":437},"    const",[424,1037,1038],{"class":441}," fp",[424,1040,445],{"class":437},[424,1042,476],{"class":448},[424,1044,1045],{"class":452},"(v.id, node);\n",[424,1047,1048,1051,1054],{"class":426,"line":806},[424,1049,1050],{"class":452},"    seen.",[424,1052,1053],{"class":448},"add",[424,1055,1056],{"class":452},"(fp);\n",[424,1058,1060,1063,1065,1068,1071,1074,1077,1079,1081,1083],{"class":426,"line":1059},13,[424,1061,1062],{"class":437},"    if",[424,1064,740],{"class":452},[424,1066,1067],{"class":437},"!",[424,1069,1070],{"class":452},"baseline[fp]) fresh.",[424,1072,1073],{"class":448},"push",[424,1075,1076],{"class":452},"({ rule: v.id, impact: v.impact, selector: node.target.",[424,1078,514],{"class":448},[424,1080,453],{"class":452},[424,1082,519],{"class":456},[424,1084,1085],{"class":452},") });\n",[424,1087,1089],{"class":426,"line":1088},14,[424,1090,798],{"class":452},[424,1092,1094],{"class":426,"line":1093},15,[424,1095,629],{"class":452},[424,1097,1099,1101,1104,1106,1109,1112,1115,1118,1121,1124,1126,1129,1132,1135,1138],{"class":426,"line":1098},16,[424,1100,438],{"class":437},[424,1102,1103],{"class":441}," fixed",[424,1105,445],{"class":437},[424,1107,1108],{"class":452}," Object.",[424,1110,1111],{"class":448},"keys",[424,1113,1114],{"class":452},"(baseline).",[424,1116,1117],{"class":448},"filter",[424,1119,1120],{"class":452},"((",[424,1122,1123],{"class":481},"fp",[424,1125,841],{"class":452},[424,1127,1128],{"class":437},"=>",[424,1130,1131],{"class":437}," !",[424,1133,1134],{"class":452},"seen.",[424,1136,1137],{"class":448},"has",[424,1139,1140],{"class":452},"(fp));\n",[424,1142,1144],{"class":426,"line":1143},17,[424,1145,467],{"emptyLinePlaceholder":466},[424,1147,1149,1152,1155,1157,1160,1162,1165],{"class":426,"line":1148},18,[424,1150,1151],{"class":452},"console.",[424,1153,1154],{"class":448},"log",[424,1156,453],{"class":452},[424,1158,1159],{"class":456},"`### Accessibility regression check",[424,1161,849],{"class":441},[424,1163,1164],{"class":456},"`",[424,1166,460],{"class":452},[424,1168,1170,1172,1174,1176,1179,1182,1184,1187,1190,1192,1194,1196,1199,1201,1203],{"class":426,"line":1169},19,[424,1171,1151],{"class":452},[424,1173,1154],{"class":448},[424,1175,453],{"class":452},[424,1177,1178],{"class":456},"`New: **${",[424,1180,1181],{"class":452},"fresh",[424,1183,638],{"class":456},[424,1185,1186],{"class":441},"length",[424,1188,1189],{"class":456},"}** · Fixed (prunable): **${",[424,1191,888],{"class":452},[424,1193,638],{"class":456},[424,1195,1186],{"class":441},[424,1197,1198],{"class":456},"}**",[424,1200,849],{"class":441},[424,1202,1164],{"class":456},[424,1204,460],{"class":452},[424,1206,1208,1211,1214,1216],{"class":426,"line":1207},20,[424,1209,1210],{"class":437},"if",[424,1212,1213],{"class":452}," (fresh.",[424,1215,1186],{"class":441},[424,1217,491],{"class":452},[424,1219,1221,1224,1226,1228,1231,1233,1236],{"class":426,"line":1220},21,[424,1222,1223],{"class":452},"  console.",[424,1225,1154],{"class":448},[424,1227,453],{"class":452},[424,1229,1230],{"class":456},"'| Rule | Impact | Selector |",[424,1232,849],{"class":441},[424,1234,1235],{"class":456},"| --- | --- | --- |'",[424,1237,460],{"class":452},[424,1239,1241,1243,1245,1247,1250,1252,1255,1257,1259,1262,1265,1267,1270,1273,1275,1277,1280,1283,1286,1289,1291,1293,1295,1298,1300,1303],{"class":426,"line":1240},22,[424,1242,756],{"class":437},[424,1244,740],{"class":452},[424,1246,438],{"class":437},[424,1248,1249],{"class":441}," f",[424,1251,748],{"class":437},[424,1253,1254],{"class":452}," fresh) console.",[424,1256,1154],{"class":448},[424,1258,453],{"class":452},[424,1260,1261],{"class":456},"`| ${",[424,1263,1264],{"class":452},"f",[424,1266,638],{"class":456},[424,1268,1269],{"class":452},"rule",[424,1271,1272],{"class":456},"} | ${",[424,1274,1264],{"class":452},[424,1276,638],{"class":456},[424,1278,1279],{"class":452},"impact",[424,1281,1282],{"class":456},"} | ",[424,1284,1285],{"class":441},"\\`",[424,1287,1288],{"class":456},"${",[424,1290,1264],{"class":452},[424,1292,638],{"class":456},[424,1294,593],{"class":452},[424,1296,1297],{"class":456},"}",[424,1299,1285],{"class":441},[424,1301,1302],{"class":456}," |`",[424,1304,460],{"class":452},[424,1306,1308],{"class":426,"line":1307},23,[424,1309,629],{"class":452},[424,1311,1313],{"class":426,"line":1312},24,[424,1314,1315],{"class":430},"\u002F\u002F Non-zero ONLY on new violations -> red required check on regressions.\n",[424,1317,1319,1322,1325,1328,1330,1333,1336,1339,1342],{"class":426,"line":1318},25,[424,1320,1321],{"class":452},"process.",[424,1323,1324],{"class":448},"exit",[424,1326,1327],{"class":452},"(fresh.",[424,1329,1186],{"class":441},[424,1331,1332],{"class":437}," ?",[424,1334,1335],{"class":441}," 1",[424,1337,1338],{"class":437}," :",[424,1340,1341],{"class":441}," 0",[424,1343,460],{"class":452},[415,1345,1349],{"className":1346,"code":1347,"language":1348,"meta":420,"style":420},"language-yaml shiki shiki-themes github-light github-dark","# .github\u002Fworkflows\u002Fa11y-regression.yml\nname: a11y-regression\non:\n  pull_request:\n    branches: [main]\njobs:\n  diff:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with: { node-version: 20, cache: npm }\n      - run: npm ci\n      - run: npm run test:a11y:json     # writes a11y-report.json\n      - name: Diff against baseline\n        run: node .\u002Fscripts\u002Fdiff-baseline.js >> \"$GITHUB_STEP_SUMMARY\"\n","yaml",[343,1350,1351,1356,1368,1376,1383,1397,1404,1411,1421,1428,1441,1452,1481,1493,1507,1518],{"__ignoreMap":420},[424,1352,1353],{"class":426,"line":427},[424,1354,1355],{"class":430},"# .github\u002Fworkflows\u002Fa11y-regression.yml\n",[424,1357,1358,1362,1365],{"class":426,"line":434},[424,1359,1361],{"class":1360},"s9eBZ","name",[424,1363,1364],{"class":452},": ",[424,1366,1367],{"class":456},"a11y-regression\n",[424,1369,1370,1373],{"class":426,"line":463},[424,1371,1372],{"class":441},"on",[424,1374,1375],{"class":452},":\n",[424,1377,1378,1381],{"class":426,"line":470},[424,1379,1380],{"class":1360},"  pull_request",[424,1382,1375],{"class":452},[424,1384,1385,1388,1391,1394],{"class":426,"line":494},[424,1386,1387],{"class":1360},"    branches",[424,1389,1390],{"class":452},": [",[424,1392,1393],{"class":456},"main",[424,1395,1396],{"class":452},"]\n",[424,1398,1399,1402],{"class":426,"line":500},[424,1400,1401],{"class":1360},"jobs",[424,1403,1375],{"class":452},[424,1405,1406,1409],{"class":426,"line":561},[424,1407,1408],{"class":1360},"  diff",[424,1410,1375],{"class":452},[424,1412,1413,1416,1418],{"class":426,"line":626},[424,1414,1415],{"class":1360},"    runs-on",[424,1417,1364],{"class":452},[424,1419,1420],{"class":456},"ubuntu-latest\n",[424,1422,1423,1426],{"class":426,"line":632},[424,1424,1425],{"class":1360},"    steps",[424,1427,1375],{"class":452},[424,1429,1430,1433,1436,1438],{"class":426,"line":795},[424,1431,1432],{"class":452},"      - ",[424,1434,1435],{"class":1360},"uses",[424,1437,1364],{"class":452},[424,1439,1440],{"class":456},"actions\u002Fcheckout@v4\n",[424,1442,1443,1445,1447,1449],{"class":426,"line":801},[424,1444,1432],{"class":452},[424,1446,1435],{"class":1360},[424,1448,1364],{"class":452},[424,1450,1451],{"class":456},"actions\u002Fsetup-node@v4\n",[424,1453,1454,1457,1460,1463,1465,1468,1470,1473,1475,1478],{"class":426,"line":806},[424,1455,1456],{"class":1360},"        with",[424,1458,1459],{"class":452},": { ",[424,1461,1462],{"class":1360},"node-version",[424,1464,1364],{"class":452},[424,1466,1467],{"class":441},"20",[424,1469,485],{"class":452},[424,1471,1472],{"class":1360},"cache",[424,1474,1364],{"class":452},[424,1476,1477],{"class":456},"npm",[424,1479,1480],{"class":452}," }\n",[424,1482,1483,1485,1488,1490],{"class":426,"line":1059},[424,1484,1432],{"class":452},[424,1486,1487],{"class":1360},"run",[424,1489,1364],{"class":452},[424,1491,1492],{"class":456},"npm ci\n",[424,1494,1495,1497,1499,1501,1504],{"class":426,"line":1088},[424,1496,1432],{"class":452},[424,1498,1487],{"class":1360},[424,1500,1364],{"class":452},[424,1502,1503],{"class":456},"npm run test:a11y:json",[424,1505,1506],{"class":430},"     # writes a11y-report.json\n",[424,1508,1509,1511,1513,1515],{"class":426,"line":1093},[424,1510,1432],{"class":452},[424,1512,1361],{"class":1360},[424,1514,1364],{"class":452},[424,1516,1517],{"class":456},"Diff against baseline\n",[424,1519,1520,1523,1525],{"class":426,"line":1098},[424,1521,1522],{"class":1360},"        run",[424,1524,1364],{"class":452},[424,1526,1527],{"class":456},"node .\u002Fscripts\u002Fdiff-baseline.js >> \"$GITHUB_STEP_SUMMARY\"\n",[324,1529,1530,1531,1534],{},"The diff makes the gate adoptable: a team with 300 known violations sees a green check until someone ",[333,1532,1533],{},"adds"," the 301st, at which point the job exits non-zero and branch protection blocks the merge.",[866,1536,1537],{},[324,1538,1539,1541,1542,1544],{},[328,1540,872],{}," Report the count of ",[333,1543,888],{}," baseline entries too. Surfacing prunable items nudges engineers to shrink the baseline, turning the gate into a ratchet that only tightens.",[400,1546],{},[403,1548,1550],{"id":1549},"scheduled-full-audits-beyond-pr-scope","Scheduled Full Audits Beyond PR Scope",[324,1552,1553,1554,1557,1558,638],{},"Pull-request runs only test the routes a diff touches, so untouched pages drift. A nightly ",[343,1555,1556],{},"schedule"," trigger runs the full audit across every route, catches third-party and content regressions, and can open an issue when the baseline grows on ",[343,1559,1393],{},[415,1561,1563],{"className":1346,"code":1562,"language":1348,"meta":420,"style":420},"# .github\u002Fworkflows\u002Fa11y-nightly.yml\nname: a11y-nightly\non:\n  schedule:\n    - cron: '0 6 * * *'          # 06:00 UTC daily, full-site sweep\n  workflow_dispatch: {}          # allow manual runs\njobs:\n  full-audit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with: { node-version: 20, cache: npm }\n      - run: npm ci\n      - run: npx playwright install --with-deps chromium\n      - run: npm run test:e2e:a11y:full   # crawls all routes, writes report\n      - name: Open issue on new debt\n        if: failure()\n        run: gh issue create --title \"A11y regression on main\" --body-file a11y-summary.md\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n",[343,1564,1565,1570,1579,1585,1592,1608,1619,1625,1632,1640,1646,1656,1666,1688,1698,1709,1723,1734,1744,1753,1760],{"__ignoreMap":420},[424,1566,1567],{"class":426,"line":427},[424,1568,1569],{"class":430},"# .github\u002Fworkflows\u002Fa11y-nightly.yml\n",[424,1571,1572,1574,1576],{"class":426,"line":434},[424,1573,1361],{"class":1360},[424,1575,1364],{"class":452},[424,1577,1578],{"class":456},"a11y-nightly\n",[424,1580,1581,1583],{"class":426,"line":463},[424,1582,1372],{"class":441},[424,1584,1375],{"class":452},[424,1586,1587,1590],{"class":426,"line":470},[424,1588,1589],{"class":1360},"  schedule",[424,1591,1375],{"class":452},[424,1593,1594,1597,1600,1602,1605],{"class":426,"line":494},[424,1595,1596],{"class":452},"    - ",[424,1598,1599],{"class":1360},"cron",[424,1601,1364],{"class":452},[424,1603,1604],{"class":456},"'0 6 * * *'",[424,1606,1607],{"class":430},"          # 06:00 UTC daily, full-site sweep\n",[424,1609,1610,1613,1616],{"class":426,"line":500},[424,1611,1612],{"class":1360},"  workflow_dispatch",[424,1614,1615],{"class":452},": {}          ",[424,1617,1618],{"class":430},"# allow manual runs\n",[424,1620,1621,1623],{"class":426,"line":561},[424,1622,1401],{"class":1360},[424,1624,1375],{"class":452},[424,1626,1627,1630],{"class":426,"line":626},[424,1628,1629],{"class":1360},"  full-audit",[424,1631,1375],{"class":452},[424,1633,1634,1636,1638],{"class":426,"line":632},[424,1635,1415],{"class":1360},[424,1637,1364],{"class":452},[424,1639,1420],{"class":456},[424,1641,1642,1644],{"class":426,"line":795},[424,1643,1425],{"class":1360},[424,1645,1375],{"class":452},[424,1647,1648,1650,1652,1654],{"class":426,"line":801},[424,1649,1432],{"class":452},[424,1651,1435],{"class":1360},[424,1653,1364],{"class":452},[424,1655,1440],{"class":456},[424,1657,1658,1660,1662,1664],{"class":426,"line":806},[424,1659,1432],{"class":452},[424,1661,1435],{"class":1360},[424,1663,1364],{"class":452},[424,1665,1451],{"class":456},[424,1667,1668,1670,1672,1674,1676,1678,1680,1682,1684,1686],{"class":426,"line":1059},[424,1669,1456],{"class":1360},[424,1671,1459],{"class":452},[424,1673,1462],{"class":1360},[424,1675,1364],{"class":452},[424,1677,1467],{"class":441},[424,1679,485],{"class":452},[424,1681,1472],{"class":1360},[424,1683,1364],{"class":452},[424,1685,1477],{"class":456},[424,1687,1480],{"class":452},[424,1689,1690,1692,1694,1696],{"class":426,"line":1088},[424,1691,1432],{"class":452},[424,1693,1487],{"class":1360},[424,1695,1364],{"class":452},[424,1697,1492],{"class":456},[424,1699,1700,1702,1704,1706],{"class":426,"line":1093},[424,1701,1432],{"class":452},[424,1703,1487],{"class":1360},[424,1705,1364],{"class":452},[424,1707,1708],{"class":456},"npx playwright install --with-deps chromium\n",[424,1710,1711,1713,1715,1717,1720],{"class":426,"line":1098},[424,1712,1432],{"class":452},[424,1714,1487],{"class":1360},[424,1716,1364],{"class":452},[424,1718,1719],{"class":456},"npm run test:e2e:a11y:full",[424,1721,1722],{"class":430},"   # crawls all routes, writes report\n",[424,1724,1725,1727,1729,1731],{"class":426,"line":1143},[424,1726,1432],{"class":452},[424,1728,1361],{"class":1360},[424,1730,1364],{"class":452},[424,1732,1733],{"class":456},"Open issue on new debt\n",[424,1735,1736,1739,1741],{"class":426,"line":1148},[424,1737,1738],{"class":1360},"        if",[424,1740,1364],{"class":452},[424,1742,1743],{"class":456},"failure()\n",[424,1745,1746,1748,1750],{"class":426,"line":1169},[424,1747,1522],{"class":1360},[424,1749,1364],{"class":452},[424,1751,1752],{"class":456},"gh issue create --title \"A11y regression on main\" --body-file a11y-summary.md\n",[424,1754,1755,1758],{"class":426,"line":1207},[424,1756,1757],{"class":1360},"        env",[424,1759,1375],{"class":452},[424,1761,1762,1765,1767],{"class":426,"line":1220},[424,1763,1764],{"class":1360},"          GH_TOKEN",[424,1766,1364],{"class":452},[424,1768,1769],{"class":456},"${{ secrets.GITHUB_TOKEN }}\n",[324,1771,1772,1773,638],{},"The nightly job uses the same diff logic but against the full route map, so it surfaces regressions that no PR exercised—a CMS content change that broke contrast, or a dependency bump that stripped an accessible name. Page-level budgets that complement this sweep are detailed in ",[338,1774,237],{"href":1775},"\u002Ftesting-and-automating-accessibility\u002Faccessibility-audits-with-lighthouse\u002Fsetting-lighthouse-ci-accessibility-budgets\u002F",[400,1777],{},[403,1779,1781],{"id":1780},"caching-and-matrix-for-speed","Caching and Matrix for Speed",[324,1783,1784],{},"A full sweep is heavier than a PR diff, so cache the expensive pieces and parallelize across routes with a matrix.",[415,1786,1788],{"className":1346,"code":1787,"language":1348,"meta":420,"style":420},"jobs:\n  full-audit:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false           # report every shard, not just the first failure\n      matrix:\n        shard: [1, 2, 3, 4]      # split the route map four ways\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with: { node-version: 20, cache: npm }\n      - uses: actions\u002Fcache@v4\n        with:\n          path: ~\u002F.cache\u002Fms-playwright    # reuse browser binaries\n          key: pw-${{ hashFiles('package-lock.json') }}\n      - run: npm ci\n      - run: npm run test:e2e:a11y -- --shard=${{ matrix.shard }}\u002F4\n",[343,1789,1790,1796,1802,1810,1817,1830,1837,1867,1873,1883,1893,1915,1926,1932,1945,1955,1965],{"__ignoreMap":420},[424,1791,1792,1794],{"class":426,"line":427},[424,1793,1401],{"class":1360},[424,1795,1375],{"class":452},[424,1797,1798,1800],{"class":426,"line":434},[424,1799,1629],{"class":1360},[424,1801,1375],{"class":452},[424,1803,1804,1806,1808],{"class":426,"line":463},[424,1805,1415],{"class":1360},[424,1807,1364],{"class":452},[424,1809,1420],{"class":456},[424,1811,1812,1815],{"class":426,"line":470},[424,1813,1814],{"class":1360},"    strategy",[424,1816,1375],{"class":452},[424,1818,1819,1822,1824,1827],{"class":426,"line":494},[424,1820,1821],{"class":1360},"      fail-fast",[424,1823,1364],{"class":452},[424,1825,1826],{"class":441},"false",[424,1828,1829],{"class":430},"           # report every shard, not just the first failure\n",[424,1831,1832,1835],{"class":426,"line":500},[424,1833,1834],{"class":1360},"      matrix",[424,1836,1375],{"class":452},[424,1838,1839,1842,1844,1847,1849,1851,1853,1856,1858,1861,1864],{"class":426,"line":561},[424,1840,1841],{"class":1360},"        shard",[424,1843,1390],{"class":452},[424,1845,1846],{"class":441},"1",[424,1848,485],{"class":452},[424,1850,838],{"class":441},[424,1852,485],{"class":452},[424,1854,1855],{"class":441},"3",[424,1857,485],{"class":452},[424,1859,1860],{"class":441},"4",[424,1862,1863],{"class":452},"]      ",[424,1865,1866],{"class":430},"# split the route map four ways\n",[424,1868,1869,1871],{"class":426,"line":626},[424,1870,1425],{"class":1360},[424,1872,1375],{"class":452},[424,1874,1875,1877,1879,1881],{"class":426,"line":632},[424,1876,1432],{"class":452},[424,1878,1435],{"class":1360},[424,1880,1364],{"class":452},[424,1882,1440],{"class":456},[424,1884,1885,1887,1889,1891],{"class":426,"line":795},[424,1886,1432],{"class":452},[424,1888,1435],{"class":1360},[424,1890,1364],{"class":452},[424,1892,1451],{"class":456},[424,1894,1895,1897,1899,1901,1903,1905,1907,1909,1911,1913],{"class":426,"line":801},[424,1896,1456],{"class":1360},[424,1898,1459],{"class":452},[424,1900,1462],{"class":1360},[424,1902,1364],{"class":452},[424,1904,1467],{"class":441},[424,1906,485],{"class":452},[424,1908,1472],{"class":1360},[424,1910,1364],{"class":452},[424,1912,1477],{"class":456},[424,1914,1480],{"class":452},[424,1916,1917,1919,1921,1923],{"class":426,"line":806},[424,1918,1432],{"class":452},[424,1920,1435],{"class":1360},[424,1922,1364],{"class":452},[424,1924,1925],{"class":456},"actions\u002Fcache@v4\n",[424,1927,1928,1930],{"class":426,"line":1059},[424,1929,1456],{"class":1360},[424,1931,1375],{"class":452},[424,1933,1934,1937,1939,1942],{"class":426,"line":1088},[424,1935,1936],{"class":1360},"          path",[424,1938,1364],{"class":452},[424,1940,1941],{"class":456},"~\u002F.cache\u002Fms-playwright",[424,1943,1944],{"class":430},"    # reuse browser binaries\n",[424,1946,1947,1950,1952],{"class":426,"line":1093},[424,1948,1949],{"class":1360},"          key",[424,1951,1364],{"class":452},[424,1953,1954],{"class":456},"pw-${{ hashFiles('package-lock.json') }}\n",[424,1956,1957,1959,1961,1963],{"class":426,"line":1098},[424,1958,1432],{"class":452},[424,1960,1487],{"class":1360},[424,1962,1364],{"class":452},[424,1964,1492],{"class":456},[424,1966,1967,1969,1971,1973],{"class":426,"line":1143},[424,1968,1432],{"class":452},[424,1970,1487],{"class":1360},[424,1972,1364],{"class":452},[424,1974,1975],{"class":456},"npm run test:e2e:a11y -- --shard=${{ matrix.shard }}\u002F4\n",[324,1977,1978,1981,1982,1985],{},[343,1979,1980],{},"fail-fast: false"," ensures every shard reports its own regressions instead of cancelling siblings on the first failure—critical for an audit whose job is to surface ",[333,1983,1984],{},"all"," drift.",[400,1987],{},[403,1989,1991],{"id":1990},"uploading-reports-as-artifacts","Uploading Reports as Artifacts",[324,1993,1994,1995,1998],{},"Persist the full axe JSON, the diff summary, and any HTML report so a failure is investigable after the runner is gone. Upload on ",[343,1996,1997],{},"always()"," so the artifact survives a red run.",[415,2000,2002],{"className":1346,"code":2001,"language":1348,"meta":420,"style":420},"      - uses: actions\u002Fupload-artifact@v4\n        if: always()\n        with:\n          name: a11y-report-shard-${{ matrix.shard }}\n          path: |\n            a11y-report.json\n            a11y-summary.md\n            playwright-report\u002F\n          retention-days: 30      # keep history to trend regressions\n",[343,2003,2004,2015,2024,2030,2040,2049,2054,2059,2064],{"__ignoreMap":420},[424,2005,2006,2008,2010,2012],{"class":426,"line":427},[424,2007,1432],{"class":452},[424,2009,1435],{"class":1360},[424,2011,1364],{"class":452},[424,2013,2014],{"class":456},"actions\u002Fupload-artifact@v4\n",[424,2016,2017,2019,2021],{"class":426,"line":434},[424,2018,1738],{"class":1360},[424,2020,1364],{"class":452},[424,2022,2023],{"class":456},"always()\n",[424,2025,2026,2028],{"class":426,"line":463},[424,2027,1456],{"class":1360},[424,2029,1375],{"class":452},[424,2031,2032,2035,2037],{"class":426,"line":470},[424,2033,2034],{"class":1360},"          name",[424,2036,1364],{"class":452},[424,2038,2039],{"class":456},"a11y-report-shard-${{ matrix.shard }}\n",[424,2041,2042,2044,2046],{"class":426,"line":494},[424,2043,1936],{"class":1360},[424,2045,1364],{"class":452},[424,2047,2048],{"class":437},"|\n",[424,2050,2051],{"class":426,"line":500},[424,2052,2053],{"class":456},"            a11y-report.json\n",[424,2055,2056],{"class":426,"line":561},[424,2057,2058],{"class":456},"            a11y-summary.md\n",[424,2060,2061],{"class":426,"line":626},[424,2062,2063],{"class":456},"            playwright-report\u002F\n",[424,2065,2066,2069,2071,2074],{"class":426,"line":632},[424,2067,2068],{"class":1360},"          retention-days",[424,2070,1364],{"class":452},[424,2072,2073],{"class":441},"30",[424,2075,2076],{"class":430},"      # keep history to trend regressions\n",[324,2078,2079],{},"Thirty-day retention lets you trend the violation count over time and answer \"when did this regress?\" by diffing two archived baselines.",[400,2081],{},[403,2083,2085],{"id":2084},"how-to-verify","How to Verify",[324,2087,2088],{},"Confirm the regression gate behaves correctly in both directions—new violations must fail, baselined ones must not.",[2090,2091,2092,2105,2119,2125,2131],"ol",{},[360,2093,2094,2097,2098,2101,2102,638],{},[328,2095,2096],{},"Baseline passes (tool check):"," With an up-to-date baseline, open a no-op PR and confirm the ",[343,2099,2100],{},"diff"," job is green and the summary reports ",[343,2103,2104],{},"New: 0",[360,2106,2107,2110,2111,2114,2115,2118],{},[328,2108,2109],{},"New violation fails (tool check):"," Introduce a fresh ",[343,2112,2113],{},"4.1.2"," defect (remove an ",[343,2116,2117],{},"aria-label"," on an un-baselined element), push, and confirm the job exits non-zero and lists the new selector in the step summary.",[360,2120,2121,2124],{},[328,2122,2123],{},"Baselined debt does not fail (manual check):"," Confirm a PR that merely touches code near an existing baselined violation stays green—proving the diff suppresses accepted debt.",[360,2126,2127,2130],{},[328,2128,2129],{},"Fixed items surface (manual check):"," Repair one baselined violation and confirm the summary reports it under \"Fixed (prunable),\" prompting a baseline trim.",[360,2132,2133,2136,2137,2140],{},[328,2134,2135],{},"Nightly sweep runs (tool check):"," Trigger the nightly workflow via ",[343,2138,2139],{},"workflow_dispatch"," and confirm it audits routes no PR touched and uploads the artifact.",[400,2142],{},[403,2144,2146],{"id":2145},"conclusion","Conclusion",[324,2148,2149,2150,2152],{},"Regression testing is what lets an accessibility gate ship on a real codebase without a flag day. Fingerprint and commit a baseline of accepted violations, diff every PR so only ",[333,2151,335],{}," defects fail, sweep the full site on a nightly cron, and archive reports to trend the debt. Done right, the baseline only ratchets down: new regressions are blocked at the PR, and each fix shrinks the accepted set until the gate guards a fully clean tree.",[400,2154],{},[403,2156,2158],{"id":2157},"frequently-asked-questions","Frequently Asked Questions",[324,2160,2161,2164,2165,2168,2169,2171],{},[328,2162,2163],{},"How is a baseline different from disabling rules?","\nA baseline suppresses ",[333,2166,2167],{},"specific known instances","—a rule on a specific element—while still failing on any ",[333,2170,335],{}," instance of that same rule elsewhere. Disabling a rule blinds the gate to every occurrence, including future regressions. The baseline is a tracked debt list; a disabled rule is a permanent blind spot.",[324,2173,2174,2177],{},[328,2175,2176],{},"Should CI update the baseline automatically?","\nNo. Auto-updating launders new regressions straight into accepted debt and silently defeats the gate. Regenerate the baseline only on an intentional, reviewed commit, so growing the accepted-debt set is always a deliberate, visible decision.",[324,2179,2180,2183],{},[328,2181,2182],{},"Why run a nightly audit if every PR is already gated?","\nPR runs only exercise the routes a change touches. Untouched pages drift through CMS content edits, third-party widget updates, and dependency bumps that strip accessible names or break contrast. A scheduled full sweep catches regressions no pull request ever exercised.",[324,2185,2186,2189,2190,2192],{},[328,2187,2188],{},"How do I keep the full audit fast?","\nCache the Playwright browser binaries, split the route map across a build matrix with ",[343,2191,1980],{},", and reuse the npm cache. Sharding turns a long serial crawl into parallel jobs while still reporting every shard's regressions.",[324,2194,2195,2198,2199,2202],{},[328,2196,2197],{},"What should I store as an artifact?","\nThe raw axe JSON, the Markdown diff summary, and the HTML report, uploaded with ",[343,2200,2201],{},"if: always()"," and a retention window. Keeping history lets you diff two archived baselines to pinpoint exactly when and where a regression landed.",[400,2204],{},[403,2206,2208],{"id":2207},"related-guides","Related guides",[357,2210,2211,2215,2219],{},[360,2212,2213],{},[338,2214,297],{"href":340},[360,2216,2217],{},[338,2218,309],{"href":864},[360,2220,2221],{},[338,2222,237],{"href":1775},[2224,2225,2226],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}html pre.shiki code .snhLl, html code.shiki .snhLl{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":420,"searchDepth":434,"depth":434,"links":2228},[2229,2230,2231,2232,2233,2234,2235,2236,2237],{"id":405,"depth":434,"text":406},{"id":878,"depth":434,"text":879},{"id":1549,"depth":434,"text":1550},{"id":1780,"depth":434,"text":1781},{"id":1990,"depth":434,"text":1991},{"id":2084,"depth":434,"text":2085},{"id":2145,"depth":434,"text":2146},{"id":2157,"depth":434,"text":2158},{"id":2207,"depth":434,"text":2208},null,"Catch accessibility regressions automatically—snapshot known-good results, diff new violations against a baseline in GitHub Actions, and run scheduled full audits.","md",{},false,{"title":303,"description":2239},"04ztSAPkaCKGrX4-gxb2-JcRqKC4OGvYlZ1VkL5DR_4",[2246,2285,2286,2349],{"title":5,"path":6,"stem":7,"children":2247},[2248,2249,2252,2255,2261,2267,2276,2282],{"title":10,"path":6,"stem":11},{"title":13,"path":14,"stem":15,"children":2250},[2251],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":2253},[2254],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":2256},[2257,2258],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":2259},[2260],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":2262},[2263,2264],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":2265},[2266],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":2268},[2269,2270,2273],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":2271},[2272],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":2274},[2275],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":2277},[2278,2279],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":2280},[2281],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":2283},[2284],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87},{"title":89,"path":90,"stem":91,"children":2287},[2288,2289,2295,2307,2319,2322,2331,2343],{"title":94,"path":90,"stem":95},{"title":97,"path":98,"stem":99,"children":2290},[2291,2292],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":2293},[2294],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":2296},[2297,2298,2301,2304],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":2299},[2300],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":2302},[2303],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":2305},[2306],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":2308},[2309,2310,2313,2316],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":2311},[2312],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":2314},[2315],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":2317},[2318],{"title":151,"path":152,"stem":153},{"title":157,"path":158,"stem":159,"children":2320},[2321],{"title":157,"path":158,"stem":159},{"title":163,"path":164,"stem":165,"children":2323},[2324,2325,2328],{"title":163,"path":164,"stem":165},{"title":169,"path":170,"stem":171,"children":2326},[2327],{"title":169,"path":170,"stem":171},{"title":175,"path":176,"stem":177,"children":2329},[2330],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183,"children":2332},[2333,2334,2337,2340],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189,"children":2335},[2336],{"title":187,"path":188,"stem":189},{"title":193,"path":194,"stem":195,"children":2338},[2339],{"title":193,"path":194,"stem":195},{"title":199,"path":200,"stem":201,"children":2341},[2342],{"title":199,"path":200,"stem":201},{"title":205,"path":206,"stem":207,"children":2344},[2345,2346],{"title":205,"path":206,"stem":207},{"title":211,"path":212,"stem":213,"children":2347},[2348],{"title":211,"path":212,"stem":213},{"title":217,"path":218,"stem":219,"children":2350},[2351,2352,2361,2370,2379,2388],{"title":222,"path":218,"stem":223},{"title":225,"path":226,"stem":227,"children":2353},[2354,2355,2358],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":2356},[2357],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":2359},[2360],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":2362},[2363,2364,2367],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":2365},[2366],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":2368},[2369],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":2371},[2372,2373,2376],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":2374},[2375],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":2377},[2378],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":2380},[2381,2382,2385],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":2383},[2384],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":2386},[2387],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":2389},[2390,2391,2394],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":2392},[2393],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":2395},[2396],{"title":309,"path":310,"stem":311},1781785524264]