Null's direction of 2026-09-10. Punctuation only: not one word changed.
Nine of them, and the share-image alt text was on every page twice:
src/components/SEO.jsx:4 the default og:image and twitter:image alt
index.html:25,:31 the same string, as template fallbacks
src/pages/Home.jsx:257,:290
src/pages/Services.jsx:99
src/pages/Contact.jsx:183
src/data/services.js:120 the wireless card on Home and the index
public/site.webmanifest:4 linked from every page
Thirteen more sit in code comments and reach no page, so they stay. The hours
range on /contact uses en dashes, which are a different character and are not
what was asked about.
This lands before the guards that reject an em dash in content or in built
HTML, because until now every built page carried one and those guards would
have gone red on arrival.
Verified against the build, not the source: no U+2014 in any file under dist/,
including the HTML, the webmanifest, the sitemap and the JS bundle.
Closes#222.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Client directive (Levi Halford, 2026-08-01) ahead of Google/Meta lead forms.
Privacy policy:
- Publish approved policy verbatim at /privacy-policy (src/data/privacyPolicy.js
is the single source of truth; 292/292 source lines verified present)
- Privacy Policy link in the footer of every page
- Effective/Last Updated 2026-07-31, privacy@queuenorth.com as mailto
Remove St. Petersburg street address from every surface named in the brief:
footer, contact page, schema markup, SEO metadata, Google Maps links. Collapse
ProfessionalService + Organization schema into a single Organization with
areaServed: United States; drop geo coordinates, priceRange, openingHours.
Add the approved US-coverage sentence to About. No replacement address.
Crawler visibility (the site previously served 0 bytes of body HTML without JS):
- Prerender all 19 routes at build time via src/entry-server.jsx + scripts/prerender.js
- Hoist title/meta/canonical/JSON-LD into <head>; renderToString does not do this
and react-helmet-async's context is empty under React 19
- Serve prerendered HTML; return a real 404 for unknown paths instead of 200
- Hydrate instead of discarding the prerendered markup
SEO/perf:
- Titles <=60 and descriptions <=160 chars across all pages
- Add BreadcrumbList to interior pages, WebSite to home
- Generate sitemap.xml from the route list with git-derived lastmod
- 301 duplicate URL forms (trailing slash, //, /index.html), preserving query
- Immutable caching for content-hashed assets; no-cache for HTML
- Split the 522 KB bundle into app/react-vendor/router/icons
- loading/decoding/fetchpriority + per-route hero preload; drop unused asset
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>