diff --git a/blocks/events_marquee.ninjatpl b/blocks/events_marquee.ninjatpl
index 151cfd0..4a192a4 100644
--- a/blocks/events_marquee.ninjatpl
+++ b/blocks/events_marquee.ninjatpl
@@ -15,7 +15,7 @@
{% if event.room %}{{ event.room }} {% endif %}
{% if event.note %}
{{ event.note }}
{% endif %}
- {% if event.url %}Book::lucide:arrow-right:sm:: {% endif %}
+ {% if event.url %}Book {% endif %}
{% endfor %}
diff --git a/blocks/membership_tiers.ninjatpl b/blocks/membership_tiers.ninjatpl
index 62e315a..3bf0c26 100644
--- a/blocks/membership_tiers.ninjatpl
+++ b/blocks/membership_tiers.ninjatpl
@@ -22,7 +22,7 @@
{% if tier.features %}
{% for feature in tier.features %}
- ::lucide:check:sm:: {{ feature.label }}
+ {{ feature.label }}
{% endfor %}
{% endif %}
diff --git a/manifest.yaml b/manifest.yaml
index 99f7b0e..7224860 100644
--- a/manifest.yaml
+++ b/manifest.yaml
@@ -217,7 +217,7 @@ css:
/* reveal — MID-tier scroll reveal. No JS = visible; reduced-motion honoured. */
.reveal { opacity: 1; }
- .gotham-js .reveal { opacity: 0; transform: translateY(16px); transition: opacity .5s ease, transform .5s ease; }
+ .gotham-js .reveal { opacity: 0; transform: translateY(12px); transition: opacity .4s ease, transform .4s 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; }
diff --git a/presets.json b/presets.json
index 9b33a0f..d9b76f3 100644
--- a/presets.json
+++ b/presets.json
@@ -6,46 +6,46 @@
"theme": {
"mode": "both",
"lightColors": {
- "background": "40 22% 95%",
- "foreground": "30 10% 12%",
- "card": "40 24% 98%",
- "cardForeground": "30 10% 12%",
- "popover": "40 24% 98%",
- "popoverForeground": "30 10% 12%",
- "primary": "38 58% 42%",
- "primaryForeground": "40 30% 96%",
+ "background": "40 20% 96%",
+ "foreground": "28 16% 9%",
+ "card": "40 24% 99%",
+ "cardForeground": "28 16% 9%",
+ "popover": "40 24% 99%",
+ "popoverForeground": "28 16% 9%",
+ "primary": "36 62% 38%",
+ "primaryForeground": "40 30% 97%",
"secondary": "40 12% 88%",
- "secondaryForeground": "30 12% 16%",
+ "secondaryForeground": "28 14% 13%",
"muted": "40 12% 90%",
- "mutedForeground": "30 8% 40%",
- "accent": "36 62% 48%",
- "accentForeground": "40 30% 96%",
- "destructive": "0 68% 44%",
+ "mutedForeground": "28 11% 32%",
+ "accent": "34 64% 44%",
+ "accentForeground": "40 30% 97%",
+ "destructive": "0 68% 42%",
"destructiveForeground": "40 26% 96%",
- "border": "40 18% 78%",
- "input": "40 16% 82%",
- "ring": "38 58% 44%"
+ "border": "38 16% 73%",
+ "input": "40 16% 80%",
+ "ring": "36 62% 40%"
},
"darkColors": {
- "background": "30 9% 5%",
- "foreground": "40 28% 90%",
- "card": "30 9% 8%",
- "cardForeground": "40 28% 90%",
- "popover": "30 9% 8%",
- "popoverForeground": "40 28% 90%",
- "primary": "40 66% 54%",
- "primaryForeground": "30 22% 6%",
- "secondary": "30 8% 14%",
- "secondaryForeground": "40 24% 86%",
- "muted": "30 7% 12%",
- "mutedForeground": "40 12% 62%",
- "accent": "38 74% 60%",
- "accentForeground": "30 22% 6%",
- "destructive": "0 70% 50%",
+ "background": "28 13% 4%",
+ "foreground": "40 32% 93%",
+ "card": "28 12% 7%",
+ "cardForeground": "40 32% 93%",
+ "popover": "28 12% 7%",
+ "popoverForeground": "40 32% 93%",
+ "primary": "40 72% 54%",
+ "primaryForeground": "28 24% 5%",
+ "secondary": "28 9% 13%",
+ "secondaryForeground": "40 26% 88%",
+ "muted": "28 8% 11%",
+ "mutedForeground": "40 16% 67%",
+ "accent": "38 78% 62%",
+ "accentForeground": "28 24% 5%",
+ "destructive": "0 72% 52%",
"destructiveForeground": "40 26% 95%",
- "border": "40 24% 20%",
- "input": "40 18% 16%",
- "ring": "40 66% 54%"
+ "border": "40 22% 17%",
+ "input": "40 18% 15%",
+ "ring": "40 72% 54%"
}
}
},
@@ -57,17 +57,17 @@
"mode": "both",
"lightColors": {
"background": "220 16% 95%",
- "foreground": "222 18% 14%",
+ "foreground": "222 22% 10%",
"card": "220 20% 98%",
- "cardForeground": "222 18% 14%",
+ "cardForeground": "222 22% 10%",
"popover": "220 20% 98%",
- "popoverForeground": "222 18% 14%",
+ "popoverForeground": "222 22% 10%",
"primary": "40 60% 44%",
"primaryForeground": "220 20% 96%",
"secondary": "220 12% 88%",
"secondaryForeground": "222 16% 18%",
"muted": "220 12% 90%",
- "mutedForeground": "220 8% 40%",
+ "mutedForeground": "220 11% 33%",
"accent": "40 66% 50%",
"accentForeground": "222 20% 8%",
"destructive": "0 68% 46%",
@@ -77,18 +77,18 @@
"ring": "40 60% 46%"
},
"darkColors": {
- "background": "222 20% 6%",
- "foreground": "215 22% 90%",
- "card": "222 20% 9%",
- "cardForeground": "215 22% 90%",
- "popover": "222 20% 9%",
- "popoverForeground": "215 22% 90%",
+ "background": "222 26% 4%",
+ "foreground": "215 26% 93%",
+ "card": "222 22% 7%",
+ "cardForeground": "215 26% 93%",
+ "popover": "222 22% 7%",
+ "popoverForeground": "215 26% 93%",
"primary": "42 72% 58%",
"primaryForeground": "222 24% 8%",
"secondary": "222 16% 15%",
"secondaryForeground": "215 20% 86%",
- "muted": "222 14% 13%",
- "mutedForeground": "215 12% 62%",
+ "muted": "222 12% 11%",
+ "mutedForeground": "215 16% 67%",
"accent": "40 78% 62%",
"accentForeground": "222 24% 8%",
"destructive": "0 72% 52%",
@@ -107,17 +107,17 @@
"mode": "both",
"lightColors": {
"background": "20 20% 95%",
- "foreground": "18 14% 14%",
+ "foreground": "18 18% 10%",
"card": "20 24% 98%",
- "cardForeground": "18 14% 14%",
+ "cardForeground": "18 18% 10%",
"popover": "20 24% 98%",
- "popoverForeground": "18 14% 14%",
+ "popoverForeground": "18 18% 10%",
"primary": "16 52% 50%",
"primaryForeground": "20 30% 97%",
"secondary": "20 14% 88%",
"secondaryForeground": "18 14% 18%",
"muted": "20 12% 90%",
- "mutedForeground": "18 10% 40%",
+ "mutedForeground": "18 12% 33%",
"accent": "12 60% 56%",
"accentForeground": "20 30% 97%",
"destructive": "0 68% 46%",
@@ -127,18 +127,18 @@
"ring": "16 52% 50%"
},
"darkColors": {
- "background": "16 12% 6%",
- "foreground": "22 24% 90%",
- "card": "16 12% 9%",
- "cardForeground": "22 24% 90%",
- "popover": "16 12% 9%",
- "popoverForeground": "22 24% 90%",
+ "background": "16 17% 4%",
+ "foreground": "22 28% 93%",
+ "card": "16 15% 7%",
+ "cardForeground": "22 28% 93%",
+ "popover": "16 15% 7%",
+ "popoverForeground": "22 28% 93%",
"primary": "18 64% 60%",
"primaryForeground": "16 24% 8%",
"secondary": "16 12% 15%",
"secondaryForeground": "22 22% 86%",
- "muted": "16 10% 13%",
- "mutedForeground": "22 14% 62%",
+ "muted": "16 9% 11%",
+ "mutedForeground": "22 16% 67%",
"accent": "10 70% 64%",
"accentForeground": "16 24% 8%",
"destructive": "0 72% 54%",
@@ -157,17 +157,17 @@
"mode": "both",
"lightColors": {
"background": "210 8% 95%",
- "foreground": "210 10% 14%",
+ "foreground": "210 13% 10%",
"card": "210 10% 98%",
- "cardForeground": "210 10% 14%",
+ "cardForeground": "210 13% 10%",
"popover": "210 10% 98%",
- "popoverForeground": "210 10% 14%",
+ "popoverForeground": "210 13% 10%",
"primary": "210 8% 38%",
"primaryForeground": "210 12% 97%",
"secondary": "210 8% 88%",
"secondaryForeground": "210 10% 18%",
"muted": "210 8% 90%",
- "mutedForeground": "210 6% 42%",
+ "mutedForeground": "210 9% 34%",
"accent": "42 40% 52%",
"accentForeground": "210 12% 10%",
"destructive": "0 66% 46%",
@@ -177,18 +177,18 @@
"ring": "210 8% 42%"
},
"darkColors": {
- "background": "210 10% 7%",
- "foreground": "210 12% 90%",
- "card": "210 10% 10%",
- "cardForeground": "210 12% 90%",
- "popover": "210 10% 10%",
- "popoverForeground": "210 12% 90%",
+ "background": "210 13% 5%",
+ "foreground": "210 15% 93%",
+ "card": "210 12% 8%",
+ "cardForeground": "210 15% 93%",
+ "popover": "210 12% 8%",
+ "popoverForeground": "210 15% 93%",
"primary": "210 14% 74%",
"primaryForeground": "210 12% 8%",
"secondary": "210 10% 15%",
"secondaryForeground": "210 12% 86%",
- "muted": "210 8% 13%",
- "mutedForeground": "210 8% 60%",
+ "muted": "210 8% 11%",
+ "mutedForeground": "210 11% 66%",
"accent": "42 56% 60%",
"accentForeground": "210 12% 8%",
"destructive": "0 70% 52%",
@@ -207,17 +207,17 @@
"mode": "both",
"lightColors": {
"background": "36 24% 94%",
- "foreground": "28 18% 13%",
+ "foreground": "28 22% 9%",
"card": "36 26% 98%",
- "cardForeground": "28 18% 13%",
+ "cardForeground": "28 22% 9%",
"popover": "36 26% 98%",
- "popoverForeground": "28 18% 13%",
+ "popoverForeground": "28 22% 9%",
"primary": "30 62% 42%",
"primaryForeground": "36 30% 96%",
"secondary": "36 16% 87%",
"secondaryForeground": "28 16% 17%",
"muted": "36 14% 89%",
- "mutedForeground": "28 12% 40%",
+ "mutedForeground": "28 14% 33%",
"accent": "26 66% 48%",
"accentForeground": "36 30% 96%",
"destructive": "0 68% 44%",
@@ -227,18 +227,18 @@
"ring": "30 62% 44%"
},
"darkColors": {
- "background": "28 16% 6%",
- "foreground": "36 28% 89%",
- "card": "28 16% 9%",
- "cardForeground": "36 28% 89%",
- "popover": "28 16% 9%",
- "popoverForeground": "36 28% 89%",
+ "background": "28 21% 4%",
+ "foreground": "36 30% 93%",
+ "card": "28 18% 7%",
+ "cardForeground": "36 30% 93%",
+ "popover": "28 18% 7%",
+ "popoverForeground": "36 30% 93%",
"primary": "32 72% 54%",
"primaryForeground": "28 24% 7%",
"secondary": "28 14% 15%",
"secondaryForeground": "36 24% 85%",
- "muted": "28 12% 13%",
- "mutedForeground": "36 14% 60%",
+ "muted": "28 11% 11%",
+ "mutedForeground": "36 16% 66%",
"accent": "24 80% 58%",
"accentForeground": "28 24% 7%",
"destructive": "0 72% 52%",
diff --git a/seed/media/bar-interior.jpg b/seed/media/bar-interior.jpg
new file mode 100644
index 0000000..fb2d73f
Binary files /dev/null and b/seed/media/bar-interior.jpg differ
diff --git a/seed/media/bar-scene.jpg b/seed/media/bar-scene.jpg
new file mode 100644
index 0000000..9fcf54a
Binary files /dev/null and b/seed/media/bar-scene.jpg differ
diff --git a/seed/media/bar-shelf.jpg b/seed/media/bar-shelf.jpg
new file mode 100644
index 0000000..ba8ca77
Binary files /dev/null and b/seed/media/bar-shelf.jpg differ
diff --git a/seed/media/dark-lounge.jpg b/seed/media/dark-lounge.jpg
new file mode 100644
index 0000000..60218dc
Binary files /dev/null and b/seed/media/dark-lounge.jpg differ
diff --git a/seed/seed.json b/seed/seed.json
index 4a58254..772dfb4 100644
--- a/seed/seed.json
+++ b/seed/seed.json
@@ -6,6 +6,12 @@
"tagline": "A members' club after dark."
}
},
+ "media": [
+ { "id": "a1b2c3d4-0000-4000-8000-000000000001", "file": "media/bar-scene.jpg", "alt": "Bartenders at work behind a dark backbar, low-lit and grainy", "folder": "Gotham" },
+ { "id": "a1b2c3d4-0000-4000-8000-000000000002", "file": "media/bar-shelf.jpg", "alt": "Warm brass-lit shelves of whisky bottles in a dim room", "folder": "Gotham" },
+ { "id": "a1b2c3d4-0000-4000-8000-000000000003", "file": "media/bar-interior.jpg", "alt": "Backlit rows of bottles in silhouette against a dark wall", "folder": "Gotham" },
+ { "id": "a1b2c3d4-0000-4000-8000-000000000004", "file": "media/dark-lounge.jpg", "alt": "A dark lounge under low hanging lamps casting pools of gold light", "folder": "Gotham" }
+ ],
"data_tables": [
{
"key": "contact_submissions",
@@ -33,6 +39,9 @@
"content": {
"template": "centered",
"minHeight": "75vh",
+ "backgroundImage": "media:a1b2c3d4-0000-4000-8000-000000000001",
+ "overlayColor": "dark",
+ "overlayOpacity": 68,
"eyebrow": "Members only",
"headline": "Gotham House",
"subheadline": "A members' club after dark.",
@@ -148,8 +157,9 @@
"blocks": [
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The House", "level": 1 } },
{ "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "Gotham House keeps late hours behind an unmarked door. We run four nights a week and hold the rest of the week back.
The rooms are dark by design. The bar is long. The list is short. Members come first, and their guests come with them.
" } },
- { "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 3, "content": { "variant": "ornament", "icon": "lucide:diamond" } },
- { "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 4, "content": { "style": "block", "align": "center", "quote": "Come late. Stay later.", "attribution": "The House" } }
+ { "block_key": "image", "title": "The bar", "slot": "main", "sort_order": 3, "content": { "src": "media:a1b2c3d4-0000-4000-8000-000000000002", "alt": "Warm brass-lit shelves of whisky bottles in a dim room", "caption": "The long bar. Low light, and a shelf that remembers you.", "size": "lg", "aspectRatio": "wide" } },
+ { "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "ornament", "icon": "lucide:diamond" } },
+ { "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 5, "content": { "style": "block", "align": "center", "quote": "Come late. Stay later.", "attribution": "The House" } }
]
},
{
@@ -157,9 +167,9 @@
"title": "The Journal",
"template_key": "blog-index",
"blocks": [
- { "block_key": "card", "title": "Post: The Door", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "title": "How the door works", "text": "The list, the card and the guests. What to send and when.
", "link": "/blog/how-the-door-works", "linkLabel": "Read on" } },
- { "block_key": "card", "title": "Post: A Night", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "title": "A night at the house", "text": "From the first pour to the last record. How the evening runs.
", "link": "/blog/a-night-at-the-house", "linkLabel": "Read on" } },
- { "block_key": "card", "title": "Post: The Cellar", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "title": "Notes from the cellar", "text": "What we pour after midnight and why the list stays short.
", "link": "/blog/notes-from-the-cellar", "linkLabel": "Read on" } }
+ { "block_key": "card", "title": "Post: The Door", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "media": "media:a1b2c3d4-0000-4000-8000-000000000003", "title": "How the door works", "text": "The list, the card and the guests. What to send and when.
", "link": "/blog/how-the-door-works", "linkLabel": "Read on" } },
+ { "block_key": "card", "title": "Post: A Night", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "media": "media:a1b2c3d4-0000-4000-8000-000000000004", "title": "A night at the house", "text": "From the first pour to the last record. How the evening runs.
", "link": "/blog/a-night-at-the-house", "linkLabel": "Read on" } },
+ { "block_key": "card", "title": "Post: The Cellar", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "media": "media:a1b2c3d4-0000-4000-8000-000000000002", "title": "Notes from the cellar", "text": "What we pour after midnight and why the list stays short.
", "link": "/blog/notes-from-the-cellar", "linkLabel": "Read on" } }
]
},
{
@@ -169,7 +179,7 @@
"parent_slug": "/blog",
"blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "How the door works", "level": 1 } },
- { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "Send your name and party by nine. We hold the list until then and reply the same day.
Members lead. Guests come with them, and there is a cap. Bring your card. The door checks it.
" } }
+ { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "Send your name and party by nine. We hold the list until then and reply the same day. No name, no note, no entry.
Members lead. A guest comes on a member's word, and the member is the one who answers for them. Bring your card. The door checks it, every night, without exception.
There is a cap. Some nights it is generous. Most nights it is not. When the room is full the list closes, and the closing is final. We do not reopen it for a better story told at the rail.
The door is not a negotiation. The people who work it have seen every version of the conversation you are about to start, and they were unmoved the first time. Arrive as though you belong, and more often than not you will.
Dress for a dark room. We do not print a code, because the room prints it for us. You will know within a step whether you have read it right. When in doubt, wear less colour and better shoes.
Photographs stay in your pocket. The house is a place people come to be unseen, and that only holds if everyone keeps the same agreement. Break it once and the card goes quiet.
If you are late, you are late to the list, not to us. The night runs on its own clock and will not wait, but it does not end early either. Come when you can. The door will still be there.
Lose the card and tell us before you tell anyone else. A card in the wrong hands is a name in the wrong mouth, and we would rather cancel it over a quiet word than read about it later.
That is the whole of it. Send the name, bring the card, keep the room's secrets, and the door becomes the easiest part of the evening.
" } }
]
},
{
@@ -179,7 +189,7 @@
"parent_slug": "/blog",
"blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "A night at the house", "level": 1 } },
- { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "Doors open at nine. The first set starts slow. The main room fills after eleven and holds until the lights come up.
The cellar bar stays quiet. That is the point. Records, a nightcap and the last pour.
" } }
+ { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "Doors open at nine. The first set starts slow, on purpose. The room is meant to be walked into, not fallen into, and the early hour belongs to the people who like it quiet.
The main room fills after eleven. That is when the residents lean into the good part of the night, and the floor stops being a place to stand and becomes a place to stay. If you came to dance, come late.
The brass room runs colder and closer. Fewer people, a shorter bar, a door within the door. It is where the house keeps its better hours for the cards that have earned them.
The cellar bar stays quiet, and that is the point. Records, low light, a bench of rye and a host who remembers what you drank last time. Conversations that would not survive the main room live down here.
Somewhere past one, the night finds its level. The people who were going to leave have left. The people who were always going to stay have found their corner. The house exhales.
We do not announce last call. The last pour arrives when the room is ready for it, poured a little slower than the ones before, and nobody has to be told what it means.
The lights do not come up so much as lean in. First the far corners, then the rail, then the floor. The house dims the evening down the way it brought it up.
Then the door, which held the list all night, holds it open instead. You leave the way you came, by a member's word, into a street that has no idea what the room behind it was doing.
Come back on a Sunday if you want to understand the place. The crowd is smaller, the records are older, and the house is most itself when almost no one is watching.
" } }
]
},
{
@@ -189,7 +199,7 @@
"parent_slug": "/blog",
"blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Notes from the cellar", "level": 1 } },
- { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "The list is short by choice. We pour champagne by the glass, keep a bench of rye and hold a small shelf for members who ask.
Tell the host what you are drinking. The rest follows.
" } }
+ { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "The list is short by choice. A long list is a way of hiding that you do not know what you are pouring. We keep ours brief so that every bottle on it has a reason to be there.
We pour champagne by the glass, because a good glass should not require a commitment. The house brut carries most nights. The vintage rosé sits on a short shelf for the members who ask, and it does not last.
There is a bench of rye the cellar is quietly proud of. Neat, one large cube, no ceremony. If you want it drowned we will do it, but the host will remember.
The single malt is Islay, and it is not for everyone, which is exactly why we keep it. Bring water. Let it open. The cellar is a slow room, and the whisky was made by people who understood that.
Bottle service is a booth and a decision, not a display. We do not run sparklers to the floor. What arrives is what you asked for, cold, on time, and without an audience.
Ask the host what is drinking well tonight. It is the most useful sentence in the room. The list on the table is the floor of the conversation, not the ceiling.
We hold a small reserve that never makes the printed page. It goes to the cards that have been patient, on nights that have earned it, and it is offered rather than requested.
Tell the host what you are drinking and the rest follows. The cellar is built on that one exchange: a name for a glass, a preference remembered, a night made a little better than the last.
" } }
]
},
{
diff --git a/templates/gotham/article.ninjatpl b/templates/gotham/article.ninjatpl
index c81989c..a6bb3e5 100644
--- a/templates/gotham/article.ninjatpl
+++ b/templates/gotham/article.ninjatpl
@@ -6,18 +6,18 @@
-
+
{% if slots.main %}{{ slots.main|safe }} {% else %}No content blocks assigned to this page.
{% endif %}
-
+ {% if slots.aside %}
{% endif %}
{{ body_end_html|safe }}