Site Build Playbook · v2.0 · March 2026

GTMDot Site Build Playbook

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)




The Stack


RoleWhoWhat They Do
Creative DirectorBruce (Opus 4.6)Makes every design decision. Never skips steps. Writes the build brief.
BuilderClaude Sonnet subagentExecutes the build brief. Layers design system on Stitch scaffold.
ApproverJesseReviews 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.




Phase 0: Research Gate


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.




Phase 1: Research


This is the most important phase. Bad research = rebuild. An hour here saves three hours later.


Source priority order:


1. Google Business Profile

  • Exact star rating (4.8, not "5 stars")
  • Review count
  • Owner name (check owner responses: "Hi, I'm Jack and I'll personally...")
  • Business categories
  • Payment methods (About tab — "Cash, Check, Zelle")
  • Photos tab — every photo is potential hero or section material
  • Hours (note any discrepancies vs their site)
  • Badges: "Licensed," "Insured," years serving area

  • 2. Verbatim review quotes (minimum 3, maximum 6)

    Do not paraphrase. Exact words only.

  • Sandy Springs: "Mr Jack Fixed My Air at fair price" (Yellow Pages) → used verbatim as primary testimonial
  • Morales: "If I could give you 10 stars I would!" (Thumbtack) → exact words
  • Look for: specific service performed, owner name used, emotional language, comparison to competitors
  • Grammar errors are proof of authenticity. Do not clean them up.

  • 3. Thumbtack / Yelp / Angi / HomeAdvisor

    When GBP is weak or absent, Thumbtack is often the real online presence.

  • Morales: 4.4★ / 25 reviews / 32 hires / Background Checked / Top 5 Atlanta landscape design — all of this is usable on the site
  • Look for badges: "Background Checked," "Pro," "Elite"
  • Thumbtack has project photos — check the Photos tab for real job shots

  • 4. Facebook / Instagram

  • Profile bio is often where they articulate their own value proposition in their own words
  • Morales bio: "Turning ordinary yards into custom outdoor living spaces. From retaining walls to paver patios and full landscape designs — we build it right the first time." → that's the tagline. Verbatim.
  • Look for project photos — even low-res is better than stock
  • Check how they respond to reviews — that's their voice

  • 5. Their existing website (if any)

  • Usually thin or outdated, but: years in business, services, contractor license number
  • Note CTA language exactly: "Get a Free Estimate," "Call Us," "Book Now" — use their words
  • Professional associations: PHCCA, PMA, NFIB, NASTeC, EPA — list them as trust badges

  • 6. Directory listings (BBB, Yellow Pages, Yelp, Angi)

  • Old businesses: Yellow Pages often has the only surviving early reviews
  • Sandy Springs had no GBP reviews. Yellow Pages review was the anchor testimonial.
  • Professional association memberships often appear in BBB listings

  • Judgment calls from reference builds:


    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.


    Output: BRAND.md


    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
    



    Phase 2: Pre-Build Design Brief (Bruce's job — all steps mandatory)


    2a. Read mandatory reference files (in this order)


    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:

  • "Get a Free Estimate" → one-time jobs (pressure washing, drywall, landscaping, fence)
  • "Get a Free Quote" → variable-scope services (plumbing, HVAC, pool, appliance repair)
  • "Book an Appointment" → mobile services (detailing, mobile mechanic)
  • "Schedule a Free Consultation" → professional services (tax, accounting)

  • Getting the CTA wrong is a research failure, not a typo.


    2b. ui-ux-pro-max design system query


    
    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.


    2c. Refero research pass


    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:

  • How do they structure the above-the-fold section?
  • Where do stats bars live? (below headline, inline with CTA, above fold)
  • How are service grids organized? (3-col icons, photo cards, list)
  • Where does social proof sit in the hierarchy?
  • What's distinctive about the top results vs the average ones?

  • Document: which patterns to reference, which to deliberately break from. This is where the site gets personality. Without Refero it defaults to generic.


    2d. typeui aesthetic direction


    Pick exactly ONE aesthetic. Read the corresponding file before writing the build brief.


    VerticalAestheticFile
    Emergency, Locksmith, Tire, Mechanicdramatic`skills/typeui/dramatic.md`
    Plumbing, HVAC, Pool, Applianceprofessional`skills/typeui/professional.md`
    Landscaping, Fencing, Exteriorrefined`skills/typeui/refined.md`
    Auto Detailing, Mobile Beauty, Petpremium`skills/typeui/premium.md`
    Tax, Legal, Finance, Insuranceluxury`skills/typeui/luxury.md`
    15+ year old family businesseditorial`skills/typeui/editorial.md`

    The aesthetic direction determines: display font choice, color temperature, spacing density, motion style.


    2e. Design system selection


    Select from gtmdot/design-systems/:


    SystemUse for
    dark-urgent.mdEmergency, locksmith, 24/7, auto
    clean-blue.mdPlumbing, HVAC, pool, appliance
    earth-outdoor.mdLandscaping, fencing, gutters, exterior
    trade-workmanlike.mdHandyman, drywall, painting
    care-specialty.mdDetailing, fabric cleaning, mobile beauty
    legacy-trade.mdAny business 15+ years, family businesses

    Read the ENTIRE file before writing HTML.


    2f. Hero photo selection (manual vetting — do not delegate)


    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%);
    

    2g. Service area language check


  • "Fulton County" → use "Metro Atlanta" or "Atlanta and Nearby Areas" (customers search neighborhoods, not counties)
  • "Sandy Springs area" → fine, specific and searchable
  • "30327" → never use zip codes in copy
  • Rule: Use what a customer would actually type in Google, not the administrative/geographic name



  • Phase 3: Stitch Scaffold


    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.


    Step 1: Create project

    
    mcporter call stitch.create_project --args '{"title": "[Business Name]"}'
    # Returns project ID
    

    Step 2: Generate scaffold

    
    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.


    What Stitch gets right (~40-50% of the build):

  • Visual direction and section layout
  • Color + typography system locked in
  • Hero structure (headline placement, stats bar position, CTA layout)
  • Section rhythm

  • What Stitch does NOT include (Sonnet adds these):

  • Real business data (replaced by research content)
  • GTMDot required elements: claim bar, exit popup, hamburger nav, schema.org
  • Real copy from RESEARCH.md
  • Scrolling marquee
  • Mobile responsive breakpoints
  • JS (hamburger, popup trigger, scroll animations)
  • Full QA compliance

  • If Stitch is down or returns errors: flag to Jesse. Do not skip and build raw.




    Phase 4: Sonnet Build


    Sonnet subagent takes: Stitch scaffold + RESEARCH.md + DESIGN-STANDARDS.md + INDUSTRY-REFERENCE.md + gold standard reference site (gtmdot/sites/sandy-springs-plumbing/index.html).


    Required sections (all mandatory, in order):


    
    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
    

    Technical requirements (non-negotiable):


    
    /* 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);
    

    Checkout URL format:

    
    https://gtmdot.com/checkout?code=[CLAIM_CODE]&site=[slug]
    

    Not path-based. Always query params. Claim code in UPPERCASE.


    Copy rules:

  • Headlines use their words. Not "Atlanta's Premier Landscaping" — "Turning Ordinary Yards Into Oases. Ask for Jose."
  • Stats use real numbers only. "58 years" not "60 years." "4.4★" not "5★." Never round up.
  • CTA mirrors their language exactly. Match whatever their GBP or website says.
  • Reviews are verbatim or nothing. Don't paraphrase. Preserve grammar quirks.
  • Never fabricate identity claims. Black-owned, Women-owned, minority-owned — only if GBP explicitly confirms it.



  • Phase 5: Typography Pass (Sonnet subagent, ~3 min)


    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 accent
  • 3. 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)




    Phase 6: QA


    Automated check (run first):

    
    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:


    CheckWhat it catches
    [1] Emoji in structural UIEmoji in nav, service icons, footer — breaks iOS Safari
    [2] Dark section contrastWhite text on light backgrounds in service cards
    [5] Claim bar mobile layoutClaim bar not stacking vertically at mobile width
    [6] Nav logo iconEmpty nav logo area
    [8] Reviews are realPlaceholder review text, "John D." anonymized names
    [9] Phone is tap-to-callPhone numbers not wrapped in ``
    [10] Claim bar linksClaim bar not linking to gtmdot.com
    [12b] Hamburger presentNo hamburger menu for mobile
    [13a] overflow-x hiddenMissing on html/body — causes horizontal scroll
    [14] Claim bar has buttonClaim bar present but missing CTA button
    [15] Duplicate marqueesTwo adjacent scrolling marquees
    [17] opacity:0 on heroWhole hero set to invisible — iOS Safari shows nothing
    [18] Review avatarsReview cards missing avatars + Google attribution
    [21] Service icon uniquenessSame SVG path used for multiple service icons

    Manual checks Bruce does (not delegatable):


  • **Hero photo context check** — Does the photo actually match this business? (locksmith ≠ bank vault)
  • **No fabricated content** — Every stat, every review, every claim has a source in RESEARCH.md
  • **CTA language** — Matches INDUSTRY-REFERENCE.md for this vertical exactly
  • **Service area language** — City/neighborhood names only. No county. No zip code.
  • **Stats bar** — All 4 stats visually identical. No "special pill" on one.
  • **Checkout URL** — `?code=X&site=Y` format, not path-based
  • **No em dashes** anywhere in visible copy
  • **JS syntax check**: `node --check <(grep -o ']*>.*' index.html | head -1)`
  • **All CSS classes in HTML exist in stylesheet**: `grep -oh 'class="[^"]*"' index.html | grep -oP '(?<=class=")[^"]+' | tr ' ' '\n' | sort -u | while read c; do grep -q "\.$c" index.html || echo "MISSING: .$c"; done`

  • Visual QA — 390px mobile screenshot (mandatory):


    
    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:

  • Hero headline is visible (not white-on-white, not blank)
  • Nav shows hamburger icon, NOT text links
  • Claim bar stacks vertically, "Claim this site" is full-width button
  • Scrolling marquee is moving
  • Stats pills are legible and readable
  • All sections below the fold are visible (scroll down in the screenshot)
  • No blank/unstyled sections
  • Images loaded (no broken img placeholders)
  • Exit popup does NOT fire immediately on load

  • If anything fails: fix it, re-screenshot, confirm before deploying. A QA checklist without a screenshot is not QA.




    Phase 7: Deploy


    
    # 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.




    Phase 8: Report to Jesse


    Send to Telegram:

  • Screenshot of site at 390px mobile
  • Live URL: https://[slug].pages.dev
  • Claim code
  • Any flags: photo accuracy concerns, copy judgment calls, local knowledge gaps Jesse should verify

  • Jesse reviews before site enters the postcard queue. This is a checkpoint, not a formality.




    Common Failure Modes


    FailureRoot CauseFix
    Site looks genericSkipped Refero, used generic copyRedo research. Find 3 real reviews. Find owner's own words.
    Wrong hero photoNo manual context checkCheck: does photo match this exact business type and context?
    Mobile layout brokenInline `style="display:grid"` overrides CSS media queriesMove all layout to CSS classes with explicit mobile breakpoints
    Hero section blank on iOS`opacity:0` on entire hero sectionNever set opacity on sections. Only animate child elements. Add 500ms setTimeout fallback.
    Hamburger won't openJS syntax error killed all scriptsRun `node --check` on every `