--- name: local-business-website description: Build production static websites for local service businesses — blueprint-first workflow, mobile-first CSS patterns, local SEO integration, phased implementation. Absorbed small-business-website (directory structure, CSS architecture, gallery/pricing table patterns). --- ## Trigger Use this skill when the user asks to build, design, or architect a static website for a local service business (HVAC, handyman, plumbing, landscaping, roofing, electrical, etc.). Also load it when the user references a website blueprint or a multi-page brochure site for a local business. ## Workflow ### 1. Gather Requirements Before any code, collect: - Business name and owner - Service lines (primary and secondary) - Service areas (cities/neighborhoods — critical for local SEO) - USPs (24/7 emergency, family-owned, flat-rate pricing, etc.) - Phone number and email - Any specific pages needed beyond the standard set If the user is terse (common for this user), ask directly rather than guessing business type or features. ### 2. Produce a BLUEPRINT.md Write a comprehensive blueprint document saved to the project directory BEFORE writing any code. Cover: - URL structure for every page - Technology choices (static HTML/CSS/JS, no frameworks, no build step — keep it fast and portable) - Global header and footer design (desktop + mobile behavior) - Every page: section-by-section layout with copy guidance, CTA placement, and psychology notes - Mobile-specific rules (touch targets, sticky bars, typography) - Local SEO checklist: where each service area city appears (H1, H2, footer, image alt text) - Color palette and typography spec - Implementation phases: each phase produces a deployable increment The blueprint is the source of truth. All implementation decisions trace back to it. ### 3. Build in Phases Standard phase order for local business sites: | Phase | Deliverable | Priority | |-------|------------|----------| | 1 | Global shell: base HTML, CSS custom properties, header, footer, mobile nav, tap-to-call bar, shared JS | Foundation | | 2 | Emergency/urgent landing page (if applicable) | Highest conversion | | 3 | Contact/quote form page | Lead capture | | 4 | Homepage (all sections) | Main entry point | | 5+ | Secondary service pages | Supporting pages | | Final | Polish: schema.org, meta tags, image optimization, performance | SEO finish | Each phase produces a working, self-contained increment. Never deliver a half-built page. ## CSS Architecture (Mobile-First) ### Custom Properties Always use CSS custom properties on `:root`. Standard palette for local business sites: ```css :root { --color-primary: #1E40AF; /* Blue — trust */ --color-secondary: #15803D; /* Green — growth/outdoors */ --color-emergency: #DC2626; /* Red — urgency only */ --color-dark: #111827; /* Near-black body text */ --color-medium: #6B7280; /* Secondary text */ --color-light: #F9FAFB; /* Page background */ --color-white: #FFFFFF; --color-border: #E5E7EB; --font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --max-width: 72rem; --header-height: 64px; --callbar-height: 48px; } ``` Use system font stack — no Google Fonts. Zero FOUT, fastest load. ### Mobile-First Rules - Body text: 16px minimum (prevents iOS zoom on input focus) - All tappable elements: minimum 44×44px - Buttons: full-width on mobile - Phone numbers: ALWAYS `` — never plain text - Section padding: 48px top/bottom on mobile ### Header (Sticky) Three zones: 1. **Desktop (≥768px):** Logo left, nav center, phone + CTA button right. Sticky, shrinks on scroll. 2. **Mobile (<768px):** Logo left, hamburger right. Hamburger opens slide-down drawer with all links + emergency call button. 3. **Mobile nav drawer:** Full-viewport overlay below header. Links at 18px, bold, with rounded tap targets. Close on link tap. Pattern: ```html ``` ### Tap-to-Call Bar (Mobile Only) CRITICAL for service businesses. A sticky bar below the header on mobile (<768px) with phone icon + "Call Now: (XXX) XXX-XXXX — 24/7" that dials on tap. Hidden on desktop via CSS media query. ```html Call Now: (XXX) XXX-XXXX — 24/7 ``` CSS: `position: fixed; top: var(--header-height);` — sits between header and content. Use accent/emergency background color. The body gets `padding-top: calc(var(--header-height) + var(--callbar-height))` on mobile, `padding-top: var(--header-height)` on desktop. ### Footer Three-section grid on desktop (brand, nav, contact), stacked on mobile. Must include service area cities in natural language: "📍 Proudly serving: City1 · City2 · City3" ## Local SEO Patterns ### Where to Place Service Areas | Element | Location | Format | |---------|----------|--------| | H1 | Homepage hero | "Service in City1 & Surrounding Areas" | | H2 | Service area section | "Serving City1, City2 & Beyond" | | Body list | Dedicated section on main service page | Bullet points with context ("City1 — 30-min response") | | Footer | Global footer | Single line, all pages | | Image alt text | Gallery/service photos | "Fence installation in City1 TN" | | Meta description | `` per page | Include primary city | | Schema.org | JSON-LD `LocalBusiness` | `areaServed` array | ### Schema.org Template ```json { "@context": "https://schema.org", "@type": "LocalBusiness", "name": "Business Name", "telephone": "(XXX) XXX-XXXX", "areaServed": ["City1", "City2", "City3"], "hasOfferCatalog": { "@type": "OfferCatalog", "name": "Service Category", "itemListElement": [...] } } ``` Include on every page. ### Anti-Patterns - Do NOT create separate pages for each service area city — spammy, adds no value - Do NOT link city names to dedicated city pages - Do NOT keyword-stuff city names into every heading - One well-optimized service area mention beats six low-quality city pages ## JavaScript (Vanilla, No Dependencies) Three pieces of shared JS: 1. **Mobile nav toggle:** hamburger click → open/close drawer, animate hamburger icon, set `body overflow: hidden` when open, close on link tap 2. **Header shrink on scroll:** add `.scrolled` class when `scrollY > 80` 3. **Active nav highlighting:** match `window.location.pathname` against nav links Keep it simple. No frameworks. `DOMContentLoaded` wrapper. All vanilla. ## Quote/Contact Form Pattern Use Web3Forms (free tier, simple API) for form-to-email on static sites. No backend needed. ### Form Fields (6-field standard) - Name* (text, required) - Phone* (tel, required) — phone is THE critical field for local businesses - Email (email, optional) — don't require; some local customers don't use email - Service Needed* (select, required) — routes the lead mentally, helps owner prioritize - Project Description* (textarea, required) — gives context before callback - Lead Source (select, optional) — helps track which marketing works ### Validation Pattern Client-side only. On submit: check required fields, add `.error` class to empty inputs (red border), add `.visible` to error spans. On input: remove error classes — instant feedback. ### States - **Loading:** button disabled + CSS spinner (swaps button text for animated spinner via `display` toggle) - **Success:** form hidden, success card shown. Includes customer's first name + emergency phone CTA - **Error:** red banner displayed, button re-enabled for retry ### Web3Forms Setup 1. Create free account at https://web3forms.com/ 2. Replace `YOUR_ACCESS_KEY` in the form script 3. Form POSTs to `https://api.web3forms.com/submit` 4. Emails go to the address configured in dashboard Full implementation reference at `references/airrepairteam-blueprint.md`. ## Pitfalls - **Don't use Google Fonts** — system font stack is faster and looks native on every device - **Don't use iframe Google Maps** — they kill page speed. Use a static image or CSS map - **Don't add a calendar/scheduler to forms** — adds complexity, needs backend, breaks when not maintained. Simple POST-to-email via Formspree or Web3Forms is enough - **Don't require email on quote forms** — some local customers don't use email. Phone is the required field - **Don't build landing pages with nav links** — emergency landing pages should have ONE exit: the phone number - **Don't use frameworks for simple brochure sites** — Tailwind or raw CSS is fine, but React/Vue/Next.js is overkill and adds hosting complexity the owner can't maintain ## Support Files - `references/airrepairteam-blueprint.md` — Full blueprint example: 6-page HVAC/handyman site with section-by-section layout, mobile rules, and SEO checklist - `references/blueprint-template.md` — Empty website blueprint template (absorbed from small-business-website) - `references/contact-form.md` — Complete Web3Forms contact form pattern with HTML, CSS, and JS (absorbed from small-business-website) - `templates/style.css` — Copyable base CSS: custom properties, reset, header, callbar, footer, responsive breakpoints - `templates/main.js` — Copyable base JS: mobile nav toggle, header shrink, active link detection, smooth scroll ## Directory Structure ```text BusinessName/ ├── BLUEPRINT.md ├── index.html ├── css/style.css ├── js/main.js ├── contact/index.html ├── service-pages/... ├── images/ ``` ## Global CSS Architecture (Section Order) All styles go in `css/style.css`. Structure: ```text 1. CSS custom properties (colors, typography, spacing, layout vars) 2. Reset 3. Utility classes 4. Buttons (btn, btn-primary, btn-emergency, btn-outline, btn-large, btn-full) 5. Phone link (.phone-link) 6. Header (.site-header, .logo, .main-nav, .header-right, .hamburger) 7. Mobile nav drawer (.mobile-nav) 8. Tap-to-call bar (.callbar — mobile only, hidden on desktop) 9. Page sections (.page-section, .section-heading, .section-subheading) 10. Footer (.site-footer, .footer-grid, .footer-service-areas) 11. Page-specific section styles 12. Responsive: Tablet (768px) — grid layouts, header changes, hide mobile elements 13. Responsive: Desktop (1024px) — larger type, wider grids ``` ## Emergency Landing Page (if applicable) For service businesses with 24/7 emergency offerings, create a standalone stripped-down page: - Zero external resources — all CSS inline, no JS files, no images, no fonts - ~7KB total page weight, sub-1s cold load - ONE goal: phone call. Phone number is the only prominent interactive element - Red/urgent accent, pulsing emergency badge - No navigation links (people click them and bounce) - "No after-hours fees" prominently addressed ## Before/After Gallery (if applicable) For service businesses where visual proof drives conversions: - 2×2 or 4-col grid of before/after pairs side-by-side - Filter bar by service category (All, Fences, Lawns, etc.) - Filter JS: `data-category` attributes, toggles `display:none` - Place gallery filter script BEFORE main.js in the HTML - "Before"/"After" labels on each image ## Pricing Table (if applicable) - Responsive table: collapses to label-value rows on mobile using `data-label` attributes - Use "Flat Rate" or "Starting at $XX" language — don't lock in exact numbers - Disclaimer: "Final price confirmed before any work begins" - Wrap in a card with border and shadow for visual weight ## After Build Checklist 1. Search all files for `XXX-XXXX` and replace with real phone number 2. Replace placeholder email 3. Get Web3Forms access key, update contact page 4. Replace emoji/placeholder images with real photos 5. Fill in actual pricing if applicable 6. Serve via nginx