Accessibility conformance report

Product
@pacit/components 0.2.0 — the Angular component library. The documentation site and the consuming application are outside this report: a criterion about a page is theirs, and its row says so.
Standard
WCAG 2.2, levels A and AA. EN 301 549, the European standard the EAA points tenders at, refers web content to the same criteria (clause 9 is WCAG 2.1 AA, which these tables cover).
Report date
2026-09-05
Evaluation methods
the repository's own gates, run on every commit in CI and named per row — axe-core over every component view and every special state in three engines, a contrast policy measured on every token build for both themes, a keyboard map tested key by key per component, forced colours and reduced motion emulated and read back, an accessible name gate over the sources, and scans over the library's templates and stylesheets for what a criterion forbids. The assistive-technology pass: recorded (see below).

Status: conformant. Every one of the 55 rows reads Supports, on the evidence its row names, or Not Applicable, on something the library does not ship, and the assistive-technology pass is on record. The word is the one decision 0061 reserves for this report and for this state of it (amended 2026-09-28); the documentation site's landing keeps "machine-audited", a law of the same decision that the site's own suite holds and the report's word does not move.

The words

LevelWhat it means in this report
Supportsa gate that runs on every commit measures the criterion and finds nothing wrong
Partially Supportsmeasured, and a limit is named in the row — an open finding in the plan, or a component card that still owes the reading
Does Not Supportmeasured, and found wrong; the finding that owns the repair is named
Not Applicablethe criterion is about something the library does not ship, and the row says what — where a scan can prove the absence, it does
Not Evaluatedno gate measures the criterion yet, and the row names the finding that will

The last word is this report's one deviation from the ITI template, which reserves Not Evaluated for level AAA. A claim nothing measured is exactly what this document exists to avoid, so a criterion no gate reaches says so in its own row rather than borrowing a Supports from a reading of the code; the list of those rows is the work order, not a footnote.

Summary

Conformance levelLevel A (31)Level AA (24)
Supports2115
Partially Supports00
Does Not Support00
Not Applicable109
Not Evaluated00

Table 1: success criteria, level A

CriterionConformance levelRemarks and explanations
1.1.1 Non-text ContentSupportsThe library draws no image that carries meaning on its own. Icons stand inside <pct-icon> with aria-hidden and take their meaning from the control that holds them; a control's accessible name is written on the tag the consumer types and forwarded to the element that carries the role, so a name is never written where nothing reads it. The words of a name are the consumer's. An icon of the consumer's that IS the information takes a label, and is then role="img" under that name — the two attributes move together, so a name never stands on a hidden element. Evidence: tools/check-aria.mjs (points 2, 3, 4) · tools/check-icons.mjs (points 2, 3) · libs/components/icon/src/icon.ts ("'[attr.aria-hidden]': 'named() === null ? "true" : null'") · apps/sandbox-e2e/src/a11y.spec.ts › "the ${path} view has no violations" · req-a11y-built-in
1.2.1 Audio-only and Video-only (Prerecorded)Not ApplicableNo component renders audio or video: no template holds an <audio> or a <video> element and no script makes one, and the gate scans both on every run. Evidence: scan no-media-elements — no match in 216 source files
1.2.2 Captions (Prerecorded)Not ApplicableNo media, so nothing to caption — the same scan as 1.2.1. Evidence: scan no-media-elements — no match in 216 source files
1.2.3 Audio Description or Media Alternative (Prerecorded)Not ApplicableNo media, so nothing to describe — the same scan as 1.2.1. Evidence: scan no-media-elements — no match in 216 source files
1.3.1 Info and RelationshipsSupportsA label reaches its control through for or aria-labelledby, a hint and an error through aria-describedby, a group through its role and its name, and a field of two texts through both: a group named by the label, and each text named by the label and a word of its own — the wiring is the library's and gated, the text is the consumer's. The one relation that was known wrong — an empty pct-select panel rendering a role="listbox" that owned no role="option", which axe rates critical — was repaired on 2026-09-06: the panel is a surface, the listbox is the list inside it, and the empty panel is a scene of the audit in its own right. Evidence: tools/check-aria.mjs (points 3, 4, 6) · apps/sandbox-e2e/src/a11y.spec.ts › "a form in the error state has no violations", "an open panel with headings", "an empty panel", "an open panel of a calendar and time columns, and the field it belongs to" · apps/sandbox-e2e/src/field.spec.ts › "the wrapper renders the validation error and binds it to the control" · libs/components/datetime/src/datetime-field.spec.ts › "names each text by the label and a word of its own, and the group by the label (0090, E1–E3)" · req-a11y-built-in
1.3.2 Meaningful SequenceSupportsReading order is DOM order. No stylesheet names a physical side of the inline axis, so nothing is moved somewhere the DOM does not say, and the right-to-left direction is measured rather than assumed. Evidence: tools/check-styles.mjs (point 5) · apps/sandbox-e2e/src/rtl.spec.ts › "the field affix moves to the other side of the control", "the select panel inherits the direction from the trigger, not from body"
1.3.3 Sensory CharacteristicsSupportsThe library's own sentences come through PCT_TEXTS — every one of them, the gate refuses a literal in a template — and none names a shape, a size, a position or a sound. Instructions around a component are the consumer's. Evidence: tools/check-texts.mjs (points 3, 5) · the cards' Strings through row: 41 of 41 (24 measured, 17 by argument)
1.4.1 Use of ColorSupportsNo state is carried by colour alone: forced colours strip every author colour and the suite reads each state back through position, text or the system palette; an error is a sentence in an alert, not a red edge; the chosen tab, the checked box and the current page each carry an attribute. Evidence: the cards' forced-colors: active row: 41 of 41 (37 measured, 4 by argument) · apps/sandbox-e2e/src/forced-colors.spec.ts › "the switch carries its state in the thumb’s position, not in a colour" · tools/check-styles.mjs (point 7) · req-a11y-forced-colors
1.4.2 Audio ControlNot ApplicableNothing plays sound — the same scan as 1.2.1. Evidence: scan no-media-elements — no match in 216 source files
2.1.1 KeyboardSupportsEvery component's keyboard map is tested key by key in three engines, or its card argues why the map is empty (nothing focusable) or the platform's own (a native button). Evidence: the cards' Keyboard map row: 41 of 41 (37 measured, 4 by argument) · apps/sandbox-e2e/src/select.spec.ts › "the keyboard: the arrows, Home/End, Enter and aria-activedescendant" · req-api-platform
2.1.2 No Keyboard TrapSupportsThe modal dialog is the one deliberate trap, and Escape leaves it; a menu, a popover, a tooltip, the date panel, the time panel, the datetime panel and the select close on Escape and hand focus back to their trigger. Evidence: apps/sandbox-e2e/src/dialog.spec.ts › "it takes focus on open and gives it back on close", "Escape closes it and says so" · apps/sandbox-e2e/src/menu.spec.ts › "Escape closes it and gives focus back to the trigger" · apps/sandbox-e2e/src/popover.spec.ts › "Escape closes it and gives focus back to the trigger" · apps/sandbox-e2e/src/time.spec.ts › "Escape closes it and hands focus back to the field", "Tab walks the columns, one stop each, and then comes back to the field" · apps/sandbox-e2e/src/datetime.spec.ts › "Escape closes it with the value as the halves left it, focus back on the field", "Tab walks the grid, then the columns, and comes back to the field"
2.1.4 Character Key ShortcutsSupportsThe only single-character keys are the type-ahead of a list, a menu and a select, active while that component has focus and nowhere else — the exception the criterion names. No accesskey is written anywhere; the gate scans for one. Evidence: scan no-accesskey — no match in 216 source files · libs/components/core/src/list.ts ("typeahead")
2.2.1 Timing AdjustableSupportsThe toast is the only timed content. Each message names its own duration (null keeps it up), an urgent message waits, and the whole stack pauses while the pointer or the focus rests on it — that rest is how the user extends the time. Evidence: apps/sandbox-e2e/src/toast.spec.ts › "an urgent message is an alert, and it waits" · libs/components/toast/src/toaster.ts ("get paused(): boolean") · decision 0044
2.2.2 Pause, Stop, HideSupportsNothing in the library runs unattended past five seconds without a stop beside it. Every face of [pctHero] and the button's hero variant run ONE pass of four seconds and then stand still, so the criterion's second condition is not met for them at all. The skeleton's sheen is the one that runs for as long as the wait does, and it is meant to: a busy indicator that stopped would say the work had finished, so a cap after N passes was refused outright as the road that lies. What it takes instead is paused, an input — the page is the only side that knows how long its own wait has been (0073). Three mechanisms, in this order: prefers-reduced-motion is the reader's and outranks both — it slows the sheen through the motion axis rather than stopping it, since a still placeholder is the same lie more quietly told; paused is the page's; and with neither spoken the motion is the wait itself. The consumer's part is written in the card and not implied: end the wait, or say when it has gone on too long. Evidence: the cards' prefers-reduced-motion row: 41 of 41 (24 measured, 17 by argument) · apps/sandbox-e2e/src/hero.spec.ts › "the sweep runs its pass and stands still inside five seconds", "paused stops the sweep where it stands" · apps/sandbox-e2e/src/skeleton.spec.ts › "paused freezes the sheen where it stands, and lets it go again", "the stop is one page’s and not the library’s: every other skeleton keeps moving" · apps/sandbox-e2e/src/preferences.spec.ts › "the reduction covers every control, not the button alone", "a skeleton’s sheen slows to the loop token and does not stop" · tools/check-styles.mjs (point 9)
2.3.1 Three Flashes or Below ThresholdSupportsNothing flashes. The fastest periodic motion in the library is the spinner's turn and the sheen's loop, both far below three cycles a second, and every duration comes from the motion axis rather than from a stylesheet. Evidence: tools/check-styles.mjs (point 9) · libs/tokens/src/motion.reduced.json · apps/sandbox-e2e/src/preferences.spec.ts › "the transitions disappear and a continuous indicator only slows down"
2.4.1 Bypass BlocksNot ApplicableA page-level criterion: the blocks a page repeats are the consumer's. The library's regions announce themselves — the dialog is a role="dialog", the toast stack a role="log", the breadcrumb and the pager named landmarks. Evidence: apps/sandbox-e2e/src/breadcrumb.spec.ts › "a named landmark holding a counted list of steps" · apps/sandbox-e2e/src/pagination.spec.ts › "the pager is a named landmark with a list inside it"
2.4.2 Page TitledNot ApplicableA page-level criterion; the library sets no document title.
2.4.3 Focus OrderSupportsFocus order is DOM order: no positive tabindex anywhere (scanned), a dialog takes focus on open and gives it back on close, a menu and a popover return it to their trigger. A toast's action stands at the end of the document because the stack is a child of body — reachable, and far, which is why the library also ships a way out of that walk: @pacit/components/regions registers the stack as a region and moves focus to it on a key the CONSUMER mounts, F6 by default. The cycle changes no reading order and takes no keystroke by itself; with nothing mounted, this row reads exactly as it did before (0072). Evidence: scan no-positive-tabindex — no match in 216 source files · apps/sandbox-e2e/src/dialog.spec.ts › "it takes focus on open and gives it back on close" · apps/sandbox-e2e/src/menu.spec.ts › "opening puts focus on the first command", "Escape closes it and gives focus back to the trigger" · apps/sandbox-e2e/src/popover.spec.ts › "focus goes to the panel, and Tab from there reaches the content"
2.4.4 Link Purpose (In Context)SupportsThe library's own links are the breadcrumb's and the pager's; each carries its visible text or a name from PCT_TEXTS, the current one says it is current, and axe's link-name runs over every view. Evidence: apps/sandbox-e2e/src/breadcrumb.spec.ts › "every link is reachable by its exact name — the separator adds nothing" · apps/sandbox-e2e/src/pagination.spec.ts › "the current page is announced as current, and only one is" · the cards' Strings through row: 41 of 41 (24 measured, 17 by argument)
2.5.1 Pointer GesturesSupportsNo component needs a path or a multipoint gesture: the slider is the native range (a press lands the thumb, the keys move it) and everything else is a press. Evidence: apps/sandbox-e2e/src/slider.spec.ts › "a press lands the drawn thumb where the pointer is, and a drag keeps it there" · apps/sandbox-e2e/src/tooltip.spec.ts › "a long press opens it, a tap does not"
2.5.2 Pointer CancellationSupportsThe library's own pointer handling completes on click — the field row activates on the up-event, never on mousedown — and its triggers are native buttons; the one down-event behaviour is the native range's, whose move the up-event completes. Evidence: libs/components/field/src/field.ts ("Activation goes on click, not on mousedown")
2.5.3 Label in NameSupportsThe visible label is the accessible name: <label for> and aria-labelledby point at the very text that is shown, so the name contains what is read; an icon-only button is named by the tooltip that shows on it. Evidence: tools/check-aria.mjs (points 3, 4) · apps/sandbox-e2e/src/breadcrumb.spec.ts › "every link is reachable by its exact name — the separator adds nothing" · apps/sandbox-e2e/src/tooltip.spec.ts › "an icon-only button is named by its tooltip, open or not"
2.5.4 Motion ActuationNot ApplicableNothing listens to device motion or orientation, and no motion sensor is read; the gate scans the templates and the scripts for either. Evidence: scan no-device-motion — no match in 216 source files
3.1.1 Language of PageNot ApplicableA page-level criterion; the library sets no lang on the document.
3.2.1 On FocusSupportsFocus alone changes nothing: a select opens on a press or a key, never on arriving; a tooltip on focus only describes; the field row's own focus moves nothing. Evidence: apps/sandbox-e2e/src/tooltip.spec.ts › "the keyboard opens it and a click does not" · apps/sandbox-e2e/src/select.spec.ts › "a click opens the panel; picking closes it and shows the label"
3.2.2 On InputSupportsChanging a value submits nothing and navigates nowhere: picking an option closes the panel it came from, a toggle leaves the panel standing, and a form turns valid only when the consumer's schema says so. Evidence: apps/sandbox-e2e/src/select.spec.ts › "a click opens the panel; picking closes it and shows the label", "the keyboard toggles the active row and leaves the panel standing" · apps/sandbox-e2e/src/forms.spec.ts › "the form turns valid only once every required field is filled"
3.2.6 Consistent HelpNot ApplicableA criterion across pages about where help is found; the library ships no help mechanism.
3.3.1 Error IdentificationSupportsAn error is a sentence: the field's alert region speaks the schema's message, the control says aria-invalid, and the message replaces the hint below the field — one line, never two. A warning is the same sentence without the verdict: it takes the same line after the error, in its own tone with a glyph and a word for a reader, and leaves aria-invalid off, because the value is allowed. A field of two texts says which of them is wrong: junk in one half is that half's sentence with aria-invalid on that text alone and the other half kept, and a half left empty when focus leaves the field is a sentence of its own, marked on the empty text. Evidence: tools/check-aria.mjs (points 6, 7) · apps/sandbox-e2e/src/field.spec.ts › "the wrapper renders the validation error and binds it to the control", "there is one line below the field: the error replaces the hint", "a warning takes the line once the field is left, and the field stays valid" · apps/sandbox-e2e/src/datetime.spec.ts › "junk in one half keeps the other, says which half, and the panel opens on the month it names", "a day with no time is no value, and the field says so once it is left" · req-api-message · req-api-warning
3.3.2 Labels or InstructionsSupportsEvery control takes a label, a hint and a required sign, drawn by the control outside a field and by the field inside one; a control whose widget sits inside its template exposes ariaLabel and ariaLabelledby, and the gate holds both. Evidence: tools/check-aria.mjs (points 3, 4, 5) · apps/sandbox-e2e/src/a11y.spec.ts › "a form in the error state has no violations"
3.3.7 Redundant EntryNot ApplicableAn application-level criterion about information asked twice in one process; the library ships no process.
4.1.2 Name, Role, ValueSupportsEvery widget is native where the platform has one and an APG pattern where it has not; the name written on the host reaches the element with the role, states are attributes, and axe's ARIA rules run over every view and every special state in three engines. The one value known wrong — the empty select's listbox — was repaired on 2026-09-06. Three readers walked all thirty-six views on 2026-09-16 and, on 2026-09-28, opened the nine things that open — a modal, a menu, a popover, a toast, a month grid, a tab panel, a listbox, a docked region, a disclosure — and every card carries what was heard. The names, roles and values arrive: aria-valuetext reaches the readers, a described control speaks its description, a password value is spoken by none, the chip's cross names what it removes, a modal is announced by name and role as it takes focus, a menu's first row and a revealed tab, with their positions where a reader gives them, a message in the log as it arrives, a trigger's state the moment its region opens. Where the readers differ the cards say so, and none of it is a name, a role or a value the library failed to expose: Orca reads a grid cell by its column and text rather than by its name and says nothing when a modal takes focus — the plan holds that one as a finding — VoiceOver was silent at four of the nine openings — a grid it had opened, a list, a message, a tab its arrow did not move — and which of those is the reader and which the component the record does not settle, a read-only checkbox and switch are announced plainly checked and on with aria-readonly on the control, NVDA names the theme group and not the option, and Orca says nothing of a collapsed combobox's value where the other two read it. Evidence: tools/check-aria.mjs (points 1, 2, 3, 4, 8) · apps/sandbox-e2e/src/a11y.spec.ts › "the ${path} view has no violations", "the a11y gate really does detect violations (a control of the gate)" · req-a11y-built-in · req-a11y-axe · the cards' Screen-reader log row: 41 of 41 (41 measured, 0 by argument)

Table 2: success criteria, level AA

CriterionConformance levelRemarks and explanations
1.2.4 Captions (Live)Not ApplicableNo media, live or recorded — the same scan as 1.2.1. Evidence: scan no-media-elements — no match in 216 source files
1.2.5 Audio Description (Prerecorded)Not ApplicableNo media — the same scan as 1.2.1. Evidence: scan no-media-elements — no match in 216 source files
1.3.4 OrientationSupportsNo stylesheet and no script reads the display orientation; the components lay out the same either way. The gate scans every stylesheet as it compiles, the theme the package ships among them, the templates' media queries, and the scripts, for a reading of it. Evidence: scan no-orientation-lock — no match in 271 source files
1.3.5 Identify Input PurposeSupportsThe text and date fields are the native <input> the consumer writes, so an autocomplete purpose written on the tag stays on the element. The number field writes autocomplete="off" by default — a browser's formatted string is a value its parser refuses — and takes an autocomplete input typed as the platform's own AutoFill, so the three numeric purposes on the criterion's list (bday-day, bday-month, bday-year) can be declared on it. The time field writes autocomplete="off" on the input inside it: what a browser remembers is a string its parser would have to guess at, and a time of day is no purpose on the criterion's list. The datetime field writes the same on both of its texts, for the same reason. Evidence: libs/components/field/src/number.spec.ts › "refuses autofill until a consumer asks for it", "takes the purpose a consumer declares" · libs/components/field/src/number.ts ("readonly autocomplete = input<AutoFill>('off');") · libs/components/time/src/time-field.spec.ts › "is a plain textbox for a numeric keypad, with nothing the browser fills in" · libs/components/datetime/src/datetime-field.spec.ts › "is two plain textboxes for a numeric keypad, with nothing the browser fills in"
1.4.3 Contrast (Minimum)SupportsEvery colour a stylesheet paints stands as a foreground/background pair in the contrast policy, measured on every token build for both themes at 4.5:1 for text and 3:1 for large text; axe measures the composed DOM again, in three engines, every view. Evidence: tools/check-tokens.mjs (point 7) · libs/tokens/src/contrast.policy.json (""level": "AA"") · apps/sandbox-e2e/src/a11y.spec.ts › "a card with a dark stage has no violations" · req-token-contrast
1.4.4 Resize TextSupportsEvery component of the library stands on one page (/all) with the root font size doubled, and no box that clips is left with content outside it. Text alone is enlarged rather than the page zoomed — zoom scales the layout with the text and would measure nothing. Evidence: apps/sandbox-e2e/src/adaptation.spec.ts › "text at 200 % cuts nothing off"
1.4.5 Images of TextNot ApplicableThe library ships no image of text: icons are glyph drawings without a <text> element, and every word is live text — a chart's axis labels among them, SVG <text> the browser lays out in the skin's font and the reader's zoom. The gate scans the templates, the drawings and the scripts for any other one. Evidence: scan no-svg-text — no match in 215 of 216 source files; libs/components/chart/src/chart.html: the chart's axis labels, live SVG text written from the data, in the skin's font (0100)
1.4.10 ReflowSupportsAll thirty-five sandbox views laid out at 320 CSS pixels, one case each, in three engines: the document may not be scrolled on the inline axis at all. Two harness defects and one library one came out of the first run — a column of flex items sized to their own content, a grid track with a 280 px floor, and a field whose automatic minimum was the native input's twenty-character intrinsic width; pct-field now carries min-width: 0 so it shrinks instead of pushing the page sideways. Evidence: apps/sandbox-e2e/src/adaptation.spec.ts › "lays out at 320 px with nothing to scroll sideways" · libs/components/field/src/field.scss ("min-width: 0;")
1.4.11 Non-text ContrastSupportsBorders, the focus ring and the states of the controls are UI pairs in the same contrast policy as the text, held at 3:1 in both themes on every token build. Evidence: tools/check-tokens.mjs (point 7) · libs/tokens/src/contrast.policy.json ("UI: focus ring")
1.4.12 Text SpacingSupportsThe criterion's own four declarations — line height 1.5, letter spacing 0.12 em, word spacing 0.16 em, paragraph spacing 2 em — applied with !important over everything on the page that holds every component, with no box that clips left holding content outside it. Evidence: apps/sandbox-e2e/src/adaptation.spec.ts › "own text spacing cuts nothing off"
1.4.13 Content on Hover or FocusSupportsThe tooltip is the only content that appears on hover or on focus, and each of the criterion's three demands is measured: Escape dismisses it and leaves focus where it was, the pointer can travel onto it, and it stays until the pointer or the focus leaves. Evidence: apps/sandbox-e2e/src/tooltip.spec.ts › "Escape dismisses it and leaves focus where it was (WCAG 1.4.13)", "the pointer can travel onto the panel and read it", "the leave is waited out rather than cut off"
2.4.5 Multiple WaysNot ApplicableA page-level criterion about finding pages within a set; the library ships no pages.
2.4.6 Headings and LabelsSupportsA dialog is named by its heading, a field by its label, a group by its legend — wired by the library, worded by the consumer; the gate refuses a name written where nothing reads it. Evidence: tools/check-aria.mjs (points 2, 3, 4, 5) · apps/sandbox-e2e/src/a11y.spec.ts › "an open dialog"
2.4.7 Focus VisibleSupportsOne focus ring, one token, drawn with :focus-visible by every control that takes focus (a field draws it around its whole row) and measured as a UI pair at 3:1 in both themes; under forced colours it is drawn in Highlight. Evidence: tools/check-tokens.mjs (point 7) · libs/tokens/src/contrast.policy.json ("UI: focus ring") · apps/sandbox-e2e/src/forced-colors.spec.ts › "the focus ring is drawn in Highlight, not in the border colour" · libs/components/field/src/text.scss ("The chrome draws focus around the whole row")
2.4.11 Focus Not Obscured (Minimum)SupportsThe library keeps one fixed layer on screen — the toast stack, in a corner — and anchors every panel to its trigger. With a standing toast open, every focusable of the view is focused in turn and the element under the middle of its own box is asked for: it is the control itself and not the stack. elementsFromPoint and not a rectangle comparison, because a box that overlaps another is not obscured if it is the one in front. Evidence: apps/sandbox-e2e/src/adaptation.spec.ts › "a standing toast leaves every control in front of it"
2.5.7 Dragging MovementsSupportsThe slider is the only dragging there is, and a press on the track or the arrow keys do the same without a drag. Evidence: apps/sandbox-e2e/src/slider.spec.ts › "a press lands the drawn thumb where the pointer is, and a drag keeps it there"
2.5.8 Target Size (Minimum)SupportsA stricter promise than the criterion: 24 × 24 px outright, with no spacing exception, measured per control — the smallest control height is 28 px, and a field's border and affixes are part of its hit area. Evidence: the cards' Touch target row: 41 of 41 (27 measured, 14 by argument) · req-a11y-touch · apps/sandbox-e2e/src/field-hitarea.spec.ts › "a click on the left border padding focuses the field" · apps/sandbox-e2e/src/size.spec.ts › "the field and the button at size ${size} have the same height" · lesson-14
3.1.2 Language of PartsNot ApplicableThe library renders no text in a language of its own: every string it speaks comes through PCT_TEXTS, so a passage in another language cannot come from the library. Evidence: tools/check-texts.mjs (points 3, 5) · the cards' Strings through row: 41 of 41 (24 measured, 17 by argument)
3.2.3 Consistent NavigationNot ApplicableA criterion across pages; the library ships no navigation of pages.
3.2.4 Consistent IdentificationNot ApplicableA criterion across pages. Within the library one component is one role and one naming rule, held by the gate; the words are the consumer's. Evidence: tools/check-aria.mjs (points 2, 3)
3.3.3 Error SuggestionSupportsThe text of the first error is the consumer's own message, delivered where the user reads it; the library adds the channel and takes nothing away. Evidence: libs/components/core/src/field.ts ("the text of the first error") · tools/check-aria.mjs (points 6, 7)
3.3.4 Error Prevention (Legal, Financial, Data)Not ApplicableAn application-level criterion about legal and financial commitments; the library ships no such flow.
3.3.8 Accessible Authentication (Minimum)Not ApplicableAn application-level criterion; the library ships no authentication.
4.1.3 Status MessagesSupportsA status is announced from where it happens: the toast stack is a role="log" and an urgent message a role="alert", the field's error an alert and its warning a polite status — a value allowed and suspect waits its turn where an error interrupts — the select's empty panel a polite announcement, a refused day is said out loud, and so is text in the time field that is not a time, and a half of the datetime field that is junk or left empty — each measured. The announcer's assertive channel has no caller yet (4.15 in the plan), so nothing rides it. Evidence: apps/sandbox-e2e/src/toast.spec.ts › "an urgent message is an alert, and it waits" · apps/sandbox-e2e/src/select.spec.ts › "opening it announces the text the application translated" · apps/sandbox-e2e/src/date.spec.ts › "a refused day is reached, announced and not takeable" · apps/sandbox-e2e/src/time.spec.ts › "keeps junk in the field and reports it, where a native time input loses it" · apps/sandbox-e2e/src/field.spec.ts › "a warning takes the line once the field is left, and the field stays valid" · apps/sandbox-e2e/src/datetime.spec.ts › "junk in one half keeps the other, says which half, and the panel opens on the month it names" · tools/check-aria.mjs (point 7) · decision 0044

The assistive-technology pass

Recorded. NVDA with Firefox on Windows, VoiceOver with Safari on macOS and Orca with Firefox on Linux over the sandbox views the axe sweep audits (SBX_ROUTES, declared in apps/sandbox-e2e/src/support/views.ts and imported by the sweep); the logs stand under docs/acr/at/ (3 files), and every one of the 41 component cards points its Screen-reader log row at them.

What no gate measures yet

Every criterion has a gate behind its row.