# Quote page handoff (for Daniel)

This private prototype is the spec for the paid-search quote pages on edgefoodequipment.com. Implement it in your Next.js repo (`danieldevos90/edgefoodequipment`) with your own components. You do not need to copy this CSS or markup.

This repo is Guest Getter only. The ads host is go.edgefoodequipment.com (Vercel project edge-go-landing). Quote pages load GTM-5KVW4PWS. The form POSTs to /api/lead, which builds the same HighLevel handoff as the live site (https://thecesario.group/api/edge-lead, header x-edge-webhook-secret). generate_lead fires once after CRM accepts the lead. EDGE_LEAD_DRY_RUN=1 captures the payload without posting. The spec index at / and HANDOFF.md stay noindex.

## What we want, and why

These pages exist so a Google Ads click lands on a page that matches the keyword and can convert without hunting.

- **Form step 1 lives in the hero**, next to the H1 on desktop and **above the fold on mobile**. If the first question is below the photo, we lose the click.
- **Ad-page header is logo + Call only.** No main-nav, no planner, no extra links. The job of this header is brand plus a phone number.
- **One template, eight fills.** Same page chrome. Per-product H1, subline, hero, step-1 question/options, optional step-2 extra, and CTA. Copy table below is generated from `src/quote/pages.ts`.
- **Sticky mobile bar:** Get quote + Call, shown when the hero form is off screen. Hidden on desktop. Reserve bottom padding equal to the bar height so it never covers the form, last sections, or footer.
- **Below the form, in this order:** brand logos (250+ brands), numbered benefits, how-it-works (01 02 03), client logos + three published project cards, showrooms, FAQ, final CTA.
- **Back** is a real button on steps 2-4 (chevron + Back, 44px tap target), same row as "Step X of 4". Hidden on step 1. Browser back should also return to the previous step.
- On mobile, changing step should scroll the form card so Back + the step count sit just below the sticky header.

## Live routes (map 1:1)

Use these URLs on the live site:

- `/commercial-kitchen-quote/full-kitchen` — Commercial Kitchen Equipment
- `/commercial-kitchen-quote/replacement-equipment` — Replacement Equipment Quote
- `/commercial-kitchen-quote/equipment-list` — Commercial Equipment Quote
- `/commercial-kitchen-quote/equipment-list?product=ovens` — Commercial Oven Quotes: Convection, Combi & Deck, Delivered Across Canada
- `/commercial-kitchen-quote/equipment-list?product=fryers` — Commercial Fryer Quotes: Gas & Electric, Delivered Across Canada
- `/commercial-kitchen-quote/equipment-list?product=dishwashers` — Commercial Dishwasher Quotes: Undercounter to Conveyor, Delivered Across Canada
- `/commercial-kitchen-quote/equipment-list?product=refrigeration` — Commercial Refrigeration Quotes: Reach-In & Prep, Delivered Across Canada
- `/commercial-kitchen-quote/equipment-list?product=mixers` — Commercial Mixer Quotes: Planetary & Spiral, Delivered Across Canada

Unknown `?product=` or an unknown path segment falls back to the standard equipment-list page (`/commercial-kitchen-quote/equipment-list`).

This prototype also keeps the old `/quote/*` paths as aliases that serve the same pages:

- `/quote` and `/quote/equipment-list` → `/commercial-kitchen-quote/equipment-list`
- `/quote/full-kitchen` → `/commercial-kitchen-quote/full-kitchen`
- `/quote/replacement` and `/quote/replacement-equipment` → `/commercial-kitchen-quote/replacement-equipment`
- `/quote/ovens` and `/quote?product=ovens` → `/commercial-kitchen-quote/equipment-list?product=ovens`
- `/quote/fryers` and `/quote?product=fryers` → `/commercial-kitchen-quote/equipment-list?product=fryers`
- `/quote/dishwashers` and `/quote?product=dishwashers` → `/commercial-kitchen-quote/equipment-list?product=dishwashers`
- `/quote/refrigeration` and `/quote?product=refrigeration` → `/commercial-kitchen-quote/equipment-list?product=refrigeration`
- `/quote/mixers` and `/quote?product=mixers` → `/commercial-kitchen-quote/equipment-list?product=mixers`

The eight pages to review: `/commercial-kitchen-quote/full-kitchen`, `/commercial-kitchen-quote/replacement-equipment`, `/commercial-kitchen-quote/equipment-list`, `/commercial-kitchen-quote/equipment-list?product=ovens`, `/commercial-kitchen-quote/equipment-list?product=fryers`, `/commercial-kitchen-quote/equipment-list?product=dishwashers`, `/commercial-kitchen-quote/equipment-list?product=refrigeration`, `/commercial-kitchen-quote/equipment-list?product=mixers`.

## Per-page copy

Generated from `src/quote/pages.ts`. If copy changes, change that file and regenerate. Do not invent prices, reviews, or ratings.

| Live URL | H1 | Subline | Step 1 question | Step 1 options | Step 2 extra | CTA |
| --- | --- | --- | --- | --- | --- | --- |
| `/commercial-kitchen-quote/full-kitchen` | Commercial Kitchen Equipment | Tell us what you're building and we'll price the commercial kitchen equipment for the space. | What kind of project? | New build; Renovation; Multi-location rollout; I have a model number; Not sure | None | Get my kitchen quote |
| `/commercial-kitchen-quote/replacement-equipment` | Replacement Equipment Quote | Tell us what needs replacing and we'll check fit and send pricing on a match. | What needs replacing? | Oven; Fryer; Fridge or freezer; Dishwasher; Mixer; Other; I have a model number; Not sure | None | Get my replacement quote |
| `/commercial-kitchen-quote/equipment-list` | Commercial Equipment Quote | Send your list, drawings or model numbers and we'll check the fit and send pricing. | What do you have to send? | I have a list; I have drawings; I have a model number; Not sure | None | Get my equipment quote |
| `/commercial-kitchen-quote/equipment-list?product=ovens` | Commercial Oven Quotes: Convection, Combi & Deck, Delivered Across Canada | Tell us what you're baking or roasting and we'll send pricing on the right oven from brands we carry. | What kind of oven? | Convection; Combi; Pizza or deck; Not sure; I have a model number | None | Get my oven quote |
| `/commercial-kitchen-quote/equipment-list?product=fryers` | Commercial Fryer Quotes: Gas & Electric, Delivered Across Canada | Tell us what you're frying and we'll send pricing on the right fryer from brands we carry. | What kind of fryer? | Gas; Electric; Not sure; I have a model number | Countertop or floor model? (Countertop; Floor model; Not sure) | Get my fryer quote |
| `/commercial-kitchen-quote/equipment-list?product=dishwashers` | Commercial Dishwasher Quotes: Undercounter to Conveyor, Delivered Across Canada | Tell us your wash volume and space and we'll send pricing on the right dishwasher from brands we carry. | What kind of dishwasher? | Undercounter; Door-type; Conveyor; Glasswasher; Not sure; I have a model number | None | Get my dishwasher quote |
| `/commercial-kitchen-quote/equipment-list?product=refrigeration` | Commercial Refrigeration Quotes: Reach-In & Prep, Delivered Across Canada | Tell us what you need to hold cold and we'll send pricing on the right fridge or freezer from brands we carry. | What kind of refrigeration? | Reach-in; Undercounter; Prep table; Walk-in; Not sure; I have a model number | None | Get my refrigeration quote |
| `/commercial-kitchen-quote/equipment-list?product=mixers` | Commercial Mixer Quotes: Planetary & Spiral, Delivered Across Canada | Tell us your batch size and we'll send pricing on the right mixer from brands we carry. | What kind of mixer? | Planetary; Spiral; Not sure; I have a model number | What bowl size? (20 qt or under; 30-60 qt; 80 qt or more; Not sure) | Get my mixer quote |

Shared step 2 (every page): optional notes field (label varies), required **New / Used / Either**, required **ASAP / 1-3 months / Just pricing**.

Shared step 3: required Canadian postal or US ZIP (infer province from FSA when we can), optional business name.

Shared step 4: required name, required email, optional phone, required consent, optional file (list / photo / spec sheet).

## Form spec

Four steps. Submit to /api/lead (same HighLevel handoff as your other quote forms).

| Step | Visitor sees | Required | Notes |
| --- | --- | --- | --- |
| 1 | Per-page question + option cards | `type` | Most cards advance to step 2. "I have a model number" stays on step 1 and requires `model`. |
| 2 | Optional extra (fryers: mount; mixers: bowl size), notes, condition, timing | `condition`, `timing`, plus the extra when that page has one | Notes are optional. |
| 3 | Postal code, business name | `postal` | Accept Canadian postal (full or FSA) or US ZIP. Show inferred province when known. |
| 4 | Name, email, phone, consent, optional file | `name`, `email`, `consent` | Phone optional. File stays local in this prototype; on live, attach it if you already do that. |

**Back:** hidden on step 1. Visible on 2-4. Prefer `history.back()` when the previous step is in history so the browser back button matches.

**Validation messages** can stay short: pick an option, enter a model number, enter a Canadian postal or US ZIP, enter a name, enter a valid email, consent required.

## Must-haves (live site)

### 1. `generate_lead` for Google Ads

On **successful** submit (HighLevel accepted the lead), push to `dataLayer`:

```js
dataLayer.push({
  event: "generate_lead",
  transaction_id: "<unique id per successful lead>",
  product: "<slug>",
  answers: { /* step answers */ },
  attribution: { /* see below */ }
});
```

`transaction_id` must be unique per successful lead. Container **GTM-5KVW4PWS** has a Google Ads tag that fires on `generate_lead`. Conversion action **7770103168**.

`quote_step` events on each step are optional and useful for funnel debugging:

```js
dataLayer.push({ event: "quote_step", product, step, answers });
```

Do not fire `generate_lead` on a failed submit.

### 2. Paid-search attribution

Read `sessionStorage["edge_paid_search_attribution_v1"]` and the first-party cookie of the same name. They should hold whatever you already store from the landing click: `gclid`, `gbraid`, `wbraid`, and `utm_*` (`utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`).

Also read those same keys from the **current URL** if present, merge them into that sessionStorage object, and send the merged object to HighLevel with the lead, plus `product` and the form answers.

If the visitor later opens `/contact` or a product-page quote form in the same tab, send that **saved** attribution with those leads too. Ads often land on a quote page, then the person uses another form.

### 3. Other forms

`/contact` and the product-page quote forms must send the saved `edge_paid_search_attribution_v1` payload with the HighLevel lead. Same keys. Do not drop gclid because the thank-you URL is clean.

### 4. Claims and copy limits

No prices in copy. No star ratings, review scores, stock claims, or response-time promises.

Allowed claims on these ad pages:

- Family-run since the 1940s
- 250+ brands
- Delivery across Canada
- Showrooms: Toronto, London, Moncton, Melbourne FL
- Phone 1 (800) 265-5904

Keep "Family-run since the 1940s" and the London line "In the same building since 1950". Both are from Edge's own /about and /contact pages. Edge's homepage meta and schema still say "since 1940"; that is theirs to keep consistent. Do not invent a 1940 founding date for Edge itself (the company started in 2013; the family story started in the 1940s in Argentina).

## Layout notes (do this, not our CSS)

- Mobile: H1, one-line subline, then the form card with step 1. Photo sits after the form so the first question stays above the fold.
- Desktop: H1 + subline on the left, full-width hero composition under that. Kitchen photos fill the card. Product cutouts sit on a mat beside a real Edge kitchen still, with a 3-cell proof strip (250+ brands, Delivery across Canada, Family-run since the 1940s). Form card on the right with free-quote and call under it. Brand logos appear once, in Brands we carry. Do not leave a small photo with an empty slot beside it.
- Do not repeat the brand logo grid under the form. Logos live only in Brands we carry.
- FAQ: heading, one-line intro, and call/quote on the left. Accordion on the right. Not a full-width row of short questions.
- Header: Edge wordmark + Call 1 (800) 265-5904. Orange call button is fine.
- Selected option: orange border + check. Not a peach tile.
- Benefits / how-it-works: bold 01 02 03, not icons.
- Project cards: use Edge's published project text only (Nobu three kitchens / two dish pits; Mott32 main kitchen supply; Dave's Yonge & Dundas millwork). No invented reviews.

## Assets used in this prototype

Hero photos (local WebP, from Edge project photography):

- `full-kitchen`: `/quote/hero/full-kitchen.webp` (960×640)
- `replacement`: `/quote/hero/replacement.webp` (960×640)
- `equipment-list`: `/quote/hero/equipment-list.webp` (960×640)
- `ovens`: `/quote/hero/ovens.webp` (800×741, framed card)
- `fryers`: `/quote/hero/fryers.webp` (344×720, framed card)
- `dishwashers`: `/quote/hero/dishwashers.webp` (240×500, framed card)
- `refrigeration`: `/quote/hero/refrigeration.webp` (504×720, framed card)
- `mixers`: `/quote/hero/mixers.webp` (433×720, framed card)

Brand logos are cropped local copies from edgefoodequipment.com (`/quote/logos/...`): True, Hobart (PNG badge), Garland, Rational, Cambro, Vollrath, Robot Coupe, Hoshizaki, Scotsman, Vitamix, Vulcan, TurboChef. Client marks still hotlink from the live site: Nobu, Wendy's, Linny's, Deauville, Pur 'n Simple, RC Show.

Project stills: `/quote/projects/nobu.webp`, `mott32.webp`, `daves.webp` (about 800px wide).

Wordmark: `/quote/edge-logo-black.svg`.

Use your own image pipeline on the live site. You are free to implement this in your existing components.

## What this host does, and what it still needs

- Loads GTM **GTM-5KVW4PWS** on every quote page. Pushes `generate_lead` once after a successful CRM accept (not on dry-run or a failed handoff).
- POSTs to `/api/lead`, which mirrors `handoffEdgeLead`: name, email, phone, company, subject `GOOGLE ADS: COMMERCIAL KITCHEN QUOTE`, message with all four step answers plus landing URL and attribution, `pageUrl`, `submissionId`, `attribution`.
- Required env on edge-go-landing: `EDGE_LEAD_WEBHOOK_SECRET` (or `EDGE_LEAD_API_KEY`). Optional: `EDGE_LEAD_HANDOFF_URL`, `EDGE_LEAD_DRY_RUN`.
- Quote pages are indexable. `/`, `/HANDOFF.md`, and `/planner` stay noindex.
- Privacy link: https://edgefoodequipment.com/privacy-policy
- The room planner lives at `/planner` in this repo only. Full-kitchen can keep a "Have your room dimensions? Sketch it" link if you want that path live.
- This host does not send Resend confirmation email. That stays on the live Next.js quote-request route if you want it.

## Review

Open `/` in this prototype for the spec index (all eight pages). `HANDOFF.md` is generated from `src/quote/pages.ts` when the Vite build runs. Alias HTML also exists under `/quote/*` (`quote/full-kitchen/index.html`, `quote/replacement/index.html`, `quote/_default/index.html`, `quote/ovens/index.html`, `quote/fryers/index.html`, `quote/dishwashers/index.html`, `quote/refrigeration/index.html`, `quote/mixers/index.html`).
