Compare commits

..

No commits in common. "8adbe8c64ca741738a6f2997e68bb87a4277a7b3" and "d4e21e484b80606b8a2e4b14e645c15377bd9170" have entirely different histories.

44 changed files with 58 additions and 62 deletions

View File

@ -10,10 +10,14 @@
<figure class="pd-frame overflow-hidden flex flex-col">
{% if cake.image %}<div class="relative w-full overflow-hidden aspect-square pd-torn-bottom bg-secondary">{% img cake.image alt=cake.name|default:"Cake" class="block h-full w-full object-cover" %}</div>{% endif %}
<figcaption class="p-5 md:p-6">
<div class="flex items-start justify-between gap-3">
<div>
{% if cake.name %}<h3 class="pd-display text-xl text-primary">{{ cake.name }}</h3>{% endif %}
{% if cake.flavour %}<p class="pd-hand text-base text-accent">{{ cake.flavour }}</p>{% endif %}
{% if cake.price %}<p class="pd-mono mt-1.5 text-lg text-accent tabular-nums">{% if currency %}{{ currency }}{% endif %}{{ cake.price }}</p>{% endif %}
{% if cake.orderUrl %}<a href="{{ cake.orderUrl }}" class="pd-tag pd-tag--ghost mt-4 text-sm">Order this cake<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div>
{% if cake.price %}<span class="pd-mono shrink-0 text-lg text-accent tabular-nums">{% if currency %}{{ currency }}{% endif %}{{ cake.price }}</span>{% endif %}
</div>
{% if cake.orderUrl %}<a href="{{ cake.orderUrl }}" class="pd-tag pd-tag--ghost mt-4 text-sm">Order this cake<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</figcaption>
</figure>
{% endfor %}

View File

@ -9,7 +9,7 @@
</div>
{% if ctaLabel %}
<div class="shrink-0">
<a href="{{ ctaUrl|default:"/contact" }}" class="pd-tag text-base">{{ ctaLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>
<a href="{{ ctaUrl|default:"/contact" }}" class="pd-tag text-base">{{ ctaLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>
</div>
{% endif %}
</div>

View File

@ -11,11 +11,11 @@
<article class="pd-card overflow-hidden flex flex-col">
{% if item.image %}<div class="relative w-full overflow-hidden aspect-[4/3] bg-secondary">{% img item.image alt=item.name|default:"Seasonal special" class="block h-full w-full object-cover" %}</div>{% endif %}
<div class="p-5 md:p-6">
<div class="flex items-start justify-between gap-3">
<h3 class="pd-display text-xl text-primary">{{ item.name }}</h3>
<div class="mt-1.5 flex flex-wrap items-center gap-x-3 gap-y-1.5">
{% if item.price %}<span class="pd-mono text-lg text-accent tabular-nums">{% if currency %}{{ currency }}{% endif %}{{ item.price }}</span>{% endif %}
{% if item.badge %}<span class="pd-hand inline-flex rounded-full bg-accent/15 px-3 py-0.5 text-sm text-accent">{{ item.badge }}</span>{% endif %}
{% if item.price %}<span class="pd-mono shrink-0 text-lg text-accent tabular-nums">{% if currency %}{{ currency }}{% endif %}{{ item.price }}</span>{% endif %}
</div>
{% if item.badge %}<span class="pd-hand mt-2 inline-flex rounded-full bg-accent/15 px-3 py-0.5 text-sm text-accent">{{ item.badge }}</span>{% endif %}
{% if item.note %}<p class="pd-body mt-3 text-sm text-muted-foreground">{{ item.note }}</p>{% endif %}
</div>
</article>

View File

@ -2,7 +2,7 @@
name = "pastel-dream"
display_name = "Pastel Dream"
scope = "@themes"
version = "0.4.0"
version = "0.3.0"
description = "Soft bakery and patisserie theme — watercolor washes, scalloped edges, rounded menu cards, and seasonal specials in blush, berry, and lilac."
kind = "theme"
categories = ["templates"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 399 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

View File

@ -6,14 +6,6 @@
"site_description": "A small patisserie baking cakes, pastries and seasonal treats."
}
},
"media": [
{ "id": "a1b2c3d4-0001-4a00-8000-000000000001", "file": "media/strawberry-tart.jpg", "alt": "Strawberry tart with vanilla custard and a glaze of fresh berries", "folder": "Petal & Crumb" },
{ "id": "a1b2c3d4-0001-4a00-8000-000000000002", "file": "media/croissants.jpg", "alt": "Golden laminated croissants fresh from the oven", "folder": "Petal & Crumb" },
{ "id": "a1b2c3d4-0001-4a00-8000-000000000003", "file": "media/lemon-loaf.jpg", "alt": "Lemon poppy loaf dusted with sugar, sliced", "folder": "Petal & Crumb" },
{ "id": "a1b2c3d4-0001-4a00-8000-000000000004", "file": "media/sponge-cake.jpg", "alt": "Light sponge cake layered with cream", "folder": "Petal & Crumb" },
{ "id": "a1b2c3d4-0001-4a00-8000-000000000005", "file": "media/fruit-galette.jpg", "alt": "Rustic fruit galette with berries and whipped cream", "folder": "Petal & Crumb" },
{ "id": "a1b2c3d4-0001-4a00-8000-000000000006", "file": "media/bakery-interior.jpg", "alt": "The counter at Petal & Crumb, breads and pastries on display", "folder": "Petal & Crumb" }
],
"data_tables": [
{
"key": "contact_submissions",
@ -44,9 +36,9 @@
{ "block_key": "navbar", "title": "Navigation", "slot": "header", "sort_order": 0, "content": { "menuName": "main", "companyName": "Petal & Crumb", "ctaLabel": "Order a cake", "ctaUrl": "/contact" } },
{ "block_key": "hero", "title": "Hero", "slot": "main", "sort_order": 0, "content": { "template": "centered", "eyebrow": "Open from 8", "headline": "Cakes and pastries, baked fresh each morning", "subheadline": "A small patisserie on the corner. Everything is made by hand the day you eat it.", "ctaPrimary": { "text": "See the menu", "url": "/#menu" }, "ctaSecondary": { "text": "Order a cake", "url": "/contact" }, "minHeight": "50vh" } },
{ "block_key": "pastel-dream:seasonal_specials", "title": "Seasonal Specials", "slot": "main", "sort_order": 1, "content": { "kicker": "This week", "heading": "On the counter now", "intro": "A short list of what we are proud of this week. It changes with the season.", "currency": "$", "items": [
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000001", "name": "Strawberry tart", "note": "Vanilla custard, fresh strawberries, a thin glaze.", "price": "8.00", "badge": "New" },
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000002", "name": "Pistachio croissant", "note": "Laminated overnight, filled with pistachio cream.", "price": "6.50", "badge": "Popular" },
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000003", "name": "Lemon poppy loaf", "note": "Soft, tangy, dusted with sugar. Sold by the slice.", "price": "5.00", "badge": "" }
{ "name": "Strawberry tart", "note": "Vanilla custard, fresh strawberries, a thin glaze.", "price": "8.00", "badge": "New" },
{ "name": "Pistachio croissant", "note": "Laminated overnight, filled with pistachio cream.", "price": "6.50", "badge": "Popular" },
{ "name": "Lemon poppy loaf", "note": "Soft, tangy, dusted with sugar. Sold by the slice.", "price": "5.00", "badge": "" }
] } },
{ "block_key": "menu-list", "title": "Menu", "slot": "main", "sort_order": 2, "content": { "heading": "The full menu", "intro": "Prices are for takeaway. We can box anything for a gift.", "currency": "$", "columns": 2, "sections": [
{ "title": "Pastries", "items": [
@ -82,7 +74,7 @@
"blocks": [
{ "block_key": "navbar", "title": "Navigation", "slot": "header", "sort_order": 0, "content": { "menuName": "main", "companyName": "Petal & Crumb", "ctaLabel": "Order a cake", "ctaUrl": "/contact" } },
{ "block_key": "hero", "title": "Hero", "slot": "main", "sort_order": 0, "content": { "template": "centered", "eyebrow": "Our story", "headline": "One oven, one small room", "subheadline": "We opened with a single oven and a short menu. We kept it that way on purpose.", "minHeight": "auto" } },
{ "block_key": "rich-section", "title": "Story", "slot": "main", "sort_order": 1, "content": { "eyebrow": "How we bake", "heading": "Made the same day", "body": "<p>We start before dawn. The pastry is laminated the night before and baked in the morning, so it reaches you the same day it is made.</p><p>The menu is short because we make everything ourselves. When something is out, it is out until the next bake.</p>", "mediaPosition": "right", "media": "media:a1b2c3d4-0001-4a00-8000-000000000006", "mediaAlt": "The counter at Petal & Crumb, breads and pastries on display" } },
{ "block_key": "rich-section", "title": "Story", "slot": "main", "sort_order": 1, "content": { "eyebrow": "How we bake", "heading": "Made the same day", "body": "<p>We start before dawn. The pastry is laminated the night before and baked in the morning, so it reaches you the same day it is made.</p><p>The menu is short because we make everything ourselves. When something is out, it is out until the next bake.</p>", "mediaPosition": "right" } },
{ "block_key": "pastel-dream:bakers_note", "title": "Baker's Note", "slot": "main", "sort_order": 2, "content": { "kicker": "A note from the kitchen", "body": "<p>Thank you for buying from a small shop. Every order helps us keep baking by hand. We taste each batch before it reaches the counter, and we would rather sell out than cut a corner.</p>", "signatureName": "Cara Wells", "signatureRole": "Baker and owner" } },
{ "block_key": "team", "title": "Team", "slot": "main", "sort_order": 3, "content": { "heading": "The people at the bench", "members": [
{ "name": "Cara", "role": "Baker and owner", "bio": "Laminates the pastry and runs the morning bake." },
@ -113,11 +105,11 @@
"blocks": [
{ "block_key": "navbar", "title": "Navigation", "slot": "header", "sort_order": 0, "content": { "menuName": "main", "companyName": "Petal & Crumb", "ctaLabel": "Order a cake", "ctaUrl": "/contact" } },
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 0, "content": { "level": 1, "text": "Strawberries are in" } },
{ "block_key": "text", "title": "Body", "slot": "main", "sort_order": 1, "content": { "text": "<p>The first ripe strawberries came in this week. They are small, sweet, and they do not keep, so we use them fast. A grower two towns over drops a tray at the back door before we open, still cool from the morning.</p><p>We sort them by hand at the bench. The neat ones go on the tarts, where they sit in rows and catch the light. The soft ones are just as good, so they go into the jam pan and cook down for the sponge.</p><p>A strawberry tart is a simple thing done carefully. We blind bake the pastry until it is properly short, cool it, then pipe in vanilla custard the same morning. The fruit goes on last, with a thin brush of glaze so it shines without turning sticky.</p><p>The sponge is the other side of the same fruit. We fold cream and a spoon of that quick jam between two light layers, then a dusting of sugar on top. It is the cake we make when we want the strawberry to taste like summer rather than like a garnish.</p><p>Strawberries do not wait. They are best the day they are picked and a little tired by the next, so we do not hold them back or freeze a batch for later. What comes in is what we bake, and when it is gone it is gone.</p><p>That is the whole reason the menu changes. We would rather follow the fruit than force it. Next it will be the first stone fruit, and the tarts will turn gold instead of red.</p><p>If you have a favourite, tell us at the counter. We keep a short list of who asked for what, and we will put one aside when the season is at its best.</p><p>Come in early if you can. The tarts tend to go before lunch, and the sponge is usually cut by mid afternoon. There is always something on the counter, but the strawberries are worth the early trip.</p>" } },
{ "block_key": "text", "title": "Body", "slot": "main", "sort_order": 1, "content": { "text": "<p>The first ripe strawberries came in this week. They are small, sweet, and they do not keep, so we use them fast.</p><p>This week they go into the strawberry tart and a plain sponge with cream. When they run out, we move on to the next fruit.</p><p>Come in early. The tarts tend to go before lunch.</p>" } },
{ "block_key": "pastel-dream:cake_gallery", "title": "Cake Gallery", "slot": "main", "sort_order": 2, "content": { "heading": "What we made this week", "intro": "A few things that came out of the oven.", "currency": "$", "cakes": [
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000001", "name": "Strawberry tart", "flavour": "Vanilla custard", "price": "8.00", "orderUrl": "/contact" },
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000004", "name": "Strawberry sponge", "flavour": "Cream and jam", "price": "7.00", "orderUrl": "/contact" },
{ "image": "media:a1b2c3d4-0001-4a00-8000-000000000005", "name": "Fruit galette", "flavour": "Seasonal", "price": "6.50", "orderUrl": "/contact" }
{ "name": "Strawberry tart", "flavour": "Vanilla custard", "price": "8.00", "orderUrl": "/contact" },
{ "name": "Strawberry sponge", "flavour": "Cream and jam", "price": "7.00", "orderUrl": "/contact" },
{ "name": "Fruit galette", "flavour": "Seasonal", "price": "6.50", "orderUrl": "/contact" }
] } },
{ "block_key": "footer", "title": "Footer", "slot": "footer", "sort_order": 0, "content": { "companyName": "Petal & Crumb", "tagline": "A small patisserie, baked fresh each morning.", "email": "hello@petalandcrumb.test", "copyright": "Petal & Crumb" } }
]

View File

@ -1,4 +1,4 @@
<figure class="bn-audio pd-card my-8 overflow-hidden{% if class %} {{ class }}{% endif %}" data-bn-audio data-audio-url="{{ url|default:"" }}" data-audio-media="{% if media %}{{ media|mediaURL }}{% endif %}"><div class="flex items-center gap-4 p-4">{% if artwork %}<div class="h-16 w-16 shrink-0 overflow-hidden rounded-sm bg-secondary">{% img artwork alt=title|default:"" class="h-full w-full object-cover" %}</div>{% endif %}<div class="min-w-0 flex-1">{% if title %}<p class="pd-display truncate text-lg text-primary">{{ title }}</p>{% endif %}{% if artist %}<p class="pd-hand truncate text-lg text-accent">{{ artist }}</p>{% endif %}<div class="mt-2 flex items-center gap-3" data-bn-audio-slot><button type="button" data-bn-audio-play class="pd-tag text-xs" aria-label="Play{% if title %}: {{ title }}{% endif %}"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#play"></use></svg> Play</button>{% if download %}<a href="{% if media %}{{ media|mediaURL }}{% else %}{{ url }}{% endif %}" download class="pd-body inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#download"></use></svg> Download</a>{% endif %}</div></div></div></figure><script>
<figure class="bn-audio pd-card my-8 overflow-hidden{% if class %} {{ class }}{% endif %}" data-bn-audio data-audio-url="{{ url|default:"" }}" data-audio-media="{% if media %}{{ media|mediaURL }}{% endif %}"><div class="flex items-center gap-4 p-4">{% if artwork %}<div class="h-16 w-16 shrink-0 overflow-hidden rounded-sm bg-secondary">{% img artwork alt=title|default:"" class="h-full w-full object-cover" %}</div>{% endif %}<div class="min-w-0 flex-1">{% if title %}<p class="pd-display truncate text-lg text-primary">{{ title }}</p>{% endif %}{% if artist %}<p class="pd-hand truncate text-lg text-accent">{{ artist }}</p>{% endif %}<div class="mt-2 flex items-center gap-3" data-bn-audio-slot><button type="button" data-bn-audio-play class="pd-tag text-xs" aria-label="Play{% if title %}: {{ title }}{% endif %}"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#play"></use></svg> Play</button>{% if download %}<a href="{% if media %}{{ media|mediaURL }}{% else %}{{ url }}{% endif %}" download class="pd-body inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#download"></use></svg> Download</a>{% endif %}</div></div></div></figure><script>
(function(){
if(window.__bnAudioFacade)return;window.__bnAudioFacade=true;
document.addEventListener('click',function(e){

View File

@ -10,7 +10,7 @@
<button type="button" onclick="this.nextElementSibling.classList.toggle('hidden')" class="pd-body flex items-center gap-2 rounded-lg px-3 py-1.5 text-sm font-medium opacity-90 transition-colors hover:bg-muted hover:opacity-100">
<span class="pd-hand flex h-7 w-7 items-center justify-center rounded-full bg-accent text-sm text-accent-foreground">{{ auth.display_name|first|upper }}</span>
<span>{{ auth.display_name }}</span>
<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg>
<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg>
</button>
<div id="auth-dropdown-menu" class="pd-card absolute right-0 top-full z-50 mt-1 hidden w-48 py-1 shadow-lg">
<a href="/account" class="pd-body block px-4 py-2 text-sm text-foreground hover:bg-muted">My profile</a>

View File

@ -10,10 +10,10 @@
{% if author.location %}<span>{{ author.location }}</span>{% endif %}
</div>
{% if showSocial %}<div class="mt-5 flex items-center justify-center gap-3">
{% if author.website_url %}<a href="{{ author.website_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="Website"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/lucide.svg#globe"></use></svg></a>{% endif %}
{% if author.twitter_handle %}<a href="https://twitter.com/{{ author.twitter_handle|cut:"@" }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="Twitter"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#x"></use></svg></a>{% endif %}
{% if author.linkedin_url %}<a href="{{ author.linkedin_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="LinkedIn"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#linkedin"></use></svg></a>{% endif %}
{% if author.github_url %}<a href="{{ author.github_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="GitHub"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#github"></use></svg></a>{% endif %}
{% if author.website_url %}<a href="{{ author.website_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="Website"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/lucide.svg#globe"></use></svg></a>{% endif %}
{% if author.twitter_handle %}<a href="https://twitter.com/{{ author.twitter_handle|cut:"@" }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="Twitter"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#x"></use></svg></a>{% endif %}
{% if author.linkedin_url %}<a href="{{ author.linkedin_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="LinkedIn"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#linkedin"></use></svg></a>{% endif %}
{% if author.github_url %}<a href="{{ author.github_url }}" target="_blank" rel="noopener" class="text-muted-foreground transition-colors hover:text-accent" title="GitHub"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#github"></use></svg></a>{% endif %}
</div>{% endif %}
</div>
</section>

View File

@ -4,7 +4,7 @@
{% if showHome %}<li class="flex items-center"><a href="/" class="text-muted-foreground transition-colors hover:text-accent">{{ homeLabel|default:"Home" }}</a></li>{% endif %}
{% for item in breadcrumbs %}
<li class="flex items-center">
{% if showHome or not forloop.First %}{% if arrows %}<svg width="16" height="16" class="mx-2 h-4 w-4 text-accent" aria-hidden="true"><use href="/icons/lucide.svg#chevron-right"></use></svg>{% else %}<span class="mx-2 text-accent">{{ separator|default:"/" }}</span>{% endif %}{% endif %}
{% if showHome or not forloop.First %}{% if arrows %}<svg class="mx-2 h-4 w-4 text-accent" aria-hidden="true"><use href="/icons/lucide.svg#chevron-right"></use></svg>{% else %}<span class="mx-2 text-accent">{{ separator|default:"/" }}</span>{% endif %}{% endif %}
{% if item.is_current %}{% if showCurrent %}<span class="pd-display text-foreground" aria-current="page">{{ item.label }}</span>{% endif %}{% else %}<a href="{{ item.url }}" class="text-muted-foreground transition-colors hover:text-accent">{{ item.label }}</a>{% endif %}
</li>
{% endfor %}

View File

@ -1,5 +1,5 @@
{% with align=align|default:"left" style=style|default:"primary" %}
<div class="bn-button flex {% if align == "center" %}justify-center{% elif align == "right" %}justify-end{% else %}justify-start{% endif %}{% if class %} {{ class }}{% endif %}">
{% if link %}<a href="{{ link }}"{% if newTab %} target="_blank" rel="noopener"{% endif %} class="pd-tag {% if style == "secondary" %}bg-secondary text-secondary-foreground{% elif style == "outline" or style == "ghost" %}pd-tag--ghost{% elif style == "destructive" %}bg-destructive text-destructive-foreground{% endif %} {% if size == "lg" %}text-base px-6 py-3{% elif size == "sm" %}text-xs px-3 py-1.5{% endif %}">{% if icon and iconPosition != "right" %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}</a>{% else %}<button type="button" class="pd-tag {% if style == "secondary" %}bg-secondary text-secondary-foreground{% elif style == "outline" or style == "ghost" %}pd-tag--ghost{% elif style == "destructive" %}bg-destructive text-destructive-foreground{% endif %} {% if size == "lg" %}text-base px-6 py-3{% elif size == "sm" %}text-xs px-3 py-1.5{% endif %}">{% if icon and iconPosition != "right" %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}</button>{% endif %}
{% if link %}<a href="{{ link }}"{% if newTab %} target="_blank" rel="noopener"{% endif %} class="pd-tag {% if style == "secondary" %}bg-secondary text-secondary-foreground{% elif style == "outline" or style == "ghost" %}pd-tag--ghost{% elif style == "destructive" %}bg-destructive text-destructive-foreground{% endif %} {% if size == "lg" %}text-base px-6 py-3{% elif size == "sm" %}text-xs px-3 py-1.5{% endif %}">{% if icon and iconPosition != "right" %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}</a>{% else %}<button type="button" class="pd-tag {% if style == "secondary" %}bg-secondary text-secondary-foreground{% elif style == "outline" or style == "ghost" %}pd-tag--ghost{% elif style == "destructive" %}bg-destructive text-destructive-foreground{% endif %} {% if size == "lg" %}text-base px-6 py-3{% elif size == "sm" %}text-xs px-3 py-1.5{% endif %}">{% if icon and iconPosition != "right" %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"></use></svg>{% endif %}</button>{% endif %}
</div>
{% endwith %}

View File

@ -5,7 +5,7 @@
<div class="flex flex-col gap-2 p-5 md:p-6 {% if layout == "horizontal" %}justify-center{% endif %}">
{% if title %}<h3 class="pd-display text-xl text-primary">{{ title }}</h3>{% endif %}
{% if text %}<div class="pd-body text-sm leading-relaxed text-muted-foreground">{{ text|safe }}</div>{% endif %}
{% if linkLabel and link %}<span class="pd-hand mt-2 inline-flex items-center gap-1 text-lg text-accent">{{ linkLabel }} <svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></span>{% endif %}
{% if linkLabel and link %}<span class="pd-hand mt-2 inline-flex items-center gap-1 text-lg text-accent">{{ linkLabel }} <svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></span>{% endif %}
</div>
{% if link %}</a>{% endif %}
</article>

View File

@ -5,7 +5,7 @@
<div class="mt-10 grid grid-cols-1 gap-4 {% if columns == 3 %}sm:grid-cols-2 lg:grid-cols-3{% elif columns == 1 %}{% else %}sm:grid-cols-2{% endif %}">
{% for channel in channels %}
<div class="pd-card flex items-start gap-4 p-5">
{% if channel.icon %}<span class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent/15 text-accent"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"></use></svg></span>{% endif %}
{% if channel.icon %}<span class="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent/15 text-accent"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"></use></svg></span>{% endif %}
<div class="min-w-0">
{% if channel.label %}<div class="pd-hand text-lg text-accent">{{ channel.label }}</div>{% endif %}
{% if channel.value %}<div class="pd-body mt-0.5 break-words font-medium">{% if channel.link %}<a href="{{ channel.link }}" class="transition-colors hover:text-accent">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %}

View File

@ -3,7 +3,7 @@
<div class="mx-auto max-w-2xl px-4">
{% if form.submitted %}
<div class="pd-card pd-torn-top pd-torn-bottom p-8 text-center">
<div class="mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full bg-accent/15 text-accent"><svg width="24" height="24" class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg></div>
<div class="mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-full bg-accent/15 text-accent"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg></div>
<p class="pd-display text-xl text-primary">{{ form.message|default:successMessage|default:"Thanks. Your message is on its way." }}</p>
</div>
{% else %}

View File

@ -11,7 +11,7 @@
</div>
<div class="mt-8 hidden" data-countdown-expired>
<p class="pd-display text-xl text-primary">{{ expiredMessage|default:"This has started." }}</p>
{% if expiredUrl and expiredLabel %}<a href="{{ expiredUrl }}" class="pd-tag mt-4 text-base px-5 py-3">{{ expiredLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if expiredUrl and expiredLabel %}<a href="{{ expiredUrl }}" class="pd-tag mt-4 text-base px-5 py-3">{{ expiredLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div>
</div>
<noscript><p class="pd-body mt-6 text-muted-foreground">Counting down to <time datetime="{{ target }}">{{ target }}</time>.</p></noscript>

View File

@ -6,7 +6,7 @@
{% if text %}<p class="pd-body mt-3 text-lg {% if background == "band" %}text-primary-foreground/80{% else %}text-muted-foreground{% endif %}">{{ text }}</p>{% endif %}
</div>
<div class="flex flex-wrap items-center justify-center gap-3 {% if background != "split" %}mt-8{% else %}shrink-0{% endif %}">
{% if primaryUrl and primaryLabel %}<a href="{{ primaryUrl }}" class="pd-tag text-base px-6 py-3 {% if background == "band" %}bg-background text-foreground{% endif %}">{{ primaryLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if primaryUrl and primaryLabel %}<a href="{{ primaryUrl }}" class="pd-tag text-base px-6 py-3 {% if background == "band" %}bg-background text-foreground{% endif %}">{{ primaryLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if secondaryUrl and secondaryLabel %}<a href="{{ secondaryUrl }}" class="pd-tag pd-tag--ghost text-base px-6 py-3 {% if background == "band" %}border-primary-foreground/40 text-primary-foreground{% endif %}">{{ secondaryLabel }}</a>{% endif %}
</div>
</div>

View File

@ -12,7 +12,7 @@
<h3 class="pd-display text-lg text-primary">{{ event.title }}</h3>
{% if event.venue %}<p class="pd-body text-sm text-muted-foreground">{{ event.venue }}</p>{% endif %}
{% if event.description %}<p class="pd-body text-sm text-muted-foreground">{{ event.description }}</p>{% endif %}
{% if event.link %}<a href="{{ event.link }}" class="pd-hand mt-auto inline-flex items-center gap-1 pt-2 text-lg text-accent hover:underline">{{ event.linkLabel|default:"Details" }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if event.link %}<a href="{{ event.link }}" class="pd-hand mt-auto inline-flex items-center gap-1 pt-2 text-lg text-accent hover:underline">{{ event.linkLabel|default:"Details" }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div>
</article>
{% endif %}{% endfor %}

View File

@ -7,7 +7,7 @@
<details class="group py-2"{% if variant == "open-list" %} open{% endif %}>
<summary class="pd-display flex cursor-pointer list-none items-center justify-between gap-4 py-3 text-lg text-primary marker:content-none [&::-webkit-details-marker]:hidden">
<span>{{ item.question }}</span>
<svg width="20" height="20" class="h-5 w-5 shrink-0 text-accent transition-transform duration-200 group-open:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg>
<svg class="h-5 w-5 shrink-0 text-accent transition-transform duration-200 group-open:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg>
</summary>
<div class="pd-body pb-4 text-muted-foreground [&_a]:text-accent [&_a]:underline [&_a]:decoration-dashed">{{ item.answer|safe }}</div>
</details>

View File

@ -6,10 +6,10 @@
<div class="mt-12 grid grid-cols-1 gap-8 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}">
{% for item in items %}
<div class="{% if layout == "card" %}pd-card p-6 transition-shadow hover:shadow-md{% elif layout == "centered" %}text-center{% endif %}">
{% if item.icon %}<div class="mb-4 inline-flex h-11 w-11 items-center justify-center rounded-full bg-accent/15 text-accent{% if layout == "centered" %} mx-auto{% endif %}"><svg width="24" height="24" class="h-6 w-6" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg></div>{% endif %}
{% if item.icon %}<div class="mb-4 inline-flex h-11 w-11 items-center justify-center rounded-full bg-accent/15 text-accent{% if layout == "centered" %} mx-auto{% endif %}"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg></div>{% endif %}
<h3 class="pd-display text-xl text-primary">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" class="transition-colors hover:text-accent">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3>
{% if item.text %}<p class="pd-body mt-2 text-muted-foreground">{{ item.text }}</p>{% endif %}
{% if item.linkUrl and item.linkLabel %}<a href="{{ item.linkUrl }}" class="pd-hand mt-3 inline-flex items-center gap-1 text-lg text-accent hover:underline">{{ item.linkLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if item.linkUrl and item.linkLabel %}<a href="{{ item.linkUrl }}" class="pd-hand mt-3 inline-flex items-center gap-1 text-lg text-accent hover:underline">{{ item.linkLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div>
{% endfor %}
</div>

View File

@ -1,7 +1,7 @@
{# pastel-dream footer — scalloped top edge, soft pastel chrome, builtin footer_menus provider. #}
{% set fl = layout %}
{% if not fl %}{% if template == "centered" %}{% set fl = "centered" %}{% else %}{% set fl = "columns" %}{% endif %}{% endif %}
{% macro sociallinks(cls) %}{% if social_items %}<div class="flex items-center gap-3 {{ cls }}">{% for s in social_items %}<a href="{{ s.url }}" target="_blank" rel="noopener" title="{{ s.label }}" class="text-muted-foreground transition-colors hover:text-accent"><span class="sr-only">{{ s.label }}</span>{% if s.icon %}<svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ s.icon|split:":"|first }}.svg#{{ s.icon|split:":"|last }}"></use></svg>{% else %}{{ s.label }}{% endif %}</a>{% endfor %}</div>{% endif %}{% endmacro %}
{% macro sociallinks(cls) %}{% if social_items %}<div class="flex items-center gap-3 {{ cls }}">{% for s in social_items %}<a href="{{ s.url }}" target="_blank" rel="noopener" title="{{ s.label }}" class="text-muted-foreground transition-colors hover:text-accent"><span class="sr-only">{{ s.label }}</span>{% if s.icon %}<svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ s.icon|split:":"|first }}.svg#{{ s.icon|split:":"|last }}"></use></svg>{% else %}{{ s.label }}{% endif %}</a>{% endfor %}</div>{% endif %}{% endmacro %}
{% macro newsletter() %}{% if showNewsletter %}<div class="max-w-sm"><h3 class="pd-hand text-2xl text-accent">{{ newsletterTitle|default:"Stay in the loop" }}</h3>{% if newsletterDescription %}<p class="pd-body mt-1 text-sm text-muted-foreground">{{ newsletterDescription }}</p>{% endif %}<div class="mt-3">{% signup_form list=newsletterListSlug|default:"main" source="footer" submit=newsletterButtonText|default:"Subscribe" %}</div></div>{% endif %}{% endmacro %}
{% macro legalbar() %}<div class="mt-10 flex flex-col items-center justify-between gap-3 border-t border-dashed border-border pt-6 text-sm text-muted-foreground sm:flex-row"><p class="pd-body">{% if copyright %}&copy; {{ copyright }}{% else %}&copy; {{ companyName }}{% endif %}</p>{% if legal_items %}<nav class="flex flex-wrap items-center gap-x-4 gap-y-1">{% for l in legal_items %}<a href="{{ l.url|default:'#' }}"{% if l.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body transition-colors hover:text-foreground">{{ l.label }}</a>{% endfor %}</nav>{% endif %}</div>{% endmacro %}
<footer class="pd-torn-top w-full bg-muted/50 text-foreground {{ class }}">

View File

@ -18,11 +18,11 @@
{% if specialHoursNote %}<p class="pd-body mt-4 rounded-md border border-dashed border-border bg-muted px-3 py-2 text-sm text-muted-foreground">{{ specialHoursNote }}</p>{% endif %}
{% if address %}<div class="mt-6"><div class="pd-hand text-lg text-accent">Find us</div><address class="pd-body mt-1 whitespace-pre-line not-italic">{{ address }}</address></div>{% endif %}
{% if phone %}<div class="mt-4"><div class="pd-hand text-lg text-accent">Call ahead</div><a href="tel:{{ phone }}" class="pd-body mt-1 inline-block font-medium transition-colors hover:text-accent">{{ phone }}</a></div>{% endif %}
{% if directionsUrl %}<a href="{{ directionsUrl }}" target="_blank" rel="noopener" class="pd-tag mt-6 text-sm"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#navigation"></use></svg>Get directions</a>{% endif %}
{% if directionsUrl %}<a href="{{ directionsUrl }}" target="_blank" rel="noopener" class="pd-tag mt-6 text-sm"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#navigation"></use></svg>Get directions</a>{% endif %}
</div>
{% if mapEmbedUrl %}
<div class="pd-frame aspect-square w-full overflow-hidden rounded-sm bg-secondary md:aspect-auto">
<button type="button" data-map-src="{{ mapEmbedUrl }}" onclick="var f=document.createElement('iframe');f.src=this.getAttribute('data-map-src');f.setAttribute('class','h-full w-full border-0');f.setAttribute('loading','lazy');f.setAttribute('referrerpolicy','no-referrer-when-downgrade');f.setAttribute('title','Map');this.parentNode.replaceChild(f,this);" class="pd-body flex h-full min-h-[16rem] w-full items-center justify-center gap-2 text-sm font-medium transition-colors hover:bg-muted"><svg width="20" height="20" class="h-5 w-5 pd-pin" aria-hidden="true"><use href="/icons/lucide.svg#map-pin"></use></svg>{{ mapButtonLabel|default:"Load map" }}</button>
<button type="button" data-map-src="{{ mapEmbedUrl }}" onclick="var f=document.createElement('iframe');f.src=this.getAttribute('data-map-src');f.setAttribute('class','h-full w-full border-0');f.setAttribute('loading','lazy');f.setAttribute('referrerpolicy','no-referrer-when-downgrade');f.setAttribute('title','Map');this.parentNode.replaceChild(f,this);" class="pd-body flex h-full min-h-[16rem] w-full items-center justify-center gap-2 text-sm font-medium transition-colors hover:bg-muted"><svg class="h-5 w-5 pd-pin" aria-hidden="true"><use href="/icons/lucide.svg#map-pin"></use></svg>{{ mapButtonLabel|default:"Load map" }}</button>
</div>
{% endif %}
</div>

View File

@ -6,7 +6,7 @@
{% set cta_text = cta.text|default:ctaLabel %}
{% set cta_url = cta.url|default:ctaUrl %}
{% macro navlink(item) %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} class="pd-body px-3 py-2 text-sm font-medium text-foreground/80 transition-colors hover:text-accent {{ item.css_class }}">{{ item.label }}</a>{% endmacro %}
{% macro dropdown(item) %}<div class="relative group"><button type="button" class="pd-body inline-flex items-center gap-1 px-3 py-2 text-sm font-medium text-foreground/80 transition-colors hover:text-accent">{{ item.label }}<svg width="16" height="16" class="h-4 w-4 transition-transform group-hover:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg></button><div class="absolute left-0 z-50 mt-1 w-56 invisible opacity-0 transition-all duration-200 group-hover:visible group-hover:opacity-100"><div class="pd-card py-2 shadow-lg">{% for child in item.children %}{% if child.item_type == "header" %}<div class="pd-hand px-4 py-2 text-base text-accent">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-4 py-2 text-sm text-foreground transition-colors hover:bg-muted {{ child.css_class }}">{{ child.label }}</a>{% endif %}{% endfor %}</div></div></div>{% endmacro %}
{% macro dropdown(item) %}<div class="relative group"><button type="button" class="pd-body inline-flex items-center gap-1 px-3 py-2 text-sm font-medium text-foreground/80 transition-colors hover:text-accent">{{ item.label }}<svg class="h-4 w-4 transition-transform group-hover:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg></button><div class="absolute left-0 z-50 mt-1 w-56 invisible opacity-0 transition-all duration-200 group-hover:visible group-hover:opacity-100"><div class="pd-card py-2 shadow-lg">{% for child in item.children %}{% if child.item_type == "header" %}<div class="pd-hand px-4 py-2 text-base text-accent">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-4 py-2 text-sm text-foreground transition-colors hover:bg-muted {{ child.css_class }}">{{ child.label }}</a>{% endif %}{% endfor %}</div></div></div>{% endmacro %}
{% macro brand(size) %}<a href="/" class="flex flex-shrink-0 items-center gap-2">{% if logoType == "text" and logoText.text %}<span class="pd-display text-2xl text-primary {{ logoText.color }}">{{ logoText.text }}</span>{% elif logo %}<img src="{{ logo }}" alt="{{ alt|default:companyName }}" class="{{ size }} w-auto"{% if logoMaxWidth or logoMaxHeight %} style="{% if logoMaxWidth %}max-width:{{ logoMaxWidth }};{% endif %}{% if logoMaxHeight %}max-height:{{ logoMaxHeight }};{% endif %}"{% endif %}/>{% elif companyName %}<span class="pd-display text-2xl text-primary">{{ companyName }}</span>{% endif %}</a>{% endmacro %}
{% macro ctabtn(extra) %}{% if cta_text %}<a href="{{ cta_url|default:'#' }}" class="pd-tag text-sm {{ extra }}">{{ cta_text }}</a>{% endif %}{% endmacro %}
<nav data-bn-navbar data-bn-sticky="{{ sb }}" class="bn-navbar w-full {% if sb == "sticky" or sb == "shrink-on-scroll" %}sticky top-0 z-40 {% endif %}bg-background/95 backdrop-blur border-b border-dashed border-border {{ class }}">
@ -30,7 +30,7 @@
<label for="bn-navbar-toggle" class="bn-navbar-overlay fixed inset-0 z-40 bg-black/50 md:hidden" aria-hidden="true"></label>
<div id="bn-navbar-drawer" class="bn-navbar-drawer fixed right-0 top-0 z-50 flex h-full w-80 max-w-[85vw] flex-col bg-background text-foreground shadow-xl md:hidden" role="dialog" aria-modal="true" aria-label="Site menu">
<div class="flex items-center justify-between border-b border-dashed border-border p-4">{{ brand("h-8") }}<label for="bn-navbar-toggle" data-bn-nav-close class="cursor-pointer rounded-md p-2 text-muted-foreground hover:bg-muted hover:text-foreground"><span class="sr-only">Close menu</span><svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></label></div>
<nav class="flex-1 overflow-y-auto py-4" aria-label="Mobile">{% for item in menu.items %}{% if item.children %}<details class="group/acc"><summary class="pd-body flex cursor-pointer list-none items-center justify-between px-6 py-3 text-base font-medium transition-colors hover:bg-muted">{{ item.label }}<svg width="16" height="16" class="h-4 w-4 transition-transform group-open/acc:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg></summary><div class="pb-2 pl-8">{% for child in item.children %}{% if child.item_type != "header" %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-2 py-2 text-sm text-muted-foreground transition-colors hover:text-foreground">{{ child.label }}</a>{% endif %}{% endfor %}</div></details>{% else %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-6 py-3 text-base font-medium transition-colors hover:bg-muted">{{ item.label }}</a>{% endif %}{% endfor %}</nav>
<nav class="flex-1 overflow-y-auto py-4" aria-label="Mobile">{% for item in menu.items %}{% if item.children %}<details class="group/acc"><summary class="pd-body flex cursor-pointer list-none items-center justify-between px-6 py-3 text-base font-medium transition-colors hover:bg-muted">{{ item.label }}<svg class="h-4 w-4 transition-transform group-open/acc:rotate-180" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"></use></svg></summary><div class="pb-2 pl-8">{% for child in item.children %}{% if child.item_type != "header" %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-2 py-2 text-sm text-muted-foreground transition-colors hover:text-foreground">{{ child.label }}</a>{% endif %}{% endfor %}</div></details>{% else %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="pd-body block px-6 py-3 text-base font-medium transition-colors hover:bg-muted">{{ item.label }}</a>{% endif %}{% endfor %}</nav>
{% if cta_text %}<div class="border-t border-dashed border-border p-4"><a href="{{ cta_url|default:'#' }}" class="pd-tag w-full justify-center">{{ cta_text }}</a></div>{% endif %}
</div>
<style>

View File

@ -15,6 +15,6 @@
{% else %}
<p class="pd-body mx-auto mt-4 max-w-xl text-muted-foreground">{{ emptyMessage|default:"That page has wandered off. Head back to the counter and start again." }}</p>
{% endif %}
<a href="/" class="pd-tag mt-8"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#home"></use></svg>Back home</a>
<a href="/" class="pd-tag mt-8"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#home"></use></svg>Back home</a>
</div>
</section>

View File

@ -13,7 +13,7 @@
</p>
{% if tier.description %}<p class="pd-body mt-3 text-sm text-muted-foreground">{{ tier.description }}</p>{% endif %}
{% if tier.features %}<ul class="mt-6 flex-1 space-y-3 text-sm">
{% for feature in tier.features %}<li class="pd-body flex items-start gap-2"><svg width="16" height="16" class="mt-0.5 h-4 w-4 shrink-0 text-accent" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg><span>{{ feature }}</span></li>{% endfor %}
{% for feature in tier.features %}<li class="pd-body flex items-start gap-2"><svg class="mt-0.5 h-4 w-4 shrink-0 text-accent" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg><span>{{ feature }}</span></li>{% endfor %}
</ul>{% endif %}
{% if tier.ctaUrl and tier.ctaLabel %}<a href="{{ tier.ctaUrl }}" class="pd-tag mt-8 w-full justify-center {% if not tier.highlighted %}pd-tag--ghost{% endif %}">{{ tier.ctaLabel }}</a>{% endif %}
</div>

View File

@ -4,7 +4,7 @@
{% if eyebrow %}<p class="pd-hand text-2xl text-accent">{{ eyebrow }}</p>{% endif %}
{% if heading %}<h2 class="pd-display mt-1 text-3xl text-primary md:text-4xl"><span class="pd-doodle-underline">{{ heading }}</span></h2>{% endif %}
{% if body %}<div class="pd-body mt-4 space-y-4 text-lg text-muted-foreground [&_a]:text-accent [&_a]:underline [&_a]:decoration-dashed [&_strong]:text-primary">{{ body|safe }}</div>{% endif %}
{% if ctaUrl and ctaLabel %}<a href="{{ ctaUrl }}" class="pd-tag mt-6 text-base px-5 py-3">{{ ctaLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if ctaUrl and ctaLabel %}<a href="{{ ctaUrl }}" class="pd-tag mt-6 text-base px-5 py-3">{{ ctaLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div>
<div class="{% if mediaPosition == "left" %}md:order-1{% else %}md:order-2{% endif %}">
{% if media %}<div class="pd-frame pd-torn-bottom overflow-hidden rounded-sm p-2">{% img media alt=mediaAlt class="h-auto w-full rounded-sm object-cover" %}</div>{% endif %}

View File

@ -3,7 +3,7 @@
{% if title %}<h3 class="pd-hand {% if compact %}px-2 mb-3 text-lg{% else %}px-3 mb-4 text-xl{% endif %} text-accent">{{ title }}</h3>{% endif %}
<ul class="{% if compact %}space-y-0.5{% else %}space-y-1{% endif %}">
{% for item in menu.items %}
<li><a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} data-bn-sidebar-link class="pd-body flex items-center rounded-md text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground {% if compact %}px-2 py-1.5{% else %}px-3 py-2{% endif %} {{ item.css_class }}">{% if item.icon %}<svg width="16" height="16" class="mr-2 h-4 w-4" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg>{% endif %}{{ item.label }}</a></li>
<li><a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} data-bn-sidebar-link class="pd-body flex items-center rounded-md text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground {% if compact %}px-2 py-1.5{% else %}px-3 py-2{% endif %} {{ item.css_class }}">{% if item.icon %}<svg class="mr-2 h-4 w-4" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg>{% endif %}{{ item.label }}</a></li>
{% endfor %}
</ul>
</nav>

View File

@ -4,7 +4,7 @@
{% for link in links %}{% if link.url %}
<li>
<a href="{{ link.url }}" target="_blank" rel="noopener" aria-label="{{ link.label|default:link.network }}" class="inline-flex items-center gap-2 rounded-full border border-dashed border-border text-foreground transition-colors hover:border-accent hover:text-accent {% if style == "stack" %}w-full px-4 py-2{% else %}p-2.5{% endif %}">
{% if link.network %}<svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ link.network|split:":"|first }}.svg#{{ link.network|split:":"|last }}"></use></svg>{% endif %}
{% if link.network %}<svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ link.network|split:":"|first }}.svg#{{ link.network|split:":"|last }}"></use></svg>{% endif %}
{% if style == "stack" and link.label %}<span class="pd-body text-sm font-medium">{{ link.label }}</span>{% endif %}
</a>
</li>

View File

@ -11,7 +11,7 @@
{% if member.role %}<p class="pd-hand text-lg text-accent">{{ member.role }}</p>{% endif %}
{% if member.bio %}<p class="pd-body mt-2 text-sm text-muted-foreground">{{ member.bio }}</p>{% endif %}
{% if member.socials %}<div class="mt-3 flex gap-3 {% if layout != "list" %}justify-center{% endif %}">
{% for social in member.socials %}{% if social.url %}<a href="{{ social.url }}" class="text-muted-foreground transition-colors hover:text-accent" aria-label="Social link"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ social.icon|split:":"|first }}.svg#{{ social.icon|split:":"|last }}"></use></svg></a>{% endif %}{% endfor %}
{% for social in member.socials %}{% if social.url %}<a href="{{ social.url }}" class="text-muted-foreground transition-colors hover:text-accent" aria-label="Social link"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ social.icon|split:":"|first }}.svg#{{ social.icon|split:":"|last }}"></use></svg></a>{% endif %}{% endfor %}
</div>{% endif %}
</div>
</div>

View File

@ -5,11 +5,11 @@
{% for q in quotes %}
<figure class="pd-card flex flex-col p-6{% if layout == "carousel" %} min-w-[18rem] max-w-sm shrink-0 snap-start{% endif %}">
{% if q.rating %}<div class="mb-3 flex gap-0.5" aria-label="Rated {{ q.rating }} out of 5">
<svg width="16" height="16" class="h-4 w-4 {% if q.rating >= 1 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg width="16" height="16" class="h-4 w-4 {% if q.rating >= 2 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg width="16" height="16" class="h-4 w-4 {% if q.rating >= 3 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg width="16" height="16" class="h-4 w-4 {% if q.rating >= 4 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg width="16" height="16" class="h-4 w-4 {% if q.rating >= 5 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg class="h-4 w-4 {% if q.rating >= 1 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg class="h-4 w-4 {% if q.rating >= 2 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg class="h-4 w-4 {% if q.rating >= 3 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg class="h-4 w-4 {% if q.rating >= 4 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
<svg class="h-4 w-4 {% if q.rating >= 5 %}text-accent{% else %}text-muted-foreground/30{% endif %}" aria-hidden="true"><use href="/icons/lucide.svg#star"></use></svg>
</div>{% endif %}
<blockquote class="pd-body flex-1 text-lg leading-relaxed text-foreground">{% if q.quote %}&ldquo;{{ q.quote }}&rdquo;{% endif %}</blockquote>
<figcaption class="mt-5 flex items-center gap-3">

View File

@ -6,7 +6,7 @@
{% for step in steps %}
<li class="{% if orientation == "horizontal" %}text-center{% else %}relative pl-14{% endif %}">
<span class="pd-stamp pd-stamp-sm {% if orientation == "horizontal" %}mx-auto{% else %}absolute left-0 top-0 ring-4 ring-background{% endif %}">
{% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}<span class="h-2 w-2 rounded-full bg-accent-foreground"></span>{% else %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#croissant"></use></svg>{% endif %}
{% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}<span class="h-2 w-2 rounded-full bg-accent-foreground"></span>{% else %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#croissant"></use></svg>{% endif %}
</span>
<div class="{% if orientation == "horizontal" %}mt-4{% else %}pt-1{% endif %}">
{% if step.label %}<p class="pd-hand text-lg text-accent">{{ step.label }}</p>{% endif %}

View File

@ -1,7 +1,7 @@
{# pastel-dream utility-bar — thin contact strip; left/right item lists {icon,label,link}. #}
{% set ubcls = "bg-muted text-muted-foreground border-b border-dashed border-border" %}
{% if variant == "primary" %}{% set ubcls = "bg-primary text-primary-foreground" %}{% elif variant == "dark" %}{% set ubcls = "bg-foreground text-background" %}{% endif %}
{% macro ubitem(it) %}{% if it.link %}<a href="{{ it.link }}" class="inline-flex items-center gap-1.5 transition-opacity hover:opacity-80">{% if it.icon %}<svg width="12" height="12" class="h-3.5 w-3.5" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"></use></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</a>{% else %}<span class="inline-flex items-center gap-1.5">{% if it.icon %}<svg width="12" height="12" class="h-3.5 w-3.5" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"></use></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</span>{% endif %}{% endmacro %}
{% macro ubitem(it) %}{% if it.link %}<a href="{{ it.link }}" class="inline-flex items-center gap-1.5 transition-opacity hover:opacity-80">{% if it.icon %}<svg class="h-3.5 w-3.5" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"></use></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</a>{% else %}<span class="inline-flex items-center gap-1.5">{% if it.icon %}<svg class="h-3.5 w-3.5" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"></use></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</span>{% endif %}{% endmacro %}
<div class="pd-body w-full text-xs {% if not showOnMobile %}hidden sm:block{% endif %} {{ ubcls }} {{ class }}">
<div class="mx-auto flex h-9 max-w-7xl items-center justify-between gap-4 px-4 sm:px-6 lg:px-8">
<div class="flex flex-wrap items-center gap-4">{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}</div>

View File

@ -1,4 +1,4 @@
{% with aspect=aspect|default:"16:9" %}<figure class="bn-video my-8{% if class %} {{ class }}{% endif %}"><div class="bn-video-frame pd-frame relative w-full overflow-hidden rounded-sm bg-secondary p-1.5 {% if aspect == "4:3" %}aspect-[4/3]{% elif aspect == "1:1" %}aspect-square{% elif aspect == "21:9" %}aspect-[21/9]{% else %}aspect-video{% endif %}" data-bn-video data-video-url="{{ url|default:"" }}" data-video-media="{% if media %}{{ media|mediaURL }}{% endif %}"><button type="button" data-bn-video-play class="group absolute inset-0 flex h-full w-full items-center justify-center focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" aria-label="Play video{% if title %}: {{ title }}{% endif %}">{% if poster %}{% img poster alt=title|default:"" class="absolute inset-0 h-full w-full rounded-sm object-cover" %}{% endif %}<span class="absolute inset-0 bg-foreground/10 transition-colors group-hover:bg-foreground/20" aria-hidden="true"></span><span class="relative inline-flex h-16 w-16 items-center justify-center rounded-full bg-accent text-accent-foreground shadow-lg transition-transform group-hover:scale-105 motion-reduce:transform-none"><svg width="28" height="28" class="h-7 w-7" aria-hidden="true"><use href="/icons/lucide.svg#play"></use></svg></span></button></div>{% if caption %}<figcaption class="pd-hand mt-3 text-center text-xl text-accent">{{ caption }}</figcaption>{% endif %}</figure><script>
{% with aspect=aspect|default:"16:9" %}<figure class="bn-video my-8{% if class %} {{ class }}{% endif %}"><div class="bn-video-frame pd-frame relative w-full overflow-hidden rounded-sm bg-secondary p-1.5 {% if aspect == "4:3" %}aspect-[4/3]{% elif aspect == "1:1" %}aspect-square{% elif aspect == "21:9" %}aspect-[21/9]{% else %}aspect-video{% endif %}" data-bn-video data-video-url="{{ url|default:"" }}" data-video-media="{% if media %}{{ media|mediaURL }}{% endif %}"><button type="button" data-bn-video-play class="group absolute inset-0 flex h-full w-full items-center justify-center focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring" aria-label="Play video{% if title %}: {{ title }}{% endif %}">{% if poster %}{% img poster alt=title|default:"" class="absolute inset-0 h-full w-full rounded-sm object-cover" %}{% endif %}<span class="absolute inset-0 bg-foreground/10 transition-colors group-hover:bg-foreground/20" aria-hidden="true"></span><span class="relative inline-flex h-16 w-16 items-center justify-center rounded-full bg-accent text-accent-foreground shadow-lg transition-transform group-hover:scale-105 motion-reduce:transform-none"><svg class="h-7 w-7" aria-hidden="true"><use href="/icons/lucide.svg#play"></use></svg></span></button></div>{% if caption %}<figcaption class="pd-hand mt-3 text-center text-xl text-accent">{{ caption }}</figcaption>{% endif %}</figure><script>
(function(){
if(window.__bnVideoFacade)return;window.__bnVideoFacade=true;
function yt(u){var m=u.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([\w-]{6,})/);return m?m[1]:null;}