# 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} ```