# Art Deco — Build Report
Status: **SHIPPED**.
Compiled `.so` produced and the safety check exits 0.
## What landed
### Plugin metadata (`plugin.mod`)
- `kind = "theme"`, `scope = "@themes"`, `version = "0.1.0"`.
- `categories = ["templates"]` (single whitelist entry).
- `tags = ["luxury", "gold", "hospitality", "hotel", "wedding", "jewellery", "vintage", "glam", "fine-dining"]` (9 tags, within the 5–9 UAT range).
- `[compatibility].block_core = ">=0.11.0 <0.12.0"`.
### System & page templates
- System template registered with `Key: "art-deco"`.
- 4 page templates registered:
- `default` → slots `header, main, footer`.
- `landing` → slots `marquee, main, cta, footer`.
- `article` → slots `header, main, aside, footer`.
- `full-width` → slots `header, main, footer`.
### Blocks (7, all `Source: "art-deco"`)
| Key | Schema | Notes |
|---|---|---|
| `reservation` | `schemas/reservation.schema.json` | Sticky gold-on-black strip with phone, OpenTable CTA, hours. |
| `menu` | `schemas/menu.schema.json` | Symmetric menu card with rich-text course descriptions and prices. |
| `gallery_fan` | `schemas/gallery_fan.schema.json` | Mirrored gallery framed by sunburst, 2/3/4 columns, collapses to 1 col <640px. |
| `divider_fan` | `schemas/divider_fan.schema.json` | Pure-CSS sunburst / scallop / ziggurat divider — falls back to sunburst on unknown variant. |
| `footer` | `schemas/footer.schema.json` | Centered footer with gold rule, address, reservations email, social row, menu name. |
| `marquee_hero` | `schemas/marquee_hero.schema.json` | Wide hero with stepped ziggurat frame and sunburst overlay. |
| `press_quote` | `schemas/press_quote.schema.json` | Italic Cormorant pull-quote with stars (clamped 0–5). |
Schemas are loaded BEFORE any `br.Register(...)` call (line ordering enforced in `register.go`).
### Template overrides (4)
- `heading` — caps tracking + hairline gold underline, Italiana display family.
- `text` — Cormorant body with italic drop-cap on first paragraph.
- `button` — black pill with gold border, stamped inset shadow on hover/focus.
- `image` — stepped ziggurat frame variant (also scallop / plain).
### Email wrapper
- `tr.RegisterEmailWrapper("art-deco", ArtDecoEmailWrapper)` wired.
- 600px centered column, ivory body, jet-black masthead.
- Masthead uses a flat-gold SVG `
` (not a CSS gradient) so Outlook renders it correctly.
- Reservation phone / `SupportEmail` auto-injected as italic postscript line.
### Master pages (2)
- `art-deco:default-master` covers `default`, `article` — `navbar` (header,0), `art-deco:divider_fan` (header,1,sunburst), `slot` (main,0,slotName=main), `art-deco:footer` (footer,0).
- `art-deco:marquee-master` covers `landing`, `full-width` — `navbar` (marquee,0), `art-deco:reservation` (marquee,1), `slot` (main,0,slotName=main), `art-deco:divider_fan` (cta,0,scallop), `art-deco:footer` (footer,0).
### Presets (`presets.json`, 3)
- `champagne-noir` (`mode: both`, lightColors + darkColors, all 19 tokens each).
- `ivory-rose` (`mode: light`, lightColors only, all 19 tokens).
- `velvet-onyx` (`mode: dark`, darkColors only, all 19 tokens).
- Every value is an HSL triple `H S% L%` — no `hsl(...)` wrappers, no hex.
### CSS manifest
- `CSSManifest.InputCSSAppend` registered via `ThemeCSSManifest()` in `embed.go`/`registration.go`.
- The injected CSS declares `@layer utilities` blocks for `.deco-rule`, `.deco-frame`, `.deco-step`, `.deco-grain`, plus aesthetic helpers `.deco-foil`, `.deco-sunburst`, `.deco-scallop`, `.deco-ziggurat`, `.deco-caps`, `.deco-dropcap`, `.deco-underline`, `.deco-pill`, `.deco-link`.
- All colour values consume `hsl(var(--token))`; all `font-family` declarations go through `var(--font-heading|body|mono, )`.
### Fonts policy (Wave-1)
- `fonts.json = []` (no bundled woff2s in this pass).
- `RECOMMENDED_FONTS.md` lists the spec §5 fonts as Google Fonts picker recommendations (Italiana, Cormorant Garamond, JetBrains Mono).
- Fallback stacks for `--font-heading`, `--font-body`, `--font-mono` are embedded inline in every template + utility.
## Build output
```
$ cd ~/src/blockninja/themes/art-deco && go mod tidy
(no output — clean)
$ /home/alex/go/bin/templ generate
(✓) Complete [ updates=13 duration=… ]
$ make
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o art-deco.so .
$ ls -lh art-deco.so
-rw-rw-r-- 1 alex alex 21M art-deco.so
```
## Safety check
```
$ cd ~/src/blockninja/check-safety && go run . ~/src/blockninja/themes/art-deco \
--plugin-dir ~/src/blockninja/themes/art-deco
…
=== Check 2c: Standalone plugin SDK import boundaries ===
OK: Standalone plugin imports and go.mod stay on SDK version v0.11.1
=== Check 3: Go code compiles and passes go fix, golangci-lint --fix, go vet, and strict lint ===
OK: Go lint pipeline clean for 1 module(s)
=== Check 6: No hardcoded colors in frontend (use theme tokens) ===
OK: No hardcoded colors in .templ files
=== Check 11: No placeholder code; only shipped features ===
OK: No placeholder code found
…
exit=0
```
Only WARN remaining is Check 2e (`any` usage in `content map[string]any` signatures). This is the
exact same warning Gotham emits — it is the standalone-plugin block signature contract and is
non-blocking.
## Open items / deferred
### Wave-1 deferrals (intentional, per `themes/docs/FONTS.md`)
- **No bundled woff2 fonts**. Theme ships `fonts.json = []` and a `RECOMMENDED_FONTS.md` for the
admin to pick Italiana / Cormorant Garamond / JetBrains Mono from the Google Fonts tab.
- **No `LICENSES.md`** — nothing is bundled.
### Wave-2 follow-ups (out of scope for this pass)
- Commission a redistributable Art Deco display face (Italiana variants are limited) and bundle
via `fonts.json` if Italiana proves brittle at retina sizes. UAT §11 FOUT timing and the licence
audit only become checkable once a face is bundled.
- Capture the 6 UAT marketplace screenshots (`docs/uat/art-deco-shots/01..06.png`). Requires
a running CMS instance — outside the autonomous build scope.
- Seed the "Maison Étoile" demo content (6 pages, 4 courses, 1 press quote, 9 gallery images).
Same constraint as above — requires the instance container.
- Run the UAT browser-side gates: WCAG contrast pairs, focus-visible ring sweep, viewport
scroll-width checks at 360/768/1024/1440. The CSS is wired to satisfy them but the verification
is an instance-side workflow.
- Master-page UAT cell "Replacing `art-deco:footer` on `default-master` in admin produces a
ghost-free re-render" — admin-side verification, not a build-side check.
### Not implemented (called out by spec but explicitly listed in BUILD_REPORT)
- `make rebuild` and the container deploy targets — by build-instructions, `make rebuild` is
off-limits to the autonomous build pass. The Makefile here ships only `all`, `templ`, `clean`,
`help` — production deploy is reserved for the gotham-style upstream Makefile and a human run.
- Real woff2 bundles in `assets/fonts/` — deferred to Wave-2 per FONTS.md.
## File inventory
```
art-deco/
├── BUILD_REPORT.md ← this file
├── Makefile ← local-only build (make, make templ, make clean)
├── RECOMMENDED_FONTS.md ← Wave-1 Google Fonts picker guide
├── assets/style.css ← @layer utilities CSS (foil, frame, fan, grain, pill…)
├── button_override.{go,templ,_templ.go}
├── divider_fan.{go,templ,_templ.go}
├── email_wrapper.{templ,_templ.go}
├── embed.go ← //go:embed directives + CSSManifest hook
├── fonts.json ← []
├── footer.{go,templ,_templ.go}
├── gallery_fan.{go,templ,_templ.go}
├── go.{mod,sum} ← block/core v0.11.1, no replace directives
├── heading_override.{go,templ,_templ.go}
├── helpers.go ← getString / getInt / getSlice / getStringSlice / clampInt
├── image_override.{go,templ,_templ.go}
├── marquee_hero.{go,templ,_templ.go}
├── menu.{go,templ,_templ.go}
├── plugin.mod ← TOML metadata, kind=theme
├── presets.json ← 3 presets, 19 tokens each, HSL triples
├── press_quote.{go,templ,_templ.go}
├── press_quote_helpers.go
├── register.go ← Register(tr,br) + DefaultMasterPages()
├── registration.go ← var Registration plugin.PluginRegistration
├── reservation.{go,templ,_templ.go}
├── schemas/
│ ├── divider_fan.schema.json
│ ├── footer.schema.json
│ ├── gallery_fan.schema.json
│ ├── marquee_hero.schema.json
│ ├── menu.schema.json
│ ├── press_quote.schema.json
│ └── reservation.schema.json
├── template.templ + template_templ.go
└── text_override.{go,templ,_templ.go}
```