diff --git a/BUILD_REPORT.md b/BUILD_REPORT.md
deleted file mode 100644
index 6260341..0000000
--- a/BUILD_REPORT.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Corporate Modernist — build report
-
-## What landed
-
-### Module / metadata
-- `go.mod` — `git.dev.alexdunmow.com/block/themes/corporate-modernist`, `go 1.26.4`, `block/core v0.11.1`, `templ v0.3.1020`. No `replace` directives.
-- `plugin.mod` — `name = "corporate-modernist"`, `scope = "@themes"`, `kind = "theme"`, `version = "0.1.0"`, `categories = ["templates"]`, `tags` set to the 8 forward-declared values per spec §2, `[compatibility] block_core = ">=0.11.0 <0.12.0"`.
-- `Makefile` — local-only. `make` builds the `.so` via `CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w"`. `make templ` regenerates the `*_templ.go` files; `make clean` removes the artifact. No `rebuild` target — wave-1 policy keeps this off live CMS containers.
-- `embed.go` — canonical `//go:embed` directives for `assets/*`, `schemas/*`, `presets.json`, `fonts.json`, `plugin.mod`. Accessors: `Assets`, `Schemas`, `AssetsHandler`, `ThemePresets`, `BundledFonts`.
-- `registration.go` — single `var Registration plugin.PluginRegistration`. Wires `Assets`, `Schemas`, `ThemePresets`, `BundledFonts`, `MasterPages`, and `CSSManifest`. Version is `plugin.ParseModVersion(pluginModBytes)`.
-
-### System / page templates
-- System template `corporate-modernist` registered once.
-- Page templates registered with the slot sets from spec §6:
- - `default` — `[header, main, footer]`, capped at 1280px content well.
- - `landing` — `[hero, main, cta, footer]`.
- - `article` — `[header, main, aside, footer]`, centred `cm-article-measure` band.
- - `full-width` — `[header, main, footer]`, edge-to-edge sections, internal grid kept.
-- Renderer entry points: `RenderCM`, `RenderCMLanding`, `RenderCMArticle`, `RenderCMFullWidth` (see `template.templ`).
-
-### Blocks
-Eight theme-owned blocks, each registered with `Source = "corporate-modernist"` and a draft-07 JSON Schema. Standalone-plugin signature `(ctx, content) string`:
-
-| Key | Category | Source files |
-|---|---|---|
-| `hero_statement` | layout | `hero_statement.go`, `hero_statement.templ`, `schemas/hero_statement.schema.json` |
-| `logo_strip` | content | `logo_strip.*`, schema |
-| `testimonial_quote` | content | `testimonial_quote.*`, schema |
-| `case_study_card` | content | `case_study_card.*`, schema |
-| `leadership_grid` | content | `leadership_grid.*`, schema |
-| `stat_pair` | content | `stat_pair.*`, schema |
-| `cta_strip` | layout | `cta_strip.*`, schema |
-| `footer` | navigation | `footer.*`, schema |
-
-`br.LoadSchemasFromFS(Schemas())` is called before any `br.Register` call (see `register.go`).
-
-### Block overrides
-- `heading` — `CorporateModernistHeadingBlock` / `heading_override.templ`: tighter tracking, accent underline on H2.
-- `text` — `CorporateModernistTextBlock` / `text_override.templ`: Inter at 17/28, tabular figures, hanging punctuation.
-- `button` — `CorporateModernistButtonBlock` / `button_override.templ`: squared 4px corners, accent fill or 1px outline, no shadow, no gradient.
-- `card` — `CorporateModernistCardBlock` / `card_override.templ`: flat hairline surface, optional accent top rule.
-
-### Master pages
-`DefaultMasterPages()` returns the two seeded definitions from spec §7:
-- `corporate-modernist:default-master` — templates `[default, article]`; blocks: `navbar` (header), `slot {slotName: main}` (main), `corporate-modernist:footer {variant: compact, showLegal: true}` (footer).
-- `corporate-modernist:landing-master` — templates `[landing, full-width]`; blocks: `navbar`, `corporate-modernist:hero_statement {eyebrow, headline}`, `slot {slotName: main}`, `corporate-modernist:cta_strip {variant: book-call}`, `corporate-modernist:footer {variant: full, showLegal: true}`.
-
-### Presets
-`presets.json` ships the three locked presets from spec §4, each `mode: "both"` with full 19-token `lightColors` + `darkColors` blocks. All values are HSL triple strings (`"218 65% 22%"`); no `hsl()` wrappers.
-
-| id | name | accent (light) | accent (dark) |
-|---|---|---|---|
-| `navy-classic` | Navy Classic | `218 65% 22%` | `218 70% 60%` |
-| `forest-quiet` | Forest Quiet | `155 45% 22%` | `155 50% 55%` |
-| `burgundy-tradition` | Burgundy Tradition | `350 55% 30%` | `350 60% 60%` |
-
-### Fonts (wave-1 policy)
-- `fonts.json = []` per `docs/FONTS.md`. No woff2 files bundled.
-- CSS uses `var(--font-heading)` / `var(--font-body)` / `var(--font-mono)` exclusively, with the spec §3 typography stack baked in as the fallback list (Inter Tight → Inter → system-ui; JetBrains Mono → ui-monospace).
-- `RECOMMENDED_FONTS.md` documents the Google Fonts picker recommendations for the three families (`Inter Tight`, `Inter`, `JetBrains Mono`).
-
-### CSS strategy
-- `assets/style.css` holds the self-contained theme stylesheet served at `/templates/corporate-modernist/style.css`. Uses `hsl(var(--token))` exclusively; no hex literals, no `rgb(`/`rgba(` calls, no banned named colours.
-- `registration.go` exposes the same `.cm-*` rules to the host Tailwind input via `CSSManifest.InputCSSAppend` (`css_manifest.go`). No `@font-face` blocks are injected here — `fonts.json` is empty, so the CMS would have nothing to upsert; per FONTS.md the wrapper supplies CSS variable fallbacks instead.
-
-### Email wrapper
-- `CorporateModernistEmailWrapper` registered via `tr.RegisterEmailWrapper("corporate-modernist", …)`.
-- 600px wrapper, paper-white surface, single accent rule beneath the header, footer with site name, optional unsubscribe link.
-- Tokens are locked to the navy-classic light preset (per spec §10). Colours are expressed as `hsl(H S% L%)` (HSL function syntax, no hex / no `rgb()`) and gated through `var(--cm-email-*, hsl(…))` fallbacks declared in `
` so the check-safety inline-colour rule is satisfied.
-
-## Build output
-
-```
-$ cd /home/alex/src/blockninja/themes/corporate-modernist
-$ go mod tidy # OK, populated go.sum
-$ /home/alex/go/bin/templ generate # OK, 14 *_templ.go files produced
-$ make
-CGO_ENABLED=1 go build -buildmode=plugin -ldflags="-s -w" -o corporate-modernist.so .
-$ ls -la corporate-modernist.so
--rw-rw-r-- 1 alex alex 21581920 corporate-modernist.so # ~20.6 MB
-```
-
-No warnings emitted by `go build` (`-ldflags="-s -w"`). Default Makefile target produces `corporate-modernist.so` in one invocation; no live-CMS deployment touched.
-
-## Safety check
-
-The brief points at `/home/alex/src/blockninja/backend/cmd/check-safety`; in this checkout the safety tool lives at `/home/alex/src/blockninja/check-safety` (standalone module). The functionally equivalent invocation:
-
-```
-$ cd /home/alex/src/blockninja/check-safety
-$ go run . /home/alex/src/blockninja/themes/corporate-modernist
-…
-EXITCODE=0
-```
-
-All gating checks pass:
-
-- Check 1 — secret env reads: OK
-- Check 2c — standalone plugin SDK boundary: OK on `block/core v0.11.1`, no `replace` directives.
-- Check 3 — Go lint pipeline (`go fix` / `golangci-lint` / `go vet` / strict lints): OK.
-- Check 6 — no hardcoded colours in `.templ`: OK (inline styles use `var(--cm-email-*)` fallbacks where colour rules are present).
-- Check 10 — plugin frontend discovery: OK.
-- Check 11 — no placeholder code: OK (renamed `cm-img-placeholder` → `cm-img-empty`).
-- Check 17 — no TODO markers: OK.
-- Check 21 — presets.json validates against `theme.Theme`: OK.
-- Check 22 — no hand-rolled HTML sanitization: OK.
-
-One non-blocking advisory:
-
-- Check 2e — "warn on `any` usage": 32 WARN. Block render functions use `map[string]any` because that is the standalone-plugin SDK signature (`blocks.BlockFunc`); typed parsing happens inside each block's `*Block` function. WARN is non-fatal and the script's exit code remains `0`.
-
-## Open items / deferred
-
-- **Live CMS verification (UAT §2 deploy gate)** — `make rebuild`, `podman ps` "Up" check, and `instance-corporate-modernist` log scan are deferred. This pass is local-build only per the brief's hard scope rules.
-- **Visual screenshots (UAT §12)** — the six 1440×900 marketplace shots (`01-navy-landing-hero` … `06-navy-dark`) require a running container; not produced in this pass.
-- **Meridian Advisory demo seed (UAT §12)** — 4 case studies / 6 bios / 8 client logos / 3 testimonials / 2 long-form posts are not seeded; needs CMS RPCs.
-- **Marketplace launch copy / preview banner** — `marketplace/launch-copy.txt` not authored in this pass.
-- **Bundled fonts** — per wave-1 policy (`docs/FONTS.md`), `fonts.json = []`. Wave-2 will revisit Inter Tight / Inter / JetBrains Mono via Google Fonts integration; commercial bundling is not on the roadmap because these are already curated Google Fonts.
-- **`LICENSES.md`** — not produced this pass (FONTS.md §"Wave-1 implementation policy" item 4 explicitly waives this until any woff2 is bundled).
-- **Browser-driven aesthetic checks (UAT §13)** — items 1, 4, 5, 6 etc require a running site to read `getComputedStyle(...)`. The corresponding CSS (`.cm-content-well`, `cm-swiss-12`, `cm-btn-primary`, `cm-metric`) is shipped and uses the required tokens; verification is deferred to the container pass.
-- **Tailwind grid token `swiss-12` mapping** — implemented as a custom CSS class (`.cm-swiss-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }`) inside `CSSManifest.InputCSSAppend`. The UAT §13.3 grep expects this in `tailwind.config*`; the implementation chose CSS-manifest injection because standalone themes don't ship `tailwind.config.js`. A future pass can add a host-side Tailwind extension if the grep is enforced literally.
-- **Accessibility ratio sign-off (UAT §6)** — preset combinations should each clear AA contrast; the tokens come straight from the spec but no automated audit ran this pass.
-- **Plugin-version sync to git tag (UAT §1)** — `plugin.mod` ships `0.1.0` and the repo is not yet tagged; tagging is a release-pass task.
-- **Frontend-discovery deeper hooks** — none registered (no admin pages, no settings panels). The theme has no editor extensions for v0.1.0.
-- **`.gitignore`** — not authored this pass; `.so` artifacts are in scope for the host `.gitignore` (the brief explicitly says "commit *_templ.go, ignore *.so"). Add as part of the release pass.
diff --git a/RECOMMENDED_FONTS.md b/RECOMMENDED_FONTS.md
index e8682ad..1afee54 100644
--- a/RECOMMENDED_FONTS.md
+++ b/RECOMMENDED_FONTS.md
@@ -1,57 +1,36 @@
-# Recommended fonts — Corporate Modernist
+# Corporate Modernist — recommended fonts
-This theme ships `fonts.json = []`; it does not bundle any woff2 files. The
-CSS uses `var(--font-heading)`, `var(--font-body)`, and `var(--font-mono)`
-with system-font fallback stacks so the design holds together before an
-admin assigns fonts.
+This theme **bundles** two libre families (OFL-1.1) so it renders on-brand with
+no admin setup:
-Per `docs/FONTS.md`, the spec's typography list is treated as **recommended
-Google Fonts**. Open the theme's typography panel in the BlockNinja admin,
-pick from the Google Fonts tab, and assign each family to the matching slot.
+| Slot | Bundled family | Role |
+|------|----------------|------|
+| Heading | **Inter** | Grotesque display and UI. Tight tracking, 600 weight for headlines. |
+| Body | **Inter** | 17px/28px body with tabular figures. |
+| Mono | **JetBrains Mono** | Oversized numerals, stats, prices, metadata. Tabular by design. |
-## Heading / display — `Inter Tight`
+Bundled files live in `assets/fonts/` (latin subsets); licenses in
+`assets/fonts/LICENSES.md`. The theme CSS resolves every family through
+`var(--font-heading | --font-body | --font-mono, )`, and the fallback
+stacks name the bundled families, so the identity holds even before an admin
+touches the typography panel.
-- Source: `google:Inter Tight`
-- Where to assign: Open the typography panel, pick "Inter Tight" from the
- Google Fonts tab, assign to **Heading**.
-- Why: Tight tracking, restrained letterforms, sits closer to Vignelli
- Helvetica than stock Inter — the spec calls for "Inter Tight for display
- and UI."
+## Optional upgrades (Google Fonts tab)
-## Body / long-form — `Inter`
+The locked direction also allows two display alternatives. Both are OFL and in
+the curated Google Fonts picker. Assign them from **Admin → Theme → Typography
+→ Google Fonts** if you want more geometric character:
-- Source: `google:Inter`
-- Where to assign: Open the typography panel, pick "Inter" from the Google
- Fonts tab, assign to **Body**.
-- Why: Pair Inter Tight for display with Inter for body to keep the rhythm
- intact at the 17/28 reading size.
+| Slot | Source | Family | Why |
+|------|--------|--------|-----|
+| Heading | `google:Archivo` | Archivo | Grotesque with a wider, more architectural feel than Inter. A drop-in for the Heading slot. |
+| Numerals | `google:Space Grotesk` | Space Grotesk | The signature oversized-numeral face in the locked direction. Assign to Mono for stat figures and metrics. |
-## Mono / figures — `JetBrains Mono`
+## How to apply an override
-- Source: `google:JetBrains Mono`
-- Where to assign: Open the typography panel, pick "JetBrains Mono" from the
- Google Fonts tab, assign to **Mono**.
-- Why: Used for `stat_pair` figures and `case_study_card` metrics. Tabular
- numerals are critical for financial table alignment.
-
-## Quick set-up summary
-
-1. Open **Admin → Typography**.
+1. Open **Admin → Theme → Typography**.
2. Switch to the **Google Fonts** tab.
-3. Pick `Inter Tight`, `Inter`, and `JetBrains Mono` in turn — each "Add"
- click stages the family for the site's font registry.
-4. Assign:
- - **Heading** → Inter Tight
- - **Body** → Inter
- - **Mono** → JetBrains Mono
-5. Save. The CMS will emit `@import` URLs for each Google font and the
- `--font-heading`, `--font-body`, `--font-mono` custom properties update
- automatically.
-
-## Why no bundled woff2s
-
-Wave-1 implementation policy in `docs/FONTS.md` asks every theme to ship
-`fonts.json = []` in this build pass. Wave-2 will revisit bundling for
-themes whose identity hinges on a commercial display face. For
-Corporate Modernist all three recommended families are already in the
-Google Fonts curated list, so bundling is unnecessary even long-term.
+3. Search and pick the family.
+4. Assign it to the matching slot (Heading / Body / Mono).
+5. Save. The pick is stored as `google:` and binds the `--font-*`
+ variable, overriding the bundled fallback.
diff --git a/RECOMMENDED_ICONS.md b/RECOMMENDED_ICONS.md
new file mode 100644
index 0000000..885368e
--- /dev/null
+++ b/RECOMMENDED_ICONS.md
@@ -0,0 +1,16 @@
+# Corporate Modernist — required icon packs
+
+The theme renders icons via the sprite system only
+(` ` and the `::pack:name::`
+shorthand). It declares its packs in `manifest.yaml` `required_icon_packs`.
+Until the loader auto-installs declared packs, install them by hand before
+activation.
+
+| Pack | Used for | Install |
+|------|----------|---------|
+| **lucide** | All UI accents: arrows, chevrons, checks, geometric marks, contact channels, nav, play controls. Bundled with the CMS. | Ships with the CMS. Verify it is enabled at `/admin/icons`. |
+| **simple-icons** | Brand marks on author-bio-hero and social links (X, LinkedIn, GitHub). Bundled with the CMS. | Ships with the CMS. Enable at `/admin/icons` if not already active. |
+
+Both packs ship with BlockNinja, so no npm download is needed. If a block picks
+an icon from a different pack, install that pack at `/admin/icons` first
+(`lucide` is the safe default fallback for any icon-picker field).
diff --git a/assets/fonts/LICENSES.md b/assets/fonts/LICENSES.md
new file mode 100644
index 0000000..96b2ca0
--- /dev/null
+++ b/assets/fonts/LICENSES.md
@@ -0,0 +1,19 @@
+# Bundled font licenses
+
+Both bundled families are libre and redistributable. Latin subsets only.
+
+## Inter
+
+- Files: `inter-latin-400.woff2`, `inter-latin-500.woff2`, `inter-latin-600.woff2`, `inter-latin-700.woff2`
+- Family: Inter (Rasmus Andersson)
+- License: SIL Open Font License 1.1 (OFL-1.1)
+- Source: https://github.com/rsms/inter — latin subset as distributed by @fontsource / google-webfonts-helper (inter-v12-latin).
+
+## JetBrains Mono
+
+- File: `jetbrains-mono-latin.woff2` (variable, weight axis 100-800; theme uses 400 and 500)
+- Family: JetBrains Mono (JetBrains)
+- License: SIL Open Font License 1.1 (OFL-1.1)
+- Source: https://github.com/JetBrains/JetBrainsMono — latin subset as distributed by @fontsource-variable/jetbrains-mono.
+
+The full OFL-1.1 text applies to both. See https://openfontlicense.org.
diff --git a/assets/fonts/inter-latin-400.woff2 b/assets/fonts/inter-latin-400.woff2
new file mode 100644
index 0000000..c659f5e
Binary files /dev/null and b/assets/fonts/inter-latin-400.woff2 differ
diff --git a/assets/fonts/inter-latin-500.woff2 b/assets/fonts/inter-latin-500.woff2
new file mode 100644
index 0000000..6fc94ad
Binary files /dev/null and b/assets/fonts/inter-latin-500.woff2 differ
diff --git a/assets/fonts/inter-latin-600.woff2 b/assets/fonts/inter-latin-600.woff2
new file mode 100644
index 0000000..bc76d10
Binary files /dev/null and b/assets/fonts/inter-latin-600.woff2 differ
diff --git a/assets/fonts/inter-latin-700.woff2 b/assets/fonts/inter-latin-700.woff2
new file mode 100644
index 0000000..8fcc432
Binary files /dev/null and b/assets/fonts/inter-latin-700.woff2 differ
diff --git a/assets/fonts/jetbrains-mono-latin.woff2 b/assets/fonts/jetbrains-mono-latin.woff2
new file mode 100644
index 0000000..cd5102a
Binary files /dev/null and b/assets/fonts/jetbrains-mono-latin.woff2 differ
diff --git a/blocks/blocks.yaml b/blocks/blocks.yaml
index 6c93b14..33adffb 100644
--- a/blocks/blocks.yaml
+++ b/blocks/blocks.yaml
@@ -1,54 +1,34 @@
-# Corporate Modernist theme block definitions (codeless .bnp, WO-WZ-021).
+# Corporate Modernist theme block definitions (codeless .bnp, WO-TF-014).
# Keys are fully qualified (corporate-modernist:) because the codeless loader
# registers definitions verbatim — there is no PluginBlockRegistry prefixing in the
# codeless path (unlike the wasm/templ path). The qualified keys match the hardcoded
-# data-block attributes and the master_pages.json references.
+# data-block attributes and the master_pages.json / seed references.
+#
+# Only true persona furniture stays a theme block. Everything that duplicated a
+# builtin (hero, logo strip, testimonial, team grid, stats, cta, footer) is now a
+# template override of the builtin key instead (templates/overrides/...).
blocks:
- - key: corporate-modernist:hero_statement
- title: Hero Statement
- description: Restrained hero with eyebrow, headline, lede, and a single accent CTA.
- category: layout
- schema: hero_statement.schema.json
- template: hero_statement.ninjatpl
- - key: corporate-modernist:logo_strip
- title: Client Logo Strip
- description: Row of client logos, greyscale until hover.
- category: content
- schema: logo_strip.schema.json
- template: logo_strip.ninjatpl
- - key: corporate-modernist:testimonial_quote
- title: Testimonial
- description: Pull-quote testimonial with attribution, headshot, and company mark.
- category: content
- schema: testimonial_quote.schema.json
- template: testimonial_quote.ninjatpl
- key: corporate-modernist:case_study_card
title: Case Study Card
- description: Single case study card with a big tabular metric.
+ description: Single engagement case with an oversized tabular metric and outcome.
category: content
schema: case_study_card.schema.json
template: case_study_card.ninjatpl
- - key: corporate-modernist:leadership_grid
- title: Leadership Grid
- description: Responsive 2/3/4-up grid of leadership profiles.
+ - key: corporate-modernist:capability_matrix
+ title: Capability Matrix
+ description: Swiss-grid matrix of service capabilities, each with a Bauhaus mark.
category: content
- schema: leadership_grid.schema.json
- template: leadership_grid.ninjatpl
- - key: corporate-modernist:stat_pair
- title: Stat Pair
- description: Row of mono-numeral statistics separated by a hairline rule.
+ schema: capability_matrix.schema.json
+ template: capability_matrix.ninjatpl
+ - key: corporate-modernist:engagement_process
+ title: Engagement Process
+ description: Numbered engagement phases on a hairline rail with oversized numerals.
category: content
- schema: stat_pair.schema.json
- template: stat_pair.ninjatpl
- - key: corporate-modernist:cta_strip
- title: CTA Strip
- description: Single-line accent strip with a headline and a primary call to action.
- category: layout
- schema: cta_strip.schema.json
- template: cta_strip.ninjatpl
- - key: corporate-modernist:footer
- title: Footer
- description: Multi-column footer with legal line; compact and full variants.
- category: navigation
- schema: footer.schema.json
- template: footer.ninjatpl
+ schema: engagement_process.schema.json
+ template: engagement_process.ninjatpl
+ - key: corporate-modernist:credential_bar
+ title: Credential Bar
+ description: Row of firm credentials (years, offices, sectors) as mono figures.
+ category: content
+ schema: credential_bar.schema.json
+ template: credential_bar.ninjatpl
diff --git a/blocks/capability_matrix.ninjatpl b/blocks/capability_matrix.ninjatpl
new file mode 100644
index 0000000..df25d56
--- /dev/null
+++ b/blocks/capability_matrix.ninjatpl
@@ -0,0 +1 @@
+{% if eyebrow %}
{{ eyebrow }}
{% endif %}{% if heading %}
{{ heading }} {% endif %}{% if intro %}
{{ intro }}
{% endif %}{% if capabilities %}
{% for cap in capabilities %}
{% if cap.title %}
{{ cap.title }} {% endif %}{% if cap.text %}
{{ cap.text }}
{% endif %}
{% endfor %}
{% else %}
No capabilities configured.
{% endif %}
diff --git a/blocks/capability_matrix.schema.json b/blocks/capability_matrix.schema.json
new file mode 100644
index 0000000..85e51e2
--- /dev/null
+++ b/blocks/capability_matrix.schema.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Capability Matrix",
+ "description": "Swiss-grid matrix of service capabilities.",
+ "type": "object",
+ "properties": {
+ "eyebrow": { "type": "string", "title": "Eyebrow", "x-editor": "text" },
+ "heading": { "type": "string", "title": "Heading", "x-editor": "text" },
+ "intro": { "type": "string", "title": "Intro", "x-editor": "textarea" },
+ "columns": {
+ "type": "integer",
+ "title": "Columns",
+ "enum": [2, 3, 4],
+ "default": 3,
+ "x-editor": "select"
+ },
+ "capabilities": {
+ "type": "array",
+ "title": "Capabilities",
+ "x-editor": "collection",
+ "items": {
+ "type": "object",
+ "properties": {
+ "mark": {
+ "type": "string",
+ "title": "Mark",
+ "description": "Bauhaus mark: circle, triangle, or square",
+ "enum": ["circle", "triangle", "square"],
+ "default": "square",
+ "x-editor": "select"
+ },
+ "title": { "type": "string", "title": "Title", "x-editor": "text" },
+ "text": { "type": "string", "title": "Description", "x-editor": "textarea" }
+ }
+ }
+ }
+ }
+}
diff --git a/blocks/credential_bar.ninjatpl b/blocks/credential_bar.ninjatpl
new file mode 100644
index 0000000..13043b8
--- /dev/null
+++ b/blocks/credential_bar.ninjatpl
@@ -0,0 +1 @@
+{% if items %}
{% for item in items %}
{% if item.figure %}
{{ item.figure }}
{% endif %}{% if item.label %}
{{ item.label }}
{% endif %}
{% endfor %}
{% else %}
No credentials configured.
{% endif %}
diff --git a/blocks/credential_bar.schema.json b/blocks/credential_bar.schema.json
new file mode 100644
index 0000000..30c4733
--- /dev/null
+++ b/blocks/credential_bar.schema.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Credential Bar",
+ "description": "Row of firm credentials as mono figures on a hairline rule.",
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "title": "Credentials",
+ "x-editor": "collection",
+ "items": {
+ "type": "object",
+ "properties": {
+ "figure": { "type": "string", "title": "Figure", "description": "e.g. \"18\", \"6\", \"200+\"", "x-editor": "text" },
+ "label": { "type": "string", "title": "Label", "x-editor": "text" }
+ }
+ }
+ }
+ }
+}
diff --git a/blocks/cta_strip.ninjatpl b/blocks/cta_strip.ninjatpl
deleted file mode 100644
index 26350f4..0000000
--- a/blocks/cta_strip.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/blocks/cta_strip.schema.json b/blocks/cta_strip.schema.json
deleted file mode 100644
index 6778448..0000000
--- a/blocks/cta_strip.schema.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "CTA Strip",
- "description": "Single-line accent strip with a headline and a primary call to action.",
- "type": "object",
- "properties": {
- "headline": {
- "type": "string",
- "title": "Headline",
- "x-editor": "text"
- },
- "primaryCta": {
- "type": "object",
- "title": "Primary CTA",
- "x-editor": "link",
- "properties": {
- "label": { "type": "string", "title": "Label" },
- "href": { "type": "string", "title": "Href" }
- }
- },
- "variant": {
- "type": "string",
- "title": "Variant",
- "description": "Visual treatment for the strip",
- "x-editor": "select",
- "enum": ["book-call", "download", "quiet"],
- "default": "book-call"
- }
- }
-}
diff --git a/blocks/engagement_process.ninjatpl b/blocks/engagement_process.ninjatpl
new file mode 100644
index 0000000..3004e97
--- /dev/null
+++ b/blocks/engagement_process.ninjatpl
@@ -0,0 +1 @@
+{% if eyebrow %}
{{ eyebrow }}
{% endif %}{% if heading %}
{{ heading }} {% endif %}{% if intro %}
{{ intro }}
{% endif %}{% if steps %}
{% for step in steps %}
{{ forloop.Counter }} {% if not forloop.Last %} {% endif %}
{% if step.title %}
{{ step.title }} {% endif %}{% if step.text %}
{{ step.text }}
{% endif %}
{% endfor %}
{% else %}
No steps configured.
{% endif %}
diff --git a/blocks/engagement_process.schema.json b/blocks/engagement_process.schema.json
new file mode 100644
index 0000000..c6a890e
--- /dev/null
+++ b/blocks/engagement_process.schema.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Engagement Process",
+ "description": "Numbered engagement phases on a hairline rail.",
+ "type": "object",
+ "properties": {
+ "eyebrow": { "type": "string", "title": "Eyebrow", "x-editor": "text" },
+ "heading": { "type": "string", "title": "Heading", "x-editor": "text" },
+ "intro": { "type": "string", "title": "Intro", "x-editor": "textarea" },
+ "steps": {
+ "type": "array",
+ "title": "Steps",
+ "x-editor": "collection",
+ "items": {
+ "type": "object",
+ "properties": {
+ "title": { "type": "string", "title": "Title", "x-editor": "text" },
+ "text": { "type": "string", "title": "Description", "x-editor": "textarea" }
+ }
+ }
+ }
+ }
+}
diff --git a/blocks/footer.ninjatpl b/blocks/footer.ninjatpl
deleted file mode 100644
index 44d0731..0000000
--- a/blocks/footer.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/blocks/footer.schema.json b/blocks/footer.schema.json
deleted file mode 100644
index 559cd91..0000000
--- a/blocks/footer.schema.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Footer",
- "description": "Multi-column footer with legal line, available in compact and full variants.",
- "type": "object",
- "properties": {
- "columns": {
- "type": "array",
- "title": "Columns",
- "description": "Each column lists a title and a set of links",
- "default": [],
- "x-editor": "collection",
- "items": {
- "type": "object",
- "properties": {
- "title": { "type": "string", "title": "Title", "x-editor": "text" },
- "links": {
- "type": "array",
- "title": "Links",
- "x-editor": "collection",
- "items": {
- "type": "object",
- "properties": {
- "label": { "type": "string", "title": "Label", "x-editor": "text" },
- "href": { "type": "string", "title": "Href", "x-editor": "link" }
- }
- }
- }
- }
- }
- },
- "legalLine": {
- "type": "string",
- "title": "Legal line",
- "description": "Copyright or compliance statement",
- "x-editor": "text"
- },
- "showLegal": {
- "type": "boolean",
- "title": "Show legal line",
- "default": true,
- "x-editor": "select"
- },
- "variant": {
- "type": "string",
- "title": "Variant",
- "x-editor": "select",
- "enum": ["compact", "full"],
- "default": "compact"
- }
- }
-}
diff --git a/blocks/hero_statement.ninjatpl b/blocks/hero_statement.ninjatpl
deleted file mode 100644
index 71ad6dd..0000000
--- a/blocks/hero_statement.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-{% if eyebrow %}
{{ eyebrow }}
{% endif %}{% if headline %}
{{ headline }} {% endif %}{% if lede %}
{{ lede }}
{% endif %}{% if primaryCta.label or primaryCta.text or primaryCta.href or primaryCta.url or secondaryCta.label or secondaryCta.text or secondaryCta.href or secondaryCta.url %}
{% endif %}
diff --git a/blocks/hero_statement.schema.json b/blocks/hero_statement.schema.json
deleted file mode 100644
index e1578bf..0000000
--- a/blocks/hero_statement.schema.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Hero Statement",
- "description": "Restrained hero with eyebrow, headline, lede, and a single accent CTA (plus optional outline secondary).",
- "type": "object",
- "properties": {
- "eyebrow": {
- "type": "string",
- "title": "Eyebrow",
- "description": "Small uppercase label above the headline",
- "x-editor": "text"
- },
- "headline": {
- "type": "string",
- "title": "Headline",
- "description": "Lead statement, typically one short sentence",
- "x-editor": "text"
- },
- "lede": {
- "type": "string",
- "title": "Lede",
- "description": "Supporting paragraph below the headline",
- "x-editor": "textarea"
- },
- "primaryCta": {
- "type": "object",
- "title": "Primary CTA",
- "description": "Accent-filled call to action",
- "x-editor": "link",
- "properties": {
- "label": { "type": "string", "title": "Label" },
- "href": { "type": "string", "title": "Href" }
- }
- },
- "secondaryCta": {
- "type": "object",
- "title": "Secondary CTA",
- "description": "Optional outline call to action",
- "x-editor": "link",
- "properties": {
- "label": { "type": "string", "title": "Label" },
- "href": { "type": "string", "title": "Href" }
- }
- }
- }
-}
diff --git a/blocks/leadership_grid.ninjatpl b/blocks/leadership_grid.ninjatpl
deleted file mode 100644
index c4d6f4c..0000000
--- a/blocks/leadership_grid.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-{% if title %}
{{ title }} {% endif %}{% if members %}
{% for m in members %}{% if m.name %}
{% if m.photo %} {% else %} {% endif %}{{ m.name }}
{% if m.role %}{{ m.role }}
{% endif %}{% if m.bio %}{{ m.bio }}
{% endif %}{% if m.linkedin %}{% endif %} {% endif %}{% endfor %}
{% else %}
No team members configured.
{% endif %}
diff --git a/blocks/leadership_grid.schema.json b/blocks/leadership_grid.schema.json
deleted file mode 100644
index 1922497..0000000
--- a/blocks/leadership_grid.schema.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Leadership Grid",
- "description": "Responsive 2/3/4-up grid of leadership profiles.",
- "type": "object",
- "properties": {
- "title": {
- "type": "string",
- "title": "Title",
- "description": "Section title above the grid",
- "x-editor": "text"
- },
- "members": {
- "type": "array",
- "title": "Members",
- "description": "Each member is a card with photo, name, role, short bio, and optional LinkedIn link",
- "default": [],
- "x-editor": "collection",
- "items": {
- "type": "object",
- "properties": {
- "name": { "type": "string", "title": "Name", "x-editor": "text" },
- "role": { "type": "string", "title": "Role", "x-editor": "text" },
- "bio": { "type": "string", "title": "Bio", "x-editor": "textarea" },
- "photo": { "type": "string", "title": "Photo", "x-editor": "media" },
- "linkedin": { "type": "string", "title": "LinkedIn URL", "x-editor": "link" }
- },
- "required": ["name"]
- }
- }
- }
-}
diff --git a/blocks/logo_strip.ninjatpl b/blocks/logo_strip.ninjatpl
deleted file mode 100644
index 7207d11..0000000
--- a/blocks/logo_strip.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-{% if caption %}
{{ caption }}
{% endif %}{% if logos %}
{% else %}
No client logos configured.
{% endif %}
diff --git a/blocks/logo_strip.schema.json b/blocks/logo_strip.schema.json
deleted file mode 100644
index a87e925..0000000
--- a/blocks/logo_strip.schema.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Client Logo Strip",
- "description": "Row of client logos rendered greyscale until hover.",
- "type": "object",
- "properties": {
- "caption": {
- "type": "string",
- "title": "Caption",
- "description": "Short heading above the logo row",
- "x-editor": "text"
- },
- "logos": {
- "type": "array",
- "title": "Logos",
- "description": "Client logos shown in a single restrained row",
- "default": [],
- "x-editor": "collection",
- "items": {
- "type": "object",
- "properties": {
- "src": {
- "type": "string",
- "title": "Image",
- "x-editor": "media"
- },
- "alt": {
- "type": "string",
- "title": "Alt text",
- "x-editor": "text"
- },
- "href": {
- "type": "string",
- "title": "Link",
- "x-editor": "link"
- }
- },
- "required": ["alt"]
- }
- }
- }
-}
diff --git a/blocks/stat_pair.ninjatpl b/blocks/stat_pair.ninjatpl
deleted file mode 100644
index 96bc3fe..0000000
--- a/blocks/stat_pair.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-{% if title %}
{{ title }} {% endif %}{% if stats %}
{% for s in stats %}{% if s.figure %}
{{ s.figure }}
{% if s.label %}
{{ s.label }}
{% endif %}{% if s.source %}
{{ s.source }}
{% endif %}
{% endif %}{% endfor %}
{% else %}
No statistics configured.
{% endif %}
diff --git a/blocks/stat_pair.schema.json b/blocks/stat_pair.schema.json
deleted file mode 100644
index 4ca74a1..0000000
--- a/blocks/stat_pair.schema.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Stat Pair",
- "description": "Pair (or row) of mono-numeral statistics, separated by a hairline rule.",
- "type": "object",
- "properties": {
- "title": {
- "type": "string",
- "title": "Title",
- "description": "Optional title above the stats row",
- "x-editor": "text"
- },
- "stats": {
- "type": "array",
- "title": "Stats",
- "description": "Individual statistic entries",
- "default": [],
- "x-editor": "collection",
- "items": {
- "type": "object",
- "properties": {
- "figure": { "type": "string", "title": "Figure", "x-editor": "text" },
- "label": { "type": "string", "title": "Label", "x-editor": "text" },
- "source": { "type": "string", "title": "Source", "x-editor": "text" }
- },
- "required": ["figure"]
- }
- }
- }
-}
diff --git a/blocks/testimonial_quote.ninjatpl b/blocks/testimonial_quote.ninjatpl
deleted file mode 100644
index ac52b46..0000000
--- a/blocks/testimonial_quote.ninjatpl
+++ /dev/null
@@ -1 +0,0 @@
-{% if quote %}{{ quote }} {% else %}No testimonial provided. {% endif %}{% if headshot %} {% else %} {% endif %}{% if name %}
{{ name }}
{% endif %}{% if role or company %}
{% if role and company %}{{ role }}, {{ company }}{% elif role %}{{ role }}{% else %}{{ company }}{% endif %}
{% endif %}
{% if logo %} {% endif %}
diff --git a/blocks/testimonial_quote.schema.json b/blocks/testimonial_quote.schema.json
deleted file mode 100644
index e7346ca..0000000
--- a/blocks/testimonial_quote.schema.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "Testimonial",
- "description": "Pull-quote testimonial with attribution and optional headshot and company logo.",
- "type": "object",
- "properties": {
- "quote": {
- "type": "string",
- "title": "Quote",
- "description": "Testimonial body text",
- "x-editor": "textarea"
- },
- "name": {
- "type": "string",
- "title": "Name",
- "x-editor": "text"
- },
- "role": {
- "type": "string",
- "title": "Role",
- "x-editor": "text"
- },
- "company": {
- "type": "string",
- "title": "Company",
- "x-editor": "text"
- },
- "headshot": {
- "type": "string",
- "title": "Headshot",
- "description": "Portrait image of the quoted person",
- "x-editor": "media"
- },
- "logo": {
- "type": "string",
- "title": "Company logo",
- "description": "Optional company mark beside the attribution",
- "x-editor": "media"
- }
- }
-}
diff --git a/fonts.json b/fonts.json
index fe51488..218e7cd 100644
--- a/fonts.json
+++ b/fonts.json
@@ -1 +1,20 @@
-[]
+[
+ {
+ "name": "Inter",
+ "family": "Inter",
+ "variants": [
+ { "weight": "400", "style": "normal", "file": "fonts/inter-latin-400.woff2" },
+ { "weight": "500", "style": "normal", "file": "fonts/inter-latin-500.woff2" },
+ { "weight": "600", "style": "normal", "file": "fonts/inter-latin-600.woff2" },
+ { "weight": "700", "style": "normal", "file": "fonts/inter-latin-700.woff2" }
+ ]
+ },
+ {
+ "name": "JetBrains Mono",
+ "family": "JetBrains Mono",
+ "variants": [
+ { "weight": "400", "style": "normal", "file": "fonts/jetbrains-mono-latin.woff2" },
+ { "weight": "500", "style": "normal", "file": "fonts/jetbrains-mono-latin.woff2" }
+ ]
+ }
+]
diff --git a/manifest.yaml b/manifest.yaml
index 1d9ea5b..b278053 100644
--- a/manifest.yaml
+++ b/manifest.yaml
@@ -1,13 +1,22 @@
-# Corporate Modernist theme — codeless .bnp manifest (WO-WZ-021 Phase B).
+# Corporate Modernist theme — codeless .bnp manifest (WO-TF-014, Wave A).
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
+#
+# Identity: Swiss grid disciplined by Bauhaus geometric accents (circle /
+# triangle / square), oversized tabular numerals, hairline dividers. Restrained
+# B2B-consultancy authority. Light = gallery white + graphite ink; dark =
+# graphite boardroom. Motion is CSS-first (no canvas, no JS showpiece).
theme_presets: presets.json
bundled_fonts: fonts.json
master_pages: master_pages.json
+required_icon_packs:
+ - lucide
+ - simple-icons
+
system_templates:
- key: corporate-modernist
title: Corporate Modernist
- description: "Swiss-grid B2B theme with restrained typography, a single configurable accent, and trust-signal blocks for enterprise sites."
+ description: "Swiss-grid B2B theme with restrained typography, a single configurable accent, oversized numerals, and trust-signal chrome for consultancy and enterprise sites."
page_templates:
- system: corporate-modernist
@@ -15,6 +24,11 @@ page_templates:
title: Default
description: "Header + 12-col main + footer, capped at 1280px."
slots: [header, main, footer]
+ - system: corporate-modernist
+ key: full-width
+ title: Full width
+ description: "Edge-to-edge sections; internal grid kept."
+ slots: [header, main, footer]
- system: corporate-modernist
key: landing
title: Landing
@@ -26,60 +40,315 @@ page_templates:
description: "Centered measure for long-form thought leadership."
slots: [header, main, aside, footer]
- system: corporate-modernist
- key: full-width
- title: Full width
- description: "Edge-to-edge sections, internal grid kept."
- slots: [header, main, footer]
+ key: blog-index
+ title: Blog index
+ description: "Title band, featured lead, and a hairline-ruled post grid."
+ slots: [header, featured, main, footer]
+ - system: corporate-modernist
+ key: contact
+ title: Contact
+ description: "Two-column contact: form on the grid, details in the aside."
+ slots: [header, main, aside, footer]
+ - system: corporate-modernist
+ key: auth
+ title: Auth
+ description: "Centered card on a quiet ground for login and reset surfaces."
+ slots: [main, footer]
template_overrides:
+ # Chrome (4)
+ - { template: corporate-modernist, block: navbar }
+ - { template: corporate-modernist, block: footer }
+ - { template: corporate-modernist, block: utility-bar }
+ - { template: corporate-modernist, block: announcement-bar }
+ # Marketing (12)
+ - { template: corporate-modernist, block: hero }
+ - { template: corporate-modernist, block: feature-grid }
+ - { template: corporate-modernist, block: rich-section }
+ - { template: corporate-modernist, block: stats }
+ - { template: corporate-modernist, block: testimonial }
+ - { template: corporate-modernist, block: logo-strip }
+ - { template: corporate-modernist, block: pricing }
+ - { template: corporate-modernist, block: team }
+ - { template: corporate-modernist, block: faq }
+ - { template: corporate-modernist, block: timeline }
+ - { template: corporate-modernist, block: cta }
+ - { template: corporate-modernist, block: countdown }
+ # Primitives (11)
- { template: corporate-modernist, block: heading }
- { template: corporate-modernist, block: text }
+ - { template: corporate-modernist, block: rich-text }
+ - { template: corporate-modernist, block: image }
+ - { template: corporate-modernist, block: quote }
+ - { template: corporate-modernist, block: divider }
- { template: corporate-modernist, block: button }
- { template: corporate-modernist, block: card }
+ - { template: corporate-modernist, block: gallery }
+ - { template: corporate-modernist, block: video-embed }
+ - { template: corporate-modernist, block: audio-embed }
+ # Commerce / local (6)
+ - { template: corporate-modernist, block: menu-list }
+ - { template: corporate-modernist, block: event-list }
+ - { template: corporate-modernist, block: contact-form }
+ - { template: corporate-modernist, block: contact-card }
+ - { template: corporate-modernist, block: hours-location }
+ - { template: corporate-modernist, block: social-links }
+ # Blog family (12)
+ - { template: corporate-modernist, block: blog-hero }
+ - { template: corporate-modernist, block: featured-posts }
+ - { template: corporate-modernist, block: related-posts }
+ - { template: corporate-modernist, block: popular-posts }
+ - { template: corporate-modernist, block: category-list }
+ - { template: corporate-modernist, block: post-hero }
+ - { template: corporate-modernist, block: post-metadata }
+ - { template: corporate-modernist, block: author-bio }
+ - { template: corporate-modernist, block: author-bio-hero }
+ - { template: corporate-modernist, block: newsletter-signup }
+ - { template: corporate-modernist, block: breadcrumbs }
+ - { template: corporate-modernist, block: sidebar-nav }
+ # Auth surface (3)
+ - { template: corporate-modernist, block: auth-form }
+ - { template: corporate-modernist, block: password-reset-form }
+ - { template: corporate-modernist, block: auth-status }
+ # System (1)
+ - { template: corporate-modernist, block: page-suggestions }
email_wrappers:
- corporate-modernist
css:
input_css_append: |
- /* Corporate Modernist — appended utility CSS. */
+ /* ============================================================
+ Corporate Modernist — appended component CSS.
+ Semantic tokens only: hsl(var(--token)). No literal colors.
+ Swiss grid + Bauhaus geometric marks + oversized numerals.
+ ============================================================ */
+
+ /* --- Layout primitives --- */
.cm-content-well { width: 100%; max-width: 1280px; margin-left: auto; margin-right: auto; padding-left: 1.5rem; padding-right: 1.5rem; box-sizing: border-box; }
+ .cm-measure { max-width: 70ch; }
.cm-swiss-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 1.5rem; row-gap: 1.5rem; }
- .cm-hairline { border-color: hsl(var(--border)); border-width: 1px; border-style: solid; }
+ .cm-section { padding-top: 4rem; padding-bottom: 4rem; }
+ .cm-section-tight { padding-top: 2.5rem; padding-bottom: 2.5rem; }
+ .cm-hairline { border: 1px solid hsl(var(--border)); }
.cm-hairline-top { border-top: 1px solid hsl(var(--border)); }
.cm-hairline-bottom { border-bottom: 1px solid hsl(var(--border)); }
- .numeric-tabular { font-variant-numeric: tabular-nums; }
- .cm-display { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; }
- .cm-body { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; font-variant-numeric: tabular-nums; }
- .cm-mono { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; }
+ .cm-hairline-y > * + * { border-top: 1px solid hsl(var(--border)); }
.cm-accent-rule { border-top: 2px solid hsl(var(--accent)); }
- .cm-btn-primary { display: inline-block; padding: 0.625rem 1.25rem; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border: 1px solid hsl(var(--accent)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: background-color 150ms ease; }
+ .cm-stack > * + * { margin-top: 1.5rem; }
+ .cm-stack-sm > * + * { margin-top: 0.75rem; }
+
+ /* --- Typography --- */
+ .cm-display { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; color: hsl(var(--foreground)); margin: 0; }
+ .cm-body { font-family: var(--font-body, "Inter", system-ui, sans-serif); }
+ .cm-mono { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; }
+ .numeric-tabular { font-variant-numeric: tabular-nums; }
+ .cm-heading { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; color: hsl(var(--foreground)); margin: 0; }
+ .cm-heading-h2-accent { border-bottom: 2px solid hsl(var(--accent)); padding-bottom: 0.25rem; display: inline-block; }
+ .cm-text { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); font-variant-numeric: tabular-nums; }
+ .cm-text a { color: hsl(var(--accent)); text-decoration: underline; text-underline-offset: 2px; }
+ .cm-text strong { font-weight: 600; }
+ .cm-lede { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 1.25rem; line-height: 1.6; color: hsl(var(--muted-foreground)); }
+ .cm-eyebrow { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-size: 0.8125rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.12em; color: hsl(var(--accent)); margin: 0 0 1rem 0; }
+ .cm-kicker { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; color: hsl(var(--muted-foreground)); }
+
+ /* --- Bauhaus geometric marks (circle / triangle / square) --- */
+ .cm-mark { display: inline-block; width: 0.75rem; height: 0.75rem; flex: none; }
+ .cm-mark-circle { border-radius: 9999px; background-color: hsl(var(--accent)); }
+ .cm-mark-square { background-color: hsl(var(--accent)); }
+ .cm-mark-triangle { width: 0; height: 0; border-left: 0.4375rem solid transparent; border-right: 0.4375rem solid transparent; border-bottom: 0.75rem solid hsl(var(--accent)); background: none; }
+ .cm-mark-ring { border-radius: 9999px; background: none; border: 2px solid hsl(var(--accent)); }
+
+ /* --- Numerals / metrics (oversized signature) --- */
+ .cm-metric { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: clamp(2.5rem, 5vw, 3.5rem); line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--accent)); letter-spacing: -0.02em; }
+ .cm-stat-figure { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: clamp(2.25rem, 4vw, 3rem); line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); letter-spacing: -0.02em; }
+ .cm-stat-label { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.8125rem; color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 0.5rem; }
+ .cm-numeral-index { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 2rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--accent)); }
+
+ /* --- Buttons (squared, flat, no gradient/shadow) --- */
+ .cm-btn-primary { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.625rem 1.25rem; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border: 1px solid hsl(var(--accent)); border-radius: 4px; font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: background-color 150ms ease; cursor: pointer; }
.cm-btn-primary:hover { background-color: hsl(var(--accent) / 0.9); }
.cm-btn-primary:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
- .cm-btn-outline { display: inline-block; padding: 0.625rem 1.25rem; background-color: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: border-color 150ms ease; }
+ .cm-btn-outline { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.625rem 1.25rem; background-color: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; box-shadow: none; background-image: none; transition: border-color 150ms ease, color 150ms ease; cursor: pointer; }
.cm-btn-outline:hover { border-color: hsl(var(--foreground)); }
.cm-btn-outline:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; }
+ .cm-btn-ghost { display: inline-flex; align-items: center; gap: 0.375rem; color: hsl(var(--accent)); font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 500; text-decoration: none; line-height: 1.4; transition: gap 150ms ease; }
+ .cm-btn-ghost:hover { gap: 0.625rem; }
+ .cm-btn-sm { padding: 0.375rem 0.875rem; font-size: 0.875rem; }
+ .cm-btn-lg { padding: 0.875rem 1.75rem; font-size: 1.0625rem; }
+ .cm-btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
+ .cm-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.125em; }
+
+ /* --- Surfaces / cards --- */
.cm-card { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); border-radius: 4px; padding: 1.5rem; box-shadow: none; }
- .cm-card.cm-card-accent { border-top: 2px solid hsl(var(--accent)); }
- .cm-heading { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; color: hsl(var(--foreground)); margin: 0; }
- .cm-heading-h2-accent { border-bottom: 2px solid hsl(var(--accent)); padding-bottom: 0.25rem; display: inline-block; }
- .cm-text { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); font-variant-numeric: tabular-nums; hanging-punctuation: first last; }
- .cm-logo { filter: grayscale(1); opacity: 0.7; transition: filter 200ms ease, opacity 200ms ease; }
- .cm-logo:hover { filter: grayscale(0); opacity: 1; }
- .cm-pull-quote { border-top: 2px solid hsl(var(--accent)); padding-top: 1.25rem; font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 1.5rem; line-height: 1.4; font-weight: 500; color: hsl(var(--foreground)); }
- .cm-metric { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 3rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--accent)); }
- .cm-stat-figure { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 2.5rem; line-height: 1; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); }
- .cm-stat-label { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.875rem; color: hsl(var(--muted-foreground)); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.5rem; }
- .cm-eyebrow { font-family: var(--font-heading, "Inter Tight", "Inter", system-ui, sans-serif); font-size: 0.875rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.1em; color: hsl(var(--accent)); margin-bottom: 1rem; }
- .cm-cta-strip-accent { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
- .cm-cta-strip-accent .cm-btn-primary { background-color: hsl(var(--accent-foreground)); color: hsl(var(--accent)); border-color: hsl(var(--accent-foreground)); }
- .cm-cta-strip-quiet { background-color: hsl(var(--muted)); color: hsl(var(--foreground)); }
- .cm-footer { background-color: hsl(var(--background)); color: hsl(var(--foreground)); border-top: 1px solid hsl(var(--border)); padding: 3rem 0; }
- .cm-footer-legal { color: hsl(var(--muted-foreground)); font-size: 0.875rem; border-top: 1px solid hsl(var(--border)); padding-top: 1.5rem; margin-top: 2rem; }
- .cm-leadership-grid { display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); gap: 1.5rem; }
+ .cm-card-accent { border-top: 2px solid hsl(var(--accent)); }
+ .cm-panel { background-color: hsl(var(--muted)); border-radius: 4px; padding: 1.5rem; }
+ .cm-surface-muted { background-color: hsl(var(--muted)); }
+ .cm-surface-card { background-color: hsl(var(--card)); }
+ .cm-media-frame { display: block; width: 100%; overflow: hidden; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }
+ .cm-media-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
+ .cm-img-empty { display: block; width: 100%; aspect-ratio: 4 / 3; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }
+
+ /* --- Responsive grids --- */
+ .cm-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(1, minmax(0, 1fr)); }
+ @media (min-width: 640px) { .cm-grid-2, .cm-grid-3, .cm-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+ @media (min-width: 1024px) { .cm-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .cm-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
+ .cm-leadership-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(1, minmax(0, 1fr)); }
@media (min-width: 640px) { .cm-leadership-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cm-leadership-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .cm-leadership-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
- .cm-article-measure { max-width: 70ch; margin-left: auto; margin-right: auto; font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 17px; line-height: 28px; color: hsl(var(--foreground)); }
- .cm-section { padding-top: 4rem; padding-bottom: 4rem; }
- .cm-img-empty { display: block; width: 100%; aspect-ratio: 4 / 3; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }
+
+ /* --- Chrome: navbar --- */
+ .cm-navbar { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: 1.25rem 0; }
+ .cm-brand { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 700; font-size: 1.125rem; letter-spacing: -0.01em; color: hsl(var(--foreground)); text-decoration: none; display: inline-flex; align-items: center; gap: 0.625rem; }
+ .cm-nav-links { display: none; align-items: center; gap: 2rem; }
+ @media (min-width: 768px) { .cm-nav-links { display: flex; } }
+ .cm-nav-link { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.9375rem; color: hsl(var(--foreground)); text-decoration: none; padding-bottom: 2px; border-bottom: 2px solid transparent; transition: border-color 150ms ease; }
+ .cm-nav-link:hover { border-bottom-color: hsl(var(--accent)); }
+ .cm-nav-toggle { display: inline-flex; }
+ @media (min-width: 768px) { .cm-nav-toggle { display: none; } }
+ .cm-nav-drawer { display: none; flex-direction: column; gap: 0.25rem; padding: 0.5rem 0 1rem; border-top: 1px solid hsl(var(--border)); width: 100%; }
+ @media (min-width: 768px) { .cm-nav-drawer { display: none !important; } }
+ .cm-nav-drawer a { padding: 0.625rem 0; font-family: var(--font-body, "Inter", system-ui, sans-serif); color: hsl(var(--foreground)); text-decoration: none; border-bottom: 1px solid hsl(var(--border)); }
+
+ /* --- Chrome: utility bar + announcement bar --- */
+ .cm-utility-bar { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.8125rem; padding: 0.5rem 0; }
+ .cm-utility-bar--muted { background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
+ .cm-utility-bar--primary { background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); }
+ .cm-utility-bar--dark { background-color: hsl(var(--foreground)); color: hsl(var(--background)); }
+ .cm-utility-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
+ .cm-utility-group { display: flex; align-items: center; gap: 1.25rem; }
+ .cm-utility-item { display: inline-flex; align-items: center; gap: 0.375rem; color: inherit; text-decoration: none; }
+ .cm-announce { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.875rem; padding: 0.625rem 0; }
+ .cm-announce--info { background-color: hsl(var(--muted)); color: hsl(var(--foreground)); }
+ .cm-announce--promo { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
+ .cm-announce--alert { background-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); }
+ .cm-announce-row { display: flex; align-items: center; justify-content: center; gap: 0.75rem; }
+ .cm-announce a { color: inherit; text-decoration: underline; text-underline-offset: 2px; font-weight: 600; }
+ .cm-announce-close { margin-left: auto; background: none; border: 0; color: inherit; cursor: pointer; line-height: 1; padding: 0 0.25rem; }
+
+ /* --- Chrome: footer --- */
+ .cm-footer { background-color: hsl(var(--background)); color: hsl(var(--foreground)); border-top: 2px solid hsl(var(--accent)); padding: 3.5rem 0 2.5rem; }
+ .cm-footer-cols { display: grid; gap: 2rem; grid-template-columns: repeat(1, minmax(0, 1fr)); }
+ @media (min-width: 640px) { .cm-footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+ @media (min-width: 1024px) { .cm-footer-cols { grid-template-columns: 2fr repeat(3, 1fr); } }
+ .cm-footer-head { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-size: 0.8125rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: hsl(var(--muted-foreground)); margin: 0 0 0.875rem; }
+ .cm-footer-link { display: block; font-size: 0.9375rem; color: hsl(var(--foreground)); text-decoration: none; padding: 0.25rem 0; }
+ .cm-footer-link:hover { color: hsl(var(--accent)); }
+ .cm-footer-legal { color: hsl(var(--muted-foreground)); font-size: 0.8125rem; border-top: 1px solid hsl(var(--border)); padding-top: 1.5rem; margin-top: 2.5rem; display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; }
+
+ /* --- Marketing: hero --- */
+ .cm-hero { padding: 5rem 0; }
+ .cm-hero-headline { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.03em; line-height: 1.05; font-size: clamp(2.5rem, 6vw, 4.5rem); color: hsl(var(--foreground)); margin: 0; }
+ .cm-hero-sub { font-size: clamp(1.125rem, 2vw, 1.5rem); line-height: 1.5; color: hsl(var(--muted-foreground)); margin: 1.25rem 0 0; }
+ .cm-hero-split { display: grid; gap: 3rem; grid-template-columns: repeat(1, minmax(0, 1fr)); align-items: center; }
+ @media (min-width: 1024px) { .cm-hero-split { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+
+ /* --- Marketing: logo strip --- */
+ .cm-logo { filter: grayscale(1); opacity: 0.65; transition: filter 200ms ease, opacity 200ms ease; }
+ .cm-logo:hover { filter: grayscale(0); opacity: 1; }
+ .cm-logo-row { display: flex; flex-wrap: wrap; align-items: center; gap: 2.5rem; }
+
+ /* --- Marketing: feature grid --- */
+ .cm-feature { border-top: 2px solid hsl(var(--accent)); padding-top: 1.25rem; }
+ .cm-feature-title { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; font-size: 1.125rem; color: hsl(var(--foreground)); margin: 0.75rem 0 0.5rem; }
+
+ /* --- Marketing: pull quote / testimonial --- */
+ .cm-pull-quote { border-top: 2px solid hsl(var(--accent)); padding-top: 1.25rem; font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-size: 1.5rem; line-height: 1.4; font-weight: 500; color: hsl(var(--foreground)); }
+ .cm-quote-block { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-size: 1.375rem; line-height: 1.45; font-weight: 500; color: hsl(var(--foreground)); }
+ .cm-quote-cite { font-size: 0.875rem; color: hsl(var(--muted-foreground)); margin-top: 0.75rem; }
+ .cm-avatar { width: 2.75rem; height: 2.75rem; border-radius: 9999px; object-fit: cover; background-color: hsl(var(--muted)); }
+
+ /* --- Marketing: pricing --- */
+ .cm-price { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 2.5rem; font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); letter-spacing: -0.02em; }
+ .cm-price-period { font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 0.9375rem; color: hsl(var(--muted-foreground)); }
+ .cm-price-tier { display: flex; flex-direction: column; }
+ .cm-price-tier--featured { border-top: 4px solid hsl(var(--accent)); }
+ .cm-badge { display: inline-block; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.6875rem; letter-spacing: 0.08em; text-transform: uppercase; padding: 0.25rem 0.5rem; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border-radius: 3px; }
+ .cm-check { color: hsl(var(--accent)); flex: none; }
+
+ /* --- Marketing: faq --- */
+ .cm-faq-item { border-top: 1px solid hsl(var(--border)); }
+ .cm-faq-item summary { cursor: pointer; list-style: none; padding: 1.25rem 0; display: flex; align-items: center; justify-content: space-between; gap: 1rem; font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; color: hsl(var(--foreground)); }
+ .cm-faq-item summary::-webkit-details-marker { display: none; }
+ .cm-faq-item[open] summary .cm-faq-chevron { transform: rotate(180deg); }
+ .cm-faq-chevron { transition: transform 150ms ease; color: hsl(var(--accent)); }
+ .cm-faq-answer { padding: 0 0 1.25rem; color: hsl(var(--muted-foreground)); font-size: 1rem; line-height: 1.65; }
+
+ /* --- Marketing: timeline --- */
+ .cm-timeline-step { display: grid; grid-template-columns: auto 1fr; gap: 1.25rem; padding-bottom: 2rem; }
+ .cm-timeline-rail { position: relative; display: flex; flex-direction: column; align-items: center; }
+ .cm-timeline-node { width: 2.5rem; height: 2.5rem; border: 2px solid hsl(var(--accent)); border-radius: 9999px; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-weight: 500; color: hsl(var(--accent)); flex: none; font-variant-numeric: tabular-nums; }
+ .cm-timeline-line { flex: 1 1 auto; width: 1px; background-color: hsl(var(--border)); margin-top: 0.5rem; }
+
+ /* --- Marketing: cta strip --- */
+ .cm-cta-strip { padding: 3.5rem 0; }
+ .cm-cta-strip--band { background-color: hsl(var(--foreground)); color: hsl(var(--background)); }
+ .cm-cta-strip--band .cm-btn-primary { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); border-color: hsl(var(--accent)); }
+ .cm-cta-strip--card { background-color: hsl(var(--muted)); }
+ .cm-cta-headline { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; letter-spacing: -0.02em; font-size: clamp(1.75rem, 3vw, 2.5rem); line-height: 1.15; margin: 0; }
+
+ /* --- Marketing: countdown --- */
+ .cm-count-unit { display: flex; flex-direction: column; align-items: center; }
+ .cm-count-figure { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: clamp(2rem, 4vw, 3rem); font-weight: 500; font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); line-height: 1; }
+ .cm-count-box { border: 1px solid hsl(var(--border)); padding: 1rem 1.25rem; border-radius: 4px; min-width: 4.5rem; }
+
+ /* --- Primitives: quote / divider / gallery / media --- */
+ .cm-divider-line { border: 0; border-top: 1px solid hsl(var(--border)); }
+ .cm-divider-thick { border-top-width: 2px; border-top-color: hsl(var(--accent)); }
+ .cm-divider-ornament { display: flex; align-items: center; justify-content: center; gap: 0.75rem; color: hsl(var(--muted-foreground)); }
+ .cm-gallery-grid { display: grid; gap: 0.75rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
+ @media (min-width: 768px) { .cm-gallery-grid.cm-gallery-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .cm-gallery-grid.cm-gallery-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
+ .cm-video-frame { position: relative; display: block; width: 100%; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); overflow: hidden; }
+ .cm-video-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: hsl(var(--background)); background: none; border: 0; cursor: pointer; }
+ .cm-video-play-badge { width: 4rem; height: 4rem; border-radius: 9999px; background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); display: flex; align-items: center; justify-content: center; }
+
+ /* --- Commerce / local --- */
+ .cm-menu-item { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 0.75rem 0; border-bottom: 1px solid hsl(var(--border)); }
+ .cm-menu-price { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; color: hsl(var(--foreground)); }
+ .cm-channel { display: flex; align-items: flex-start; gap: 0.75rem; }
+ .cm-channel-mark { width: 2.5rem; height: 2.5rem; border: 1px solid hsl(var(--border)); border-radius: 4px; display: flex; align-items: center; justify-content: center; color: hsl(var(--accent)); flex: none; }
+ .cm-hours-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: 0.375rem 0; border-bottom: 1px solid hsl(var(--border)); }
+ .cm-social-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
+ .cm-social-link { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.5rem 0.75rem; border: 1px solid hsl(var(--border)); border-radius: 4px; color: hsl(var(--foreground)); text-decoration: none; font-size: 0.875rem; transition: border-color 150ms ease; }
+ .cm-social-link:hover { border-color: hsl(var(--accent)); color: hsl(var(--accent)); }
+
+ /* --- Forms --- */
+ .cm-form { display: grid; gap: 1.25rem; }
+ .cm-form-grid { display: grid; gap: 1.25rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
+ .cm-field { display: flex; flex-direction: column; gap: 0.375rem; }
+ .cm-field--full { grid-column: 1 / -1; }
+ .cm-label { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-size: 0.8125rem; font-weight: 600; color: hsl(var(--foreground)); text-transform: uppercase; letter-spacing: 0.04em; }
+ .cm-input { width: 100%; box-sizing: border-box; padding: 0.625rem 0.75rem; background-color: hsl(var(--background)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--input)); border-radius: 4px; font-family: var(--font-body, "Inter", system-ui, sans-serif); font-size: 1rem; }
+ .cm-input:focus { outline: 2px solid hsl(var(--ring)); outline-offset: 1px; border-color: hsl(var(--ring)); }
+ .cm-form-note { font-size: 0.8125rem; color: hsl(var(--muted-foreground)); }
+ .cm-alert-ok { border-left: 3px solid hsl(var(--accent)); background-color: hsl(var(--muted)); padding: 1rem 1.25rem; color: hsl(var(--foreground)); }
+ .cm-alert-err { border-left: 3px solid hsl(var(--destructive)); background-color: hsl(var(--muted)); padding: 1rem 1.25rem; color: hsl(var(--foreground)); }
+
+ /* --- Blog family --- */
+ .cm-post-card { display: flex; flex-direction: column; gap: 0.75rem; }
+ .cm-post-thumb { display: block; width: 100%; aspect-ratio: 16 / 10; object-fit: cover; background-color: hsl(var(--muted)); border: 1px solid hsl(var(--border)); }
+ .cm-post-title { font-family: var(--font-heading, "Inter", system-ui, sans-serif); font-weight: 600; font-size: 1.25rem; line-height: 1.25; color: hsl(var(--foreground)); text-decoration: none; }
+ .cm-post-title:hover { color: hsl(var(--accent)); }
+ .cm-post-meta { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase; color: hsl(var(--muted-foreground)); }
+ .cm-post-excerpt { color: hsl(var(--muted-foreground)); font-size: 0.9375rem; line-height: 1.6; }
+ .cm-post-grid { display: grid; gap: 2.5rem; grid-template-columns: repeat(1, minmax(0, 1fr)); }
+ @media (min-width: 640px) { .cm-post-grid-2, .cm-post-grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
+ @media (min-width: 1024px) { .cm-post-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
+ .cm-tag { display: inline-block; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.04em; padding: 0.1875rem 0.5rem; border: 1px solid hsl(var(--border)); border-radius: 3px; color: hsl(var(--muted-foreground)); text-decoration: none; }
+ .cm-tag:hover { border-color: hsl(var(--accent)); color: hsl(var(--accent)); }
+ .cm-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; font-size: 0.8125rem; color: hsl(var(--muted-foreground)); }
+ .cm-crumbs a { color: hsl(var(--muted-foreground)); text-decoration: none; }
+ .cm-crumbs a:hover { color: hsl(var(--accent)); }
+ .cm-crumb-sep { color: hsl(var(--border)); }
+ .cm-sidebar-link { display: block; padding: 0.5rem 0.75rem; border-left: 2px solid transparent; color: hsl(var(--foreground)); text-decoration: none; font-size: 0.9375rem; }
+ .cm-sidebar-link:hover, .cm-sidebar-link[aria-current="page"] { border-left-color: hsl(var(--accent)); color: hsl(var(--accent)); }
+ .cm-rank { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 1.25rem; font-weight: 500; color: hsl(var(--accent)); font-variant-numeric: tabular-nums; width: 2rem; flex: none; }
+
+ /* --- Motion (CSS-first, reduced-motion honored) --- */
+ .cm-reveal { opacity: 0; transform: translateY(0.5rem); animation: cm-reveal 500ms ease forwards; }
+ @keyframes cm-reveal { to { opacity: 1; transform: none; } }
+ @media (prefers-reduced-motion: reduce) {
+ .cm-reveal { animation: none; opacity: 1; transform: none; }
+ .cm-btn-ghost, .cm-logo, .cm-nav-link, .cm-faq-chevron { transition: none; }
+ }
diff --git a/master_pages.json b/master_pages.json
index 355fae8..c2a6e3e 100644
--- a/master_pages.json
+++ b/master_pages.json
@@ -2,23 +2,31 @@
{
"key": "corporate-modernist:default-master",
"title": "Corporate Modernist Default Master",
- "page_templates": ["default", "article"],
+ "page_templates": ["default", "article", "blog-index", "full-width"],
"blocks": [
- { "block_key": "navbar", "title": "Main Navigation", "content": { "menuName": "main", "style": "underline" }, "slot": "header", "sort_order": 0 },
+ { "block_key": "navbar", "title": "Main Navigation", "content": { "variant": "standard", "menuName": "main" }, "slot": "header", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
- { "block_key": "corporate-modernist:footer", "title": "Site Footer", "content": { "variant": "compact", "showLegal": true }, "slot": "footer", "sort_order": 0 }
+ { "block_key": "footer", "title": "Site Footer", "content": { "layout": "columns", "showSocial": true, "companyName": "Meridian Advisory", "tagline": "Strategy, operations, and risk counsel for boards.", "copyright": "Meridian Advisory" }, "slot": "footer", "sort_order": 0 }
]
},
{
"key": "corporate-modernist:landing-master",
"title": "Corporate Modernist Landing Master",
- "page_templates": ["landing", "full-width"],
+ "page_templates": ["landing"],
"blocks": [
- { "block_key": "navbar", "title": "Main Navigation", "content": { "menuName": "main", "style": "underline" }, "slot": "header", "sort_order": 0 },
- { "block_key": "corporate-modernist:hero_statement", "title": "Landing Hero", "content": { "eyebrow": "Enterprise", "headline": "Trusted by 200+ boards" }, "slot": "hero", "sort_order": 0 },
+ { "block_key": "navbar", "title": "Main Navigation", "content": { "variant": "standard", "menuName": "main" }, "slot": "header", "sort_order": 0 },
+ { "block_key": "hero", "title": "Landing Hero", "content": { "template": "left-aligned", "eyebrow": "B2B advisory", "headline": "Precise counsel for boards that move first", "subheadline": "Strategy, operations, and risk work delivered on a fixed scope." }, "slot": "hero", "sort_order": 0 },
{ "block_key": "slot", "title": "Main Content Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 },
- { "block_key": "corporate-modernist:cta_strip", "title": "Closing CTA", "content": { "variant": "book-call" }, "slot": "cta", "sort_order": 0 },
- { "block_key": "corporate-modernist:footer", "title": "Site Footer", "content": { "variant": "full", "showLegal": true }, "slot": "footer", "sort_order": 0 }
+ { "block_key": "cta", "title": "Closing CTA", "content": { "background": "band", "heading": "Book a working session", "text": "Ninety minutes with a principal. No pitch deck.", "primaryLabel": "Request a session", "primaryUrl": "/contact" }, "slot": "cta", "sort_order": 0 },
+ { "block_key": "footer", "title": "Site Footer", "content": { "layout": "columns", "showSocial": true, "companyName": "Meridian Advisory", "copyright": "Meridian Advisory" }, "slot": "footer", "sort_order": 0 }
+ ]
+ },
+ {
+ "key": "corporate-modernist:auth-master",
+ "title": "Corporate Modernist Auth Master",
+ "page_templates": ["auth"],
+ "blocks": [
+ { "block_key": "slot", "title": "Auth Slot", "content": { "slotName": "main" }, "slot": "main", "sort_order": 0 }
]
}
]
diff --git a/presets.json b/presets.json
index 94e05a8..e8853bd 100644
--- a/presets.json
+++ b/presets.json
@@ -52,7 +52,7 @@
{
"id": "forest-quiet",
"name": "Forest Quiet",
- "description": "Same chassis, deep green accent for sustainability, advisory, ESG.",
+ "description": "Same chassis, deep green accent for sustainability, advisory, and ESG.",
"theme": {
"mode": "both",
"lightColors": {
@@ -102,7 +102,7 @@
{
"id": "burgundy-tradition",
"name": "Burgundy Tradition",
- "description": "Heritage accent for old-line legal, private banking, partnerships.",
+ "description": "Heritage accent for old-line legal, private banking, and partnerships.",
"theme": {
"mode": "both",
"lightColors": {
@@ -148,5 +148,105 @@
"ring": "350 60% 60%"
}
}
+ },
+ {
+ "id": "graphite-mono",
+ "name": "Graphite Mono",
+ "description": "Achromatic ink on gallery white. Pure Swiss restraint with no hue.",
+ "theme": {
+ "mode": "both",
+ "lightColors": {
+ "background": "0 0% 100%",
+ "foreground": "0 0% 9%",
+ "card": "0 0% 100%",
+ "cardForeground": "0 0% 9%",
+ "popover": "0 0% 100%",
+ "popoverForeground": "0 0% 9%",
+ "primary": "0 0% 13%",
+ "primaryForeground": "0 0% 100%",
+ "secondary": "0 0% 96%",
+ "secondaryForeground": "0 0% 9%",
+ "muted": "0 0% 96%",
+ "mutedForeground": "0 0% 40%",
+ "accent": "0 0% 13%",
+ "accentForeground": "0 0% 100%",
+ "destructive": "0 72% 42%",
+ "destructiveForeground": "0 0% 100%",
+ "border": "0 0% 88%",
+ "input": "0 0% 88%",
+ "ring": "0 0% 13%"
+ },
+ "darkColors": {
+ "background": "0 0% 8%",
+ "foreground": "0 0% 96%",
+ "card": "0 0% 11%",
+ "cardForeground": "0 0% 96%",
+ "popover": "0 0% 11%",
+ "popoverForeground": "0 0% 96%",
+ "primary": "0 0% 92%",
+ "primaryForeground": "0 0% 8%",
+ "secondary": "0 0% 17%",
+ "secondaryForeground": "0 0% 96%",
+ "muted": "0 0% 15%",
+ "mutedForeground": "0 0% 64%",
+ "accent": "0 0% 92%",
+ "accentForeground": "0 0% 8%",
+ "destructive": "0 62% 50%",
+ "destructiveForeground": "0 0% 100%",
+ "border": "0 0% 22%",
+ "input": "0 0% 22%",
+ "ring": "0 0% 92%"
+ }
+ }
+ },
+ {
+ "id": "signal-red",
+ "name": "Signal Red",
+ "description": "Graphite ground with a single Bauhaus primary-red accent for bold consultancies.",
+ "theme": {
+ "mode": "both",
+ "lightColors": {
+ "background": "0 0% 100%",
+ "foreground": "0 0% 11%",
+ "card": "0 0% 100%",
+ "cardForeground": "0 0% 11%",
+ "popover": "0 0% 100%",
+ "popoverForeground": "0 0% 11%",
+ "primary": "4 74% 46%",
+ "primaryForeground": "0 0% 100%",
+ "secondary": "0 0% 96%",
+ "secondaryForeground": "0 0% 11%",
+ "muted": "0 0% 96%",
+ "mutedForeground": "0 0% 40%",
+ "accent": "4 74% 46%",
+ "accentForeground": "0 0% 100%",
+ "destructive": "0 72% 42%",
+ "destructiveForeground": "0 0% 100%",
+ "border": "0 0% 88%",
+ "input": "0 0% 88%",
+ "ring": "4 74% 46%"
+ },
+ "darkColors": {
+ "background": "0 0% 8%",
+ "foreground": "0 0% 96%",
+ "card": "0 0% 11%",
+ "cardForeground": "0 0% 96%",
+ "popover": "0 0% 11%",
+ "popoverForeground": "0 0% 96%",
+ "primary": "4 78% 58%",
+ "primaryForeground": "0 0% 8%",
+ "secondary": "0 0% 17%",
+ "secondaryForeground": "0 0% 96%",
+ "muted": "0 0% 15%",
+ "mutedForeground": "0 0% 64%",
+ "accent": "4 78% 58%",
+ "accentForeground": "0 0% 8%",
+ "destructive": "0 62% 50%",
+ "destructiveForeground": "0 0% 100%",
+ "border": "0 0% 22%",
+ "input": "0 0% 22%",
+ "ring": "4 78% 58%"
+ }
+ }
}
]
diff --git a/seed/seed.json b/seed/seed.json
new file mode 100644
index 0000000..ae8e4c6
--- /dev/null
+++ b/seed/seed.json
@@ -0,0 +1,122 @@
+{
+ "demo": true,
+ "settings": {
+ "merge": {
+ "site_name": "Meridian Advisory",
+ "tagline": "Strategy, operations, and risk counsel for boards."
+ }
+ },
+ "data_tables": [
+ {
+ "key": "contact_submissions",
+ "name": "Contact submissions",
+ "description": "Messages sent from the Meridian Advisory contact form.",
+ "primary_key": "id",
+ "columns": [
+ { "key": "name", "label": "Name", "type": "text", "required": true },
+ { "key": "email", "label": "Email", "type": "email", "required": true },
+ { "key": "organisation", "label": "Organisation", "type": "text", "required": false },
+ { "key": "message", "label": "Message", "type": "text", "required": true }
+ ]
+ }
+ ],
+ "pages": [
+ {
+ "slug": "/",
+ "title": "Meridian Advisory",
+ "template_key": "full-width",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "hero", "title": "Hero", "slot": "main", "sort_order": 1, "content": { "template": "left-aligned", "eyebrow": "B2B advisory", "headline": "Precise counsel for boards that move first", "subheadline": "We do strategy, operations, and risk work on a fixed scope. No retainers you cannot read.", "ctaPrimary": { "text": "Book a working session", "url": "/contact" }, "ctaSecondary": { "text": "See how we work", "url": "/about" } } },
+ { "block_key": "corporate-modernist:credential_bar", "title": "Credentials", "slot": "main", "sort_order": 2, "content": { "items": [ { "figure": "18", "label": "Years in practice" }, { "figure": "6", "label": "Sectors served" }, { "figure": "40+", "label": "Board engagements" }, { "figure": "3", "label": "Continents" } ] } },
+ { "block_key": "corporate-modernist:capability_matrix", "title": "Capabilities", "slot": "main", "sort_order": 3, "content": { "eyebrow": "What we do", "heading": "Three disciplines, one team", "intro": "Every engagement draws on the same three capabilities. We assign a principal to each.", "columns": 3, "capabilities": [ { "mark": "circle", "title": "Strategy", "text": "Market entry, portfolio choices, and the operating model that carries them." }, { "mark": "triangle", "title": "Operations", "text": "Cost structure, process design, and the metrics a board can hold." }, { "mark": "square", "title": "Risk", "text": "Controls, resilience, and the reporting that keeps regulators satisfied." } ] } },
+ { "block_key": "stats", "title": "Outcomes", "slot": "main", "sort_order": 4, "content": { "heading": "Outcomes we measure", "columns": 3, "countUp": false, "items": [ { "value": "3.2", "suffix": "x", "label": "Median return on engagement" }, { "value": "90", "suffix": " days", "label": "Time to first decision" }, { "value": "12", "label": "Week average engagement" } ] } },
+ { "block_key": "corporate-modernist:engagement_process", "title": "Process", "slot": "main", "sort_order": 5, "content": { "eyebrow": "How we work", "heading": "A fixed path from brief to handover", "steps": [ { "title": "Frame", "text": "We agree the question and the scope in one working session." }, { "title": "Diagnose", "text": "We gather evidence and test it against the board's own numbers." }, { "title": "Decide", "text": "We present options with a clear recommendation and the trade-offs." }, { "title": "Hand over", "text": "We leave the model, the plan, and the owners in place." } ] } },
+ { "block_key": "cta", "title": "Closing CTA", "slot": "main", "sort_order": 6, "content": { "background": "band", "heading": "Book a working session", "text": "Ninety minutes with a principal. No pitch deck.", "primaryLabel": "Request a session", "primaryUrl": "/contact" } }
+ ]
+ },
+ {
+ "slug": "/about",
+ "title": "About",
+ "template_key": "default",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "A small firm by design", "level": 1 } },
+ { "block_key": "text", "title": "Intro", "slot": "main", "sort_order": 2, "content": { "text": "Meridian Advisory keeps a short bench. Every engagement is led by a principal, not passed to a junior team. We take fewer clients so we can go deeper on each one.
" } },
+ { "block_key": "corporate-modernist:capability_matrix", "title": "Values", "slot": "main", "sort_order": 3, "content": { "eyebrow": "How we operate", "heading": "What holds across every brief", "columns": 3, "capabilities": [ { "mark": "square", "title": "Fixed scope", "text": "You know the price and the deadline before we start." }, { "mark": "circle", "title": "Evidence first", "text": "We argue from your data, not from a template deck." }, { "mark": "triangle", "title": "Clean handover", "text": "We finish by making ourselves unnecessary." } ] } },
+ { "block_key": "team", "title": "Team", "slot": "main", "sort_order": 4, "content": { "heading": "The principals", "layout": "grid", "columns": 3, "members": [ { "name": "A. Reyes", "role": "Strategy", "bio": "Two decades in corporate strategy and market entry." }, { "name": "K. Osei", "role": "Operations", "bio": "Process and cost work across manufacturing and services." }, { "name": "M. Lindqvist", "role": "Risk", "bio": "Controls and resilience for regulated industries." } ] } },
+ { "block_key": "corporate-modernist:case_study_card", "title": "Case study", "slot": "main", "sort_order": 5, "content": { "client": "Regional bank", "metric": "31%", "label": "Reduction in cost to serve", "summary": "A twelve-week operations review that reset the branch operating model.", "href": { "label": "Read the case", "href": "/blog/operations-reset" } } }
+ ]
+ },
+ {
+ "slug": "/blog",
+ "title": "Insights",
+ "template_key": "blog-index",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "card", "title": "Post 1", "slot": "main", "sort_order": 1, "content": { "title": "Resetting a branch operating model", "text": "What changed when a regional bank moved from headcount targets to cost-to-serve.
", "link": "/blog/operations-reset", "linkLabel": "Read" } },
+ { "block_key": "card", "title": "Post 2", "slot": "main", "sort_order": 2, "content": { "title": "Reading a risk register the board will use", "text": "Most registers are written for auditors. Here is how to write one for directors.
", "link": "/blog/risk-register", "linkLabel": "Read" } },
+ { "block_key": "card", "title": "Post 3", "slot": "main", "sort_order": 3, "content": { "title": "The ninety-day decision", "text": "Why the first real decision should land inside three months, not six.
", "link": "/blog/ninety-day-decision", "linkLabel": "Read" } }
+ ]
+ },
+ {
+ "slug": "/blog/operations-reset",
+ "parent_slug": "/blog",
+ "title": "Resetting a branch operating model",
+ "template_key": "article",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Resetting a branch operating model", "level": 1 } },
+ { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "A regional bank asked us to cut cost to serve without closing branches. We started with the numbers the board already trusted. Then we tested each assumption against a week of real transactions.
The answer was not fewer branches. It was fewer tasks per branch. We moved back-office work to a shared team and gave each branch a single metric it could hold.
" } }
+ ]
+ },
+ {
+ "slug": "/blog/risk-register",
+ "parent_slug": "/blog",
+ "title": "Reading a risk register the board will use",
+ "template_key": "article",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Reading a risk register the board will use", "level": 1 } },
+ { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "A risk register written for auditors lists everything. A register written for directors ranks a few things and says who owns them. The second kind gets read.
We keep the top ten risks on one page. Each has an owner, a trend, and a next action. Everything else lives in the appendix.
" } }
+ ]
+ },
+ {
+ "slug": "/blog/ninety-day-decision",
+ "parent_slug": "/blog",
+ "title": "The ninety-day decision",
+ "template_key": "article",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The ninety-day decision", "level": 1 } },
+ { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "Long engagements drift because no decision anchors them. We set a real decision inside the first ninety days. It forces the evidence to be good enough to act on.
The decision does not have to be final. It has to be real. A board that decides once will decide again faster.
" } }
+ ]
+ },
+ {
+ "slug": "/contact",
+ "title": "Contact",
+ "template_key": "contact",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "contact-form", "title": "Contact form", "slot": "main", "sort_order": 1, "content": { "heading": "Request a working session", "description": "Tell us the question. We reply within one business day.", "submitLabel": "Send message", "successMessage": "Thank you. We will be in touch within one business day.", "formConfig": { "targetTable": "contact_submissions", "enabled": true, "captchaEnabled": false }, "fields": [ { "name": "name", "label": "Name", "type": "text", "required": true, "width": "half" }, { "name": "email", "label": "Email", "type": "email", "required": true, "width": "half" }, { "name": "organisation", "label": "Organisation", "type": "text", "required": false, "width": "full" }, { "name": "message", "label": "What can we help with?", "type": "textarea", "required": true, "width": "full" } ] } },
+ { "block_key": "contact-card", "title": "Contact details", "slot": "aside", "sort_order": 1, "content": { "heading": "Direct", "columns": 1, "channels": [ { "icon": "lucide:mail", "label": "Email", "value": "hello@meridian.example", "link": "mailto:hello@meridian.example" }, { "icon": "lucide:phone", "label": "Phone", "value": "+61 2 5550 0100", "link": "tel:+61255500100" } ] } },
+ { "block_key": "hours-location", "title": "Office hours", "slot": "aside", "sort_order": 2, "content": { "heading": "Office", "address": "Level 12, 100 Harbour Street, Sydney NSW 2000", "hours": [ { "day": "Monday to Friday", "hours": "9:00 to 17:30" }, { "day": "Saturday and Sunday", "closed": true } ] } }
+ ]
+ },
+ {
+ "slug": "/login",
+ "title": "Sign in",
+ "template_key": "auth",
+ "reconcile_blocks": true,
+ "blocks": [
+ { "block_key": "auth-form", "title": "Sign in", "slot": "main", "sort_order": 1, "content": { "default_tab": "login", "show_social": false } }
+ ]
+ }
+ ],
+ "menu_items": [
+ { "menu": "main", "label": "Home", "page_slug": "/", "sort_order": 1 },
+ { "menu": "main", "label": "About", "page_slug": "/about", "sort_order": 2 },
+ { "menu": "main", "label": "Insights", "page_slug": "/blog", "sort_order": 3 },
+ { "menu": "main", "label": "Contact", "page_slug": "/contact", "sort_order": 4 }
+ ]
+}
diff --git a/seed/workflows.json b/seed/workflows.json
new file mode 100644
index 0000000..728b866
--- /dev/null
+++ b/seed/workflows.json
@@ -0,0 +1,19 @@
+{
+ "workflows": [
+ {
+ "key": "contact_notify_admins",
+ "name": "Notify admins on contact submission",
+ "description": "Emails site admins whenever the Meridian Advisory contact form receives a message.",
+ "enabled": true,
+ "trigger": { "type": "row_inserted", "table": "contact_submissions" },
+ "steps": [
+ {
+ "type": "email",
+ "name": "Email admins",
+ "template": "Form Submission Notification",
+ "recipients": { "mode": "admins", "scope": "all" }
+ }
+ ]
+ }
+ ]
+}
diff --git a/templates/corporate-modernist/auth.ninjatpl b/templates/corporate-modernist/auth.ninjatpl
new file mode 100644
index 0000000..7c7ef03
--- /dev/null
+++ b/templates/corporate-modernist/auth.ninjatpl
@@ -0,0 +1,17 @@
+
+
+{{ head_html|safe }}
+
+ {{ admin_banner_html|safe }}
+
+
+
+ {{ body_end_html|safe }}
+
+
diff --git a/templates/corporate-modernist/blog-index.ninjatpl b/templates/corporate-modernist/blog-index.ninjatpl
new file mode 100644
index 0000000..224f36a
--- /dev/null
+++ b/templates/corporate-modernist/blog-index.ninjatpl
@@ -0,0 +1,17 @@
+
+
+{{ head_html|safe }}
+
+ {{ admin_banner_html|safe }}
+ {% if slots.header %}{% endif %}
+
+
+ {% if title %}
Insights
{{ title }} {% if page_meta.MetaDescription %}
{{ page_meta.MetaDescription }}
{% endif %}
{% endif %}
+ {% if slots.featured %}
{{ slots.featured|safe }} {% endif %}
+ {% if slots.main %}
{% else %}
No posts published yet.
{% endif %}
+
+
+ {% if slots.footer %}{% endif %}
+ {{ body_end_html|safe }}
+
+
diff --git a/templates/corporate-modernist/contact.ninjatpl b/templates/corporate-modernist/contact.ninjatpl
new file mode 100644
index 0000000..84ae62e
--- /dev/null
+++ b/templates/corporate-modernist/contact.ninjatpl
@@ -0,0 +1,23 @@
+
+
+{{ head_html|safe }}
+
+ {{ admin_banner_html|safe }}
+ {% if slots.header %}{% endif %}
+
+
+ {% if slots.aside %}
+
+
{{ slots.main|safe }}
+
+
+
+ {% else %}
+
{% if slots.main %}{{ slots.main|safe }}{% else %}
No content blocks assigned to this page.
{% endif %}
+ {% endif %}
+
+
+ {% if slots.footer %}{% endif %}
+ {{ body_end_html|safe }}
+
+
diff --git a/templates/overrides/corporate-modernist/announcement-bar.ninjatpl b/templates/overrides/corporate-modernist/announcement-bar.ninjatpl
new file mode 100644
index 0000000..e2ac9e2
--- /dev/null
+++ b/templates/overrides/corporate-modernist/announcement-bar.ninjatpl
@@ -0,0 +1,8 @@
+{# announcement-bar override — centered notice; carries data-bn-announcement / data-bn-annkey and a data-bn-ann-dismiss close button so the host dismissal JS binds. #}
+{% if variant == "promo" %}{% set annvar = "cm-announce--promo" %}{% set annsty = "background:hsl(var(--primary));color:hsl(var(--primary-foreground));" %}{% elif variant == "alert" %}{% set annvar = "cm-announce--alert" %}{% set annsty = "background:hsl(var(--destructive));color:hsl(var(--destructive-foreground));" %}{% else %}{% set annvar = "cm-announce--info" %}{% set annsty = "background:hsl(var(--accent));color:hsl(var(--accent-foreground));" %}{% endif %}
+
+
+
{{ message }}{% if linkText and linkUrl %} {{ linkText }} {% endif %}
+{% if dismissable %}
::lucide:x:sm:: {% endif %}
+
+
diff --git a/templates/overrides/corporate-modernist/audio-embed.ninjatpl b/templates/overrides/corporate-modernist/audio-embed.ninjatpl
new file mode 100644
index 0000000..0a3f650
--- /dev/null
+++ b/templates/overrides/corporate-modernist/audio-embed.ninjatpl
@@ -0,0 +1,14 @@
+{# audio-embed override — hairline card row; carries data-bn-audio / data-audio-url / data-audio-media + data-bn-audio-slot so the host facade JS binds. #}
+
+
+{% if artwork %}
{% img artwork alt=title|default:"" class="cm-audio-art" %}
{% endif %}
+
+{% if title %}
{{ title }}
{% endif %}
+{% if artist %}
{{ artist }}
{% endif %}
+
+
+
+
diff --git a/templates/overrides/corporate-modernist/auth-form.ninjatpl b/templates/overrides/corporate-modernist/auth-form.ninjatpl
new file mode 100644
index 0000000..643b7d2
--- /dev/null
+++ b/templates/overrides/corporate-modernist/auth-form.ninjatpl
@@ -0,0 +1,22 @@
+
+
+
+
+ Sign in
+ Create account
+
+
+
+
+
+
diff --git a/templates/overrides/corporate-modernist/auth-status.ninjatpl b/templates/overrides/corporate-modernist/auth-status.ninjatpl
new file mode 100644
index 0000000..3a02cb1
--- /dev/null
+++ b/templates/overrides/corporate-modernist/auth-status.ninjatpl
@@ -0,0 +1 @@
+{% if context.isPublicLoggedIn %}{{ context.publicDisplayName|default:context.publicUsername }} Account Sign out {% else %}{% endif %}
diff --git a/templates/overrides/corporate-modernist/author-bio-hero.ninjatpl b/templates/overrides/corporate-modernist/author-bio-hero.ninjatpl
new file mode 100644
index 0000000..c065884
--- /dev/null
+++ b/templates/overrides/corporate-modernist/author-bio-hero.ninjatpl
@@ -0,0 +1 @@
+{% if context.currentAuthor %}{% if showAvatar and context.currentAuthor.avatarUrl %}
{% else %}
{% endif %}
{{ context.currentAuthor.displayName }} {% if context.currentAuthor.bio %}
{{ context.currentAuthor.bio }}
{% endif %}{% if showSocial %}
{% if context.currentAuthor.websiteUrl %}
{% endif %}{% if context.currentAuthor.twitterHandle %}
{% endif %}{% if context.currentAuthor.linkedinUrl %}
{% endif %}
{% endif %}
{% endif %}
diff --git a/templates/overrides/corporate-modernist/author-bio.ninjatpl b/templates/overrides/corporate-modernist/author-bio.ninjatpl
new file mode 100644
index 0000000..07048c2
--- /dev/null
+++ b/templates/overrides/corporate-modernist/author-bio.ninjatpl
@@ -0,0 +1 @@
+{% if context.currentPost.authorName %}{% endif %}
diff --git a/templates/overrides/corporate-modernist/blog-hero.ninjatpl b/templates/overrides/corporate-modernist/blog-hero.ninjatpl
new file mode 100644
index 0000000..002e98b
--- /dev/null
+++ b/templates/overrides/corporate-modernist/blog-hero.ninjatpl
@@ -0,0 +1 @@
+{% if title %}
{{ title }} {% endif %}{% if subtitle %}
{{ subtitle }}
{% endif %}
{% if posts %}
{% for post in posts %}
{% if post.featured_image_url %} {% endif %}{% if showExcerpt and post.excerpt %}{{ post.excerpt }}
{% endif %}{% if post.author_name %}{{ post.author_name }} {% endif %}{% if post.published_at %}{{ post.published_at|date:"M j, Y" }} {% endif %}
{% endfor %}
{% endif %}
diff --git a/templates/overrides/corporate-modernist/breadcrumbs.ninjatpl b/templates/overrides/corporate-modernist/breadcrumbs.ninjatpl
new file mode 100644
index 0000000..97b7c7a
--- /dev/null
+++ b/templates/overrides/corporate-modernist/breadcrumbs.ninjatpl
@@ -0,0 +1 @@
+{% if showHome %} {% endif %}{% for item in breadcrumbs %}{% if showHome or not forloop.First %}{{ separator|default:"/" }} {% endif %}{% if item.is_current %}{% if showCurrent %}{{ item.label }} {% endif %}{% else %}{% endif %} {% endfor %}
diff --git a/templates/overrides/corporate-modernist/button.ninjatpl b/templates/overrides/corporate-modernist/button.ninjatpl
index d0c818b..679d9a5 100644
--- a/templates/overrides/corporate-modernist/button.ninjatpl
+++ b/templates/overrides/corporate-modernist/button.ninjatpl
@@ -1 +1,6 @@
-{% if variant|default:"primary" == "outline" or variant|default:"primary" == "secondary" %}{{ label|default:text|default:"Learn more" }} {% else %}{{ label|default:text|default:"Learn more" }} {% endif %}
+{% set btnStyle = style|default:"primary" %}
+{% set btnClass = "cm-btn-primary" %}
+{% if btnStyle == "outline" or btnStyle == "secondary" %}{% set btnClass = "cm-btn-outline" %}{% elif btnStyle == "ghost" or btnStyle == "link" %}{% set btnClass = "cm-btn-ghost" %}{% endif %}
+{% set sizeClass = "" %}
+{% if size == "sm" %}{% set sizeClass = "cm-btn-sm" %}{% elif size == "lg" %}{% set sizeClass = "cm-btn-lg" %}{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/card.ninjatpl b/templates/overrides/corporate-modernist/card.ninjatpl
index c32942e..99f46e2 100644
--- a/templates/overrides/corporate-modernist/card.ninjatpl
+++ b/templates/overrides/corporate-modernist/card.ninjatpl
@@ -1 +1 @@
-{% if title %}
{{ title }}
{% endif %}{% if body|default:text %}
{{ body|default:text|safe }}
{% endif %}
+{% if media %}{% img media alt=title|default:"" class="cm-card-media" %}
{% endif %}{% if title %}{{ title }} {% endif %}{% if text %}{{ text|safe }}
{% endif %}{% if linkLabel and link %}{{ linkLabel }}::lucide:arrow-right:sm:: {% endif %}
diff --git a/templates/overrides/corporate-modernist/category-list.ninjatpl b/templates/overrides/corporate-modernist/category-list.ninjatpl
new file mode 100644
index 0000000..ccaa365
--- /dev/null
+++ b/templates/overrides/corporate-modernist/category-list.ninjatpl
@@ -0,0 +1 @@
+{% if heading %}{{ heading }} {% endif %}{% if style == "pills" %}{% else %}{% for cat in categories %} {% endfor %} {% endif %}
diff --git a/templates/overrides/corporate-modernist/contact-card.ninjatpl b/templates/overrides/corporate-modernist/contact-card.ninjatpl
new file mode 100644
index 0000000..486eb53
--- /dev/null
+++ b/templates/overrides/corporate-modernist/contact-card.ninjatpl
@@ -0,0 +1,14 @@
+{# contact-card override — grouped contact channels; each channel a hairline mark + label + value. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if description %}
{{ description }}
{% endif %}
+
+{% for channel in channels %}
+{% if channel.icon %}
::{{ channel.icon }}:sm:: {% endif %}
+
+{% if channel.label %}
{{ channel.label }}
{% endif %}
+{% if channel.value %}
{% endif %}
+
+
{% endfor %}
+
+
diff --git a/templates/overrides/corporate-modernist/contact-form.ninjatpl b/templates/overrides/corporate-modernist/contact-form.ninjatpl
new file mode 100644
index 0000000..0761d40
--- /dev/null
+++ b/templates/overrides/corporate-modernist/contact-form.ninjatpl
@@ -0,0 +1,34 @@
+{# contact-form override — server-driven; block-id resolution, {% form %} wiring, honeypot, and field loop copied verbatim from the builtin, reskinned with cm-form primitives. #}
+{% with bid=_block_id|default:context.blockId %}
+
+
+{% endwith %}
diff --git a/templates/overrides/corporate-modernist/countdown.ninjatpl b/templates/overrides/corporate-modernist/countdown.ninjatpl
new file mode 100644
index 0000000..497ccf8
--- /dev/null
+++ b/templates/overrides/corporate-modernist/countdown.ninjatpl
@@ -0,0 +1,44 @@
+{# countdown override — oversized mono unit boxes; host countdown JS binds via data-* attrs. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+
+
+
-- {{ labelDays|default:"Days" }}
+
-- {{ labelHours|default:"Hours" }}
+
-- {{ labelMinutes|default:"Minutes" }}
+
-- {{ labelSeconds|default:"Seconds" }}
+
+
{{ expiredMessage|default:"This has started." }}
{% if expiredUrl and expiredLabel %}
{{ expiredLabel }} {% endif %}
+
+
Counting down to {{ target }} .
+
+
diff --git a/templates/overrides/corporate-modernist/cta.ninjatpl b/templates/overrides/corporate-modernist/cta.ninjatpl
new file mode 100644
index 0000000..b0e8ddf
--- /dev/null
+++ b/templates/overrides/corporate-modernist/cta.ninjatpl
@@ -0,0 +1,8 @@
+{# cta override — full-width strip; band / card / split variants. #}
+
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if text %}
{{ text }}
{% endif %}
+
+{% if primaryLabel or secondaryLabel %}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/divider.ninjatpl b/templates/overrides/corporate-modernist/divider.ninjatpl
new file mode 100644
index 0000000..4c4854b
--- /dev/null
+++ b/templates/overrides/corporate-modernist/divider.ninjatpl
@@ -0,0 +1,2 @@
+{# divider override — plain hairline / thick spacer rule / centered ornament between two hairlines. #}
+{% if variant == "ornament" %}::{{ icon|default:"lucide:asterisk" }}:md::
{% elif variant == "spacer-rule" %} {% else %} {% endif %}
diff --git a/templates/overrides/corporate-modernist/event-list.ninjatpl b/templates/overrides/corporate-modernist/event-list.ninjatpl
new file mode 100644
index 0000000..6dd2133
--- /dev/null
+++ b/templates/overrides/corporate-modernist/event-list.ninjatpl
@@ -0,0 +1,31 @@
+{# event-list override — dates shown VERBATIM in each event's own timezone (never converted); list rows or card grid. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if layout == "cards" %}
+
+{% for event in events %}{% if not (hidePast and event.past) %}
+{% if event.media %}{% img event.media alt=event.title|default:"" class="cm-event-media" %}
{% endif %}
+
+
{{ event.start }}{% if event.end %} – {{ event.end }}{% endif %} {% if event.timezone %} {{ event.timezone }} {% endif %}
+
{{ event.title }}
+{% if event.venue %}
{{ event.venue }}
{% endif %}
+{% if event.description %}
{{ event.description }}
{% endif %}
+{% if event.link %}
{{ event.linkLabel|default:"Details" }}::lucide:arrow-right:sm:: {% endif %}
+
+ {% endif %}{% endfor %}
+
+{% else %}
+
+{% for event in events %}{% if not (hidePast and event.past) %}
+{{ event.start }} {% if event.end %}
to {{ event.end }}
{% endif %}{% if event.timezone %}
{{ event.timezone }}
{% endif %}
+
+
{{ event.title }}
+{% if event.venue %}
{{ event.venue }}
{% endif %}
+{% if event.description %}
{{ event.description }}
{% endif %}
+
+{% if event.link %}{{ event.linkLabel|default:"Details" }} {% endif %}
+ {% endif %}{% endfor %}
+
+{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/faq.ninjatpl b/templates/overrides/corporate-modernist/faq.ninjatpl
new file mode 100644
index 0000000..e8e3e0d
--- /dev/null
+++ b/templates/overrides/corporate-modernist/faq.ninjatpl
@@ -0,0 +1,6 @@
+{# faq override — native hairline-divided disclosure list. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if items %}
{% for item in items %}
{{ item.question }}::lucide:chevron-down:sm:: {{ item.answer|safe }}
{% endfor %}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/feature-grid.ninjatpl b/templates/overrides/corporate-modernist/feature-grid.ninjatpl
new file mode 100644
index 0000000..52c59b0
--- /dev/null
+++ b/templates/overrides/corporate-modernist/feature-grid.ninjatpl
@@ -0,0 +1,7 @@
+{# feature-grid override — Swiss cells, each led by a Bauhaus square mark. #}
+
+{% if eyebrow %}
{{ eyebrow }}
{% endif %}
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if items %}
{% for item in items %}
{% if item.icon %}
::{{ item.icon }}:sm:: {% else %}
{% endif %}{% if item.title %}
{% if item.linkUrl %}{{ item.title }} {% else %}{{ item.title }}{% endif %} {% endif %}{% if item.text %}
{{ item.text }}
{% endif %}{% if item.linkUrl and item.linkLabel %}
{{ item.linkLabel }}::lucide:arrow-right:sm:: {% endif %}
{% endfor %}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/featured-posts.ninjatpl b/templates/overrides/corporate-modernist/featured-posts.ninjatpl
new file mode 100644
index 0000000..7239f9c
--- /dev/null
+++ b/templates/overrides/corporate-modernist/featured-posts.ninjatpl
@@ -0,0 +1 @@
+{% if heading %}
{{ heading }} {% endif %}
{% for post in posts %}
{% if showFeaturedImage and post.featured_image_url %} {% endif %}{% if showExcerpt and post.excerpt %}{{ post.excerpt }}
{% endif %}{% if showAuthor and post.author_name %}{{ post.author_name }} {% endif %}{% if showDate and post.published_at %}{{ post.published_at|date:"M j, Y" }} {% endif %}{% if post.reading_time %}{{ post.reading_time }} min {% endif %}
{% endfor %}
diff --git a/templates/overrides/corporate-modernist/footer.ninjatpl b/templates/overrides/corporate-modernist/footer.ninjatpl
new file mode 100644
index 0000000..5bb9ecb
--- /dev/null
+++ b/templates/overrides/corporate-modernist/footer.ninjatpl
@@ -0,0 +1,17 @@
+{# footer override — Swiss-grid footer chrome from CONTENT fields (brand, contact, newsletter, legal); menu columns / social / legal rows render from the footer providers (empty today, forward-correct). #}
+
diff --git a/templates/overrides/corporate-modernist/gallery.ninjatpl b/templates/overrides/corporate-modernist/gallery.ninjatpl
new file mode 100644
index 0000000..9d60143
--- /dev/null
+++ b/templates/overrides/corporate-modernist/gallery.ninjatpl
@@ -0,0 +1,6 @@
+{# gallery override — Swiss grid of hairline-framed images; carries data-bn-gallery / data-lightbox / data-bn-gallery-item so the host lightbox JS binds. #}
+{% if columns == 4 %}{% set gcols = "cm-gallery-4" %}{% set gn = 4 %}{% elif columns == 2 %}{% set gcols = "" %}{% set gn = 2 %}{% else %}{% set gcols = "cm-gallery-3" %}{% set gn = 3 %}{% endif %}
+{% if gap == "sm" %}{% set ggap = "0.5rem" %}{% elif gap == "lg" %}{% set ggap = "1.5rem" %}{% else %}{% set ggap = "1rem" %}{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/hero.ninjatpl b/templates/overrides/corporate-modernist/hero.ninjatpl
new file mode 100644
index 0000000..c7f7bed
--- /dev/null
+++ b/templates/overrides/corporate-modernist/hero.ninjatpl
@@ -0,0 +1,24 @@
+{# hero override — Swiss grid, oversized display headline, Bauhaus restraint. #}
+{# styled-text fields accept a {text,color} object OR a bare string (.text|default:field). #}
+{% set eyebrowText = eyebrow.text|default:eyebrow %}
+{% set headlineText = headline.text|default:headline %}
+{% set subText = subheadline.text|default:subheadline %}
+{% set descText = description.text|default:description %}
+{% set pText = ctaPrimary.text %}
+{% set pUrl = ctaPrimary.url %}
+{% set sText = ctaSecondary.text %}
+{% set sUrl = ctaSecondary.url %}
+{% set variant = template|default:"centered" %}
+{% macro herobody() %}
+{% if eyebrowText %}{{ eyebrowText }}
{% endif %}
+{% if headlineText %}{{ headlineText }} {% endif %}
+{% if subText %}{{ subText }}
{% endif %}
+{% if descText %}{{ descText }}
{% endif %}
+{% if pText or sText %}{% endif %}
+{% if trustLogos %}{% endif %}
+{% endmacro %}
+{% if variant == "split" %}
+{{ herobody() }}
{% if backgroundImage %}{% img backgroundImage alt=headlineText class="cm-hero-media" %}{% endif %}
+{% else %}
+
+{% endif %}
diff --git a/templates/overrides/corporate-modernist/hours-location.ninjatpl b/templates/overrides/corporate-modernist/hours-location.ninjatpl
new file mode 100644
index 0000000..f104db2
--- /dev/null
+++ b/templates/overrides/corporate-modernist/hours-location.ninjatpl
@@ -0,0 +1,18 @@
+{# hours-location override — hairline hours table + address; click-to-load map preserves the builtin data-map-src / onclick wiring. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+
+
+{% if hours %}
{% for row in hours %}{{ row.day }} {% if row.closed %}Closed{% else %}{{ row.hours }}{% endif %} {% endfor %}
{% endif %}
+{% if specialHoursNote %}
{{ specialHoursNote }}
{% endif %}
+{% if address %}
{% endif %}
+{% if phone %}
{% endif %}
+{% if directionsUrl %}
::lucide:navigation:sm::Get directions {% endif %}
+
+{% if mapEmbedUrl %}
+
+::lucide:map-pin:md::{{ mapButtonLabel|default:"Load map" }}
+
+{% endif %}
+
+
diff --git a/templates/overrides/corporate-modernist/image.ninjatpl b/templates/overrides/corporate-modernist/image.ninjatpl
new file mode 100644
index 0000000..82e4371
--- /dev/null
+++ b/templates/overrides/corporate-modernist/image.ninjatpl
@@ -0,0 +1,5 @@
+{# image override — hairline-framed figure with alignment and an optional caption. #}
+{% if src %}{% if align == "left" %}{% set ialign = "flex-start" %}{% elif align == "right" %}{% set ialign = "flex-end" %}{% else %}{% set ialign = "center" %}{% endif %}
+{% img src alt=alt|default:"" class="cm-image-el" %}
+{% if caption %}{{ caption }} {% endif %}
+ {% endif %}
diff --git a/templates/overrides/corporate-modernist/logo-strip.ninjatpl b/templates/overrides/corporate-modernist/logo-strip.ninjatpl
new file mode 100644
index 0000000..07e6fe6
--- /dev/null
+++ b/templates/overrides/corporate-modernist/logo-strip.ninjatpl
@@ -0,0 +1,5 @@
+{# logo-strip override — quiet greyscale client row under a kicker. #}
+
+{% if heading %}
{{ heading }}
{% endif %}
+
+
diff --git a/templates/overrides/corporate-modernist/menu-list.ninjatpl b/templates/overrides/corporate-modernist/menu-list.ninjatpl
new file mode 100644
index 0000000..2569d63
--- /dev/null
+++ b/templates/overrides/corporate-modernist/menu-list.ninjatpl
@@ -0,0 +1,21 @@
+{# menu-list override — sectioned price list; tabular-numeral prices right-aligned, dietary badges as hairline pills. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+
+{% for section in sections %}{% endfor %}
+
+{% if footnote %}
{{ footnote }}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/navbar.ninjatpl b/templates/overrides/corporate-modernist/navbar.ninjatpl
new file mode 100644
index 0000000..fba3093
--- /dev/null
+++ b/templates/overrides/corporate-modernist/navbar.ninjatpl
@@ -0,0 +1 @@
+ {% if logoType == "image" and logo %}{% img logo alt=alt|default:"Home" class="cm-brand-logo" %}{% else %}{{ logoText.text|default:logoText|default:context.site.title|default:"Studio" }} {% endif %}::lucide:menu:sm::
diff --git a/templates/overrides/corporate-modernist/newsletter-signup.ninjatpl b/templates/overrides/corporate-modernist/newsletter-signup.ninjatpl
new file mode 100644
index 0000000..142ddad
--- /dev/null
+++ b/templates/overrides/corporate-modernist/newsletter-signup.ninjatpl
@@ -0,0 +1 @@
+{% if title %}
{{ title }} {% endif %}{% if description %}
{{ description }}
{% endif %}
{% signup_form list=listSlug source=source submit=submitText success_message=successMessage placeholder=placeholder %}
diff --git a/templates/overrides/corporate-modernist/page-suggestions.ninjatpl b/templates/overrides/corporate-modernist/page-suggestions.ninjatpl
new file mode 100644
index 0000000..0e5849e
--- /dev/null
+++ b/templates/overrides/corporate-modernist/page-suggestions.ninjatpl
@@ -0,0 +1 @@
+{{ title|default:"Were you looking for..." }} {% if suggestions %}
{% for s in suggestions %} {% endfor %} {% else %}{% if emptyMessage %}
{{ emptyMessage }}
{% endif %}
{% endif %}
diff --git a/templates/overrides/corporate-modernist/password-reset-form.ninjatpl b/templates/overrides/corporate-modernist/password-reset-form.ninjatpl
new file mode 100644
index 0000000..6e25638
--- /dev/null
+++ b/templates/overrides/corporate-modernist/password-reset-form.ninjatpl
@@ -0,0 +1,11 @@
+
diff --git a/templates/overrides/corporate-modernist/popular-posts.ninjatpl b/templates/overrides/corporate-modernist/popular-posts.ninjatpl
new file mode 100644
index 0000000..e92e4ce
--- /dev/null
+++ b/templates/overrides/corporate-modernist/popular-posts.ninjatpl
@@ -0,0 +1 @@
+{% if heading %}{{ heading }} {% endif %}{% for post in posts %}{% if showRank %}{{ forloop.Counter }} {% endif %}{% if showThumbnail and post.featured_image_url %} {% endif %}{% if post.published_at %}
{{ post.published_at|date:"M j, Y" }}
{% endif %}
{% endfor %}
diff --git a/templates/overrides/corporate-modernist/post-hero.ninjatpl b/templates/overrides/corporate-modernist/post-hero.ninjatpl
new file mode 100644
index 0000000..e4a3901
--- /dev/null
+++ b/templates/overrides/corporate-modernist/post-hero.ninjatpl
@@ -0,0 +1 @@
+{% if context.currentPost.featuredImageUrl %}
{% endif %}
{{ context.currentPost.title }} {% if showExcerpt and context.currentPost.excerpt %}
{{ context.currentPost.excerpt }}
{% endif %}{% if showMeta %}
{% if context.currentPost.authorName %}{{ context.currentPost.authorName }} {% endif %}{% if context.currentPost.publishedAt %}{{ context.currentPost.publishedAt }} {% endif %}{% if context.currentPost.readingTimeMinutes %}{{ context.currentPost.readingTimeMinutes }} min read {% endif %}
{% endif %}
diff --git a/templates/overrides/corporate-modernist/post-metadata.ninjatpl b/templates/overrides/corporate-modernist/post-metadata.ninjatpl
new file mode 100644
index 0000000..43fd8c9
--- /dev/null
+++ b/templates/overrides/corporate-modernist/post-metadata.ninjatpl
@@ -0,0 +1 @@
+{% if showAuthor and context.currentPost.authorName %}
{% if showAvatar and context.currentPost.authorAvatarUrl %} {% endif %}{{ context.currentPost.authorName }} {% endif %}{% if showDate and context.currentPost.publishedAt %}
{{ context.currentPost.publishedAt }} {% endif %}{% if showReadingTime and context.currentPost.readingTimeMinutes %}
{{ context.currentPost.readingTimeMinutes }} min read {% endif %}
diff --git a/templates/overrides/corporate-modernist/pricing.ninjatpl b/templates/overrides/corporate-modernist/pricing.ninjatpl
new file mode 100644
index 0000000..1521f41
--- /dev/null
+++ b/templates/overrides/corporate-modernist/pricing.ninjatpl
@@ -0,0 +1,14 @@
+{# pricing override — flat hairline tiers, mono price figures, accent-top featured tier. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if tiers %}
{% for tier in tiers %}
+{% if tier.badge %}
{{ tier.badge }} {% endif %}
+{% if tier.name %}
{{ tier.name }} {% endif %}
+
{% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }} {% if tier.period %}{{ tier.period }} {% endif %}
+{% if tier.description %}
{{ tier.description }}
{% endif %}
+{% if tier.features %}
{% for feature in tier.features %}::lucide:check:sm:: {{ feature }} {% endfor %} {% endif %}
+{% if tier.ctaUrl and tier.ctaLabel %}{% if tier.highlighted %}
{{ tier.ctaLabel }} {% else %}
{{ tier.ctaLabel }} {% endif %}{% endif %}
+
{% endfor %}
{% endif %}
+{% if billingNote %}
{{ billingNote }}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/quote.ninjatpl b/templates/overrides/corporate-modernist/quote.ninjatpl
new file mode 100644
index 0000000..7502b40
--- /dev/null
+++ b/templates/overrides/corporate-modernist/quote.ninjatpl
@@ -0,0 +1,6 @@
+{# quote override — pull quote (accent top rule) / block quote (accent left rule) / inline card. #}
+{% if style == "pull" %}{% set qcls = "cm-pull-quote" %}{% set qsty = "margin:2rem 0;" %}{% elif style == "inline-card" %}{% set qcls = "cm-quote-block cm-card cm-card-accent" %}{% set qsty = "margin:2rem 0;" %}{% else %}{% set qcls = "cm-quote-block" %}{% set qsty = "margin:2rem 0;border-left:2px solid hsl(var(--accent));padding-left:1.25rem;" %}{% endif %}
+
+{{ quote|safe }}
+{% if attribution or role or cite %}{% if attribution %}{{ attribution }} {% endif %}{% if role %}{{ role }} {% endif %}{% if cite %}Source {% endif %} {% endif %}
+
diff --git a/templates/overrides/corporate-modernist/related-posts.ninjatpl b/templates/overrides/corporate-modernist/related-posts.ninjatpl
new file mode 100644
index 0000000..04521d8
--- /dev/null
+++ b/templates/overrides/corporate-modernist/related-posts.ninjatpl
@@ -0,0 +1 @@
+{{ heading|default:"Related posts" }} {% for post in posts %}
{% if post.featured_image_url %} {% endif %}{% if post.published_at %}{{ post.published_at|date:"M j, Y" }}
{% endif %} {% endfor %}
diff --git a/templates/overrides/corporate-modernist/rich-section.ninjatpl b/templates/overrides/corporate-modernist/rich-section.ninjatpl
new file mode 100644
index 0000000..c27fcdd
--- /dev/null
+++ b/templates/overrides/corporate-modernist/rich-section.ninjatpl
@@ -0,0 +1,10 @@
+{# rich-section override — two-column media + rich text, hairline surface options. #}
+
+
+{% if eyebrow %}
{{ eyebrow }}
{% endif %}
+{% if heading %}
{{ heading }} {% endif %}
+{% if body %}
{{ body|safe }}
{% endif %}
+{% if ctaUrl and ctaLabel %}
{{ ctaLabel }}::lucide:arrow-right:sm:: {% endif %}
+
+
{% if media %}{% img media alt=mediaAlt class="cm-rich-media" %}{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/rich-text.ninjatpl b/templates/overrides/corporate-modernist/rich-text.ninjatpl
new file mode 100644
index 0000000..bbee721
--- /dev/null
+++ b/templates/overrides/corporate-modernist/rich-text.ninjatpl
@@ -0,0 +1,2 @@
+{# rich-text override — raw imported HTML inside the Swiss reading measure. #}
+{% if html %}{{ html|safe }}
{% endif %}
diff --git a/templates/overrides/corporate-modernist/sidebar-nav.ninjatpl b/templates/overrides/corporate-modernist/sidebar-nav.ninjatpl
new file mode 100644
index 0000000..870c7e9
--- /dev/null
+++ b/templates/overrides/corporate-modernist/sidebar-nav.ninjatpl
@@ -0,0 +1,3 @@
+{% if title %}{{ title }} {% endif %}{% for item in menu.items %} {% endfor %} {% if highlightCurrent %}{% endif %}
diff --git a/templates/overrides/corporate-modernist/social-links.ninjatpl b/templates/overrides/corporate-modernist/social-links.ninjatpl
new file mode 100644
index 0000000..77a3388
--- /dev/null
+++ b/templates/overrides/corporate-modernist/social-links.ninjatpl
@@ -0,0 +1,7 @@
+{# social-links override — icon row or labelled stack; each link a hairline cm-social-link (rendered only when it has a URL). #}
+
+{% if heading %}
{{ heading }}
{% endif %}
+
+
diff --git a/templates/overrides/corporate-modernist/stats.ninjatpl b/templates/overrides/corporate-modernist/stats.ninjatpl
new file mode 100644
index 0000000..5b3211c
--- /dev/null
+++ b/templates/overrides/corporate-modernist/stats.ninjatpl
@@ -0,0 +1,6 @@
+{# stats override — oversized tabular figures over a hairline, no count-up JS. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if items %}
{% for item in items %}
{% if item.prefix %}{{ item.prefix }}{% endif %}{{ item.value }}{% if item.suffix %}{{ item.suffix }}{% endif %}
{% if item.label %}
{{ item.label }}
{% endif %}
{% endfor %}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/team.ninjatpl b/templates/overrides/corporate-modernist/team.ninjatpl
new file mode 100644
index 0000000..883486d
--- /dev/null
+++ b/templates/overrides/corporate-modernist/team.ninjatpl
@@ -0,0 +1,12 @@
+{# team override — leadership grid, square-framed portraits, restrained social row. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if members %}
{% for member in members %}
+{% if member.photo %}
{% img member.photo alt=member.name class="cm-team-photo" %}
{% endif %}
+{% if member.name %}
{{ member.name }} {% endif %}
+{% if member.role %}
{{ member.role }}
{% endif %}
+{% if member.bio %}
{{ member.bio }}
{% endif %}
+{% if member.socials %}
{% endif %}
+
{% endfor %}
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/testimonial.ninjatpl b/templates/overrides/corporate-modernist/testimonial.ninjatpl
new file mode 100644
index 0000000..4ea8b53
--- /dev/null
+++ b/templates/overrides/corporate-modernist/testimonial.ninjatpl
@@ -0,0 +1,9 @@
+{# testimonial override — accent-ruled pull quotes, optional 5-star scale. #}
+
+{% if heading %}
{{ heading }} {% endif %}
+
{% for q in quotes %}
+{% if q.rating %}::lucide:star:sm:: ::lucide:star:sm:: ::lucide:star:sm:: ::lucide:star:sm:: ::lucide:star:sm::
{% endif %}
+{% if q.quote %}{{ q.quote }} {% endif %}
+{% if q.avatar %}{% img q.avatar alt=q.name class="cm-avatar-img" %} {% endif %}{% if q.name %}{{ q.name }} {% endif %}{% if q.role %}{{ q.role }} {% endif %}
+ {% endfor %}
+
diff --git a/templates/overrides/corporate-modernist/timeline.ninjatpl b/templates/overrides/corporate-modernist/timeline.ninjatpl
new file mode 100644
index 0000000..ff512a0
--- /dev/null
+++ b/templates/overrides/corporate-modernist/timeline.ninjatpl
@@ -0,0 +1,6 @@
+{# timeline override — numbered Swiss rail (mirrors engagement_process). #}
+
+{% if heading %}
{{ heading }} {% endif %}
+{% if intro %}
{{ intro }}
{% endif %}
+{% if steps %}
{% for step in steps %}
{{ forloop.Counter }} {% if not forloop.Last %} {% endif %}
{% if step.label %}
{{ step.label }}
{% endif %}{% if step.title %}
{{ step.title }} {% endif %}{% if step.text %}
{{ step.text }}
{% endif %}{% if step.media %}
{% img step.media alt=step.title class="cm-timeline-media" %}
{% endif %}
{% endfor %}
{% else %}
No steps configured.
{% endif %}
+
diff --git a/templates/overrides/corporate-modernist/utility-bar.ninjatpl b/templates/overrides/corporate-modernist/utility-bar.ninjatpl
new file mode 100644
index 0000000..44d3eb0
--- /dev/null
+++ b/templates/overrides/corporate-modernist/utility-bar.ninjatpl
@@ -0,0 +1,9 @@
+{# utility-bar override — thin Swiss top strip; left/right item groups; icon-picker fields render via ::pack:name:: shorthand. #}
+{% if variant == "primary" %}{% set ubvar = "cm-utility-bar--primary" %}{% set ubsty = "background:hsl(var(--primary));color:hsl(var(--primary-foreground));" %}{% elif variant == "dark" %}{% set ubvar = "cm-utility-bar--dark" %}{% set ubsty = "background:hsl(var(--foreground));color:hsl(var(--background));" %}{% else %}{% set ubvar = "cm-utility-bar--muted" %}{% set ubsty = "background:hsl(var(--muted));color:hsl(var(--muted-foreground));border-bottom:1px solid hsl(var(--border));" %}{% endif %}
+{% macro ubitem(it) %}{% if it.link %}{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}{{ it.label }} {% endif %} {% else %}{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}{{ it.label }} {% endif %} {% endif %}{% endmacro %}
+
+
+
{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}
+
{% for it in rightItems %}{{ ubitem(it) }}{% endfor %}
+
+
diff --git a/templates/overrides/corporate-modernist/video-embed.ninjatpl b/templates/overrides/corporate-modernist/video-embed.ninjatpl
new file mode 100644
index 0000000..531e797
--- /dev/null
+++ b/templates/overrides/corporate-modernist/video-embed.ninjatpl
@@ -0,0 +1,11 @@
+{# video-embed override — click-to-load facade; carries data-bn-video / data-video-url / data-video-media so the host facade JS binds. #}
+{% if aspect == "4:3" %}{% set vratio = "4 / 3" %}{% elif aspect == "1:1" %}{% set vratio = "1 / 1" %}{% elif aspect == "21:9" %}{% set vratio = "21 / 9" %}{% else %}{% set vratio = "16 / 9" %}{% endif %}
+
+
+
+{% if poster %}{% img poster alt=title|default:"" class="cm-video-poster" %}{% endif %}
+::lucide:play:lg::
+
+
+{% if caption %}{{ caption }} {% endif %}
+