A website for a cleaning and junk removal company

A&J Commercial & Residential Cleaning is the other business run by the people behind A&J Gates & Fences: cleaning for homes and businesses, and junk removal, around Central Florida. They had a logo and two phone numbers and needed a site that says what they do and takes a quote request.
What it is
One page plus privacy and terms. The hero has the logo with the truck and a call button. Services is a plain list: vacuum, mopping, trash removal, yard services. Junk removal is the second service line, with its own option on the form. Then the quote form, contact details and footer.
The copy went through the same cut as the gates site. An early draft had a 5.0 rating badge and a satisfaction line; they came out, and what is left is the confirmed facts: what they do, where, the phone numbers, and that they have been licensed since 2016.
The palette comes from the logo: blue, teal, a green accent, navy, white. The supplied logo was one PNG. I cut it into a full version with the truck for the hero and a wordmark for the header and footer, made the backgrounds transparent, and saved both as WebP. Inter and Plus Jakarta Sans are self-hosted. There are no cookies, no analytics and no third-party fonts, so the privacy page is short and there is no cookie banner.
Same stack, shared Worker
Vite, React, TypeScript and Tailwind v4, with the same 21st.dev header and
shadcn-style primitives as the gates site. Production is a Cloudflare Worker with
static assets; wrangler deploy builds, uploads and owns the custom domains. The
old Pages project stays up only to redirect its pages.dev address to the domain,
because the QR codes point there.
The quote endpoint is the same Worker code on both sites. The two forms name the
message field differently, description on gates and message here, so the
handler accepts either. Otherwise it does the same work: honeypot, server-side
Turnstile verification pinned to the quote action and the site’s hostnames,
limits on fields, and an email through Cloudflare Email Service with the visitor
as reply-to.
The form fallback
The first version posted to Formspree with fetch, and Formspree’s own bot check
blocked background submissions. The fix was to keep a real action on the form: if
the JavaScript path fails, the browser posts the form the ordinary way, and a
hidden _next field brings the visitor back to /?sent=1#quote so the page can
show its own thank-you instead of Formspree’s. When the site’s own endpoint
replaced Formspree as the main path, the fallback stayed. Both sites now try their
own Worker first and fall back to a plain Formspree post on any server error. A
hidden business field and a _subject line tell the two businesses’ requests
apart when they land in the shared Formspree inbox.
Tagged cloudflare, workers, react, vite, tailwind, client work.