# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this is

A static marketing site for beSingular and its product CASE (Placement Intelligence for galleries, fashion designers, and auction houses). Plain HTML + one shared CSS file + three PHP form handlers. No framework, no build step, no package.json, no tests. Hosted at `besingular.site` (forms require a PHP-capable host).

## Working locally

There is no build or test command. To preview, open the HTML files directly in a browser, or serve the directory:

```
php -S localhost:8000      # needed if testing the sendmail*.php endpoints
# or: python3 -m http.server 8000   (HTML/CSS only — forms will 404)
```

The `Old/` folder contains historical backups (older `index*.html`, old `styles.css` variants, a huge zip). Treat it as archive — do not edit and do not include it in changes.

## Page map and translation triplets

The site has parallel language versions. **Any content edit to one file in a triplet must be mirrored in the others** — they are maintained by hand, not generated.

The CASE landing page exists in **three vertical sets**, each a full EN/PT/ES triplet:

- **Mixed homepage** (galleries + fashion + auction houses) — `index.html`, `index-pt.html`, `index-es.html` at the repo root. This is the catch-all entry point and the only set linked from `https://besingular.site/`.
- **Art set** (galleries + auction houses) — `art/index.html`, `art/index-pt.html`, `art/index-es.html`. Mostly the same structure as the mixed set with fashion language removed; same hero video and references (Fortes D'Aloia Gabriel, Galeria Raquel Arnaud); form posts to `/sendmail_art.php`.
- **Fashion set** (fashion designers & brands) — `fashion/index.html`, `fashion/index-pt.html`, `fashion/index-es.html`. Heavier rework: vocabulary swapped (pieces / clients / VIP buyers / walk-ins), the YouTube hero replaced with `/hero.jpg`, the References section removed, the Medium feed swapped for two **hardcoded** article links (dynamic-fetch code kept commented underneath); form posts to `/sendmail_fashion.php`.

Each set's header carries two toggle bars: vertical (`All | Art | Fashion`) and language (`EN | PT | ES`). The vertical toggle uses root-absolute hrefs (`/`, `/art/`, `/fashion/`); the language toggle uses relative hrefs (`./index-pt.html`) so it stays within the same vertical folder.

Printable one-pagers follow the same three-vertical pattern: `CASE-1-pager*.html` at root (mixed), `art/CASE-1-pager*.html`, `fashion/CASE-1-pager*.html`. Self-contained — inline `<style>` with `@page` print rules, no dependency on `styles.css`.

Standalone pages (EN only): `services.html` (older beSingular services page), `zapsummary.html` (ZapSummary product page, fully inline styles — does **not** use `styles.css`), `policy.html` (privacy policy). `og-image-template.html` — source for generating the OG image PNG; not linked from the site. `index_copy.html` — stale backup of the landing page; ignore unless explicitly asked.

**Subfolder asset path rule**: pages under `art/` and `fashion/` reference shared assets with `../foo` (parent-relative) paths — for example `../styles.css?v=1.9`, `../Logo CASE - Horizontal - Large.png`, `../alex_ribenboim.jpg`, `../hero.jpg`, `../CASE_Favicon.png`, `../sendmail_art.php`, `../sendmail_fashion.php`. Do **not** use root-absolute paths (`/styles.css`) — those work on the production server but break when previewing locally via `file://` (they resolve to the filesystem root). Vertical-toggle links use `../`, `../art/`, `../fashion/` for the same reason.

`sitemap.xml` currently lists only `index.html`, `art/`, `fashion/`, `services.html`, `zapsummary.html`, `policy.html` — translated variants and the 1-pagers are intentionally not in the sitemap.

## Shared stylesheet and cache busting

`styles.css` is used by `index*.html` and `services.html` only. References use a query-string version: `styles.css?v=1.9` on the index pages, `?v=1.2` on `services.html`. **When you change `styles.css`, bump the `?v=` number** in every HTML file that links it, or browsers will serve stale CSS. The index trio is currently in lockstep at `v=1.9`; `services.html` is intentionally pinned to an older snapshot of the CSS contract and may need to be retested if you bump it.

`zapsummary.html` and the `CASE-1-pager*.html` files use their own inline `<style>` blocks — changes to `styles.css` do not affect them.

## Contact forms (PHP)

Five near-identical handlers, one per form/audience. They differ **only** in the email subject line — everything else (reCAPTCHA verification, sanitization, recipient `hi@besingular.site`, Reply-To handling) is byte-for-byte identical:

| Page | Handler | Subject prefix | Required fields |
| --- | --- | --- | --- |
| `index*.html` (mixed homepage) | `sendmail.php` | "Sales Engine - …" | name, company, email |
| `art/index*.html` | `sendmail_art.php` | "CASE Art - …" | name, company, email |
| `fashion/index*.html` | `sendmail_fashion.php` | "CASE Fashion - …" | name, company, email |
| `services.html` | `sendmail_other_services.php` | (its own subject) | (mirrors `sendmail.php`) |
| `zapsummary.html` | `sendmail_zapsum.php` | (its own subject) | name, **gallery**, email |

All three:

1. Verify Google reCAPTCHA v3 token (site key embedded in the HTML, secret key embedded in each PHP file — yes, this is committed; flag before changing).
2. Reject score < 0.5 as bot.
3. Sanitize with `htmlspecialchars` / `FILTER_VALIDATE_EMAIL`.
4. `mail()` to `hi@besingular.site` with `Reply-To` = submitter.
5. Return JSON `{status, message}` consumed by the page's `fetch()` handler.

**If you change validation, reCAPTCHA logic, or the recipient address, change all five handlers together** — they share no code, so drift is the failure mode.

## Third-party integrations baked into pages

- **Google Tag Manager** (`GTM-N3S5DW`) — inline script + noscript iframe in `<head>`/`<body>` of every page.
- **Google reCAPTCHA v3** — site key `6LdsOvwrAAAAANYAszECAyQQnZ8jVboRe64-5tHE` loaded in `<head>`; matching secret is in each `sendmail*.php`.
- **Calendly** — booking link `https://calendly.com/alexbesingular/20-min-call` appears in multiple CTAs.
- **Medium feed** — `index*.html` pulls `@aribenboim`'s Medium RSS via `api.rss2json.com`, filters by tag `ai-art-gallery`, renders into `#my-medium-feed`. Filter tag and username are hard-coded near the bottom of each index file.
- **YouTube** — hero `<iframe>` embeds video `gK3Mc1tBSF0` on the index pages.

## Conventions worth knowing before editing

- Section IDs (`#why`, `#deliver`, `#team`, `#contact`, `#pilot`, `#benefits`) are used both by the in-page nav and by external links — renaming an ID is a breaking change.
- Mobile nav: toggled by `.mobile-nav-toggle` flipping `body.nav-open`. The CSS reveals `.mobile-nav` only under `@media (max-width: 680px)`. Both the desktop `.site-nav` and the `.mobile-nav` lists exist in the DOM simultaneously, so nav-link changes must be made twice per page.
- Buttons follow two variants: solid `.button` and outlined `.button--ghost`. Inside `.section.cta` (the black band) these invert automatically — don't add inline color overrides there.
- Images are deliberately rendered grayscale via CSS `filter: grayscale(100%)` on `.hero-figure img` and `.bio-photo img`. That is the brand treatment, not a bug.
- `Logo CASE - Horizontal - Large.png` and `Logo CASE - Stacked - Large.png` contain spaces in filenames — quote them in shell commands.
