# CLAUDE.md

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

## What this is

Static website for **Gumirom**, a tyre shop (vulcanizare) in Gherla, Romania: a sales homepage (`app/index.html`) and an online tyre shop MVP (`app/magazin.html`, new + second-hand tyres, reservation without online payment). Plain HTML/CSS/vanilla JS — no build step, no package.json, no backend, no dependencies. `app/` is the deployable folder (keep docs/tests/tooling out of it). All visible copy is Romanian.

Not a git repository. The pre-rewrite original lives in `_backup/app-original-2026-10-06/`. Design spec, implementation plan and execution ledger (with every decision taken) are in `docs/superpowers/` and `.superpowers/sdd/`; `docs/GHID-PROPRIETAR.md` is the owner's guide (what to confirm before launch, how to edit the catalogue).

## Commands (run from `v1/`)

```bash
node --test tests/core.test.js                                   # unit tests for app/js/core.js
node --test --test-name-pattern="pluralRo" tests/core.test.js    # single test by name
for f in app/js/*.js; do node --check "$f"; done                 # syntax check
node tests/browser/run.js [baseUrl]                              # headless browser suite (~80 checks, desktop + mobile)
```

- The browser suite drives **headless Edge** (`C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe`, temp profile in the OS temp dir) over the DevTools Protocol (`tests/browser/cdp.js`, Node 22 global `WebSocket`). Without `baseUrl` it serves `app/` from an in-process static server on a free port and stops it at the end. Screenshots go to `%TEMP%/gumirom-shots`. Needs ~1 GB free RAM. It exits non-zero on any failed check and also fails on any console error/exception.
- To view the site manually: `python -m http.server <port> --bind 127.0.0.1 --directory app`. Port 8765 is used by another local project, and the XAMPP `localhost` does not serve this path.

## Architecture

**Script load order matters** (classic `defer` scripts, no ES modules so pages also work from `file://`):
`config.js → core.js → lead.js → main.js` on both pages, plus `catalog.js → shop.js` on `magazin.html`. They communicate through globals:

| Global | File | Role |
|---|---|---|
| `GUMIROM_CONFIG` | `config.js` | phone, `formspreeId`, `whatsapp`, `email`, `rezervareZile`, weekly `program` (index 0 = Sunday, `null` = closed), time zone |
| `GumiromCore` | `core.js` | **all pure logic** (UMD: also `module.exports` for Node tests) — schedule/open status in Europe/Bucharest, season, tyre-size parsing, catalogue sanitising, filters/sort/URL criteria, cart operations, lead/order message text, SMS/WhatsApp/mailto links, validation, quiz verdict, Romanian plurals |
| `GumiromLead` | `lead.js` | delivers leads: Formspree POST (10 s timeout) if `formspreeId` is set, otherwise a fallback panel (prefilled SMS, optional WhatsApp/e-mail, call, copy) |
| `GumiromMenu` | `main.js` | `close()` for the mobile menu (used by the shop cart) |
| `GUMIROM_CATALOG` | `catalog.js` | owner-edited product list (`demo: true` shows demo banners and tags reservations `[DEMO]`) |

- **Put decision logic in `core.js` and test it there.** DOM files stay thin; `core.js` must never touch the DOM. `sanitizeProduct` deliberately tolerates hand-edit mistakes (string numbers, `"1.200"` prices, diacritics/aliases, 4-digit DOT codes) and drops rows it can't trust.
- **`main.js` runs on both pages**: every block guards on its elements existing. It owns the header, scrollspy (only `.nav-link[href^="#"]`), mobile menu, reveal, accordion (opens from `#id` hash), live open status, seasonal text, CTA tracking, the contact form, the 2-minute quiz and the size finder.
- **`shop.js`** owns filters (state mirrored in the query string via `replaceState`; deep links like `?latime=175&profil=65&diametru=14` from the homepage finder must keep working even for sizes not in stock), card rendering (`innerHTML` — every catalogue string goes through `escapeHtml`), the cart (`localStorage["gumirom_cart_v1"]` with in-memory fallback, normalised against the catalogue on load), the cart dialog (focus trap, Escape, focus return) and the reservation/offer forms.
- **Lead fallback UI**: `renderFallback(status, …)` puts the panel in a `.lead-slot` *sibling* of the `role=status` element (not inside the live region) and focuses its heading; use `GumiromLead.clear(status)` to reset both. In fallback mode the cart is emptied only after the visitor clicks "Am trimis mesajul".
- **`inert` coordination**: the mobile menu (`main.js`) and the cart (`shop.js`) both make the page inert; the cart closes the menu first via `GumiromMenu.close()`, and both cancel pending hide timers on reopen. Keep that invariant when adding overlays.
- **DOM hooks driven by data attributes**: `[data-open-status]` + `.status-dot` (live open/closed), `[data-days="1-5"|"6"|"0"]` (today's schedule row), `[data-winter][data-summer]` (seasonal text, Sep–Feb = winter), `[data-track]` (pushes to `window.dataLayer` only if GTM exists), `[data-reservation-days]`.
- **CSS**: `css/style.css` is shared (tokens in `:root`), `css/shop.css` loads only on the shop. Reveal animations only apply under `html.js` (set by an inline head script) so content stays visible without JS; a global `[hidden] { display: none !important; }` is relied on throughout.

## Content rules

- `index.html` sections follow the *Sell Like Crazy* 17-step order (call-out → big-promise H1 → problem → mechanism → Godfather/Hormozi offer stack → guarantees → stock → HVCO quiz → credentials → proof → objections/FAQ → CTA → P.S.); keep that order when editing.
- **Never invent business facts.** New commitments (guarantees, bonuses, reservation period) carry `<!-- DE CONFIRMAT -->`; reviews are flagged `DE VERIFICAT`; prices and stock in `catalog.js` are demo data. Scarcity must stay real (seasonal rush, unique SH sets, stock ≤ 2) — no fake countdowns.
- Romanian text uses comma-below diacritics (ș ț), and counts go through `pluralRo` ("20 de anvelope").
- The phone number and schedule are hard-coded in both HTML files (links, copy, JSON-LD) **and** in `config.js`; change all of them together.
