Curbcut
Fix pack for curbcuthq.com
80/100
Needs work

curbcuthq.com

59 failures, 30 warnings across 4 pages. Generated Sat, 05 Sep 2026 02:27:01 GMT.
33
for your content team
56
for a developer
6
to check by hand
27
fixes already written

Where to start

The few changes that clear the most. Most failures on most sites are one template line repeated on every page.

1. Images with no alt text
11 instances
Image has no alt attribute; assistive technology will announce the file name.
2. Your stylesheet
19 instances
Content has to reflow into a single column at 320 CSS pixels. Having to scroll in two directions to read a line of text makes a page very hard to use on a phone, and unusable for someone relying on heavy zoom.
3. Control is labelled only by its placeholder ("Your name"), which vanishes on input and is not a reliable accessible name
5 instances

What is in the pack

start-here/
Read this first. The roadmap, a one-page summary for whoever signs things off, and what your site sounds like to a screen reader.
4 items
for-your-content-team/
Fixes that need no code: alt text, link wording, headings, titles. Anyone who can edit the site can do these.
33 items
for-your-developer/
Fixes that touch templates, stylesheets or the server. Each subfolder is self-contained.
29 items
apply-with-ai/
A ready-made prompt for Claude Code, Cursor, Copilot or any coding agent. Paste it and the agent applies every fix in this pack.
PROMPT.md and fixes.json
check-by-hand/
What automated testing cannot settle, scoped to what we found on your site.
6 items
export/
The same findings as GitHub issues, Jira, Linear and Trello imports, plus a bookmarklet that highlights every failing element on your live site.
19 items

Roadmap

Risk
High
Total effort
6 hours
84 minutes content, 4.5 hours developer
First three changes
clear 23%
in about 17 minutes
By hand afterwards
83 minutes
the checks no tool can do
Multiple Level A failures across the site. These are the ones complaints and demand letters cite.

Ordered by how much each change clears per minute it takes. Where the same element repeats on every page it is priced as one template change, because that is what it is.

#ChangeWhoClearsEffortRunning total
1 Write alt text for images that have none
11 instances on 4 pages, 11 already written
Content 15%10 minutes15%
2 Give every link an accessible name
4 instances on 4 pages, 4 already written
Content 6%5 minutes21%
3 Replace placeholder alt text
1 instance on 1 page, 1 already written
Content 1%2 minutes23%
4 Replace alt text that is just the file name
1 instance on 1 page, 1 already written
Content 1%2 minutes24%
5 Title every embedded frame
1 instance on 1 page
Content 1%2 minutes25%
6 Fix the <head> of the page template
17 instances on 4 pages
Developer 16%25 minutes42%
7 Write titles and descriptions for every page template
9 instances on 4 pages, 9 already written
Content 8%12 minutes49%
8 Control is labelled only by its placeholder ("Your name"), which vanishes on input and is not a reliable accessible name
5 instances on 1 page, 5 already written
Developer 7%15 minutes56%
9 Label every form field
2 instances on 1 page, 2 already written
Developer 3%6 minutes59%
10 Give every button a name
1 instance on 1 page
Developer 1%4 minutes61%
11 Link returns 404
2 instances on 2 pages
Developer 3%10 minutes63%
12 Rewrite links that say "click here" or similar
1 instance on 1 page, 1 already written
Content 1%2 minutes64%
13 Fix skipped heading levels
3 instances on 3 pages
Content 2%9 minutes66%
14 Fix the stylesheet
19 instances on 4 pages, 4 already written
Developer 27%2.5 hours92%
15 Mark header cells in data tables
1 instance on 1 page
Developer 1%10 minutes94%
16 Fix how images are written into the page
4 instances on 4 pages
Developer 2%20 minutes96%
17 Fix the page layout template
4 instances on 4 pages
Developer 2%30 minutes98%
18 Replace the heavy image files
1 instance on 1 page
Developer 1%15 minutes99%
19 Main content is about 97 words once rendered
2 instances on 2 pages
Content 1%40 minutes100%

The one-page version for whoever signs this off is in start-here/2-executive-summary.md.

For your content team

None of this needs code. Where we could write the fix, it is shown in green. The full list is in for-your-content-team/ as CSV.

Failure Image has no alt attribute; assistive technology will announce the file name.
11 instances on 4 pages
WCAG 2.1 SC 1.1.1 (A)
Where
/demo/index.html
img[src$="logo.png"] · https://curbcuthq.com/demo/img/logo.png
Home
/demo/index.html
img[src$="bread.png"] · https://curbcuthq.com/demo/img/bread.png
Round golden-brown bread loaf, flat illustration
/demo/index.html
img[src$="hours.png"] · https://curbcuthq.com/demo/img/hours.png
Open daily 7am to 3pm
/demo/index.html
img[src$="cake.png"] · https://curbcuthq.com/demo/img/cake.png
Mark as decorative (alt="")
/demo/menu.html
img[src$="logo.png"] · https://curbcuthq.com/demo/img/logo.png
Home
/demo/menu.html
img[src$="croissant.png"] · https://curbcuthq.com/demo/img/croissant.png
Mark as decorative (alt="")
/demo/menu.html
img[src$="bread.png"] · https://curbcuthq.com/demo/img/bread.png
Round golden-brown bread loaf, flat illustration
/demo/menu.html
img[src$="cake.png"] · https://curbcuthq.com/demo/img/cake.png
Mark as decorative (alt="")
/demo/about.html
img[src$="logo.png"] · https://curbcuthq.com/demo/img/logo.png
Home
/demo/order.html
img[src$="logo.png"] · https://curbcuthq.com/demo/img/logo.png
Harbor Lane home
/demo/order.html
img[src$="logo.png"] · https://curbcuthq.com/demo/img/logo.png
Harbor Lane home
Failure Link has no text, no label, and no image alt text, so it has no accessible name.
4 instances on 4 pages
WCAG 2.1 SC 2.4.4 (A)
Where
/demo/index.html
a
Home
/demo/menu.html
a
Home
/demo/about.html
a
Home
/demo/order.html
a
Home
Failure Page has no meta description.
3 instances on 3 pages · fix in: Page titles and descriptions
Search engines fall back to scraping arbitrary body text for the result snippet.
Where
/demo/index.html
meta[name=description]
Handmade sourdough from $9, three-day laminated croissants from $4.50 and order-ahead cakes, baked from 4am on Harbor Lane in Sausalito. Pickup available.
/demo/about.html
meta[name=description]
Harbor Lane Bakery began as a 2014 Sausalito market stall with one oven and one starter. Flour from Petaluma, butter from up the road, baked to sell out.
/demo/order.html
meta[name=description]
Order sourdough loaves, croissants and cakes for collection. Pickup only, order by 8pm for the next morning, and allow two days' notice for cakes.
Failure Alt text is a generic placeholder ("image") and conveys no information.
1 instance on 1 page
WCAG 2.1 SC 1.1.1 (A)
Where
/demo/index.html
img[src$="croissant.png"] · https://curbcuthq.com/demo/img/croissant.png
Mark as decorative (alt="")
Failure Alt text is the image file name ("bread.png"), which describes nothing.
1 instance on 1 page
WCAG 2.1 SC 1.1.1 (A)
Where
/demo/index.html
img[src$="bread.png"] · https://curbcuthq.com/demo/img/bread.png
Round golden-brown bread loaf, flat illustration
Failure Frame has no title, so its contents are announced only as "frame".
1 instance on 1 page
WCAG 2.1 SC 4.1.2 (A)
Where
/demo/about.html
iframe · https://www.openstreetmap.org/export/embed.html?bbox=-122.49%2C37.85%2C-122.47%2C37.87&layer=mapnik
Warning Heading level jumps from h1 to h3, breaking the document outline users navigate by.
3 instances on 3 pages
WCAG 2.1 SC 1.3.1 (A)
Where
/demo/index.html
h3
/demo/menu.html
h3
/demo/about.html
h4
Warning Title is only 4 characters.
3 instances on 3 pages · fix in: Page titles and descriptions
Too short to describe the page or carry useful terms.
Where
/demo/index.html
head > title
Harbor Lane Bakery — Sausalito Sourdough & Pastries
/demo/menu.html
head > title
Harbor Lane Bakery menu
/demo/order.html
head > title
Order ahead — Curbcut
Warning Main content is about 97 words once rendered.
2 instances on 2 pages
Below roughly 120 words a page rarely competes for anything.
Where
/demo/menu.html
body
/demo/order.html
body
Warning Link text "click here" does not describe its destination; screen-reader users often browse a list of links with no surrounding context.
1 instance on 1 page
WCAG 2.1 SC 2.4.4 (A)
Where
/demo/index.html
a
Home
Warning Meta description is only 23 characters.
1 instance on 1 page · fix in: Page titles and descriptions
Wastes the snippet space available in results.
Where
/demo/menu.html
meta[name=description]
Sourdough loaves from $9, croissants and morning buns from $4.50, whole lemon cakes to order. Bread out of the oven at 7, pastry at 6, allergen details inside.
Warning Title is 125 characters and will be truncated in search results.
1 instance on 1 page · fix in: Page titles and descriptions
Aim for 10-60.
Where
/demo/about.html
head > title
Our story — Harbor Lane Bakery
Warning 2 pages share the title "Home".
1 instance on 1 page · fix in: Page titles and descriptions
Search engines cannot tell which of them answers a query, so they compete with each other.
Where
/demo/index.html
head > title
Harbor Lane Bakery — Sausalito Sourdough & Pastries

For your developer

Grouped by where the fix lives. Ready-made files are in for-your-developer/: server config, optimised images, markup edits, link redirects.

Colour contrast

Measured on the rendered page. Each entry is one colour pair, so one CSS change clears every instance.

Failure #8f8f8f on #ffffff - 3.23:1, needs 4.5:1
23 elements on 4 pages
Screenshot with the failing text ringed in red
Where
body > div.page:nth-of-type(1) > div.hero:nth-of-type(1) > div > p:nth-of-type(1)
"Sourdough, croissants and cakes baked every morning from 4am"
body > div.page:nth-of-type(1) > div.hero:nth-of-type(1) > div > p:nth-of-type(2)
"to see this week's menu."
div.page:nth-of-type(1) > div.hero:nth-of-type(1) > div > p:nth-of-type(2) > a
"click here"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(1) > p
"Laminated over three days. Plain, almond, or ham and gruyere"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(2) > p
"Our starter is older than the shop. Country, seeded, or oliv"
Failure #8a8a8a on #ffffff - 3.45:1, needs 4.5:1
19 elements on 1 page
Where
div.page > table > tbody > tr:nth-of-type(1) > td:nth-of-type(1)
"Country sourdough"
div.page > table > tbody > tr:nth-of-type(1) > td:nth-of-type(2)
"Wheat, rye, salt, time"
div.page > table > tbody > tr:nth-of-type(1) > td:nth-of-type(3)
"$9"
div.page > table > tbody > tr:nth-of-type(2) > td:nth-of-type(1)
"Seeded sourdough"
div.page > table > tbody > tr:nth-of-type(2) > td:nth-of-type(2)
"Sunflower, flax, sesame"
Failure #b5b5b5 on #ffffff - 2.05:1, needs 4.5:1
13 elements on 4 pages
Screenshot with the failing text ringed in red
Where
body > div.page:nth-of-type(1) > header > nav > a:nth-of-type(1)
"Menu"
body > div.page:nth-of-type(1) > header > nav > a:nth-of-type(2)
"Our story"
body > div.page:nth-of-type(1) > header > nav > a:nth-of-type(3)
"Order"
body > div.page:nth-of-type(1) > header > nav > a:nth-of-type(4)
"Specials"
body > div.page > header > nav > a:nth-of-type(1)
"Menu"
Failure #a8a8a8 on #ffffff - 2.38:1, needs 4.5:1
10 elements on 4 pages
Screenshot with the failing text ringed in red
Where
body > div.page:nth-of-type(1) > div.hero:nth-of-type(1) > div > h3
"Sausalito, California"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(1) > h3
"Croissants"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(2) > h3
"Sourdough"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(3) > h3
"Cakes"
html > body > div.page > h3
"This week"
Failure #c4c4c4 on #ffffff - 1.74:1, needs 4.5:1
5 elements on 2 pages
Where
html > body > div.page:nth-of-type(1) > p.fine
"Prices include tax. Menu changes with the season and with wh"
body > div.page > form > div > span.fine
"I agree to the terms"
html > body > div.page > form > span.fine
"Press the logo to send"
html > body > div.page > p.fine:nth-of-type(2)
"We do not deliver. If you need delivery, several local servi"
html > body > div.page > p.fine:nth-of-type(2) > a
"see this list"
Failure #c0c0c0 on #ffffff - 1.82:1, needs 4.5:1
4 elements on 4 pages
Where
html > body > div.page:nth-of-type(1) > footer
"© Harbor Lane Bakery · 12 Harbor Lane, Sausalito CA · ·"
html > body > div.page > footer
"© Harbor Lane Bakery ·"
html > body > div.page > footer
"© Harbor Lane Bakery ·"
html > body > div.page > footer
"© Harbor Lane Bakery ·"
Failure #bbbbbb on #ffffff - 1.92:1, needs 4.5:1
3 elements on 1 page
Where
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(1) > span.price
"from $4.50"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(2) > span.price
"$9"
body > div.page:nth-of-type(1) > div.grid:nth-of-type(2) > div.card:nth-of-type(3) > span.price
"from $38"
Failure #d9534f on #ffffff - 3.96:1, needs 4.5:1
3 elements on 1 page
Where
html > body > div.page > p:nth-of-type(1) > span
"red"
table > tbody > tr:nth-of-type(3) > td:nth-of-type(1) > span
"Olive and rosemary"
table > tbody > tr:nth-of-type(6) > td:nth-of-type(1) > span
"Morning bun"
Failure #ffffff on #e9d8a6 - 1.42:1, needs 4.5:1
1 element on 1 page
Where
body > div.page:nth-of-type(1) > div.hero:nth-of-type(1) > div > a.btn
"Order for pickup"
Failure #555555 on #2b2b2b - 1.9:1, needs 4.5:1
1 element on 1 page
Where
html > body > div.banner:nth-of-type(2) > div.close
"×"
Failure #666666 on #2b2b2b - 2.47:1, needs 4.5:1
1 element on 1 page
Where
html > body > div.banner:nth-of-type(2)
"We use cookies to make the site work and to see which pages "
Failure Control is labelled only by its placeholder ("Your name"), which vanishes on input and is not a reliable accessible name.
5 instances on 1 page
WCAG 2.1 SC 3.3.2 (A)
Where
/demo/order.html
input
/demo/order.html
input
/demo/order.html
input
/demo/order.html
input
/demo/order.html
textarea
Failure The page does not declare a language, so screen readers may read it with the wrong pronunciation rules.
4 instances on 4 pages · fix in: The <head> of your page template
WCAG 2.1 SC 3.1.1 (A)
Where
/demo/index.html
html
/demo/menu.html
html
/demo/about.html
html
/demo/order.html
html
Failure The viewport disables pinch zoom, which low-vision users depend on.
4 instances on 4 pages · fix in: The <head> of your page template
WCAG 2.1 SC 1.4.4 (AA)
Where
/demo/index.html
meta[name=viewport]
/demo/menu.html
meta[name=viewport]
/demo/about.html
meta[name=viewport]
/demo/order.html
meta[name=viewport]
Failure 9 of 9 interactive elements show no visible change when focused. Keyboard users cannot tell where they are on the page.
4 instances on 4 pages · fix in: Your stylesheet
This is almost always `outline: none` applied for appearance with no replacement style. Without a focus indicator the page cannot be operated by keyboard with any confidence.
WCAG 2.1 SC 2.4.7 (AA)
Where
/demo/index.html
a
/demo/menu.html
a
/demo/about.html
a
/demo/order.html
a
Failure At a 320px viewport the page scrolls sideways by 780px. Widest offender: <div class="page"> at 1100px.
4 instances on 4 pages · fix in: Your stylesheet
Content has to reflow into a single column at 320 CSS pixels. Having to scroll in two directions to read a line of text makes a page very hard to use on a phone, and unusable for someone relying on heavy zoom.
WCAG 2.1 SC 1.4.10 (AA)
Where
/demo/index.html
div.page
/demo/menu.html
div.page
/demo/about.html
div.page
/demo/order.html
div.page
Failure Form control (select) has no associated label.
2 instances on 1 page
WCAG 2.1 SC 3.3.2 (A)
Where
/demo/order.html
select
/demo/order.html
input
Failure Link returns 404.
2 instances on 2 pages
A dead link wastes the visitor and, for internal links, wastes the crawl budget search engines give you.
Where
/demo/order.html
a[href="https://example.com/couriers"]
/demo/index.html
a[href="https://curbcuthq.com/demo/specials.html"]
Failure Table has 7 rows and 3 columns but no header cells, so screen-reader users cannot tell which column or row a value belongs to.
1 instance on 1 page
WCAG 2.1 SC 1.3.1 (A)
Where
/demo/menu.html
table
Failure Button has no text or label, so it is announced only as "button".
1 instance on 1 page
WCAG 2.1 SC 4.1.2 (A)
Where
/demo/order.html
button.icon-btn
Warning The page offers neither a <main> landmark nor a skip link, so keyboard users must tab through the navigation on every page.
4 instances on 4 pages · fix in: Page layout template
WCAG 2.1 SC 2.4.1 (A)
Where
/demo/index.html
body
/demo/menu.html
body
/demo/about.html
body
/demo/order.html
body
Warning Page declares no canonical URL.
4 instances on 4 pages · fix in: The <head> of your page template
Query strings and trailing-slash variants can be indexed as separate duplicate pages.
Where
/demo/index.html
link[rel=canonical]
/demo/menu.html
link[rel=canonical]
/demo/about.html
link[rel=canonical]
/demo/order.html
link[rel=canonical]
Warning Page has no Open Graph tags.
4 instances on 4 pages · fix in: The <head> of your page template
Links shared to Slack, LinkedIn, WhatsApp and iMessage render as a bare URL with no title or image.
Where
/demo/index.html
head
/demo/menu.html
head
/demo/about.html
head
/demo/order.html
head
Warning 6 images have no width/height, which causes layout shift as they load.
4 instances on 4 pages · fix in: How images are written into the page
Cumulative Layout Shift is a Core Web Vital.
Where
/demo/index.html
img
/demo/menu.html
img
/demo/about.html
img
/demo/order.html
img
Warning 5 images are JPEG or PNG with no WebP/AVIF alternative offered.
1 instance on 1 page · fix in: The image files themselves
WebP is typically 25-35% smaller than JPEG at the same quality and is supported everywhere current.
Where
/demo/index.html
img
Warning No page has JSON-LD structured data.
1 instance on 1 page · fix in: The <head> of your page template
Structured data is what makes rich results (ratings, breadcrumbs, FAQs) possible. It belongs on the pages that have something to show, not on every page.
Where
/demo/index.html
script[type="application/ld+json"]

Apply everything with an AI agent

The same data is in apply-with-ai/fixes.json if you would rather script it. We audited rendered pages and have never seen your source, so selectors point at what the browser received; the prompt tells the agent to search for where that comes from.

# Apply the Curbcut accessibility fixes for curbcuthq.com

You are working in the repository that produces **curbcuthq.com**. An external audit found
**54 accessibility failures** and **30 warnings** across
4 pages, plus 5 SEO and security errors, and wrote a replacement for each one it could.
Your job is to apply them to the source — not to re-audit the site and not to write new copy.

The accessibility failures are WCAG 2.1 Level A and AA, the standard that accessibility
law in most jurisdictions measures against. Which law applies to this site, if any, is
set out in start-here/4-which-law-applies.md; nothing here is legal advice.

## Rules

1. **Never invent content.** Every replacement below was written from the live page. Use
   it as given. Where a fix says UNKNOWN or is blank, leave the element alone and list it
   at the end for a human — do not guess.
2. **Find the source, do not create it.** These selectors come from rendered HTML. The
   real source may be a component, a template, a partial, a CMS field, or a build step.
   Search the repository for the surrounding text, class name, or file name. If you
   cannot find where something is generated, say so and move on — do not create a new
   file to hold it.
3. **One concern per commit.** Group changes by fix type (alt text, then labels, then
   headers), not by file. It makes review possible and a bad batch revertible.
4. **Do not reformat.** Match the surrounding indentation, quote style, and framework
   idiom. A diff full of unrelated whitespace hides the actual change.
5. **Server config is not code.** The header rules belong in the hosting config for this
   project. Identify which platform this repo deploys to and apply only that file. If you
   cannot tell, ask rather than applying all of them.
6. **Report what you could not do.** A short list of skipped items is far more useful
   than silent partial application.
7. **Confidence tags.** Items marked *(confirm)* were written by a model or inferred from
   size. Apply them, then list them at the end for a person to read in context; do not
   treat them as final. Untagged items are deterministic and safe to apply as given.

## Plan of attack

**Where these live** — The stack isn't identified, so start by reading the repository root to work out the framework and templating language before touching anything. In most setups, the `<head>` work behind section 2, section 3 and much of section 7 sits in a single shared layout or document template, or in a per-route metadata export; search for the file that renders `<html>` and `<meta name="viewport">`. Section 4's form fields and section 6's embedded frame usually live in a contact or booking component. Section 1 and section 5 are content-level: the images and links are spread across page templates, partials, and possibly CMS or Markdown content, so search for `<img` and `<a` across both code and content directories. The contrast, focus and reflow items in section 7 belong in the global stylesheet or design-token file. Section 9's optimised images replace existing assets wherever static files are served from.

**Order** — Do section 7 first: the `<head>` and stylesheet changes there are template-level and clear findings on all four pages at once. Then section 2 and section 3, which are the same template element filled per page. Then section 4, section 6 and section 5, which are contained to a small number of components. Section 1 and section 9 next, since alt text is per-image and slow. Section 8 last, as it needs judgement rather than mechanical edits.

**Watch out for** — The 404 links noted in section 8 may be Vercel rewrites or redirects rather than broken markup, so check any `vercel.json` or routing config before rewriting hrefs. Don't fix the placeholder-as-label problem by deleting placeholders outright. And confirm the optimised images in section 9 match the dimensions and formats the existing markup requests.

## 1. Image alt text

9 images need descriptive alt text. Find each image in the source and set exactly this text:

- **logo.png**
  - page: https://curbcuthq.com/demo/index.html
  - selector: `img[src$="logo.png"]`
  - set alt to: `Home`
- **logo.png**
  - page: https://curbcuthq.com/demo/menu.html
  - selector: `img[src$="logo.png"]`
  - set alt to: `Home`
- **logo.png**
  - page: https://curbcuthq.com/demo/about.html
  - selector: `img[src$="logo.png"]`
  - set alt to: `Home`
- **logo.png**
  - page: https://curbcuthq.com/demo/order.html
  - selector: `img[src$="logo.png"]`
  - set alt to: `Home`
- **hours.png**
  - page: https://curbcuthq.com/demo/index.html
  - selector: `img[src$="hours.png"]`
  - set alt to: `Open daily 7am to 3pm` *(confirm)*
- **bread.png**
  - page: https://curbcuthq.com/demo/index.html
  - selector: `img[src$="bread.png"]`
  - set alt to: `Round golden-brown bread loaf, flat illustration` *(confirm)*
- **bread.png**
  - page: https://curbcuthq.com/demo/index.html
  - selector: `img[src$="bread.png"]`
  - set alt to: `Round golden-brown bread loaf, flat illustration` *(confirm)*
- **bread.png**
  - page: https://curbcuthq.com/demo/menu.html
  - selector: `img[src$="bread.png"]`
  - set alt to: `Round golden-brown bread loaf, flat illustration` *(confirm)*
- **logo.png**
  - page: https://curbcuthq.com/demo/order.html
  - selector: `img[src$="logo.png"]`
  - set alt to: `Harbor Lane home` *(confirm)*

4 images are decorative and must be hidden from screen readers with an EMPTY alt (`alt=""`), not a description. Those marked *(confirm)* were judged by size alone:

- `img[src$="croissant.png"]` on https://curbcuthq.com/demo/index.html (croissant.png)
- `img[src$="croissant.png"]` on https://curbcuthq.com/demo/menu.html (croissant.png)
- `img[src$="cake.png"]` on https://curbcuthq.com/demo/index.html (cake.png)
- `img[src$="cake.png"]` on https://curbcuthq.com/demo/menu.html (cake.png)

## 2. Page titles

Replace each page title with this. Lengths are chosen to avoid truncation in search results. Where a title is marked *(also the visible heading)*, it comes from content (frontmatter, a CMS field, a database row) rather than a template: change it there, or add a separate SEO title field and leave the heading alone.

- https://curbcuthq.com/demo/index.html — `head > title`
  - currently: `Home`
  - set to: `Harbor Lane Bakery — Sausalito Sourdough & Pastries` *(confirm)*
- https://curbcuthq.com/demo/menu.html — `head > title`
  - currently: `Home`
  - set to: `Harbor Lane Bakery menu` *(confirm)*
- https://curbcuthq.com/demo/about.html — `head > title`
  - currently: `Our story - Harbor Lane Bakery, Sausalito - fresh sourdough bread, croissants, pastries and cakes baked daily in Marin County`
  - set to: `Our story — Harbor Lane Bakery` *(confirm)*
- https://curbcuthq.com/demo/order.html — `head > title`
  - currently: `Order`
  - set to: `Order ahead — Curbcut` *(confirm)*

## 3. Meta descriptions

Set the meta description for each page to exactly this text. It is written to fit within the length search results display.

- https://curbcuthq.com/demo/index.html — `meta[name=description]`
  - set to: `Handmade sourdough from $9, three-day laminated croissants from $4.50 and order-ahead cakes, baked from 4am on Harbor Lane in Sausalito. Pickup available.` *(confirm)*
- https://curbcuthq.com/demo/menu.html — `meta[name=description]`
  - currently: `Harbor Lane Bakery menu`
  - set to: `Sourdough loaves from $9, croissants and morning buns from $4.50, whole lemon cakes to order. Bread out of the oven at 7, pastry at 6, allergen details inside.` *(confirm)*
- https://curbcuthq.com/demo/about.html — `meta[name=description]`
  - set to: `Harbor Lane Bakery began as a 2014 Sausalito market stall with one oven and one starter. Flour from Petaluma, butter from up the road, baked to sell out.` *(confirm)*
- https://curbcuthq.com/demo/order.html — `meta[name=description]`
  - set to: `Order sourdough loaves, croissants and cakes for collection. Pickup only, order by 8pm for the next morning, and allow two days' notice for cakes.` *(confirm)*

## 4. Form labels

Each control below has no accessible name. Add a visible <label> associated with the input by id, or an aria-label if the design genuinely has no room for visible text.

- https://curbcuthq.com/demo/order.html — `input`
  - set to: `Your name` *(confirm)*
- https://curbcuthq.com/demo/order.html — `input`
  - set to: `Email address` *(confirm)*
- https://curbcuthq.com/demo/order.html — `input`
  - set to: `Phone number` *(confirm)*
- https://curbcuthq.com/demo/order.html — `select`
  - set to: `Item` *(confirm)*
- https://curbcuthq.com/demo/order.html — `input`
  - set to: `Pickup day and time` *(confirm)*
- https://curbcuthq.com/demo/order.html — `textarea`
  - set to: `What you'd like to order` *(confirm)*
- https://curbcuthq.com/demo/order.html — `input`
  - set to: `I agree to the terms` *(confirm)*

## 5. Link text

Each link has no accessible name. Add text inside the link, or an aria-label if it must stay icon-only.

- https://curbcuthq.com/demo/menu.html — `a`
  - set to: `Home` *(confirm)*
- https://curbcuthq.com/demo/index.html — `a`
  - set to: `Home` *(confirm)*
- https://curbcuthq.com/demo/about.html — `a`
  - set to: `Home` *(confirm)*
- https://curbcuthq.com/demo/order.html — `a`
  - set to: `Home` *(confirm)*

## 6. Frame titles

Add a title attribute to each iframe describing what it contains.

- https://curbcuthq.com/demo/about.html — `iframe`
  - set to: `Bakery location map` *(confirm)*

## 7. Structural fixes

These need a judgement call about the markup rather than a text replacement. Apply them where the intent is clear; flag the rest.

### missing-lang (4)

> The page does not declare a language, so screen readers may read it with the wrong pronunciation rules.

- https://curbcuthq.com/demo/index.html — `html`
- https://curbcuthq.com/demo/menu.html — `html`
- https://curbcuthq.com/demo/about.html — `html`
- https://curbcuthq.com/demo/order.html — `html`

### zoom-disabled (4)

> The viewport disables pinch zoom, which low-vision users depend on.

- https://curbcuthq.com/demo/index.html — `meta[name=viewport]`
- https://curbcuthq.com/demo/menu.html — `meta[name=viewport]`
- https://curbcuthq.com/demo/about.html — `meta[name=viewport]`
- https://curbcuthq.com/demo/order.html — `meta[name=viewport]`

### table-no-headers (1)

> Table has 7 rows and 3 columns but no header cells, so screen-reader users cannot tell which column or row a value belongs to.

- https://curbcuthq.com/demo/menu.html — `table`

### button-no-name (1)

> Button has no text or label, so it is announced only as "button".

- https://curbcuthq.com/demo/order.html — `button.icon-btn`

## 8. SEO and security errors to review

These are not accessibility failures and mostly not markup edits: most are fixed by the server configuration section, a hosting setting, or a content decision. Read each one; do not attempt them blindly.

- **seo-no-description** (3 pages): Page has no meta description.
- **link-not-found** (2 pages): Link returns 404.
  - https://example.com/couriers (on https://curbcuthq.com/demo/order.html)
  - https://curbcuthq.com/demo/specials.html (on https://curbcuthq.com/demo/index.html)

## 9. Optimised images

The pack includes recompressed images in `for-your-developer/images/`. Replace the originals
with these and update any width/height attributes to the new dimensions. Where a file
is offered as both WebP and a fallback, check `README.txt` — sometimes the fallback is
the smaller one and the WebP should not be advertised. Rows marked CHECK BY EYE saved
so much that a person should compare them with the original before they replace it;
logos and og:images are kept lossless or in their original format for that reason.

## When you are done

Report: how many of each fix type you applied, which you skipped and why, and any place
the audit pointed at something you could not locate in the source. Then run the site's
own tests and linters before proposing the change.

---

Automated checks prove specific failures exist. They cannot prove a site is accessible.
A person should confirm each replacement reads correctly in context before it ships.

Check by hand

Automated testing reaches a minority of the WCAG criteria. These are the checks a person has to make, scoped to what we found on your site. Tick them off here; the same list is in check-by-hand/CHECKLIST.md.

1. Operate the whole site with the keyboard aloneSC 2.1.1 Keyboard / 2.1.2 No Keyboard Trap (A) · about 15 min
Anyone who cannot use a mouse - through motor impairment, injury, or simply preference - needs every control to work from the keyboard. Custom controls built out of divs are the usual failure, and nothing static can prove they respond to Enter, Space or the arrow keys.
  • Put the mouse away completely.
  • Tab through each page from the top. Every link, button and field should be reachable.
  • Activate each control with Enter, and buttons with Space as well.
  • In menus, tabs and sliders, try the arrow keys.
  • Open every dialog and close it with Escape. Focus should return to whatever opened it.
  • Confirm you can always Tab back out of a widget - if focus gets stuck, that is a keyboard trap and a Level A failure.
Where to look
https://curbcuthq.com/demo/order.html - form with 7 fields
2. Check the tab order matches the visual orderSC 2.4.3 Focus Order (A) · about 10 min
CSS can move things on screen without moving them in the document, so the focus ring can jump around a page that looks perfectly ordered. We can see the focus ring exists; we cannot tell whether the order it follows makes sense.
  • Tab slowly through each page and watch where the focus ring goes.
  • It should move in reading order, roughly left to right and top to bottom.
  • Watch for it disappearing behind sticky headers or off-screen menus.
  • On pages with a modal open, focus must stay inside the modal until it is closed.
Where to look
https://curbcuthq.com/demo/index.html
https://curbcuthq.com/demo/menu.html
https://curbcuthq.com/demo/about.html
https://curbcuthq.com/demo/order.html
https://curbcuthq.com/demo/specials.html
3. Submit each form wrongly and read the errorsSC 3.3.1 Error Identification / 3.3.3 Error Suggestion (A, AA) · about 10 min
Error handling only exists after something goes wrong, so it cannot be crawled. The common failures are errors shown only in red with no text, errors that never reach a screen reader, and messages that say something is invalid without saying how to fix it.
  • Submit each form empty, then with deliberately bad data.
  • Check every error names the field it belongs to in text, not just colour.
  • Check the message says how to correct it, not only that it is wrong.
  • Check focus moves to the error, or that it is announced - a screen reader user must not have to hunt for it.
Where to look
https://curbcuthq.com/demo/order.html - 7 fields
4. Look at the site in Windows High Contrast modeSC 1.4.11 Non-text Contrast / 1.4.1 Use of Colour (AA, A) · about 10 min
A large group of low-vision users run Windows High Contrast, which replaces every colour on the page with a system palette. Buttons drawn with background colour alone become invisible rectangles, custom checkboxes vanish, and focus rings that rely on colour disappear. We rendered your home page under forced colours so you can see what survives.
  • Open high-contrast-home.png in the check-by-hand folder: that is your home page under forced colours.
  • Look for buttons and links that have lost their outline, icons that have vanished, and anything that was only distinguishable by colour.
  • On Windows: Settings, Accessibility, Contrast themes, pick one and reload the site; press Tab and confirm the focus ring is still visible on every control.
  • The fix is usually a real border on buttons and inputs, and SVG icons that use currentColor.
Where to look
https://curbcuthq.com/demo/index.html - high-contrast-home.png
5. Check navigation stays in the same place and things keep their namesSC 3.2.3 Consistent Navigation / 3.2.4 Consistent Identification (AA) · about 8 min
Repeated navigation should appear in the same order on every page, and the same function should carry the same label throughout. This is a judgement about meaning, which is not something a diff can make.
  • Compare the main navigation across several pages - same items, same order.
  • Check a control that does the same job is named the same everywhere (not "Search" on one page and "Find" on another).
  • Check icons that repeat mean the same thing each time.
Where to look
https://curbcuthq.com/demo/index.html
https://curbcuthq.com/demo/menu.html
https://curbcuthq.com/demo/about.html
https://curbcuthq.com/demo/order.html
https://curbcuthq.com/demo/specials.html
6. Listen to the key pages with a screen readerOverall verification · about 30 min
This is the check that subsumes the others. Automated testing, including everything in this pack, cannot tell you whether a page makes sense when it is read aloud. Half an hour here finds things no tool will.
  • Turn on VoiceOver (Cmd+F5 on a Mac) or NVDA (free, on Windows).
  • Work through your most important journey - usually the home page, then whatever you want people to do.
  • Listen for images announced as filenames, buttons announced as "button" with no name, and headings that do not describe what follows.
  • Check the page has a sensible heading structure when you jump between headings.
  • If you get lost or cannot complete the task, note where - that is the real finding.
Where to look
https://curbcuthq.com/demo/index.html
https://curbcuthq.com/demo/menu.html
https://curbcuthq.com/demo/about.html

Export

Take the findings somewhere else. Tickets are one per change on the roadmap, not one per finding: twelve well-formed tickets get picked up, a hundred and seventy rows get ignored.

github-issues.json
19 issues, one per roadmap change, ready for the GitHub API or the create-github-issues.sh script
jira.csv
Jira CSV import: summary, description, type, priority, labels
linear.csv
Linear CSV import with priority and estimates
trello.csv
Trello cards, split into Content and Development lists
bookmarklet.html
Drag to your bookmarks bar: rings every failing element on 4 scanned pages of your live site

What your site sounds like

This is what a screen reader announces, in order, on your key pages. It comes from the browser's accessibility tree, which is what screen readers read. Role first, then name: link, Contact or image, unlabelled. People navigate by jumping between headings and by pulling up the list of links, so both are shown.

/demo/index.html29 announcements
Listening to this page, 1 of 9 links announce as "link" with no name; 4 of 6 images are just "image".
The first minute, read by eSpeak - the default voice of the NVDA screen reader.
1/9
links with no name
4/6
images unlabelled
5
headings to jump between
3
landmarks
The first 29 announcements
banner landmark
link, (no name)
image, unlabelled
navigation landmark
link, Menu
link, Our story
link, Order
link, Specials
heading level 3, Sausalito, California
heading level 1, Bread worth crossing the bridge for.
link, Order for pickup
link, click here
to see this week's menu.
image, unlabelled
image, unlabelled
image, image
heading level 3, Croissants
from $4.50
image, bread.png
heading level 3, Sourdough
$9
image, unlabelled
heading level 3, Cakes
from $38
footer landmark
© Harbor Lane Bakery · 12 Harbor Lane, Sausalito CA ·
link, (415) 555-0142
link, Instagram
We use cookies to make the site work and to see which pages people re…
Jumping by heading
H3 Sausalito, California
H1 Bread worth crossing the bridge for.
H3 Croissants
H3 Sourdough
H3 Cakes
The list of links
no name
Menu
Our story
Order
Specials
Order for pickup
click here
(415) 555-0142
Instagram
/demo/menu.html19 announcements
Listening to this page, 1 of 5 links announce as "link" with no name; 4 of 4 images are just "image".
The first minute, read by eSpeak - the default voice of the NVDA screen reader.
1/5
links with no name
4/4
images unlabelled
5
headings to jump between
3
landmarks
The first 19 announcements
banner landmark
link, (no name)
image, unlabelled
navigation landmark
link, Menu
link, Our story
link, Order
heading level 3, This week
heading level 1, Menu
table, 7 rows
image, unlabelled
heading level 3, Pastry
image, unlabelled
heading level 3, Bread
image, unlabelled
heading level 3, Cakes
footer landmark
© Harbor Lane Bakery ·
link, Home
Jumping by heading
H3 This week
H1 Menu
H3 Pastry
H3 Bread
H3 Cakes
The list of links
no name
Menu
Our story
Order
Home
/demo/about.html18 announcements
Listening to this page, 1 of 6 links announce as "link" with no name; 1 of 1 images are just "image".
The first minute, read by eSpeak - the default voice of the NVDA screen reader.
1/6
links with no name
1/1
images unlabelled
4
headings to jump between
3
landmarks
The first 18 announcements
banner landmark
link, (no name)
image, unlabelled
navigation landmark
link, Menu
link, Our story
link, Order
heading level 3, Since 2014
heading level 1, Our story
The shop is small, so we bake to sell out rather than to have leftove…
link, order ahead
and we will keep it for you.
heading level 4, Visit us
iframe
heading level 4, The team
footer landmark
© Harbor Lane Bakery ·
link, Home
Jumping by heading
H3 Since 2014
H1 Our story
H4 Visit us
H4 The team
The list of links
no name
Menu
Our story
Order
order ahead
Home
/demo/order.html30 announcements
Listening to this page, 1 of 6 links announce as "link" with no name; 2 of 2 images are just "image"; 1 of 1 buttons have no name; 2 of 7 form fields have no label.
The first minute, read by eSpeak - the default voice of the NVDA screen reader.
1/6
links with no name
2/2
images unlabelled
2
headings to jump between
3
landmarks
The first 30 announcements
banner landmark
link, (no name)
image, unlabelled
navigation landmark
link, Menu
link, Our story
link, Order
heading level 3, Pickup only
heading level 1, Order ahead
edit text, Your name
edit text, Email
edit text, Phone (optional)
combo box, (no label)
option, Country sourdough
option, Seeded sourdough
option, Olive and rosemary
option, Croissants (box of 6)
option, Lemon cake
edit text, Pickup day and time
edit text, Anything else
checkbox, not checked, (no label)
I agree to the terms
button, (no name)
image, unlabelled
Press the logo to send
We do not deliver. If you need delivery, several local services will …
link, see this list
footer landmark
© Harbor Lane Bakery ·
link, Home
Jumping by heading
H3 Pickup only
H1 Order ahead
The list of links
no name
Menu
Our story
Order
see this list
Home
Automated checks prove failures exist; they cannot prove a site is accessible or compliant. Review every change before it goes live. For legal obligations, consult a qualified practitioner.