themes-gotham/manifest.yaml
Alex Dunmow 8da60d7d5a feat(gotham): Wave A theme-fleet rework — nightlife/private-club identity (WO-TF-018)
Re-skin gotham to the locked nightlife / private members' club persona:
cinematic near-black luxe, brass hairline accents, letterboxed heroes and
tall condensed display type. Codeless .bnp; MID motion tier (JS effects, no
canvas), prefers-reduced-motion honored, no-JS fallback.

- 49 mandatory builtin overrides in templates/overrides/gotham/ (chrome,
  marketing, primitives, commerce/local, blog family, auth surface, 404).
  Field reads, provider fields, form wiring and block JS preserved verbatim
  from the frozen builtins (cms a0f07e2ae); only presentation reskinned.
- 8 page templates (default, landing, article, full-width, blog-index,
  contact, auth + retained centered), dual-mode via theme_mode.
- 4 persona blocks: door_strip, events_marquee, membership_tiers, bottle_menu.
  Removed old theme blocks that duplicated builtins (hero, stats, features,
  footer) — now overrides.
- 5 dual-mode presets (all 19 tokens, light + dark intentional).
- Bundled OFL woff2: Antonio (heading), Cormorant Garamond (body), Inter
  (meta), IBM Plex Mono (mono); all font-family via var(--font-*).
- Themed email-safe wrapper, master pages, seed demo (home/about/blog x3/
  contact+workflow/login) in private-club voice.
- Gotham utility CSS (reel-*, film-grain, spotlight, letterbox-scrim, reveal)
  via manifest css.input_css_append; semantic color tokens only.
- plugin.mod kind="theme", required_icon_packs=["lucide"]; *.bnp gitignored.

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

226 lines
9.9 KiB
YAML

# Gotham theme — codeless .bnp manifest (WO-TF-018, Wave A).
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
#
# Nightlife / private-club identity: cinematic near-black luxe, brass hairline
# accents, letterboxed heroes, tall condensed display type. Utility CSS lives in
# `css.input_css_append` below (host Tailwind pipeline) — colour is always
# hsl(var(--token)) and font-family always var(--font-heading|body|mono, ...).
theme_presets: presets.json
bundled_fonts: fonts.json
master_pages: master_pages.json
system_templates:
- key: gotham
title: Gotham
description: "After-dark identity for a nightlife venue or private members' club — cinematic near-black luxe, brass accents and condensed display type."
page_templates:
- system: gotham
key: default
title: Default
description: "Centred near-black page with brass rails, header, main and footer."
slots: [header, main, footer]
- system: gotham
key: landing
title: Marquee Landing
description: "Letterboxed hero, door strip and a closing CTA for the main room."
slots: [hero, main, cta, footer]
- system: gotham
key: article
title: Feature
description: "Narrow editorial column for press, listings and the house journal."
slots: [header, main, aside, footer]
- system: gotham
key: full-width
title: Grand Room
description: "Edge-to-edge gallery layout for the room, lookbooks and galleries."
slots: [header, main, footer]
- system: gotham
key: blog-index
title: The Journal
description: "Blog index with a brass masthead, featured and post-grid slots."
slots: [header, featured, main, footer]
- system: gotham
key: contact
title: Reservations
description: "Contact layout with an optional aside for hours and the door."
slots: [header, main, aside, footer]
- system: gotham
key: auth
title: Members
description: "Centred members' shell with wordmark and a spotlight crest."
slots: [main, footer]
- system: gotham
key: centered
title: Centered
description: "Narrow centred column for documents and single statements."
slots: [header, main, footer]
template_overrides:
# Chrome (4)
- { template: gotham, block: navbar }
- { template: gotham, block: footer }
- { template: gotham, block: utility-bar }
- { template: gotham, block: announcement-bar }
# Marketing (12)
- { template: gotham, block: hero }
- { template: gotham, block: feature-grid }
- { template: gotham, block: rich-section }
- { template: gotham, block: stats }
- { template: gotham, block: testimonial }
- { template: gotham, block: logo-strip }
- { template: gotham, block: pricing }
- { template: gotham, block: team }
- { template: gotham, block: faq }
- { template: gotham, block: timeline }
- { template: gotham, block: cta }
- { template: gotham, block: countdown }
# Primitives (11)
- { template: gotham, block: heading }
- { template: gotham, block: text }
- { template: gotham, block: rich-text }
- { template: gotham, block: image }
- { template: gotham, block: quote }
- { template: gotham, block: divider }
- { template: gotham, block: button }
- { template: gotham, block: card }
- { template: gotham, block: gallery }
- { template: gotham, block: video-embed }
- { template: gotham, block: audio-embed }
# Commerce / local (6)
- { template: gotham, block: menu-list }
- { template: gotham, block: event-list }
- { template: gotham, block: contact-form }
- { template: gotham, block: contact-card }
- { template: gotham, block: hours-location }
- { template: gotham, block: social-links }
# Blog family (12)
- { template: gotham, block: blog-hero }
- { template: gotham, block: featured-posts }
- { template: gotham, block: related-posts }
- { template: gotham, block: popular-posts }
- { template: gotham, block: category-list }
- { template: gotham, block: post-hero }
- { template: gotham, block: post-metadata }
- { template: gotham, block: author-bio }
- { template: gotham, block: author-bio-hero }
- { template: gotham, block: newsletter-signup }
- { template: gotham, block: breadcrumbs }
- { template: gotham, block: sidebar-nav }
# Auth surface (3)
- { template: gotham, block: auth-form }
- { template: gotham, block: password-reset-form }
- { template: gotham, block: auth-status }
# System (1)
- { template: gotham, block: page-suggestions }
email_wrappers:
- gotham
css:
input_css_append: |
/* Gotham theme — cinematic near-black utility CSS.
*
* Colour is always consumed via hsl(var(--token)); font families always
* come from var(--font-heading|body|mono, <fallback>). No literal colours
* except black scrims layered over IMAGES (letterbox effect).
*/
@layer utilities {
/* reel-rule — brass hairline, 1px ascending to 2px. */
.reel-rule { border: none; border-top: 1px solid hsl(var(--primary)); margin: 0; }
.reel-rule-thick { border: none; border-top: 2px solid hsl(var(--primary)); margin: 0; }
/* reel-frame — thin film frame with brass corner ticks. */
.reel-frame { position: relative; border: 1px solid hsl(var(--border)); padding: 1.25rem 1.5rem; }
.reel-frame::before, .reel-frame::after {
content: ""; position: absolute; width: 14px; height: 14px;
border-color: hsl(var(--primary)); border-style: solid; pointer-events: none;
}
.reel-frame::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.reel-frame::after { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }
/* reel-foil — inset brass glow used on hover / featured states. */
.reel-foil {
box-shadow:
inset 0 0 0 1px hsl(var(--primary)),
inset 0 1px 0 hsl(var(--primary) / 0.5),
inset 0 -1px 0 hsl(var(--primary) / 0.3);
}
/* reel-caps — condensed caps tracking for display headings. */
.reel-caps { text-transform: uppercase; letter-spacing: 0.12em; }
/* reel-underline — brass hairline underline on headings. */
.reel-underline { position: relative; padding-bottom: 0.35em; }
.reel-underline::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: hsl(var(--primary)); }
/* reel-btn — the invitation. Brass on near-black, inverts on hover. */
.reel-btn {
display: inline-flex; align-items: center; gap: 0.5rem;
border: 1px solid hsl(var(--primary));
background-color: hsl(var(--primary)); color: hsl(var(--primary-foreground));
padding: 0.7rem 1.7rem; border-radius: 2px;
text-transform: uppercase; letter-spacing: 0.14em; font-size: 0.8rem; line-height: 1;
transition: background-color 200ms ease, color 200ms ease, box-shadow 200ms ease;
}
.reel-btn:hover, .reel-btn:focus-visible {
background-color: transparent; color: hsl(var(--primary));
box-shadow: inset 0 0 0 1px hsl(var(--primary));
}
.reel-btn:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 3px; }
/* reel-link — brass underline link. */
.reel-link { color: hsl(var(--primary)); text-decoration: none; border-bottom: 1px solid hsl(var(--primary) / 0.5); transition: color 200ms ease, border-color 200ms ease; }
.reel-link:hover, .reel-link:focus-visible { color: hsl(var(--accent)); border-bottom-color: hsl(var(--accent)); }
/* film-grain — 4% film-grain noise, dark surfaces. */
.film-grain { position: relative; isolation: isolate; }
.film-grain::after {
content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0.04;
background-image:
repeating-radial-gradient(circle at 17% 23%, hsl(var(--foreground)) 0 1px, transparent 1px 3px),
repeating-radial-gradient(circle at 73% 61%, hsl(var(--foreground)) 0 1px, transparent 1px 3px);
mix-blend-mode: overlay;
}
/* spotlight — a radial pool of brass light, hero/crest overlay. */
.spotlight { background-image: radial-gradient(ellipse 60% 55% at 50% 40%, hsl(var(--primary) / 0.16), transparent 70%); }
/* reel-strip — brass double-rule band (crest / marquee accent). */
.reel-strip {
background-image:
linear-gradient(hsl(var(--primary)), hsl(var(--primary))),
linear-gradient(hsl(var(--primary)), hsl(var(--primary)));
background-size: 100% 1px, 100% 1px;
background-position: top, bottom;
background-repeat: no-repeat;
}
/* reel-mat — brass inner-mat around framed media. */
.reel-mat { position: relative; padding: 4px; box-shadow: inset 0 0 0 1px hsl(var(--border)); }
.reel-mat > * { display: block; width: 100%; height: 100%; }
/* reel-dropcap — condensed brass dropcap on first paragraph. */
.reel-dropcap[data-deco-dropcap]::first-letter,
.reel-dropcap[data-reel-dropcap]::first-letter {
font-family: var(--font-heading, "Antonio", "Oswald", "Bebas Neue", sans-serif);
font-size: 3.2em; line-height: 0.9; float: left; padding: 0.02em 0.14em 0 0; color: hsl(var(--primary));
}
/* letterbox-scrim — black cinematic bars over hero imagery (image overlay). */
.letterbox-scrim {
background-image: linear-gradient(to bottom,
hsl(0 0% 0% / 0.78) 0%, hsl(0 0% 0% / 0.15) 16%,
transparent 40%, transparent 60%,
hsl(0 0% 0% / 0.15) 84%, hsl(0 0% 0% / 0.78) 100%);
}
/* reveal — MID-tier scroll reveal. No JS = visible; reduced-motion honoured. */
.reveal { opacity: 1; }
.gotham-js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s ease; }
.gotham-js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.gotham-js .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
}
}