Version 2.0 — March 2026
Operative process as of SITE-BUILD-PROCESS-V2.md. Both Refero and Stitch are mandatory — not optional.
Reference builds: Sandy Springs Plumbing (legacy-trade, no GBP), Morales Landscape Construction (earth-outdoor, Thumbtack-primary)
| Role | Who | What They Do |
|---|---|---|
| Creative Director | Bruce (Opus 4.6) | Makes every design decision. Never skips steps. Writes the build brief. |
| Builder | Claude Sonnet subagent | Executes the build brief. Layers design system on Stitch scaffold. |
| Approver | Jesse | Reviews final output. Approves before postcard queue. |
Model rule: Sonnet only for site builds. Never Gemini Flash for full builds — only for targeted single-element edits.
Hard stop. Confirm a verified mailing address exists before starting. No address = no postcard = no conversion path. Move to a different prospect.
If address comes only from GBP and it's service-area-only (no street address listed), flag it. Do not build.
This is the most important phase. Bad research = rebuild. An hour here saves three hours later.
1. Google Business Profile
2. Verbatim review quotes (minimum 3, maximum 6)
Do not paraphrase. Exact words only.
3. Thumbtack / Yelp / Angi / HomeAdvisor
When GBP is weak or absent, Thumbtack is often the real online presence.
4. Facebook / Instagram
5. Their existing website (if any)
6. Directory listings (BBB, Yellow Pages, Yelp, Angi)
Sandy Springs (no GBP problem): Name collision with a different "Sandy Springs Plumbing" at a different address had stolen the search results. Solution: don't fight the GBP battle — lean entirely on "58 years in business, 3rd generation master plumber, Jack Kelley personally." When you can't use star count, you use longevity.
Morales (no phone problem): Thumbtack hides phone numbers. Solution: all CTAs route to email (Morales.l.c@hotmail.com) or estimate request form. Never invent a phone number. The email address IS the contact method.
Every site gets a BRAND.md before any HTML. Required sections:
Business Identity — exact name, DBA if different, owner name, address, phone, email, founded date
Services — complete list as they describe it (their words, not generic)
Audience — who calls them, what problem they have, why they chose this business over a chain
Tone & Voice — 3-5 words, where the voice came from, what NOT to do
Design Direction — palette, typography, imagery sources (what's available and where)
Key Differentiators — what makes THIS specific business worth claiming
Site Structure — section plan with exact copy decisions locked in
Claim Bar — text and CTA
Notes — anomalies, data gaps, judgment calls made
1. LESSONS.md — hard-won rules from prior mistakes. Read all of it.
2. gtmdot/DESIGN-STANDARDS.md — vertical palettes, font rules, component patterns, hero overlay formula
3. gtmdot/INDUSTRY-REFERENCE.md — CTA language, form headings, form buttons by vertical
4. RESEARCH.md for the specific business
Never skip INDUSTRY-REFERENCE.md. It contains the exact CTA language by vertical:
Getting the CTA wrong is a research failure, not a typo.
python3 ~/.openclaw/workspace/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/search.py "[vertical] [mood]" --domain style -n 2
python3 ~/.openclaw/workspace/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/search.py "[vertical]" --domain landing -n 1
python3 ~/.openclaw/workspace/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/search.py "[vertical] typography" --domain typography -n 1
This returns: recommended visual style, color approach, effects (glassmorphism, gradients, shadows), implementation checklist, typography pairings. Lock these in the build brief before touching HTML.
Use the refero-design skill. Search for real product patterns in this vertical before building.
mcporter call refero.refero_search_screens "emergency locksmith landing page dark" web 5
mcporter call refero.refero_search_screens "local service business hero trust signals" web 5
mcporter call refero.refero_search_screens "[vertical] service mobile site" web 5
Review 3-5 real examples. Extract:
Document: which patterns to reference, which to deliberately break from. This is where the site gets personality. Without Refero it defaults to generic.
Pick exactly ONE aesthetic. Read the corresponding file before writing the build brief.
| Vertical | Aesthetic | File |
|---|---|---|
| Emergency, Locksmith, Tire, Mechanic | dramatic | `skills/typeui/dramatic.md` |
| Plumbing, HVAC, Pool, Appliance | professional | `skills/typeui/professional.md` |
| Landscaping, Fencing, Exterior | refined | `skills/typeui/refined.md` |
| Auto Detailing, Mobile Beauty, Pet | premium | `skills/typeui/premium.md` |
| Tax, Legal, Finance, Insurance | luxury | `skills/typeui/luxury.md` |
| 15+ year old family business | editorial | `skills/typeui/editorial.md` |
The aesthetic direction determines: display font choice, color temperature, spacing density, motion style.
Select from gtmdot/design-systems/:
| System | Use for |
|---|---|
| dark-urgent.md | Emergency, locksmith, 24/7, auto |
| clean-blue.md | Plumbing, HVAC, pool, appliance |
| earth-outdoor.md | Landscaping, fencing, gutters, exterior |
| trade-workmanlike.md | Handyman, drywall, painting |
| care-specialty.md | Detailing, fabric cleaning, mobile beauty |
| legacy-trade.md | Any business 15+ years, family businesses |
Read the ENTIRE file before writing HTML.
Priority order:
1. Real GBP photos (in site directory)
2. Thumbtack project photos
3. Facebook / Instagram photos
4. Gemini Imagen generation (specific prompt describing actual business context)
5. Unsplash (secondary images only — never hero)
Context check rule: Does the photo actually match the business? A locksmith site should show a residential door lock or key, NOT a bank vault. A tire shop should show roadside tire change, NOT a showroom. Jesse catches these. Do not let a wrong photo go to QA.
Hero overlay formula (always apply):
background: linear-gradient(105deg, rgba(bg,0.93) 0%, rgba(bg,0.65) 55%, rgba(bg,0.30) 100%);
Stitch generates the HTML scaffold with Gemini 3 Pro. This is mandatory, not optional.
The sites Jesse liked (Sandy Springs Plumbing, Dream Steam) used Stitch. The flat ones didn't.
mcporter call stitch.create_project --args '{"title": "[Business Name]"}'
# Returns project ID
mcporter call stitch.generate_screen_from_text \
projectId=[project_id] \
deviceType=MOBILE \
modelId=GEMINI_3_PRO \
prompt="[business type] landing page. [aesthetic from 2d]. [exact palette]. [key sections: hero, services, reviews, CTA]. [typography: display font, body font]. Dark bg [hex]. Accent [hex]."
Stitch outputs: HTML scaffold with section structure, color system, typography direction, layout grid.
If Stitch is down or returns errors: flag to Jesse. Do not skip and build raw.
Sonnet subagent takes: Stitch scaffold + RESEARCH.md + DESIGN-STANDARDS.md + INDUSTRY-REFERENCE.md + gold standard reference site (gtmdot/sites/sandy-springs-plumbing/index.html).
1. Sticky frosted glass nav — business name left, links + phone CTA right
2. Hero — real photo + gradient overlay + headline + stats bar + dual CTAs
3. Scrolling marquee — services or trust signals
4. Services grid — SVG icons (accent stroke color), card hover glow
5. About / Owner story — real photo if available, personal narrative
6. Why Us — 4 trust signals: icon + heading + 1 sentence each
7. Reviews — verbatim only, real names, real star rating
8. FAQ accordion — 4-6 questions specific to this business/vertical
9. Estimate/booking form — heading + button per INDUSTRY-REFERENCE.md
10. Service area — neighborhood/city names only, no county or zip
11. Footer — 4-col, GTMDot address, claim code prominent
12. Exit popup — Cormorant Garamond headline, claim code visible, 5s grace period
13. Claim bar — fixed top, claim code, CTA to checkout URL
14. Cookie banner — positioned above claim bar
15. Mobile sticky phone button
/* Global — must exist */
*, *::before, *::after { box-sizing: border-box; }
html, body { overflow-x: hidden; }
/* Mobile nav — never display:none on nav-right */
@media (max-width: 768px) {
.nav-links { display: none; }
.nav-right { display: flex; } /* hamburger lives here */
.nav-hamburger { display: flex; }
}
/* Every grid on mobile */
@media (max-width: 500px) {
[any-grid-class] { grid-template-columns: 1fr; }
}
/* Claim bar on mobile */
@media (max-width: 500px) {
.claim-bar-content { flex-direction: column; }
.claim-bar-btn { width: 100%; }
}
/* Required reveal animation */
@keyframes gtmReveal { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
/* Always add setTimeout fallback — never put opacity:0 on whole sections */
setTimeout(function() {
document.querySelectorAll('.reveal').forEach(el => el.classList.add('visible'));
}, 500);
https://gtmdot.com/checkout?code=[CLAIM_CODE]&site=[slug]
Not path-based. Always query params. Claim code in UPPERCASE.
Run as a separate pass after base build. Every site gets this.
Required changes:
1. Add Cormorant Garamond to Google Fonts import (alongside display + body fonts)
2. Add CSS classes:
.section-eyebrow: 12px, 700 weight, uppercase, 4px letter-spacing, accent color.section-heading-serif: Cormorant Garamond 500 italic, clamp(32px, 4.5vw, 52px).hero-quote-text: Cormorant Garamond italic, 20px, left border accent3. Apply to all section H2s: eyebrow label above + serif heading
4. Apply hero pull quote: Cormorant Garamond italic with decorative left border
5. Stats numbers: 48px desktop, clamp(32px, 6vw, 48px) responsive
6. Service card titles: 700 weight (not 900), 18px
7. Body text: minimum 16px, line-height 1.65, muted color (not pure white on dark)
python3 gtmdot/scripts/qa-check.py sites/<slug>/index.html
The qa-check.py script runs 21 checks. Hard fails block deploy. Here are the checks that fire most often:
| Check | What it catches |
|---|---|
| [1] Emoji in structural UI | Emoji in nav, service icons, footer — breaks iOS Safari |
| [2] Dark section contrast | White text on light backgrounds in service cards |
| [5] Claim bar mobile layout | Claim bar not stacking vertically at mobile width |
| [6] Nav logo icon | Empty nav logo area |
| [8] Reviews are real | Placeholder review text, "John D." anonymized names |
| [9] Phone is tap-to-call | Phone numbers not wrapped in `` |
| [10] Claim bar links | Claim bar not linking to gtmdot.com |
| [12b] Hamburger present | No hamburger menu for mobile |
| [13a] overflow-x hidden | Missing on html/body — causes horizontal scroll |
| [14] Claim bar has button | Claim bar present but missing CTA button |
| [15] Duplicate marquees | Two adjacent scrolling marquees |
| [17] opacity:0 on hero | Whole hero set to invisible — iOS Safari shows nothing |
| [18] Review avatars | Review cards missing avatars + Google attribution |
| [21] Service icon uniqueness | Same SVG path used for multiple service icons |
python3 -m http.server 8765 &
# Browser tool: navigate to http://localhost:8765, width=390, fullPage=true screenshot
pkill -f "http.server 8765"
Confirm every item in this list visually:
If anything fails: fix it, re-screenshot, confirm before deploying. A QA checklist without a screenshot is not QA.
# From the site directory
wrangler pages deploy . --project-name=gtmdot-preview
# Verify it's live
curl -sL -o /dev/null -w "%{http_code}\n" https://<slug>.pages.dev
# Must return 200
# Commit to git
cd ~/workspace && git add -A && git commit -m "$(date +%Y-%m-%d): [Business Name] site built + deployed" && git push
Log the preview URL in the CRM: crm.cloakanddagger.co → find prospect → update Preview Site URL field.
Send to Telegram:
https://[slug].pages.devJesse reviews before site enters the postcard queue. This is a checkpoint, not a formality.
| Failure | Root Cause | Fix |
|---|---|---|
| Site looks generic | Skipped Refero, used generic copy | Redo research. Find 3 real reviews. Find owner's own words. |
| Wrong hero photo | No manual context check | Check: does photo match this exact business type and context? |
| Mobile layout broken | Inline `style="display:grid"` overrides CSS media queries | Move all layout to CSS classes with explicit mobile breakpoints |
| Hero section blank on iOS | `opacity:0` on entire hero section | Never set opacity on sections. Only animate child elements. Add 500ms setTimeout fallback. |
| Hamburger won't open | JS syntax error killed all scripts | Run `node --check` on every ` |