# Starter site for Just a Good Guy

A small, fast business website that is already wired to Just a Good Guy: the AI receptionist chat bubble, the booking widget, booking buttons, live services, prices and hours from the API, a call-back widget and a message form. Plain HTML, CSS and a little JavaScript. No framework and no build step.

Read the full guide first: https://justagoodguy.us/docs/ai-build-guide

## What's in it

| File | What it is |
|---|---|
| `index.html` | Home: headline, Book / Call / Ask buttons, live hours card, first four services, suggested questions, short about, footer |
| `services.html` | Every service with its price and a Book button |
| `about.html` | The business's story |
| `contact.html` | Inline booking widget, call-back widget, message form, address and hours |
| `privacy.html` | Plain-English privacy page that covers the chat assistant |
| `404.html` | Not-found page. Served for any missing address, so its links start with `/` |
| `styles.css` | All styles. Colours and fonts are tokens at the top |
| `app.js` | Fetches live services and hours, sends the message form. About 11 KB, no dependencies |
| `favicon.svg` | Placeholder icon |
| `robots.txt`, `sitemap.xml` | For search engines |
| `tools/bake.mjs` | Writes the live data into the HTML (not part of the website) |

## Make it the business's site

1. **Get the publishable key** (`pk_...`) for the business. The operator finds it in **Admin → Businesses → the business → AI and API**, the owner in **Website** or **Developers** in the dashboard.
2. **Bake in the live data.** From this folder, with Node 18 or later:

   ```bash
   node tools/bake.mjs pk_the_business_key
   ```

   This puts the key in every page, swaps the booking link placeholder for the real booking page, writes the real services, prices and hours into the pages, fills the opening hours in the JSON-LD, and saves the raw data to `tools/business.json`. Run it again whenever prices or hours change.
3. **Replace the sample business.** Change the name, phone, address, email, headline, about text, suggested questions and page titles. Use only facts from the intake form, the dashboard and the API. Never invent prices, reviews, ratings, awards or years in business.
4. **Re-theme it.** Change the colour tokens and the font at the top of `styles.css`, and the Google Fonts link in each page's `<head>`. Keep text contrast at 4.5:1 or more. Change `--gg-color` to the brand colour so the widget matches.
5. **Replace the logo and favicon.** Use the business's logo (SVG or PNG with `width` and `height`). Add real photos with `alt` text, or none at all.
6. **Set the real web address** in every `canonical` and `og:url` tag, in the JSON-LD `url`, in `robots.txt` and in `sitemap.xml`.
7. **Check nothing is left over.** This must print nothing:

   ```bash
   grep -rnE "REPLACE|your-business-slug|Maple Street|555-01|example\.com" --include='*.html' --include='*.xml' --include='*.txt' .
   ```

## Preview it

Serve the folder over HTTP rather than opening the files directly:

```bash
python3 -m http.server 8080
```

Then open http://localhost:8080. If the business has an **allowed sites** list on its key, `localhost` isn't on it and the widget and live data will be refused (403). Leave the list empty while you build, or preview on the hosted address.

## Ship it

Zip the site files, without `tools/` and this README:

```bash
zip -r ../site.zip . -x 'tools/*' 'README.md'
unzip -l ../site.zip    # index.html must be at the top
```

Then upload `site.zip` as described in the guide: from the operator's **Website builds** queue, or in the owner's dashboard under **Website**.

## How the pieces fit

- Every page loads the widget once, just before `</body>`:

  ```html
  <script src="https://justagoodguy.us/w.js" data-key="pk_..." data-font="inherit" async></script>
  ```

  On Just a Good Guy hosting the server would add this tag for you, but it skips any page that already has one, so keeping it in the files is safe and keeps `data-font="inherit"`.
- If the business ever replaces its publishable key, these pages keep the old one. Run `node tools/bake.mjs pk_new_key` and upload again.
- Buttons with `data-gg-book`, `data-gg-open` or `data-gg-ask` open the booking or chat panel. Their `href` is the fallback when the widget can't run.
- `app.js` replaces the contents of `[data-live]` elements with live data. If the API can't be reached, the content written in the page stays. It never empties a list.
- `<div data-gg-widget="booking">` renders the booking flow. The text inside it shows until the widget draws, and stays if it can't.
