# Brutalist theme — codeless .bnp manifest (WO-WZ-021 Phase B1). # Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm). theme_presets: presets.json bundled_fonts: fonts.json master_pages: master_pages.json required_icon_packs: [lucide, simple-icons] system_templates: - key: brutalist title: Brutalist description: "Concrete, oversized type, hard 12-col grid theme for design studios, architecture firms and art galleries." page_templates: - system: brutalist key: default title: Default description: "Standard masthead + hard-ruled body + colophon footer" slots: [header, main, footer] - system: brutalist key: full-width title: Full Bleed description: "Edge-to-edge gallery layout" slots: [header, main, footer] - system: brutalist key: landing title: Index Sheet description: "Oversized display headline + stacked sections" slots: [header, hero, main, cta, footer] - system: brutalist key: article title: Case Study description: "Long-form project page with post hero and byline" slots: [header, post_hero, main, author, related, footer] - system: brutalist key: blog-index title: Index Ledger description: "Blog listing on a hard grid with featured slab" slots: [header, featured, main, footer] - system: brutalist key: contact title: Contact Sheet description: "Contact form with optional details aside" slots: [header, main, aside, footer] - system: brutalist key: auth title: Access description: "Centered bordered auth card" slots: [main, footer] template_overrides: # Chrome (4) - { template: brutalist, block: navbar } - { template: brutalist, block: footer } - { template: brutalist, block: utility-bar } - { template: brutalist, block: announcement-bar } # Marketing (12) - { template: brutalist, block: hero } - { template: brutalist, block: feature-grid } - { template: brutalist, block: rich-section } - { template: brutalist, block: stats } - { template: brutalist, block: testimonial } - { template: brutalist, block: logo-strip } - { template: brutalist, block: pricing } - { template: brutalist, block: team } - { template: brutalist, block: faq } - { template: brutalist, block: timeline } - { template: brutalist, block: cta } - { template: brutalist, block: countdown } # Primitives (11) - { template: brutalist, block: heading } - { template: brutalist, block: text } - { template: brutalist, block: rich-text } - { template: brutalist, block: image } - { template: brutalist, block: quote } - { template: brutalist, block: divider } - { template: brutalist, block: button } - { template: brutalist, block: card } - { template: brutalist, block: gallery } - { template: brutalist, block: video-embed } - { template: brutalist, block: audio-embed } # Commerce / local (6) - { template: brutalist, block: menu-list } - { template: brutalist, block: event-list } - { template: brutalist, block: contact-form } - { template: brutalist, block: contact-card } - { template: brutalist, block: hours-location } - { template: brutalist, block: social-links } # Blog family (12) - { template: brutalist, block: blog-hero } - { template: brutalist, block: featured-posts } - { template: brutalist, block: related-posts } - { template: brutalist, block: popular-posts } - { template: brutalist, block: category-list } - { template: brutalist, block: post-hero } - { template: brutalist, block: post-metadata } - { template: brutalist, block: author-bio } - { template: brutalist, block: author-bio-hero } - { template: brutalist, block: newsletter-signup } - { template: brutalist, block: breadcrumbs } - { template: brutalist, block: sidebar-nav } # Auth surface (3) - { template: brutalist, block: auth-form } - { template: brutalist, block: password-reset-form } - { template: brutalist, block: auth-status } # System (1) - { template: brutalist, block: page-suggestions } email_wrappers: - brutalist css: input_css_append: | /* === Brutalist theme utilities === */ /* Bundled display faces. The host does not yet emit @font-face for * bundled_fonts (LoadedPlugin.BundledFonts is unconsumed), so the theme * self-serves them from its packed asset dir (/templates/brutalist/fonts/...). * Presets set typography.fontHeading/body/mono to template:brutalist: * so --font-heading/body/mono resolve to these families. Families/weights * mirror fonts.json exactly (8 woff2). */ @font-face { font-family: 'Space Grotesk'; src: url('/templates/brutalist/fonts/space-grotesk-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; } @font-face { font-family: 'Space Grotesk'; src: url('/templates/brutalist/fonts/space-grotesk-700.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; } @font-face { font-family: 'Archivo Black'; src: url('/templates/brutalist/fonts/archivo-black-400.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'Inter'; src: url('/templates/brutalist/fonts/inter-400.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'Inter'; src: url('/templates/brutalist/fonts/inter-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; } @font-face { font-family: 'Inter'; src: url('/templates/brutalist/fonts/inter-700.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; } @font-face { font-family: 'IBM Plex Mono'; src: url('/templates/brutalist/fonts/ibm-plex-mono-400.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: 'IBM Plex Mono'; src: url('/templates/brutalist/fonts/ibm-plex-mono-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; } :where(.brutalist-page, .brutalist-page *) { border-radius: 0 !important; } .brutalist-page { font-family: var(--font-body, "Inter", "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif); color: hsl(var(--foreground)); background-color: hsl(var(--background)); letter-spacing: 0.005em; } .brutalist-display { font-family: var(--font-heading, "Space Grotesk", "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif); font-weight: 700; letter-spacing: -0.02em; line-height: 0.9; text-transform: uppercase; } .brutalist-mono { font-family: var(--font-mono, "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace); letter-spacing: 0.04em; text-transform: uppercase; } /* --- Hairline rules and solid slabs --- */ .brutalist-rule-ink { border-color: hsl(var(--border)); border-style: solid; border-width: 1px; } .brutalist-rule-thick { border-color: hsl(var(--border)); border-style: solid; border-width: 4px; } .brutalist-divider { border-top: 1px solid hsl(var(--border)); } /* --- 12-column grid scaffolding --- */ .brutalist-grid-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: 0; row-gap: 0; } .brutalist-col-span-8 { grid-column: span 8 / span 8; } /* Project ledger row: 12-col grid with mono leading number. */ .brutalist-ledger-row { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: baseline; padding: 1.25rem 0; border-bottom: 1px solid hsl(var(--border)); } .brutalist-ledger-row > * { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.875rem; letter-spacing: 0.06em; text-transform: uppercase; } .brutalist-ledger-row .ledger-no { grid-column: span 1; } .brutalist-ledger-row .ledger-year { grid-column: span 2; } .brutalist-ledger-row .ledger-client { grid-column: span 5; font-family: var(--font-heading, "Space Grotesk", sans-serif); font-size: 1.125rem; text-transform: none; letter-spacing: -0.005em; } .brutalist-ledger-row .ledger-role { grid-column: span 3; } .brutalist-ledger-row .ledger-arrow { grid-column: span 1; text-align: right; } @media (max-width: 768px) { .brutalist-ledger-row { grid-template-columns: 1fr; row-gap: 0.25rem; padding: 1rem 0; } .brutalist-ledger-row .ledger-no, .brutalist-ledger-row .ledger-year, .brutalist-ledger-row .ledger-client, .brutalist-ledger-row .ledger-role, .brutalist-ledger-row .ledger-arrow { grid-column: 1 / -1; text-align: left; } } /* --- Caption block --- */ .brutalist-figure figcaption { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 11px; line-height: 1.4; letter-spacing: 0.08em; text-transform: uppercase; color: hsl(var(--muted-foreground)); padding-top: 0.5rem; } /* --- Pull quote --- */ .brutalist-pullquote { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); padding: 3rem 0; border-top: 1px solid hsl(var(--border)); border-bottom: 1px solid hsl(var(--border)); } .brutalist-pullquote blockquote { grid-column: 3 / span 8; font-family: var(--font-heading, "Space Grotesk", sans-serif); font-weight: 700; font-size: clamp(1.75rem, 5vw, 3.5rem); line-height: 1; letter-spacing: -0.02em; color: hsl(var(--foreground)); } .brutalist-pullquote cite { grid-column: 3 / span 8; margin-top: 1.5rem; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; font-style: normal; color: hsl(var(--muted-foreground)); } @media (max-width: 768px) { .brutalist-pullquote blockquote, .brutalist-pullquote cite { grid-column: 1 / -1; } } /* --- Meta strip --- */ .brutalist-meta-strip { display: flex; flex-wrap: wrap; gap: 2rem; padding: 1rem 0; border-top: 1px solid hsl(var(--border)); border-bottom: 1px solid hsl(var(--border)); } .brutalist-meta-strip dt { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: hsl(var(--muted-foreground)); } .brutalist-meta-strip dd { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase; color: hsl(var(--foreground)); margin: 0; } /* --- Buttons: square, 1px ink border, hover inverts to accent --- */ .brutalist-page button, .brutalist-page .brutalist-btn, .brutalist-page [data-brutalist-btn] { display: inline-flex; align-items: center; justify-content: center; padding: 0.75rem 1.5rem; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; background-color: transparent; color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); border-radius: 0; cursor: pointer; transition: background-color 80ms linear, color 80ms linear; } .brutalist-page button:hover, .brutalist-page .brutalist-btn:hover, .brutalist-page [data-brutalist-btn]:hover { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); } .brutalist-page button:focus-visible, .brutalist-page .brutalist-btn:focus-visible, .brutalist-page [data-brutalist-btn]:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } /* --- Inputs: square --- */ .brutalist-page input, .brutalist-page select, .brutalist-page textarea { border-radius: 0; border: 1px solid hsl(var(--input)); background-color: transparent; color: hsl(var(--foreground)); padding: 0.5rem 0.75rem; } .brutalist-page input:focus, .brutalist-page select:focus, .brutalist-page textarea:focus { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } /* --- Masthead --- */ .brutalist-masthead { position: relative; padding: 4rem 0 2rem; } .brutalist-masthead .studio-name { font-family: var(--font-heading, "Space Grotesk", sans-serif); font-weight: 700; font-size: clamp(3rem, 14vw, 16rem); line-height: 0.85; letter-spacing: -0.03em; text-transform: uppercase; color: hsl(var(--foreground)); margin: 0; } .brutalist-masthead .tagline { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; color: hsl(var(--muted-foreground)); margin-top: 1rem; } .brutalist-masthead .index-counter { position: absolute; top: 1.5rem; right: 0; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: hsl(var(--muted-foreground)); } /* --- Concrete hero --- */ .brutalist-hero { position: relative; padding: 6rem 0 4rem; overflow: hidden; } .brutalist-hero .eyebrow { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.16em; text-transform: uppercase; color: hsl(var(--muted-foreground)); margin-bottom: 1.5rem; } .brutalist-hero .headline { font-family: var(--font-heading, "Space Grotesk", sans-serif); font-weight: 700; font-size: clamp(3rem, 22vw, 18rem); line-height: 0.85; letter-spacing: -0.04em; text-transform: uppercase; color: hsl(var(--foreground)); margin: 0; } .brutalist-hero[data-has-media="true"] .headline { color: hsl(var(--background)); mix-blend-mode: difference; } .brutalist-hero .media-bg { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; } .brutalist-hero .media-bg::after { content: ""; position: absolute; inset: 0; background-color: hsl(var(--background) / 0.4); } .brutalist-hero .inner { position: relative; z-index: 1; } /* --- Colophon --- */ .brutalist-colophon { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2rem; padding: 3rem 0 1.5rem; border-top: 4px solid hsl(var(--border)); 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)); } .brutalist-colophon .stamp { text-align: right; color: hsl(var(--foreground)); } @media (max-width: 768px) { .brutalist-colophon { grid-template-columns: 1fr; } .brutalist-colophon .stamp { text-align: left; } } /* --- Grid overlay debug --- */ body.brutalist-grid-debug::before { content: ""; position: fixed; inset: 0; z-index: 9999; pointer-events: none; background-image: repeating-linear-gradient( to right, hsl(var(--ring) / 0.18) 0, hsl(var(--ring) / 0.18) 1px, transparent 1px, transparent calc(100% / 12) ); } /* ============================================================ BRUTALIST OVERRIDE KIT (Wave A) — semantic classes the block overrides apply. Raw CSS (not Tailwind @apply) so it ships in the codeless manifest regardless of JIT scanning. All colour via hsl(var(--token)); all type via var(--font-*). ============================================================ */ .bru-section { padding: 2.75rem 0; } @media (min-width: 768px) { .bru-section { padding: 4rem 0; } } /* Landing: stacked full-bleed sections butt against a hard rule instead of doubling their padding into a dead void (Wave B design-review fix). The CMS wraps every block in its own
, so the .bru-section elements are NOT DOM siblings — the divider adjacency must target the block wrappers ([data-block-id] + [data-block-id]), not the sections. */ [data-brutalist-template="landing"] main .bru-section { padding-top: 2.75rem; padding-bottom: 2.75rem; } [data-brutalist-template="landing"] main [data-block-id] + [data-block-id] .bru-section { border-top: 4px solid hsl(var(--border)); } @media (min-width: 768px) { [data-brutalist-template="landing"] main .bru-section { padding-top: 3rem; padding-bottom: 3rem; } } .bru-wrap { width: 100%; max-width: 80rem; margin: 0 auto; padding: 0 1.5rem; } .bru-wrap-mid { width: 100%; max-width: 64rem; margin: 0 auto; padding: 0 1.5rem; } .bru-wrap-narrow { width: 100%; max-width: 44rem; margin: 0 auto; padding: 0 1.5rem; } /* Slab = the core bordered block. Shadow = the hard offset. */ .bru-slab { border: 3px solid hsl(var(--border)); background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); } .bru-slab-bg { border: 3px solid hsl(var(--border)); background-color: hsl(var(--background)); color: hsl(var(--foreground)); } .bru-shadow { box-shadow: 6px 6px 0 0 hsl(var(--border)); } .bru-shadow-sm { box-shadow: 4px 4px 0 0 hsl(var(--border)); } .bru-shadow-accent { box-shadow: 6px 6px 0 0 hsl(var(--accent)); } /* Hover snap: the block nudges into its own shadow. */ .bru-hover { transition: transform 90ms linear, box-shadow 90ms linear; } @media (prefers-reduced-motion: no-preference) { .bru-hover:hover { transform: translate(3px, 3px); box-shadow: 3px 3px 0 0 hsl(var(--border)); } .bru-hover.bru-shadow-sm:hover { transform: translate(2px, 2px); box-shadow: 2px 2px 0 0 hsl(var(--border)); } } /* Type utilities */ .bru-eyebrow { display: inline-block; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase; color: hsl(var(--muted-foreground)); } .bru-kicker { font-family: var(--font-heading, "Space Grotesk", "Inter Tight", sans-serif); font-weight: 700; text-transform: uppercase; letter-spacing: -0.015em; line-height: 1; color: hsl(var(--foreground)); } .bru-meta { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase; color: hsl(var(--muted-foreground)); } /* Sticker tag — candy accent chip with a hard border. */ .bru-tag { display: inline-flex; align-items: center; gap: 0.35rem; border: 2px solid hsl(var(--border)); background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); padding: 0.15rem 0.55rem; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase; line-height: 1.4; box-shadow: 2px 2px 0 0 hsl(var(--border)); } .bru-tag-ghost { background-color: transparent; color: hsl(var(--foreground)); box-shadow: none; } /* Buttons */ .bru-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.7rem 1.4rem; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase; border: 3px solid hsl(var(--border)); text-decoration: none; cursor: pointer; box-shadow: 4px 4px 0 0 hsl(var(--border)); transition: transform 90ms linear, box-shadow 90ms linear; } .bru-btn-solid { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); } .bru-btn-ghost { background-color: hsl(var(--background)); color: hsl(var(--foreground)); } @media (prefers-reduced-motion: no-preference) { .bru-btn:hover { transform: translate(2px, 2px); box-shadow: 2px 2px 0 0 hsl(var(--border)); } } .bru-btn:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } /* Hard rules */ .bru-rule { border: 0; border-top: 3px solid hsl(var(--border)); margin: 0; } .bru-rule-thin { border: 0; border-top: 1px solid hsl(var(--border)); margin: 0; } /* Inputs (block-level, complements the page-wide input reset above) */ .bru-field { width: 100%; border: 3px solid hsl(var(--input)); background-color: hsl(var(--background)); color: hsl(var(--foreground)); padding: 0.65rem 0.85rem; font-family: var(--font-body, "Inter", sans-serif); font-size: 0.95rem; } .bru-field:focus { outline: 2px solid hsl(var(--ring)); outline-offset: 2px; } .bru-label { display: block; margin-bottom: 0.4rem; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: hsl(var(--foreground)); } /* Numbered index cell (ledgers, ranks, steps) */ .bru-index { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-variant-numeric: tabular-nums; color: hsl(var(--accent)); font-weight: 700; } /* Sticker wall / changelog / spec-sheet persona furniture */ .bru-sticker { display: inline-flex; align-items: center; justify-content: center; text-align: center; border: 3px solid hsl(var(--border)); padding: 1rem 1.25rem; font-family: var(--font-heading, "Space Grotesk", sans-serif); font-weight: 700; text-transform: uppercase; letter-spacing: -0.01em; line-height: 1; box-shadow: 4px 4px 0 0 hsl(var(--border)); } .bru-changelog-row { display: grid; grid-template-columns: 8rem 1fr; gap: 1.5rem; padding: 1.5rem 0; border-top: 1px solid hsl(var(--border)); } .bru-changelog-row:last-child { border-bottom: 1px solid hsl(var(--border)); } @media (max-width: 640px) { .bru-changelog-row { grid-template-columns: 1fr; gap: 0.5rem; } } .bru-spec-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; padding: 0.85rem 0; border-top: 1px solid hsl(var(--border)); font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.8rem; letter-spacing: 0.04em; } .bru-spec-row:last-child { border-bottom: 1px solid hsl(var(--border)); } .bru-spec-row dt { text-transform: uppercase; color: hsl(var(--muted-foreground)); } .bru-spec-row dd { margin: 0; text-align: right; color: hsl(var(--foreground)); } /* Base media guarantee: element selector mirroring Tailwind preflight. All utility-class layout scaffolding -- grid, grid-cols, col-span, p, gap, space-y, aspect, object, w/h-full plus sm/md/lg variants -- was removed here: the host Tailwind build now scans theme .ninjatpl templates, so those classes compile natively from template usage. */ .brutalist-page img { max-width: 100%; }