# Brutalist — Build Report

Theme slug: `brutalist`
Module path: `git.dev.alexdunmow.com/block/themes/brutalist`
Tech: templ-style (gotham-pattern), per spec §11.
Implementation pass: wave-1 (fonts policy applies — `fonts.json = []`).

## What landed

### Module + metadata
- `plugin.mod` per spec §2 verbatim: `kind = "theme"`, `scope = "@themes"`, `version = "0.1.0"`, `categories = ["templates"]`, tags array exactly the 8 spec values, `[compatibility] block_core = ">=0.11.0 <0.12.0"`.
- `go.mod` pinned to `git.dev.alexdunmow.com/block/core v0.11.1`, `go 1.26.4`, no `replace` directives.
- `Makefile` default target builds `brutalist.so` via `CGO_ENABLED=1 go build -buildmode=plugin`. No `rebuild` target (per agent scope; deploy is explicit).

### System / page templates / blocks
- System template registered: `brutalist` ("Brutalist", spec description verbatim).
- 4 page templates registered with exact spec slot arrays:
  - `default` → `{header, main, footer}` → `RenderBrutalist`
  - `landing` ("Index Sheet") → `{hero, ledger, footer}` → `RenderBrutalistLanding`
  - `article` ("Case Study") → `{header, meta, main, footer}` → `RenderBrutalistArticle`
  - `full-width` ("Full Bleed") → `{header, main, footer}` → `RenderBrutalistFullWidth`
- 7 theme blocks registered (all `Source: "brutalist"`):
  - `masthead`, `project_ledger`, `concrete_hero`, `meta_strip`, `caption_image`, `pull_quote`, `colophon`
- 4 built-in block overrides via `RegisterTemplateOverride("brutalist", ...)`:
  - `heading`, `text`, `button`, `image` — spec §9 treatments (square corners, font-display, mono code, figure wrapping).
- Email wrapper registered via `tr.RegisterEmailWrapper("brutalist", BrutalistEmailWrapper)`.

### Master pages
3 master pages in `DefaultMasterPages()` per spec §7 row-by-row:
- `brutalist:default-master` → templates `[default, article]`, blocks navbar/masthead/slot(main)/colophon(showAddress=true)
- `brutalist:index-master` → template `[landing]`, blocks masthead(hero)/slot(ledger)/colophon(showAddress=true)
- `brutalist:fullbleed-master` → template `[full-width]`, blocks navbar/slot(main)/colophon(showAddress=false)

### Schemas
7 draft-07 schemas in `schemas/<key>.schema.json`. `x-editor` values used: `text`, `richtext`, `media`, `select`, `textarea`, `collection`, `link`. All inside the allowed set per CLAUDE.md.
- `br.LoadSchemasFromFS(Schemas())` is called BEFORE any `br.Register(...)` in `register.go` — verified by reading top-to-bottom.

### Presets
`presets.json` ships two presets:
- `concrete-red` (mode `both`) with `lightColors` + `darkColors`, all 19 tokens each, HSL triple strings only.
- `hazard-yellow` (mode `dark`) with both `darkColors` and a mirror `lightColors` for editor preview, all 19 tokens each.
- Spot values from spec verbatim: `concrete-red.lightColors.background = "40 14% 93%"`, `concrete-red.lightColors.primary = "4 86% 48%"`, `hazard-yellow.darkColors.primary = "48 100% 50%"`, `hazard-yellow.darkColors.background = "0 0% 6%"`.
- check-safety presets check (Check 21): OK.

### CSS
`CSSManifest.InputCSSAppend` ships utility CSS via `ThemeCSSManifest()`:
- `:where(.brutalist-page, .brutalist-page *) { border-radius: 0 !important; }` (kills rounding theme-wide).
- `.brutalist-display`, `.brutalist-mono` font utilities flowing through `var(--font-heading|body|mono, <fallback-stack>)`.
- Hairline / thick rule utilities (`.brutalist-rule-ink`, `.brutalist-rule-thick`, `.brutalist-divider`).
- 12-column grid scaffolding (`.brutalist-grid-12`, `.brutalist-col-span-8`).
- Block-specific styles for `.brutalist-masthead`, `.brutalist-hero`, `.brutalist-ledger-row`, `.brutalist-meta-strip`, `.brutalist-pullquote`, `.brutalist-figure figcaption`, `.brutalist-colophon`.
- Square buttons + hover-invert-to-accent (spec §9 button override surface).
- Togglable `body.brutalist-grid-debug` 12-col overlay (UAT §13.11).
- All color references go through `hsl(var(--token))`; no hex/rgb/named colors anywhere in `*.go`, `*.templ`, or the appended CSS (Check 6 OK).

### Fonts (wave-1 policy)
- `fonts.json = []` (per FONTS.md override of spec §5 / UAT §11).
- `assets/` contains only a `.gitkeep`; no woff2 bundled.
- All `font-family` declarations in templates and CSS go through `var(--font-heading|body|mono, <fallback>)` with fallback stacks derived from the spec typography list (Space Grotesk → Inter Tight → Helvetica; Inter → -apple-system → Segoe UI; JetBrains Mono → IBM Plex Mono → ui-monospace).
- `RECOMMENDED_FONTS.md` written at the theme root listing the spec §5 fonts as Google Fonts picker recommendations with admin instructions.

## Build output

```
$ make
CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o brutalist.so .

$ ls -la brutalist.so
-rw-rw-r-- 1 alex alex 21522624 brutalist.so
```

- File: `brutalist.so` (~20.5 MB; gotham reference `.so` is 21.1 MB, lcars is similar).
- No stderr warnings.
- `templ generate` produced 13 `_templ.go` files (committed alongside `.templ` sources).

## Safety check

Run from the actual check-safety location (the path in the spec's instructions points at `~/src/blockninja/backend/cmd/check-safety` but the real tool lives at `~/src/blockninja/check-safety/`).

```
$ cd /home/alex/src/blockninja/check-safety
$ go run . /home/alex/src/blockninja/themes/brutalist --plugin-dir /home/alex/src/blockninja/themes/brutalist
... (all 22 checks)
exit=0
```

Key results:
- **Check 2c** (Standalone plugin SDK import boundaries): OK — pinned to v0.11.1, no `replace` directives.
- **Check 3** (Go lint pipeline): OK after dropping unused `brutalistAccent`, `brutalistAccentFg`, `brutalistEmailCTAStyle`, and `renderPage` helpers.
- **Check 6** (No hardcoded colors in .templ): OK — all color references use `hsl(var(--token))`.
- **Check 11** (No placeholder code): OK.
- **Check 17** (No TODO markers): OK.
- **Check 21** (presets.json validation): OK.
- **Check 22** (No hand-rolled HTML sanitization): OK.

Warnings (non-fatal):
- **Check 2e** (`any` usage): 30 warnings, all from the required SDK signature `func(ctx context.Context, content map[string]any) string` and `MasterPageBlock.Content map[string]any`. Cannot be removed without breaking the SDK contract; same surface gotham exposes.

Overall: **exit 0, plugin builds, safety passes.**

## Open items / deferred

These items are explicitly deferred per the agent's hard scope rules ("local-build only, no woff2 bundling, no live deploy, no screenshots") and the FONTS.md wave-1 policy:

1. **Bundled woff2 files** — wave-2 follow-up. Currently `fonts.json = []`; `RECOMMENDED_FONTS.md` covers the admin path until Space Grotesk, Inter, and JetBrains Mono are bundled.
2. **`LICENSES.md`** — not written this pass (FONTS.md §"Wave-1 implementation policy" explicitly says "No `LICENSES.md` needed in this pass").
3. **Marketplace screenshots (spec §13.1)** — 6 frames at 1440×900 deferred until a running CMS instance is available; agent scope says "no `make rebuild`".
4. **Demo-content seed (spec §13.2)** — not implemented in this pass.
5. **`make rebuild` against running CMS** — UAT §2 "instance-brutalist Up within 15s" check cannot run from this agent's scope; needs a live instance.
6. **UAT §6, §7, §13 runtime checks** — accessibility, responsive, and aesthetic gates require a running container and visual verification; out of scope for the build agent.
7. **Email wrapper Litmus/cross-client verification (UAT §10)** — wrapper compiles and registers; live capture testing deferred.
8. **`concrete_hero.media` video support** (spec open question) — schema is `media` (image only) per the spec, deferred to v0.2 if the media type needs to widen.

## File inventory

```
brutalist/
├── BUILD_REPORT.md
├── Makefile
├── RECOMMENDED_FONTS.md
├── assets/
│   └── .gitkeep
├── brutalist.so
├── button_override.go
├── button_override.templ
├── button_override_templ.go
├── caption_image.go
├── caption_image.templ
├── caption_image_templ.go
├── colophon.go
├── colophon.templ
├── colophon_templ.go
├── concrete_hero.go
├── concrete_hero.templ
├── concrete_hero_templ.go
├── css_append.go
├── email_wrapper.go
├── email_wrapper.templ
├── email_wrapper_templ.go
├── embed.go
├── fonts.json
├── go.mod
├── go.sum
├── heading_override.go
├── heading_override.templ
├── heading_override_templ.go
├── helpers.go
├── image_override.go
├── image_override.templ
├── image_override_templ.go
├── masthead.go
├── masthead.templ
├── masthead_templ.go
├── meta_strip.go
├── meta_strip.templ
├── meta_strip_templ.go
├── page_data.go
├── plugin.mod
├── presets.json
├── project_ledger.go
├── project_ledger.templ
├── project_ledger_templ.go
├── pull_quote.go
├── pull_quote.templ
├── pull_quote_templ.go
├── register.go
├── registration.go
├── schemas/
│   ├── caption_image.schema.json
│   ├── colophon.schema.json
│   ├── concrete_hero.schema.json
│   ├── masthead.schema.json
│   ├── meta_strip.schema.json
│   ├── project_ledger.schema.json
│   └── pull_quote.schema.json
├── template.templ
├── template_templ.go
├── text_override.go
├── text_override.templ
└── text_override_templ.go
```

7 blocks, 7 schemas, 4 page templates, 4 built-in overrides, 1 email wrapper, 3 master pages, 2 presets. brutalist.so 21.5 MB. Safety check exit 0.
