{% comment %} Dedicated loading spinner (ICO-019): its own SVG with a @keyframes rotation and a reduced-motion fallback (MOT-003, handled by the global reduced-motion rule in the bundle). aria-hidden because a busy state is conveyed by the host control's aria-busy, not by the spinner glyph. A button's loading=True mounts this. States: spinning only; there is no other state, since it is never rendered except while its host is busy. The rotation is a CSS @keyframes animation, stopped under prefers-reduced-motion (the global reduced- motion rule), leaving the static glyph visible rather than an endless spin. Accessibility: aria-hidden="true" always; the busy state is conveyed by the host control's own aria-busy (e.g. _button.html's loading=True), the spinner glyph itself carries no accessible name and is never the sole signal. Covered directly by the search-.html fixture (a11y/generate_fixtures.py's render_search, #226), which renders a loading bw_button (loading=True disabled=True) alongside bw_search specifically to mount this component; the composed markup is what axe.spec.mjs examines. Not a standalone fixture of its own, since it is never rendered except while a host control is busy. Responsive: no breakpoint switch; no width-dependent CSS. Its size is fixed to --bw-component-icon-size-sm, not viewport-driven. {% endcomment %}