themes-coffee/manifest.yaml
Alex Dunmow 1a6cc30202 feat: convert to codeless .bnp — templates + manifest, Go/templ deleted (WO-WZ-021)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 15:30:42 +08:00

196 lines
8.0 KiB
YAML

# Coffee 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
system_templates:
- key: coffee
title: Coffee
description: "Warm, hand-crafted theme for cafes, bakeries, and slow-craft makers"
page_templates:
- system: coffee
key: default
title: Default
description: "Header + main + footer with warm paper background"
slots: [header, main, footer]
- system: coffee
key: landing
title: Landing
description: "Hero pour + featured menu, big imagery"
slots: [hero, menu, story, cta, footer]
- system: coffee
key: article
title: Article
description: "Narrow narrative column for journal / recipes"
slots: [header, main, footer]
- system: coffee
key: full-width
title: Full Width
description: "Edge-to-edge gallery / interior shots"
slots: [header, main, footer]
template_overrides:
- { template: coffee, block: heading }
- { template: coffee, block: text }
- { template: coffee, block: button }
- { template: coffee, block: image }
email_wrappers:
- coffee
css:
input_css_append: |
/* Coffee theme styles
*
* Uses the 19 shadcn-style HSL token CSS variables (--background,
* --foreground, --primary, --accent, --border, --muted, --card, ...) via
* `hsl(var(--token))`. Font families are resolved through the BlockNinja font
* variables (--font-heading, --font-body, --font-mono) with fallback stacks
* derived from the spec §3 typography list.
*/
/* --- Font-family fallbacks ---------------------------------------------
*
* Templates use the variable form; the second argument is the fallback the
* site shows before the admin assigns fonts via the typography picker.
*/
:root {
--coffee-heading-fallback: "Fraunces", "Playfair Display", Georgia, "Times New Roman", serif;
--coffee-body-fallback: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--coffee-mono-fallback: "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
}
/* --- Paper grain background --------------------------------------------
*
* Inline SVG noise overlay applied as the body background. Keeps file size
* tiny and palette-neutral so it works with all three presets.
*/
body.coffee-paper {
background-color: hsl(var(--background));
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cfilter id='paper-grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.18 0 0 0 0 0.13 0 0 0 0 0.09 0 0 0 0.07 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23paper-grain)'/%3E%3C/svg%3E");
background-repeat: repeat;
}
/* --- Headings ----------------------------------------------------------- */
.coffee-display {
font-family: var(--font-heading, var(--coffee-heading-fallback));
font-feature-settings: "liga" 1, "dlig" 1;
letter-spacing: -0.01em;
}
.coffee-body {
font-family: var(--font-body, var(--coffee-body-fallback));
line-height: 1.65;
}
.coffee-mono {
font-family: var(--font-mono, var(--coffee-mono-fallback));
}
/* --- Doodle underline (heading override) -------------------------------- */
.coffee-doodle-underline {
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M2 8 Q 20 2 40 7 T 80 6 T 118 7' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' opacity='0.55'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 0 100%;
background-size: 100% 0.5em;
padding-bottom: 0.18em;
}
/* --- Drop-cap (text override / article body) ---------------------------- */
.coffee-dropcap > p:first-of-type::first-letter {
font-family: var(--font-heading, var(--coffee-heading-fallback));
font-size: 4em;
line-height: 0.85;
float: left;
padding: 0.05em 0.12em 0 0;
color: hsl(var(--primary));
}
/* --- Kraft-tag button --------------------------------------------------- */
.kraft-tag {
position: relative;
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 1.1rem;
background-color: hsl(var(--primary));
color: hsl(var(--primary-foreground));
border: 1px solid hsl(var(--border));
border-radius: 0.25rem;
font-family: var(--font-body, var(--coffee-body-fallback));
font-weight: 500;
letter-spacing: 0.02em;
box-shadow: 0 1px 0 hsl(var(--border));
transition: transform 120ms ease, box-shadow 120ms ease;
cursor: pointer;
}
.kraft-tag:hover {
transform: rotate(-1.2deg);
box-shadow: 0 2px 0 hsl(var(--border));
}
.kraft-tag:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 3px;
}
/* --- Torn-edge utility -------------------------------------------------- */
.coffee-torn-top {
-webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12 L0 6 Q 5 2 10 5 T 20 4 T 30 6 T 40 3 T 50 5 T 60 4 T 70 5 T 80 3 T 90 5 T 100 4 L100 12 Z' fill='black'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 12 L0 6 Q 5 2 10 5 T 20 4 T 30 6 T 40 3 T 50 5 T 60 4 T 70 5 T 80 3 T 90 5 T 100 4 L100 12 Z' fill='black'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.coffee-torn-bottom {
-webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 0 L100 0 L100 6 Q 95 10 90 7 T 80 8 T 70 6 T 60 9 T 50 7 T 40 8 T 30 7 T 20 9 T 10 7 T 0 8 Z' fill='black'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 12' preserveAspectRatio='none'%3E%3Cpath d='M0 0 L100 0 L100 6 Q 95 10 90 7 T 80 8 T 70 6 T 60 9 T 50 7 T 40 8 T 30 7 T 20 9 T 10 7 T 0 8 Z' fill='black'/%3E%3C/svg%3E");
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
/* --- Coffee surfaces ---------------------------------------------------- */
.coffee-card {
background-color: hsl(var(--card));
color: hsl(var(--card-foreground));
border: 1px solid hsl(var(--border));
border-radius: 0.5rem;
}
.coffee-frame {
border: 1px solid hsl(var(--border));
background-color: hsl(var(--card));
}
.coffee-pencil-rule {
border-color: hsl(var(--border));
border-style: solid;
}
/* --- Today highlight ---------------------------------------------------- */
.coffee-hours-today {
background-color: hsl(var(--accent) / 0.15);
color: hsl(var(--accent-foreground));
border-left: 3px solid hsl(var(--accent));
padding-left: 0.75rem;
}
/* --- Price typography --------------------------------------------------- */
.coffee-price {
font-family: var(--font-mono, var(--coffee-mono-fallback));
font-variant-numeric: tabular-nums;
color: hsl(var(--accent));
}
/* --- Doodle pin overlay for location card ------------------------------- */
.coffee-pin {
color: hsl(var(--accent));
}