src/style.ts gives :focus-visible an outline to inputs, selects, textareas and buttons — and to nothing else, so a person tabbing through the shop loses the cursor the moment it lands on a link, which on the storefront is most of the page. There is also no skip link: the header carries a wordmark, five category links and a search box, and a keyboard or a screen reader walks all of it on every page before reaching <main> (src/html.ts:97), which already exists and is where a skip link would land.
Done looks like
[ ] The first focusable thing on every page is a "Skip to the shop" link to #main, visually hidden until focused, visible and readable when it is.
[ ] a:focus-visible carries the same outline the form controls already have, and the outline is visible against both the page and the admin bar.
[ ] <main> carries id="main" and stays the only <main> on the page; the admin's tab strip is a <nav> with a label that says which nav it is, beside the existing category <nav>.
[ ] Nothing shifts when the skip link appears: it is positioned, not inserted into the flow.
[ ] A test asserts the skip link is the first link in the document on a storefront page and on an admin page, and that the CSS names a:focus-visible.
[ ] No JavaScript is added and the CSS stays in src/style.ts, so the hashed stylesheet is still the only stylesheet.
Filessrc/html.ts, src/style.ts, src/pages/admin.ts for the tab strip, src/server.test.ts.
Risks The stylesheet's name is its hash, so changing the CSS changes the URL — that is the design, but check the asset test still passes. The skip link must not appear for a mouse (:focus-visible, never :focus), and it must not be the thing that pushes the header down on a phone.
Suggested mason, with juniper trying it on a phone and with the keyboard only.
src/style.tsgives:focus-visiblean outline to inputs, selects, textareas and buttons — and to nothing else, so a person tabbing through the shop loses the cursor the moment it lands on a link, which on the storefront is most of the page. There is also no skip link: the header carries a wordmark, five category links and a search box, and a keyboard or a screen reader walks all of it on every page before reaching<main>(src/html.ts:97), which already exists and is where a skip link would land.Done looks like
#main, visually hidden until focused, visible and readable when it is.a:focus-visiblecarries the same outline the form controls already have, and the outline is visible against both the page and the admin bar.<main>carriesid="main"and stays the only<main>on the page; the admin's tab strip is a<nav>with a label that says which nav it is, beside the existing category<nav>.a:focus-visible.src/style.ts, so the hashed stylesheet is still the only stylesheet.Files
src/html.ts,src/style.ts,src/pages/admin.tsfor the tab strip,src/server.test.ts.Risks The stylesheet's name is its hash, so changing the CSS changes the URL — that is the design, but check the asset test still passes. The skip link must not appear for a mouse (
:focus-visible, never:focus), and it must not be the thing that pushes the header down on a phone.Suggested mason, with juniper trying it on a phone and with the keyboard only.