themes-magazine-bold/manifest.yaml
Alex Dunmow 98293cf8ab feat(magazine-bold): Wave A theme lane (WO-TF-021) — streetwear / fashion drops
Full Wave A build to the OVERRIDE-CONTRACT (frozen cms a0f07e2ae):

- 49 mandatory builtin overrides in templates/overrides/magazine-bold/,
  re-skinned to streetwear cover-story chrome (massive condensed uppercase
  Archivo Black headlines, heavy 2px rules, hard square edges, mono datelines,
  fluoro accent slabs). Every content field, provider var, custom tag and JS
  block preserved verbatim from the frozen builtin defaults; legacy button
  (link/style/label) and card (media/text) field reads already reconciled.
- 7 page templates: default, full-width, landing, article, blog-index,
  contact, auth.
- 4 persona blocks (deleted masthead/photo_essay/pull_quote/issue_archive/
  colophon — now overrides of navbar/gallery/quote/post-index/footer):
  cover_story, lookbook, drop_calendar, credits_ticker.
- 5 dual-mode presets (newsprint+voltage light / ink-black+fluoro dark), all
  19 tokens, dark tuned not inverted.
- Bundled OFL woff2: Archivo Black (display), Inter (body), IBM Plex Mono
  (labels); fonts.json + assets/fonts/LICENSES.md. All font-family via
  var(--font-heading|body|mono, fallback).
- Themed email-safe wrapper (tables, inline styles, streetwear defaults).
- Master pages (navbar/footer/slot chrome) + seed demo site (OFFCUT label:
  home, about, blog + 3 posts, contact with data table + row_inserted →
  email-admins workflow, login) in fashion-label voice.
- MID motion tier: marquee ticker, scroll reveal, duotone hover, scroll
  progress bar — all prefers-reduced-motion honored with static fallback,
  no canvas.
- Icon packs (lucide, simple-icons) declared in plugin.mod + RECOMMENDED_ICONS.

Verified: `make build` exit 0; `check-safety` 32 checks 19 ok 13 skip -> OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:38:05 +08:00

457 lines
18 KiB
YAML

# Magazine Bold theme — codeless .bnp manifest (Theme Fleet Wave A, WO-TF-021).
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
#
# Persona: a streetwear label / fashion-drop publication. Print-cover energy
# translated to drops and lookbooks — massive condensed uppercase headlines
# (Archivo Black), duotone imagery, grid-breaking overlap, mono datelines and
# fluoro accent slabs. Newsprint-plus-voltage by day, ink-black-plus-fluoro by
# night. Colour ALWAYS via hsl(var(--token)); font families ALWAYS via
# var(--font-heading|body|mono, <fallback>). No literal colours, no hardcoded
# families. Motion tier MID: JS effects (marquee, scroll reveal, duotone hover),
# no canvas, prefers-reduced-motion honored with static fallbacks.
theme_presets: presets.json
bundled_fonts: fonts.json
master_pages: master_pages.json
system_templates:
- key: magazine-bold
title: Magazine Bold
description: "A streetwear label's cover-story chrome: massive condensed uppercase headlines, duotone imagery, grid-breaking overlap and fluoro accent slabs. Built for fashion drops, lookbooks and culture publications."
page_templates:
- system: magazine-bold
key: default
title: Default
description: "Standard page: masthead, single reading column, colophon footer."
slots: [header, main, footer]
- system: magazine-bold
key: full-width
title: Full Bleed
description: "Edge-to-edge for lookbooks, cover images and photo essays."
slots: [header, main, footer]
- system: magazine-bold
key: landing
title: Cover / Drop
description: "Cover-story stack: masthead, lead drop, river of stories, colophon."
slots: [masthead, lead, river, footer]
- system: magazine-bold
key: article
title: Feature
description: "Long-form feature: byline, drop-cap opener, reading column with a marginalia rail."
slots: [header, byline, main, marginalia, footer]
- system: magazine-bold
key: blog-index
title: Archive
description: "Drop archive: masthead, featured drop, and a river of stories."
slots: [header, featured, main, footer]
- system: magazine-bold
key: contact
title: Studio
description: "Contact layout with an optional aside for stockists, hours and location."
slots: [header, main, aside, footer]
- system: magazine-bold
key: auth
title: Members
description: "Centred members shell with wordmark and a fluoro rule."
slots: [main, footer]
template_overrides:
# Chrome (4)
- { template: magazine-bold, block: navbar }
- { template: magazine-bold, block: footer }
- { template: magazine-bold, block: utility-bar }
- { template: magazine-bold, block: announcement-bar }
# Marketing (12)
- { template: magazine-bold, block: hero }
- { template: magazine-bold, block: feature-grid }
- { template: magazine-bold, block: rich-section }
- { template: magazine-bold, block: stats }
- { template: magazine-bold, block: testimonial }
- { template: magazine-bold, block: logo-strip }
- { template: magazine-bold, block: pricing }
- { template: magazine-bold, block: team }
- { template: magazine-bold, block: faq }
- { template: magazine-bold, block: timeline }
- { template: magazine-bold, block: cta }
- { template: magazine-bold, block: countdown }
# Primitives (11)
- { template: magazine-bold, block: heading }
- { template: magazine-bold, block: text }
- { template: magazine-bold, block: rich-text }
- { template: magazine-bold, block: image }
- { template: magazine-bold, block: quote }
- { template: magazine-bold, block: divider }
- { template: magazine-bold, block: button }
- { template: magazine-bold, block: card }
- { template: magazine-bold, block: gallery }
- { template: magazine-bold, block: video-embed }
- { template: magazine-bold, block: audio-embed }
# Commerce / local (6)
- { template: magazine-bold, block: menu-list }
- { template: magazine-bold, block: event-list }
- { template: magazine-bold, block: contact-form }
- { template: magazine-bold, block: contact-card }
- { template: magazine-bold, block: hours-location }
- { template: magazine-bold, block: social-links }
# Blog family (12)
- { template: magazine-bold, block: blog-hero }
- { template: magazine-bold, block: featured-posts }
- { template: magazine-bold, block: related-posts }
- { template: magazine-bold, block: popular-posts }
- { template: magazine-bold, block: category-list }
- { template: magazine-bold, block: post-hero }
- { template: magazine-bold, block: post-metadata }
- { template: magazine-bold, block: author-bio }
- { template: magazine-bold, block: author-bio-hero }
- { template: magazine-bold, block: newsletter-signup }
- { template: magazine-bold, block: breadcrumbs }
- { template: magazine-bold, block: sidebar-nav }
# Auth surface (3)
- { template: magazine-bold, block: auth-form }
- { template: magazine-bold, block: password-reset-form }
- { template: magazine-bold, block: auth-status }
# System (1)
- { template: magazine-bold, block: page-suggestions }
email_wrappers:
- magazine-bold
css:
input_css_append: |
/* === Magazine Bold theme — utility layer ===
*
* Streetwear / fashion-drop identity: massive condensed uppercase headlines,
* heavy 2px rules, hard square edges, mono datelines and fluoro accent slabs.
* Colour is ALWAYS consumed via hsl(var(--token)); font families ALWAYS via
* var(--font-heading|body|mono, <fallback>). No literal colours, no hardcoded
* families.
*/
@layer utilities {
:root {
--mb-measure: 68ch;
--mb-rule: 2px solid hsl(var(--foreground));
}
/* --- Font slots (consume CMS-managed font variables) --- */
.font-display { font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif); }
.font-sans { font-family: var(--font-body, "Inter", system-ui, sans-serif); }
.font-mono { font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace); }
/* --- Page widths / reading measures --- */
.mb-column {
max-width: var(--mb-measure);
margin-left: auto; margin-right: auto;
padding-left: 1rem; padding-right: 1rem;
}
.mb-wide {
max-width: 80rem;
margin-left: auto; margin-right: auto;
padding-left: 1rem; padding-right: 1rem;
}
.mb-article-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
max-width: 84rem;
margin-left: auto; margin-right: auto;
padding-left: 1rem; padding-right: 1rem;
}
@media (min-width: 1024px) {
.mb-article-grid { grid-template-columns: minmax(0, 68ch) 18rem; }
}
/* --- Prose reading column --- */
.mb-prose {
max-width: var(--mb-measure);
margin-left: auto; margin-right: auto;
font-family: var(--font-body, "Inter", system-ui, sans-serif);
color: hsl(var(--foreground));
line-height: 1.6;
}
.mb-prose p { margin: 0 0 1.15em 0; }
.mb-prose h1, .mb-prose h2, .mb-prose h3, .mb-prose h4 {
font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif);
text-transform: uppercase;
letter-spacing: -0.01em;
line-height: 1.0;
color: hsl(var(--foreground));
}
.mb-prose a {
color: hsl(var(--accent));
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 2px;
}
.mb-prose blockquote {
font-weight: 500;
border-left: 4px solid hsl(var(--accent));
padding-left: 1rem; margin-left: 0;
color: hsl(var(--foreground));
}
/* --- Mono / tracked labels (kickers, eyebrows, meta) --- */
.mb-caps {
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
text-transform: uppercase;
letter-spacing: 0.14em;
font-weight: 500;
font-size: 0.72rem;
line-height: 1.35;
}
/* --- Display heading (Archivo Black, massive condensed caps) --- */
.mb-heading {
font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif);
text-transform: uppercase;
letter-spacing: -0.02em;
line-height: 0.95;
color: hsl(var(--foreground));
}
.mb-underline { position: relative; padding-bottom: 0.28em; }
.mb-underline::after {
content: "";
position: absolute; left: 0; right: 0; bottom: 0;
height: 4px;
background: hsl(var(--accent));
}
/* --- Heavy rules (bars, not hairlines) --- */
hr.mb-rule, .mb-rule, .mb-hairline {
border: 0;
border-top: var(--mb-rule);
margin: 0;
}
.mb-hairline-top { border-top: var(--mb-rule); }
.mb-hairline-bottom { border-bottom: var(--mb-rule); }
/* --- Body text override --- */
.mb-body {
font-family: var(--font-body, "Inter", system-ui, sans-serif);
color: hsl(var(--foreground));
line-height: 1.6;
}
/* --- Inline accent link --- */
.mb-link {
color: hsl(var(--accent));
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
transition: color 120ms ease, text-decoration-color 120ms ease;
}
.mb-link:hover, .mb-link:focus-visible { color: hsl(var(--foreground)); }
/* --- Button — fluoro / ink slab, square, uppercase mono --- */
.mb-button, .mb-btn {
display: inline-block;
padding: 0.7rem 1.4rem;
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.14em;
background-color: hsl(var(--foreground));
color: hsl(var(--background));
border: 2px solid hsl(var(--foreground));
text-decoration: none;
cursor: pointer;
transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.mb-button:hover, .mb-button:focus, .mb-btn:hover, .mb-btn:focus {
background-color: hsl(var(--accent));
color: hsl(var(--accent-foreground));
border-color: hsl(var(--accent));
}
.mb-button:focus-visible, .mb-btn:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
/* --- Panel / card — heavy 2px frame, hard edges, no shadow --- */
.mb-panel, .mb-card {
border: 2px solid hsl(var(--foreground));
background-color: hsl(var(--card));
transition: border-color 120ms ease, transform 120ms ease;
}
.mb-panel:hover, .mb-card:hover { border-color: hsl(var(--accent)); }
/* --- Form field — heavy border, square, accent focus --- */
.mb-input {
width: 100%;
border: 2px solid hsl(var(--input));
background-color: hsl(var(--background));
color: hsl(var(--foreground));
padding: 0.6rem 0.8rem;
font-family: var(--font-body, "Inter", system-ui, sans-serif);
font-size: 0.95rem;
border-radius: 0;
}
.mb-input::placeholder { color: hsl(var(--muted-foreground)); }
.mb-input:focus {
outline: none;
border-color: hsl(var(--accent));
box-shadow: 0 0 0 2px hsl(var(--accent));
}
/* --- Figure / caption --- */
.mb-figure { margin: 1.5rem 0; }
.mb-figure img { display: block; width: 100%; height: auto; }
.mb-figure figcaption {
margin-top: 0.6rem;
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: hsl(var(--muted-foreground));
}
.mb-caption {
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
font-size: 0.72rem;
line-height: 1.4;
letter-spacing: 0.04em;
color: hsl(var(--muted-foreground));
}
/* --- Drop cap — oversized Archivo Black accent first letter --- */
.mb-dropcap p:first-of-type::first-letter {
font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif);
color: hsl(var(--accent));
float: left;
font-size: 4.6em;
line-height: 0.78;
padding-right: 0.1em;
padding-top: 0.02em;
margin-bottom: -0.08em;
}
/* --- Marginalia rail (mono side notes, MID motion reveal) --- */
.mb-marginalia {
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
font-size: 0.75rem;
line-height: 1.5;
color: hsl(var(--muted-foreground));
}
.mb-marginalia aside {
margin: 0 0 1.5rem 0;
padding-left: 0.75rem;
border-left: var(--mb-rule);
opacity: 0;
animation: mb-fade-in 500ms ease forwards;
}
@keyframes mb-fade-in { to { opacity: 1; } }
@media (max-width: 768px) {
.mb-marginalia {
margin-top: 1.5rem;
border-top: var(--mb-rule);
padding-top: 1rem;
}
}
/* --- Masthead wordmark --- */
.mb-masthead-wordmark {
font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif);
text-transform: uppercase;
letter-spacing: -0.03em;
color: hsl(var(--foreground));
}
/* --- Display size utilities (folio / deck / kicker) --- */
.text-folio {
font-family: var(--font-heading, "Archivo Black", "Arial Black", sans-serif);
font-size: clamp(72px, 16vw, 220px);
line-height: 0.82;
letter-spacing: -0.04em;
text-transform: uppercase;
}
.text-deck {
font-family: var(--font-body, "Inter", system-ui, sans-serif);
font-size: clamp(24px, 3vw, 44px);
line-height: 1.12;
letter-spacing: -0.01em;
font-weight: 500;
}
.text-kicker {
font-family: var(--font-mono, "IBM Plex Mono", ui-monospace, monospace);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.18em;
font-weight: 600;
}
/* --- Asymmetric editorial grids (persona blocks) --- */
.mb-grid-12 { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 1.5rem; }
.mb-photo-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 1.25rem; }
.mb-frame-half { grid-column: span 6 / span 6; }
.mb-frame-full { grid-column: 1 / -1; }
.mb-frame-tall { grid-column: span 5 / span 5; grid-row: span 2; }
@media (max-width: 768px) {
.mb-photo-grid { grid-template-columns: 1fr; }
.mb-frame-half, .mb-frame-full, .mb-frame-tall { grid-column: 1 / -1; grid-row: auto; }
}
/* --- Color-block accent panel --- */
.colorblock-accent { background-color: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
/* --- Full-bleed image --- */
.mb-fullbleed { width: 100vw; max-width: 100vw; margin-left: 50%; transform: translateX(-50%); }
/* --- Duotone photo treatment (signature — persona blocks) --- */
.mb-duotone { position: relative; }
.mb-duotone img { filter: grayscale(1) contrast(1.15); display: block; width: 100%; height: 100%; object-fit: cover; }
.mb-duotone::after {
content: ""; position: absolute; inset: 0;
background: hsl(var(--accent));
mix-blend-mode: multiply;
opacity: 0.55;
transition: opacity 200ms ease;
pointer-events: none;
}
.mb-duotone:hover::after { opacity: 0.2; }
@media (prefers-reduced-motion: reduce) {
.mb-duotone:hover::after { opacity: 0.55; }
}
/* --- Scroll reveal (MID motion; static fallback) --- */
.mb-reveal { opacity: 0; transform: translateY(16px); transition: opacity 500ms ease, transform 500ms ease; }
.mb-reveal.mb-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.mb-reveal { opacity: 1; transform: none; transition: none; }
}
.no-js .mb-reveal { opacity: 1; transform: none; }
/* --- Marquee ticker (MID motion; paused on hover; static fallback) --- */
.mb-marquee { overflow: hidden; white-space: nowrap; }
.mb-marquee-track {
display: inline-block;
will-change: transform;
animation: mb-marquee 22s linear infinite;
}
.mb-marquee:hover .mb-marquee-track { animation-play-state: paused; }
@keyframes mb-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
.mb-marquee-track { animation: none; }
}
/* --- Reading-progress bar (fluoro; scroll-timeline; reduced-motion guard) --- */
.mb-progress {
position: sticky; top: 0;
height: 4px;
background: hsl(var(--accent));
transform-origin: 0 50%;
animation: mb-progress linear both;
animation-timeline: scroll(root block);
z-index: 50;
}
@keyframes mb-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
.mb-progress { animation: none; transform: scaleX(0); }
}
/* --- Per-instance pull-quote accent override (persona quote) --- */
[data-mb-accent="pink"] { --mb-accent-h: 330; --mb-accent-s: 95%; --mb-accent-l: 58%; }
[data-mb-accent="blue"] { --mb-accent-h: 220; --mb-accent-s: 100%; --mb-accent-l: 56%; }
[data-mb-accent="lime"] { --mb-accent-h: 78; --mb-accent-s: 90%; --mb-accent-l: 50%; }
[data-mb-accent] .mb-quote-bar { background-color: hsl(var(--mb-accent-h) var(--mb-accent-s) var(--mb-accent-l)); }
}