fix(lcars): seed hero+cover art, styled empty-media fallback, SVG geometry guard + shortcode sweep, longer episode log

- seed: wire 6 licensed cosmic images (hero split art, episode cover, episode-card + about slots); kills the empty grey hero/cover boxes with real art
- theme fix: rich-section + episode_console render a labeled LCARS console-art readout for unset image slots instead of a bare grey rectangle
- dead space: home hero -> split layout (image fills post-CTA void); lengthen first-contact episode log to ~11 paragraphs (starfleet-log voice), warp/terraforming to 5
- SVG geometry guard: explicit width/height on all <use> icon SVGs; full shortcode sweep (::pack:name:size:: -> sized <svg><use>) across every override

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-07-06 19:35:15 +08:00
parent 59bb1f453a
commit d2d27b8dd9
32 changed files with 55 additions and 41 deletions

View File

@ -1,13 +1,13 @@
<section class="lcars-section {{ class }}" data-block="lcars:episode_console"><div class="lcars-well"> <section class="lcars-section {{ class }}" data-block="lcars:episode_console"><div class="lcars-well">
<div class="lcars-panel lcars-panel-accent" style="border-radius:0 0.75rem 0.75rem 0;padding:1.5rem;"> <div class="lcars-panel lcars-panel-accent" style="border-radius:0 0.75rem 0.75rem 0;padding:1.5rem;">
<div class="lcars-hero-split" style="gap:1.75rem;align-items:start;"> <div class="lcars-hero-split" style="gap:1.75rem;align-items:start;">
{% if cover %}<div class="lcars-media-frame" style="aspect-ratio:1 / 1;max-height:22rem;align-self:start;">{% img cover alt=title|default:"Episode cover" %}</div>{% else %}<div class="lcars-console-art" aria-hidden="true"><span class="lcars-console-art-scope"><i></i><i></i><i></i><i></i><i></i></span></div>{% endif %} {% if cover %}<div class="lcars-media-frame" style="aspect-ratio:1 / 1;max-height:22rem;align-self:start;">{% img cover alt=title|default:"Episode cover" %}</div>{% else %}<div class="lcars-console-art"><span class="lcars-console-art-label">No cover art</span><span class="lcars-console-art-scope" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></span></div>{% endif %}
<div class="lcars-stack-sm" style="min-width:0;"> <div class="lcars-stack-sm" style="min-width:0;">
<div class="lcars-panel-header"><span class="lcars-pill lcars-pill-accent" aria-hidden="true"></span>{% if eyebrow %}<span class="lcars-panel-title">{{ eyebrow }}</span>{% else %}<span class="lcars-panel-title">Now Broadcasting</span>{% endif %}<span class="lcars-panel-header-bar"></span></div> <div class="lcars-panel-header"><span class="lcars-pill lcars-pill-accent" aria-hidden="true"></span>{% if eyebrow %}<span class="lcars-panel-title">{{ eyebrow }}</span>{% else %}<span class="lcars-panel-title">Now Broadcasting</span>{% endif %}<span class="lcars-panel-header-bar"></span></div>
<div style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;">{% if episodeNumber %}<span class="lcars-badge">EP {{ episodeNumber }}</span>{% endif %}{% if stardate %}<span class="lcars-stardate">Stardate {{ stardate }}</span>{% endif %}{% if duration %}<span class="lcars-readout">{{ duration }}</span>{% endif %}</div> <div style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;">{% if episodeNumber %}<span class="lcars-badge">EP {{ episodeNumber }}</span>{% endif %}{% if stardate %}<span class="lcars-stardate">Stardate {{ stardate }}</span>{% endif %}{% if duration %}<span class="lcars-readout">{{ duration }}</span>{% endif %}</div>
{% if title %}<h2 class="lcars-heading lcars-heading-2">{{ title }}</h2>{% endif %} {% if title %}<h2 class="lcars-heading lcars-heading-2">{{ title }}</h2>{% endif %}
{% if description %}<p class="lcars-text" style="color:hsl(var(--muted-foreground));">{{ description }}</p>{% endif %} {% if description %}<p class="lcars-text" style="color:hsl(var(--muted-foreground));">{{ description }}</p>{% endif %}
<div class="lcars-btn-row" style="margin-top:0.25rem;">{% if listenUrl %}<a class="lcars-btn-primary" href="{{ listenUrl }}">::lucide:play:sm::{{ listenLabel|default:"Listen now" }}</a>{% endif %}{% for p in platforms %}<a class="lcars-btn-outline lcars-btn-sm" href="{{ p.url|default:'#' }}">{{ p.label }}</a>{% endfor %}</div> <div class="lcars-btn-row" style="margin-top:0.25rem;">{% if listenUrl %}<a class="lcars-btn-primary" href="{{ listenUrl }}"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#play"/></svg>{{ listenLabel|default:"Listen now" }}</a>{% endif %}{% for p in platforms %}<a class="lcars-btn-outline lcars-btn-sm" href="{{ p.url|default:'#' }}">{{ p.label }}</a>{% endfor %}</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -197,6 +197,9 @@ css:
.lcars-btn-lg { padding: 0.75rem 1.75rem; font-size: 1.0625rem; } .lcars-btn-lg { padding: 0.75rem 1.75rem; font-size: 1.0625rem; }
.lcars-btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; } .lcars-btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.lcars-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.125em; } .lcars-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.125em; }
/* Sized <use> icons carry explicit width/height attributes (SVG geometry
guard); this only handles inline flow/alignment, never sizing. */
.lcars-inline-icon { display: inline-block; vertical-align: -0.125em; flex: none; }
/* --- Panels / cards / surfaces --- */ /* --- Panels / cards / surfaces --- */
.lcars-panel { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border-left: 0.5rem solid hsl(var(--primary)); border-radius: 0 0.5rem 0.5rem 0; padding: 1.25rem 1.5rem; box-shadow: none; } .lcars-panel { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border-left: 0.5rem solid hsl(var(--primary)); border-radius: 0 0.5rem 0.5rem 0; padding: 1.25rem 1.5rem; box-shadow: none; }
@ -213,9 +216,11 @@ css:
.lcars-media-frame { display: block; width: 100%; overflow: hidden; background-color: hsl(var(--muted)); border-radius: 0.5rem; } .lcars-media-frame { display: block; width: 100%; overflow: hidden; background-color: hsl(var(--muted)); border-radius: 0.5rem; }
.lcars-media-frame img { display: block; width: 100%; height: 100%; object-fit: cover; } .lcars-media-frame img { display: block; width: 100%; height: 100%; object-fit: cover; }
.lcars-img-empty { display: block; width: 100%; aspect-ratio: 16 / 9; max-height: 20rem; background-color: hsl(var(--muted)); border-radius: 0.5rem; } .lcars-img-empty { display: block; width: 100%; aspect-ratio: 16 / 9; max-height: 20rem; background-color: hsl(var(--muted)); border-radius: 0.5rem; }
/* Graceful empty-media state: an on-brand LCARS readout panel that stays /* Graceful empty-media state: an on-brand LCARS readout panel with a status
compact instead of ballooning into a blank square when no cover ships. */ label, shown instead of a bare grey rectangle when no image ships. Stays
.lcars-console-art { display: flex; align-items: center; justify-content: center; align-self: start; width: 100%; aspect-ratio: 4 / 3; max-height: 15rem; padding: 1.5rem; background-color: hsl(var(--muted)); border-radius: 0.5rem; box-sizing: border-box; } compact instead of ballooning into a blank square. */
.lcars-console-art { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.9rem; align-self: start; width: 100%; aspect-ratio: 4 / 3; max-height: 15rem; padding: 1.5rem; background-color: hsl(var(--muted)); border-radius: 0.5rem; box-sizing: border-box; }
.lcars-console-art-label { font-family: var(--font-mono, "Share Tech Mono", monospace); font-size: 0.6875rem; font-weight: 400; letter-spacing: 0.24em; text-transform: uppercase; color: hsl(var(--muted-foreground)); }
.lcars-console-art-scope { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; max-width: 16rem; } .lcars-console-art-scope { display: flex; flex-direction: column; gap: 0.5rem; width: 100%; max-width: 16rem; }
.lcars-console-art-scope i { display: block; height: 0.625rem; border-radius: 0.3125rem; opacity: 0.55; } .lcars-console-art-scope i { display: block; height: 0.625rem; border-radius: 0.3125rem; opacity: 0.55; }
.lcars-console-art-scope i:nth-child(1) { width: 100%; background-color: hsl(var(--primary)); } .lcars-console-art-scope i:nth-child(1) { width: 100%; background-color: hsl(var(--primary)); }

BIN
seed/media/console.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
seed/media/deep-space.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
seed/media/milky-way.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

BIN
seed/media/nebula.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

BIN
seed/media/starfield.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

View File

@ -6,6 +6,14 @@
"tagline": "A weekly transmission on science fiction and the future." "tagline": "A weekly transmission on science fiction and the future."
} }
}, },
"media": [
{ "id": "435207dd-8607-4fe6-b8fa-fba0c7486e9f", "file": "media/nebula.jpg", "alt": "The Lagoon Nebula glowing violet and gold in deep space" },
{ "id": "74eb0f23-fb2b-419a-ab3e-06410aa71d64", "file": "media/milky-way.jpg", "alt": "The Milky Way arcing over a dark horizon" },
{ "id": "5d6beec6-a06c-4af7-b1fe-48869f09cef3", "file": "media/starfield.jpg", "alt": "A dense field of stars across the night sky" },
{ "id": "78c7e990-2682-4b39-acb4-cb7868e36e41", "file": "media/deep-space.jpg", "alt": "A distant world against the depth of the cosmos" },
{ "id": "b1a9259a-919f-4ac7-855f-315f295a6536", "file": "media/console.jpg", "alt": "A futuristic spaceship control console lit in amber" },
{ "id": "68341d09-4984-4a9c-ba91-f4005bcb52fd", "file": "media/control-buttons.jpg", "alt": "Illuminated control-panel buttons on a bridge console" }
],
"data_tables": [ "data_tables": [
{ {
"key": "hail_signals", "key": "hail_signals",
@ -27,8 +35,8 @@
"template_key": "full-width", "template_key": "full-width",
"reconcile_blocks": true, "reconcile_blocks": true,
"blocks": [ "blocks": [
{ "block_key": "hero", "title": "Hero", "slot": "main", "sort_order": 1, "content": { "template": "left-aligned", "eyebrow": "Now broadcasting", "headline": "Subspace Signal", "subheadline": "A weekly transmission on science fiction, deep space, and the people building the future. Two hosts. One open channel.", "ctaPrimary": { "text": "Listen now", "url": "/episodes" }, "ctaSecondary": { "text": "Meet the crew", "url": "/about" } } }, { "block_key": "hero", "title": "Hero", "slot": "main", "sort_order": 1, "content": { "template": "split", "mediaPosition": "right", "backgroundImage": "435207dd-8607-4fe6-b8fa-fba0c7486e9f", "eyebrow": "Now broadcasting", "headline": "Subspace Signal", "subheadline": "A weekly transmission on science fiction, deep space, and the people building the future. Two hosts. One open channel.", "ctaPrimary": { "text": "Listen now", "url": "/episodes" }, "ctaSecondary": { "text": "Meet the crew", "url": "/about" } } },
{ "block_key": "lcars:episode_console", "title": "Featured episode", "slot": "main", "sort_order": 2, "content": { "eyebrow": "Latest transmission", "title": "First contact was a podcast", "episodeNumber": "048", "duration": "58:12", "stardate": "78412.3", "description": "We open the season with a simple question. If a signal reached us tomorrow, who would answer, and what would we say back.", "listenUrl": "/episodes/first-contact", "listenLabel": "Listen now", "platforms": [ { "label": "Apple", "url": "/episodes" }, { "label": "Spotify", "url": "/episodes" }, { "label": "RSS", "url": "/episodes" } ] } }, { "block_key": "lcars:episode_console", "title": "Featured episode", "slot": "main", "sort_order": 2, "content": { "eyebrow": "Latest transmission", "title": "First contact was a podcast", "cover": "74eb0f23-fb2b-419a-ab3e-06410aa71d64", "episodeNumber": "048", "duration": "58:12", "stardate": "78412.3", "description": "We open the season with a simple question. If a signal reached us tomorrow, who would answer, and what would we say back.", "listenUrl": "/episodes/first-contact", "listenLabel": "Listen now", "platforms": [ { "label": "Apple", "url": "/episodes" }, { "label": "Spotify", "url": "/episodes" }, { "label": "RSS", "url": "/episodes" } ] } },
{ "block_key": "stats", "title": "Signal log", "slot": "main", "sort_order": 3, "content": { "heading": "Signal log", "columns": 3, "countUp": false, "items": [ { "value": "48", "label": "Episodes aired" }, { "value": "4", "label": "Seasons on air" }, { "value": "26", "label": "Star systems covered" } ] } }, { "block_key": "stats", "title": "Signal log", "slot": "main", "sort_order": 3, "content": { "heading": "Signal log", "columns": 3, "countUp": false, "items": [ { "value": "48", "label": "Episodes aired" }, { "value": "4", "label": "Seasons on air" }, { "value": "26", "label": "Star systems covered" } ] } },
{ "block_key": "lcars:crew_roster", "title": "Crew", "slot": "main", "sort_order": 4, "content": { "eyebrow": "On the bridge", "heading": "Your crew", "members": [ { "name": "Vega Okonkwo", "role": "Host", "callsign": "Bridge-1", "bio": "Reads too much hard science fiction and asks the questions engineers dread." }, { "name": "Rell Tavras", "role": "Co-host", "callsign": "Science-2", "bio": "Keeps the physics honest and the metaphors from getting away from us." } ] } }, { "block_key": "lcars:crew_roster", "title": "Crew", "slot": "main", "sort_order": 4, "content": { "eyebrow": "On the bridge", "heading": "Your crew", "members": [ { "name": "Vega Okonkwo", "role": "Host", "callsign": "Bridge-1", "bio": "Reads too much hard science fiction and asks the questions engineers dread." }, { "name": "Rell Tavras", "role": "Co-host", "callsign": "Science-2", "bio": "Keeps the physics honest and the metaphors from getting away from us." } ] } },
{ "block_key": "cta", "title": "Closing CTA", "slot": "main", "sort_order": 5, "content": { "background": "band", "heading": "Tune the frequency", "text": "New transmission every week. Subscribe on your channel of choice.", "primaryLabel": "Subscribe", "primaryUrl": "/episodes" } } { "block_key": "cta", "title": "Closing CTA", "slot": "main", "sort_order": 5, "content": { "background": "band", "heading": "Tune the frequency", "text": "New transmission every week. Subscribe on your channel of choice.", "primaryLabel": "Subscribe", "primaryUrl": "/episodes" } }
@ -42,8 +50,9 @@
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "About the signal", "level": 1 } }, { "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "About the signal", "level": 1 } },
{ "block_key": "text", "title": "Intro", "slot": "main", "sort_order": 2, "content": { "text": "<p>Subspace Signal is a weekly show about science fiction and the real science it borrows from. We read the books, watch the shows, and talk to the people who build the future for a living. Every episode is one open channel between two hosts and you.</p>" } }, { "block_key": "text", "title": "Intro", "slot": "main", "sort_order": 2, "content": { "text": "<p>Subspace Signal is a weekly show about science fiction and the real science it borrows from. We read the books, watch the shows, and talk to the people who build the future for a living. Every episode is one open channel between two hosts and you.</p>" } },
{ "block_key": "lcars:transmission_status", "title": "Systems", "slot": "main", "sort_order": 3, "content": { "eyebrow": "Console", "heading": "Channel status", "systems": [ { "label": "Weekly uplink", "status": "online", "detail": "Every Tuesday" }, { "label": "Back catalogue", "status": "online", "detail": "48 episodes" }, { "label": "Listener comms", "status": "standby", "detail": "Open for hails" }, { "label": "Live recordings", "status": "standby", "detail": "Next season" } ] } }, { "block_key": "image", "title": "Bridge console", "slot": "main", "sort_order": 3, "content": { "src": "68341d09-4984-4a9c-ba91-f4005bcb52fd", "alt": "Illuminated control-panel buttons on a bridge console", "caption": "The Subspace Signal recording console, Deck 12.", "align": "center" } },
{ "block_key": "lcars:stardate_log", "title": "Log", "slot": "main", "sort_order": 4, "content": { "eyebrow": "Ship's log", "heading": "How we got here", "entries": [ { "stardate": "74001.0", "title": "Signal first opened", "text": "Two friends started recording arguments about warp drives in a spare room." }, { "stardate": "76210.5", "title": "First guest aboard", "text": "A working propulsion engineer joined to explain why the arguments were wrong." }, { "stardate": "78412.3", "title": "Season four begins", "text": "New gear, same open channel, more star systems to cover." } ] } } { "block_key": "lcars:transmission_status", "title": "Systems", "slot": "main", "sort_order": 4, "content": { "eyebrow": "Console", "heading": "Channel status", "systems": [ { "label": "Weekly uplink", "status": "online", "detail": "Every Tuesday" }, { "label": "Back catalogue", "status": "online", "detail": "48 episodes" }, { "label": "Listener comms", "status": "standby", "detail": "Open for hails" }, { "label": "Live recordings", "status": "standby", "detail": "Next season" } ] } },
{ "block_key": "lcars:stardate_log", "title": "Log", "slot": "main", "sort_order": 5, "content": { "eyebrow": "Ship's log", "heading": "How we got here", "entries": [ { "stardate": "74001.0", "title": "Signal first opened", "text": "Two friends started recording arguments about warp drives in a spare room." }, { "stardate": "76210.5", "title": "First guest aboard", "text": "A working propulsion engineer joined to explain why the arguments were wrong." }, { "stardate": "78412.3", "title": "Season four begins", "text": "New gear, same open channel, more star systems to cover." } ] } }
] ]
}, },
{ {
@ -52,9 +61,9 @@
"template_key": "blog-index", "template_key": "blog-index",
"reconcile_blocks": true, "reconcile_blocks": true,
"blocks": [ "blocks": [
{ "block_key": "card", "title": "Episode 48", "slot": "main", "sort_order": 1, "content": { "title": "First contact was a podcast", "text": "<p>If a signal reached us tomorrow, who would answer, and what would we say back.</p>", "link": "/episodes/first-contact", "linkLabel": "Listen" } }, { "block_key": "card", "title": "Episode 48", "slot": "main", "sort_order": 1, "content": { "title": "First contact was a podcast", "media": "78c7e990-2682-4b39-acb4-cb7868e36e41", "text": "<p>If a signal reached us tomorrow, who would answer, and what would we say back.</p>", "link": "/episodes/first-contact", "linkLabel": "Listen" } },
{ "block_key": "card", "title": "Episode 47", "slot": "main", "sort_order": 2, "content": { "title": "The physics of warp, honestly", "text": "<p>A propulsion engineer walks us through what the math actually allows.</p>", "link": "/episodes/warp-honestly", "linkLabel": "Listen" } }, { "block_key": "card", "title": "Episode 47", "slot": "main", "sort_order": 2, "content": { "title": "The physics of warp, honestly", "media": "5d6beec6-a06c-4af7-b1fe-48869f09cef3", "text": "<p>A propulsion engineer walks us through what the math actually allows.</p>", "link": "/episodes/warp-honestly", "linkLabel": "Listen" } },
{ "block_key": "card", "title": "Episode 46", "slot": "main", "sort_order": 3, "content": { "title": "Terraforming on a budget", "text": "<p>What it would really take to make one small world a little more livable.</p>", "link": "/episodes/terraforming", "linkLabel": "Listen" } } { "block_key": "card", "title": "Episode 46", "slot": "main", "sort_order": 3, "content": { "title": "Terraforming on a budget", "media": "b1a9259a-919f-4ac7-855f-315f295a6536", "text": "<p>What it would really take to make one small world a little more livable.</p>", "link": "/episodes/terraforming", "linkLabel": "Listen" } }
] ]
}, },
{ {
@ -65,7 +74,7 @@
"reconcile_blocks": true, "reconcile_blocks": true,
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "First contact was a podcast", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "First contact was a podcast", "level": 1 } },
{ "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>We open the season with a simple question. If a signal reached us tomorrow, who would answer, and what would we say back. The honest answer is that nobody is really in charge of the reply.</p><p>So we build the reply ourselves. We talk through who we would want on the line, what we would lead with, and why the first message matters more than the last.</p>" } } { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>Stardate 78412.3. We open the season with a simple question, the kind that sounds small until you try to answer it out loud. If a signal reached us tomorrow, who would answer, and what would we say back? The honest answer is that nobody is really in charge of the reply, and that is where this whole transmission begins.</p><p>Start with the receiving end. There is no single red phone that rings when the universe calls. A confirmed detection would arrive not as a voice but as a pattern buried in noise, checked and rechecked across observatories on three continents before anyone dared say the word out loud. By the time it was real, it would already have passed through a hundred hands, and not one of them would have the authority to speak for the planet.</p><p>So the argument that fills the first act of tonight's episode is not about aliens at all. It is about us. Who gets to draft humanity's opening line? A committee? A head of state? The astronomer who happened to be on shift? We walk through the protocols that actually exist on paper, and then we walk through how quickly those protocols would dissolve the moment a real signal turned the abstract into the urgent.</p><p>Rell makes the case that the first message should be pure mathematics. Prime numbers, the value of pi, the hydrogen line. Nothing that could be misread, nothing that carries the baggage of a culture or a century. A handshake in the only language two strangers across a galaxy could possibly share. It is a clean idea, and for about four minutes it is winning.</p><p>Then Vega asks the question that undoes it. If the whole point of answering is to say something true about who we are, why would we lead with the one part of ourselves that looks identical to every other species that can count? Mathematics proves we are here. It says nothing about what it is like to be here. And maybe, she argues, that second thing is the message.</p><p>We bring in a linguist who has spent a career thinking about first contact between human languages that share no common root. Her warning is sobering. Every act of translation smuggles in assumptions, she says, and the assumptions you cannot see are the ones that hurt you. The first message is not a greeting. It is a lens, and whoever builds it decides what the other side will see of us first.</p><p>That reframes the engineering problem entirely. Bandwidth stops being the constraint. Intent becomes the constraint. You are not trying to transmit the most information. You are trying to transmit the least misleading version of an entire civilization in a package small enough to survive the crossing intact.</p><p>Halfway through, we do the exercise ourselves. Live, unscripted, we each try to write three lines we would put at the front of the reply. It is harder than it sounds, and both attempts are worse than we expected. Every draft either flatters us or apologizes for us. Nobody writes the plain, unhurried truth on the first try, which turns out to be the most human result of all.</p><p>What we keep circling back to is patience. A conversation across light-years is measured in lifetimes. You will not hear back. Your grandchildren might. That changes the character of the message from a statement into an inheritance, something written to be finished by people you will never meet, in a context you cannot predict.</p><p>We close the way we opened, with the question turned around. Not what would we say to them, but what do we wish someone had said to us, early, before we knew enough to be afraid of the answer. That is the message. That is what we would send. And if the channel stays quiet for another thousand years, at least we will have spent the wait learning how to speak plainly to each other.</p><p>Next week we hand the microphone to a working propulsion engineer and ask him to break our hearts about warp drive. Until then, this is Subspace Signal, and the channel stays open.</p>" } }
] ]
}, },
{ {
@ -76,7 +85,7 @@
"reconcile_blocks": true, "reconcile_blocks": true,
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The physics of warp, honestly", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The physics of warp, honestly", "level": 1 } },
{ "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>Warp drive makes for a great story and a hard equation. We asked a working propulsion engineer to walk us through what the math actually allows and where the fiction quietly cheats.</p><p>The short version is that the energy budget is the whole story. Everything else is set dressing until you solve for that.</p>" } } { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>Stardate 78295.1. Warp drive makes for a great story and a hard equation. This week we asked a working propulsion engineer to walk us through what the math actually allows, and where the fiction quietly cheats to keep the plot moving.</p><p>The short version is that the energy budget is the whole story. Everything else is set dressing until you solve for that. Bend spacetime enough to matter and the numbers you get back are not large in the everyday sense. They are large in the sense that they compare to the output of stars.</p><p>Our guest is generous about the fiction. He does not want warp drive to be impossible, and he is careful to separate what is forbidden by physics from what is merely absurd by engineering. The first list is short. The second list is long, and it is where the honest heartbreak lives.</p><p>We spend a while on exotic matter, the placeholder every warp metric leans on to make the equations behave. It is not a material you could ever put in a crate. It is a property the math demands and the universe has never once been observed to provide at the scale a ship would need.</p><p>By the end, nobody at the table wants to give up the dream. We just want to hold it honestly. The stars are not close, the shortcuts are not free, and the wanting is the most real part of the whole enterprise. That, at least, the math cannot take away from us.</p>" } }
] ]
}, },
{ {
@ -87,7 +96,7 @@
"reconcile_blocks": true, "reconcile_blocks": true,
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Terraforming on a budget", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Terraforming on a budget", "level": 1 } },
{ "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>Making a whole planet livable is a project measured in centuries. So we asked a smaller question. What is the cheapest first step that would make one small world a little more forgiving.</p><p>The answer is not domes or rockets. It is patience, pressure, and a very long supply of the right microbes.</p>" } } { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "<p>Stardate 78190.7. Making a whole planet livable is a project measured in centuries. So this week we asked a smaller, more honest question. What is the cheapest first step that would make one small world a little more forgiving to the people who came to stay?</p><p>The answer is not domes or rockets. It is patience, pressure, and a very long supply of the right microbes. The glamorous engineering comes much later, if it comes at all. The early work is closer to gardening than to conquest.</p><p>Our guest, a planetary scientist who models atmospheres for a living, keeps pulling us back to the timescales. Nothing about this happens in a human career. You plant a process and you hand it to people who are not born yet, and you trust them to keep the thermostat pointed the right way.</p><p>We talk about the ethics of it too. A world you are slowly changing might already have something living on it, quiet and slow and easy to miss. The budget that matters most, she argues, is not measured in credits. It is measured in how carefully you look before you begin.</p><p>We end where terraforming actually starts, with a single greenhouse and a stubborn strain of algae. Small, unglamorous, and real. The rest is just that same patience, repeated for a thousand years, until one morning the air outside is one degree kinder than it was.</p>" } }
] ]
}, },
{ {

View File

@ -3,6 +3,6 @@
<div data-bn-announcement data-bn-annkey="{{ variant|default:'info' }}:{{ message|slugify }}" class="lcars-announce {{ annvar }} {{ class }}" style="{{ annsty }}"> <div data-bn-announcement data-bn-annkey="{{ variant|default:'info' }}:{{ message|slugify }}" class="lcars-announce {{ annvar }} {{ class }}" style="{{ annsty }}">
<div class="lcars-content-well lcars-announce-row" style="position:relative;display:flex;align-items:center;justify-content:center;gap:0.75rem;padding-top:0.5rem;padding-bottom:0.5rem;font-size:0.875rem;text-align:center;"> <div class="lcars-content-well lcars-announce-row" style="position:relative;display:flex;align-items:center;justify-content:center;gap:0.75rem;padding-top:0.5rem;padding-bottom:0.5rem;font-size:0.875rem;text-align:center;">
<p style="margin:0;font-weight:500;">{{ message }}{% if linkText and linkUrl %} <a href="{{ linkUrl }}" style="color:inherit;text-decoration:underline;text-underline-offset:2px;">{{ linkText }}</a>{% endif %}</p> <p style="margin:0;font-weight:500;">{{ message }}{% if linkText and linkUrl %} <a href="{{ linkUrl }}" style="color:inherit;text-decoration:underline;text-underline-offset:2px;">{{ linkText }}</a>{% endif %}</p>
{% if dismissable %}<button type="button" data-bn-ann-dismiss aria-label="Dismiss announcement" class="lcars-announce-close" style="position:absolute;right:0.75rem;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;padding:0.25rem;background:none;border:0;color:inherit;cursor:pointer;">::lucide:x:sm::</button>{% endif %} {% if dismissable %}<button type="button" data-bn-ann-dismiss aria-label="Dismiss announcement" class="lcars-announce-close" style="position:absolute;right:0.75rem;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;padding:0.25rem;background:none;border:0;color:inherit;cursor:pointer;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#x"/></svg></button>{% endif %}
</div> </div>
</div> </div>

View File

@ -6,8 +6,8 @@
{% if title %}<p class="lcars-display" style="margin:0;font-size:0.9375rem;color:hsl(var(--foreground));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{{ title }}</p>{% endif %} {% if title %}<p class="lcars-display" style="margin:0;font-size:0.9375rem;color:hsl(var(--foreground));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{{ title }}</p>{% endif %}
{% if artist %}<p style="margin:0;font-size:0.8125rem;color:hsl(var(--muted-foreground));">{{ artist }}</p>{% endif %} {% if artist %}<p style="margin:0;font-size:0.8125rem;color:hsl(var(--muted-foreground));">{{ artist }}</p>{% endif %}
<div data-bn-audio-slot style="display:flex;align-items:center;gap:0.75rem;margin-top:0.5rem;"> <div data-bn-audio-slot style="display:flex;align-items:center;gap:0.75rem;margin-top:0.5rem;">
<button type="button" data-bn-audio-play class="lcars-btn-primary lcars-btn-sm" aria-label="Play{% if title %}: {{ title }}{% endif %}" style="display:inline-flex;align-items:center;gap:0.375rem;">::lucide:play:sm:: Play</button> <button type="button" data-bn-audio-play class="lcars-btn-primary lcars-btn-sm" aria-label="Play{% if title %}: {{ title }}{% endif %}" style="display:inline-flex;align-items:center;gap:0.375rem;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#play"/></svg> Play</button>
{% if download %}<a href="{% if media %}{{ media|mediaURL }}{% else %}{{ url }}{% endif %}" download class="lcars-btn-ghost" style="display:inline-flex;align-items:center;gap:0.25rem;font-size:0.8125rem;color:hsl(var(--muted-foreground));text-decoration:none;">::lucide:download:sm:: Download</a>{% endif %} {% if download %}<a href="{% if media %}{{ media|mediaURL }}{% else %}{{ url }}{% endif %}" download class="lcars-btn-ghost" style="display:inline-flex;align-items:center;gap:0.25rem;font-size:0.8125rem;color:hsl(var(--muted-foreground));text-decoration:none;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#download"/></svg> Download</a>{% endif %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1 +1 @@
{% if context.currentAuthor %}<section class="lcars-section {{ class }}" data-block="lcars:author-bio-hero"><div class="lcars-content-well"><div class="lcars-measure lcars-stack" style="text-align: center; margin-left: auto; margin-right: auto;">{% if showAvatar and context.currentAuthor.avatarUrl %}<img class="lcars-avatar" src="{{ context.currentAuthor.avatarUrl }}" alt="{{ context.currentAuthor.displayName }}" style="width: 6rem; height: 6rem; border-radius: 9999px; object-fit: cover; margin-left: auto; margin-right: auto;">{% else %}<span class="lcars-mark lcars-mark-ring" aria-hidden="true" style="margin-left: auto; margin-right: auto;"></span>{% endif %}<h1 class="lcars-display" style="margin: 0;">{{ context.currentAuthor.displayName }}</h1>{% if context.currentAuthor.bio %}<p class="lcars-lede" style="margin: 0;">{{ context.currentAuthor.bio }}</p>{% endif %}{% if showSocial %}<div class="lcars-btn-row" style="justify-content: center;">{% if context.currentAuthor.websiteUrl %}<a class="lcars-btn-ghost lcars-btn-sm" href="{{ context.currentAuthor.websiteUrl }}" target="_blank" rel="noopener noreferrer" title="Website"><svg class="lcars-icon" aria-hidden="true"><use href="/icons/lucide.svg#globe"/></svg></a>{% endif %}{% if context.currentAuthor.twitterHandle %}<a class="lcars-btn-ghost lcars-btn-sm" href="https://twitter.com/{{ context.currentAuthor.twitterHandle|cut:"@" }}" target="_blank" rel="noopener noreferrer" title="X"><svg class="lcars-icon" aria-hidden="true"><use href="/icons/simple-icons.svg#x"/></svg></a>{% endif %}{% if context.currentAuthor.linkedinUrl %}<a class="lcars-btn-ghost lcars-btn-sm" href="{{ context.currentAuthor.linkedinUrl }}" target="_blank" rel="noopener noreferrer" title="LinkedIn"><svg class="lcars-icon" aria-hidden="true"><use href="/icons/simple-icons.svg#linkedin"/></svg></a>{% endif %}</div>{% endif %}</div></div></section>{% endif %} {% if context.currentAuthor %}<section class="lcars-section {{ class }}" data-block="lcars:author-bio-hero"><div class="lcars-content-well"><div class="lcars-measure lcars-stack" style="text-align: center; margin-left: auto; margin-right: auto;">{% if showAvatar and context.currentAuthor.avatarUrl %}<img class="lcars-avatar" src="{{ context.currentAuthor.avatarUrl }}" alt="{{ context.currentAuthor.displayName }}" style="width: 6rem; height: 6rem; border-radius: 9999px; object-fit: cover; margin-left: auto; margin-right: auto;">{% else %}<span class="lcars-mark lcars-mark-ring" aria-hidden="true" style="margin-left: auto; margin-right: auto;"></span>{% endif %}<h1 class="lcars-display" style="margin: 0;">{{ context.currentAuthor.displayName }}</h1>{% if context.currentAuthor.bio %}<p class="lcars-lede" style="margin: 0;">{{ context.currentAuthor.bio }}</p>{% endif %}{% if showSocial %}<div class="lcars-btn-row" style="justify-content: center;">{% if context.currentAuthor.websiteUrl %}<a class="lcars-btn-ghost lcars-btn-sm" href="{{ context.currentAuthor.websiteUrl }}" target="_blank" rel="noopener noreferrer" title="Website"><svg class="lcars-icon" width="16" height="16" aria-hidden="true"><use href="/icons/lucide.svg#globe"/></svg></a>{% endif %}{% if context.currentAuthor.twitterHandle %}<a class="lcars-btn-ghost lcars-btn-sm" href="https://twitter.com/{{ context.currentAuthor.twitterHandle|cut:"@" }}" target="_blank" rel="noopener noreferrer" title="X"><svg class="lcars-icon" width="16" height="16" aria-hidden="true"><use href="/icons/simple-icons.svg#x"/></svg></a>{% endif %}{% if context.currentAuthor.linkedinUrl %}<a class="lcars-btn-ghost lcars-btn-sm" href="{{ context.currentAuthor.linkedinUrl }}" target="_blank" rel="noopener noreferrer" title="LinkedIn"><svg class="lcars-icon" width="16" height="16" aria-hidden="true"><use href="/icons/simple-icons.svg#linkedin"/></svg></a>{% endif %}</div>{% endif %}</div></div></section>{% endif %}

View File

@ -3,4 +3,4 @@
{% if btnStyle == "outline" or btnStyle == "secondary" %}{% set btnClass = "lcars-btn-outline" %}{% elif btnStyle == "ghost" or btnStyle == "link" %}{% set btnClass = "lcars-btn-ghost" %}{% endif %} {% if btnStyle == "outline" or btnStyle == "secondary" %}{% set btnClass = "lcars-btn-outline" %}{% elif btnStyle == "ghost" or btnStyle == "link" %}{% set btnClass = "lcars-btn-ghost" %}{% endif %}
{% set sizeClass = "" %} {% set sizeClass = "" %}
{% if size == "sm" %}{% set sizeClass = "lcars-btn-sm" %}{% elif size == "lg" %}{% set sizeClass = "lcars-btn-lg" %}{% endif %} {% if size == "sm" %}{% set sizeClass = "lcars-btn-sm" %}{% elif size == "lg" %}{% set sizeClass = "lcars-btn-lg" %}{% endif %}
<div class="lcars-btn-row {{ class }}" style="{% if align == "center" %}justify-content: center;{% elif align == "right" %}justify-content: flex-end;{% endif %}">{% if newTab %}<a class="{{ btnClass }} {{ sizeClass }}" href="{{ link|default:"#" }}" target="_blank" rel="noopener noreferrer">{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}</a>{% else %}<a class="{{ btnClass }} {{ sizeClass }}" href="{{ link|default:"#" }}">{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}</a>{% endif %}</div> <div class="lcars-btn-row {{ class }}" style="{% if align == "center" %}justify-content: center;{% elif align == "right" %}justify-content: flex-end;{% endif %}">{% if newTab %}<a class="{{ btnClass }} {{ sizeClass }}" href="{{ link|default:"#" }}" target="_blank" rel="noopener noreferrer">{% if icon and iconPosition != "right" %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"/></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"/></svg>{% endif %}</a>{% else %}<a class="{{ btnClass }} {{ sizeClass }}" href="{{ link|default:"#" }}">{% if icon and iconPosition != "right" %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"/></svg>{% endif %}<span>{{ label|default:"Learn more" }}</span>{% if icon and iconPosition == "right" %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ icon|split:":"|first }}.svg#{{ icon|split:":"|last }}"/></svg>{% endif %}</a>{% endif %}</div>

View File

@ -1 +1 @@
<article class="lcars-card lcars-card-accent {{ class }}">{% if media %}<div class="lcars-media-frame" style="aspect-ratio: 16 / 9; margin: -1.5rem -1.5rem 1.25rem -1.5rem; border: 0; border-bottom: 1px solid hsl(var(--border));">{% img media alt=title|default:"" class="lcars-card-media" %}</div>{% endif %}{% if title %}<h3 class="lcars-feature-title" style="margin-top: 0; font-size: 1.25rem;">{{ title }}</h3>{% endif %}{% if text %}<div class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground));">{{ text|safe }}</div>{% endif %}{% if linkLabel and link %}<a class="lcars-btn-ghost" href="{{ link }}" style="margin-top: 1rem;">{{ linkLabel }}::lucide:arrow-right:sm::</a>{% endif %}</article> <article class="lcars-card lcars-card-accent {{ class }}">{% if media %}<div class="lcars-media-frame" style="aspect-ratio: 16 / 9; margin: -1.5rem -1.5rem 1.25rem -1.5rem; border: 0; border-bottom: 1px solid hsl(var(--border));">{% img media alt=title|default:"" class="lcars-card-media" %}</div>{% endif %}{% if title %}<h3 class="lcars-feature-title" style="margin-top: 0; font-size: 1.25rem;">{{ title }}</h3>{% endif %}{% if text %}<div class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground));">{{ text|safe }}</div>{% endif %}{% if linkLabel and link %}<a class="lcars-btn-ghost" href="{{ link }}" style="margin-top: 1rem;">{{ linkLabel }}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"/></svg></a>{% endif %}</article>

View File

@ -4,7 +4,7 @@
{% if description %}<p class="lcars-lede" style="max-width:60ch;margin:0 0 2.5rem 0;color:hsl(var(--muted-foreground));">{{ description }}</p>{% endif %} {% if description %}<p class="lcars-lede" style="max-width:60ch;margin:0 0 2.5rem 0;color:hsl(var(--muted-foreground));">{{ description }}</p>{% endif %}
<div class="lcars-grid {% if columns == 3 %}lcars-grid-3{% elif columns == 1 %}{% else %}lcars-grid-2{% endif %}" style="display:grid;gap:1rem;{% if columns == 3 %}grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));{% elif columns == 1 %}grid-template-columns:1fr;{% else %}grid-template-columns:repeat(auto-fill, minmax(280px, 1fr));{% endif %}"> <div class="lcars-grid {% if columns == 3 %}lcars-grid-3{% elif columns == 1 %}{% else %}lcars-grid-2{% endif %}" style="display:grid;gap:1rem;{% if columns == 3 %}grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));{% elif columns == 1 %}grid-template-columns:1fr;{% else %}grid-template-columns:repeat(auto-fill, minmax(280px, 1fr));{% endif %}">
{% for channel in channels %}<div class="lcars-channel lcars-card" style="display:flex;align-items:flex-start;gap:1rem;"> {% for channel in channels %}<div class="lcars-channel lcars-card" style="display:flex;align-items:flex-start;gap:1rem;">
{% if channel.icon %}<span class="lcars-channel-mark" style="display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;flex:0 0 auto;border:1px solid hsl(var(--border));border-radius:4px;color:hsl(var(--accent));">::{{ channel.icon }}:sm::</span>{% endif %} {% if channel.icon %}<span class="lcars-channel-mark" style="display:inline-flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;flex:0 0 auto;border:1px solid hsl(var(--border));border-radius:4px;color:hsl(var(--accent));"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"/></svg></span>{% endif %}
<div style="min-width:0;"> <div style="min-width:0;">
{% if channel.label %}<div class="lcars-stat-label" style="margin:0;">{{ channel.label }}</div>{% endif %} {% if channel.label %}<div class="lcars-stat-label" style="margin:0;">{{ channel.label }}</div>{% endif %}
{% if channel.value %}<div style="margin-top:0.25rem;font-weight:500;word-break:break-word;color:hsl(var(--foreground));">{% if channel.link %}<a href="{{ channel.link }}" style="color:inherit;text-decoration:none;">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %} {% if channel.value %}<div style="margin-top:0.25rem;font-weight:500;word-break:break-word;color:hsl(var(--foreground));">{% if channel.link %}<a href="{{ channel.link }}" style="color:inherit;text-decoration:none;">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %}

View File

@ -1,2 +1,2 @@
{# divider override — plain hairline / thick spacer rule / centered ornament between two hairlines. #} {# divider override — plain hairline / thick spacer rule / centered ornament between two hairlines. #}
{% if variant == "ornament" %}<div class="lcars-divider-ornament {{ class }}" role="separator" style="display:flex;align-items:center;gap:1rem;margin:2.5rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}"><span class="lcars-hairline-top" style="flex:1;height:0;"></span><span style="display:inline-flex;color:hsl(var(--muted-foreground));">::{{ icon|default:"lucide:asterisk" }}:md::</span><span class="lcars-hairline-top" style="flex:1;height:0;"></span></div>{% elif variant == "spacer-rule" %}<hr class="lcars-divider-line lcars-divider-thick {{ class }}" role="separator" style="border:0;border-top:{% if weight == "thick" %}4px{% elif weight == "medium" %}2px{% else %}1px{% endif %} solid hsl(var(--border));margin:3rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}">{% else %}<hr class="lcars-divider-line {{ class }}" role="separator" style="border:0;border-top:{% if weight == "thick" %}4px{% elif weight == "medium" %}2px{% else %}1px{% endif %} solid hsl(var(--border));margin:2rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}">{% endif %} {% if variant == "ornament" %}<div class="lcars-divider-ornament {{ class }}" role="separator" style="display:flex;align-items:center;gap:1rem;margin:2.5rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}"><span class="lcars-hairline-top" style="flex:1;height:0;"></span><span style="display:inline-flex;color:hsl(var(--muted-foreground));"><svg width="20" height="20" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ icon|default:"lucide:asterisk"|split:":"|first }}.svg#{{ icon|default:"lucide:asterisk"|split:":"|last }}"/></svg></span><span class="lcars-hairline-top" style="flex:1;height:0;"></span></div>{% elif variant == "spacer-rule" %}<hr class="lcars-divider-line lcars-divider-thick {{ class }}" role="separator" style="border:0;border-top:{% if weight == "thick" %}4px{% elif weight == "medium" %}2px{% else %}1px{% endif %} solid hsl(var(--border));margin:3rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}">{% else %}<hr class="lcars-divider-line {{ class }}" role="separator" style="border:0;border-top:{% if weight == "thick" %}4px{% elif weight == "medium" %}2px{% else %}1px{% endif %} solid hsl(var(--border));margin:2rem auto;{% if width == "narrow" %}max-width:200px;{% elif width == "wide" %}max-width:768px;{% endif %}">{% endif %}

View File

@ -11,7 +11,7 @@
<h3 class="lcars-feature-title" style="font-size:1.125rem;margin:0;">{{ event.title }}</h3> <h3 class="lcars-feature-title" style="font-size:1.125rem;margin:0;">{{ event.title }}</h3>
{% if event.venue %}<p style="margin:0;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ event.venue }}</p>{% endif %} {% if event.venue %}<p style="margin:0;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ event.venue }}</p>{% endif %}
{% if event.description %}<p style="margin:0;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ event.description }}</p>{% endif %} {% if event.description %}<p style="margin:0;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ event.description }}</p>{% endif %}
{% if event.link %}<a class="lcars-btn-ghost" href="{{ event.link }}" style="margin-top:auto;display:inline-flex;align-items:center;gap:0.375rem;">{{ event.linkLabel|default:"Details" }}::lucide:arrow-right:sm::</a>{% endif %} {% if event.link %}<a class="lcars-btn-ghost" href="{{ event.link }}" style="margin-top:auto;display:inline-flex;align-items:center;gap:0.375rem;">{{ event.linkLabel|default:"Details" }}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"/></svg></a>{% endif %}
</div> </div>
</article>{% endif %}{% endfor %} </article>{% endif %}{% endfor %}
</div><style>.lcars-event-media{display:block;width:100%;height:100%;object-fit:cover;}</style> </div><style>.lcars-event-media{display:block;width:100%;height:100%;object-fit:cover;}</style>

View File

@ -2,5 +2,5 @@
<section class="lcars-section {{ class }}"><div class="lcars-content-well lcars-measure"> <section class="lcars-section {{ class }}"><div class="lcars-content-well lcars-measure">
{% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 0.75rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %} {% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 0.75rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %}
{% if intro %}<p class="lcars-lede" style="max-width: 60ch; margin: 0 0 2rem 0; color: hsl(var(--muted-foreground));">{{ intro }}</p>{% endif %} {% if intro %}<p class="lcars-lede" style="max-width: 60ch; margin: 0 0 2rem 0; color: hsl(var(--muted-foreground));">{{ intro }}</p>{% endif %}
{% if items %}<div class="lcars-hairline-top" style="margin-top: 1.5rem;">{% for item in items %}<details class="lcars-faq-item lcars-hairline-bottom"{% if variant == "open-list" %} open{% endif %}><summary class="lcars-heading" style="display: flex; justify-content: space-between; align-items: center; gap: 1rem; cursor: pointer; padding: 1rem 0; font-size: 1.125rem; list-style: none;">{{ item.question }}<span class="lcars-faq-chevron" aria-hidden="true" style="color: hsl(var(--muted-foreground)); flex: none;">::lucide:chevron-down:sm::</span></summary><div class="lcars-faq-answer lcars-text" style="padding-bottom: 1rem; color: hsl(var(--muted-foreground));">{{ item.answer|safe }}</div></details>{% endfor %}</div>{% endif %} {% if items %}<div class="lcars-hairline-top" style="margin-top: 1.5rem;">{% for item in items %}<details class="lcars-faq-item lcars-hairline-bottom"{% if variant == "open-list" %} open{% endif %}><summary class="lcars-heading" style="display: flex; justify-content: space-between; align-items: center; gap: 1rem; cursor: pointer; padding: 1rem 0; font-size: 1.125rem; list-style: none;">{{ item.question }}<span class="lcars-faq-chevron" aria-hidden="true" style="color: hsl(var(--muted-foreground)); flex: none;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#chevron-down"/></svg></span></summary><div class="lcars-faq-answer lcars-text" style="padding-bottom: 1rem; color: hsl(var(--muted-foreground));">{{ item.answer|safe }}</div></details>{% endfor %}</div>{% endif %}
</div></section> </div></section>

View File

@ -3,5 +3,5 @@
{% if eyebrow %}<p class="lcars-eyebrow">{{ eyebrow }}</p>{% endif %} {% if eyebrow %}<p class="lcars-eyebrow">{{ eyebrow }}</p>{% endif %}
{% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 0.75rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %} {% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 0.75rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %}
{% if intro %}<p class="lcars-lede" style="max-width: 60ch; margin: 0 0 2.5rem 0; color: hsl(var(--muted-foreground));">{{ intro }}</p>{% endif %} {% if intro %}<p class="lcars-lede" style="max-width: 60ch; margin: 0 0 2.5rem 0; color: hsl(var(--muted-foreground));">{{ intro }}</p>{% endif %}
{% if items %}<div class="lcars-grid {% if columns == 2 %}lcars-grid-2{% elif columns == 4 %}lcars-grid-4{% else %}lcars-grid-3{% endif %}">{% for item in items %}<div class="lcars-feature">{% if item.icon %}<span class="lcars-mark lcars-mark-square" aria-hidden="true">::{{ item.icon }}:sm::</span>{% else %}<span class="lcars-mark lcars-mark-square" aria-hidden="true"></span>{% endif %}{% if item.title %}<h3 class="lcars-feature-title">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" style="color: inherit; text-decoration: none;">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3>{% endif %}{% if item.text %}<p class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground));">{{ item.text }}</p>{% endif %}{% if item.linkUrl and item.linkLabel %}<a class="lcars-btn-ghost" href="{{ item.linkUrl }}" style="margin-top: 0.75rem;">{{ item.linkLabel }}::lucide:arrow-right:sm::</a>{% endif %}</div>{% endfor %}</div>{% endif %} {% if items %}<div class="lcars-grid {% if columns == 2 %}lcars-grid-2{% elif columns == 4 %}lcars-grid-4{% else %}lcars-grid-3{% endif %}">{% for item in items %}<div class="lcars-feature">{% if item.icon %}<span class="lcars-mark lcars-mark-square" aria-hidden="true"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"/></svg></span>{% else %}<span class="lcars-mark lcars-mark-square" aria-hidden="true"></span>{% endif %}{% if item.title %}<h3 class="lcars-feature-title">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" style="color: inherit; text-decoration: none;">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3>{% endif %}{% if item.text %}<p class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground));">{{ item.text }}</p>{% endif %}{% if item.linkUrl and item.linkLabel %}<a class="lcars-btn-ghost" href="{{ item.linkUrl }}" style="margin-top: 0.75rem;">{{ item.linkLabel }}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"/></svg></a>{% endif %}</div>{% endfor %}</div>{% endif %}
</div></section> </div></section>

View File

@ -12,6 +12,6 @@
<div class="lcars-footer-legal" style="display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:1rem;"> <div class="lcars-footer-legal" style="display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:1rem;">
<p style="margin:0;">{% if copyright %}&copy; {{ copyright }}{% else %}&copy; {{ companyName }}{% endif %}</p> <p style="margin:0;">{% if copyright %}&copy; {{ copyright }}{% else %}&copy; {{ companyName }}{% endif %}</p>
{% if legal_items %}<nav style="display:flex;flex-wrap:wrap;gap:1.25rem;">{% for l in legal_items %}<a href="{{ l.url|default:'#' }}"{% if l.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="lcars-footer-link" style="font-size:0.8125rem;color:hsl(var(--muted-foreground));text-decoration:none;">{{ l.label }}</a>{% endfor %}</nav>{% endif %} {% if legal_items %}<nav style="display:flex;flex-wrap:wrap;gap:1.25rem;">{% for l in legal_items %}<a href="{{ l.url|default:'#' }}"{% if l.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="lcars-footer-link" style="font-size:0.8125rem;color:hsl(var(--muted-foreground));text-decoration:none;">{{ l.label }}</a>{% endfor %}</nav>{% endif %}
{% if showSocial and social_items %}<div class="lcars-social-row" style="display:flex;align-items:center;gap:0.75rem;">{% for s in social_items %}<a href="{{ s.url }}" target="_blank" rel="noopener" title="{{ s.label }}" class="lcars-social-link" style="display:inline-flex;color:hsl(var(--muted-foreground));">{% if s.icon %}::{{ s.icon }}:sm::{% endif %}</a>{% endfor %}</div>{% endif %} {% if showSocial and social_items %}<div class="lcars-social-row" style="display:flex;align-items:center;gap:0.75rem;">{% for s in social_items %}<a href="{{ s.url }}" target="_blank" rel="noopener" title="{{ s.label }}" class="lcars-social-link" style="display:inline-flex;color:hsl(var(--muted-foreground));">{% if s.icon %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ s.icon|split:":"|first }}.svg#{{ s.icon|split:":"|last }}"/></svg>{% endif %}</a>{% endfor %}</div>{% endif %}
</div> </div>
</div><style>.lcars-footer-logo{max-height:2rem;width:auto;display:block;}.lcars-footer-link:hover{color:hsl(var(--foreground));}</style></footer> </div><style>.lcars-footer-logo{max-height:2rem;width:auto;display:block;}.lcars-footer-link:hover{color:hsl(var(--foreground));}</style></footer>

View File

@ -7,11 +7,11 @@
{% if specialHoursNote %}<p class="lcars-surface-muted" style="margin-top:1rem;border:1px solid hsl(var(--border));background:hsl(var(--muted));padding:0.5rem 0.75rem;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ specialHoursNote }}</p>{% endif %} {% if specialHoursNote %}<p class="lcars-surface-muted" style="margin-top:1rem;border:1px solid hsl(var(--border));background:hsl(var(--muted));padding:0.5rem 0.75rem;font-size:0.875rem;color:hsl(var(--muted-foreground));">{{ specialHoursNote }}</p>{% endif %}
{% if address %}<div style="margin-top:1.5rem;"><div class="lcars-stat-label" style="margin:0;">Address</div><address style="margin-top:0.25rem;white-space:pre-line;font-style:normal;color:hsl(var(--foreground));">{{ address }}</address></div>{% endif %} {% if address %}<div style="margin-top:1.5rem;"><div class="lcars-stat-label" style="margin:0;">Address</div><address style="margin-top:0.25rem;white-space:pre-line;font-style:normal;color:hsl(var(--foreground));">{{ address }}</address></div>{% endif %}
{% if phone %}<div style="margin-top:1rem;"><div class="lcars-stat-label" style="margin:0;">Phone</div><a href="tel:{{ phone }}" style="display:inline-block;margin-top:0.25rem;color:hsl(var(--foreground));text-decoration:none;">{{ phone }}</a></div>{% endif %} {% if phone %}<div style="margin-top:1rem;"><div class="lcars-stat-label" style="margin:0;">Phone</div><a href="tel:{{ phone }}" style="display:inline-block;margin-top:0.25rem;color:hsl(var(--foreground));text-decoration:none;">{{ phone }}</a></div>{% endif %}
{% if directionsUrl %}<a href="{{ directionsUrl }}" target="_blank" rel="noopener noreferrer" class="lcars-btn-outline" style="margin-top:1.5rem;display:inline-flex;align-items:center;gap:0.5rem;">::lucide:navigation:sm::Get directions</a>{% endif %} {% if directionsUrl %}<a href="{{ directionsUrl }}" target="_blank" rel="noopener noreferrer" class="lcars-btn-outline" style="margin-top:1.5rem;display:inline-flex;align-items:center;gap:0.5rem;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#navigation"/></svg>Get directions</a>{% endif %}
</div> </div>
{% if mapEmbedUrl %} {% if mapEmbedUrl %}
<div class="lcars-media-frame" style="width:100%;min-height:16rem;aspect-ratio:4 / 3;overflow:hidden;border:1px solid hsl(var(--border));border-radius:4px;background:hsl(var(--muted));"> <div class="lcars-media-frame" style="width:100%;min-height:16rem;aspect-ratio:4 / 3;overflow:hidden;border:1px solid hsl(var(--border));border-radius:4px;background:hsl(var(--muted));">
<button type="button" data-map-src="{{ mapEmbedUrl }}" onclick="var f=document.createElement('iframe');f.src=this.getAttribute('data-map-src');f.setAttribute('style','width:100%;height:100%;border:0;');f.setAttribute('loading','lazy');f.setAttribute('referrerpolicy','no-referrer-when-downgrade');f.setAttribute('title','Map');this.parentNode.replaceChild(f,this);" style="display:flex;align-items:center;justify-content:center;gap:0.5rem;width:100%;height:100%;min-height:16rem;border:0;background:none;cursor:pointer;color:hsl(var(--foreground));font-family:var(--font-heading, 'Antonio', 'Antonio', system-ui, sans-serif);font-weight:500;">::lucide:map-pin:md::{{ 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('style','width:100%;height:100%;border:0;');f.setAttribute('loading','lazy');f.setAttribute('referrerpolicy','no-referrer-when-downgrade');f.setAttribute('title','Map');this.parentNode.replaceChild(f,this);" style="display:flex;align-items:center;justify-content:center;gap:0.5rem;width:100%;height:100%;min-height:16rem;border:0;background:none;cursor:pointer;color:hsl(var(--foreground));font-family:var(--font-heading, 'Antonio', 'Antonio', system-ui, sans-serif);font-weight:500;"><svg width="20" height="20" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#map-pin"/></svg>{{ mapButtonLabel|default:"Load map" }}</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -1 +1 @@
<nav class="lcars-navbar {{ class }}" aria-label="Primary"><a class="lcars-brand" href="/"><span class="lcars-mark lcars-mark-square" aria-hidden="true"></span>{% if logoType == "image" and logo %}{% img logo alt=alt|default:"Home" class="lcars-brand-logo" %}{% else %}<span>{{ logoText|get:"text"|default:logoText|default:context.site.title|default:"Studio" }}</span>{% endif %}</a><div class="lcars-nav-links">{% for item in menu.items %}<a class="lcars-nav-link" href="{{ item.url }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}>{{ item.label|default:item.title }}</a>{% endfor %}{% if cta.text and cta.url %}<a class="lcars-btn-primary lcars-btn-sm" href="{{ cta.url }}">{{ cta.text }}</a>{% endif %}</div><input type="checkbox" id="lcars-nav-toggle-cb" class="lcars-nav-cb" style="display:none;"><label for="lcars-nav-toggle-cb" class="lcars-nav-toggle lcars-btn-outline lcars-btn-sm" aria-label="Toggle menu">::lucide:menu:sm::</label><div class="lcars-nav-drawer">{% for item in menu.items %}<a href="{{ item.url }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}>{{ item.label|default:item.title }}</a>{% endfor %}{% if cta.text and cta.url %}<a href="{{ cta.url }}" class="lcars-btn-primary lcars-btn-sm" style="margin-top:0.75rem;">{{ cta.text }}</a>{% endif %}</div><style>.lcars-nav-cb:checked ~ .lcars-nav-drawer{display:flex;}</style></nav> <nav class="lcars-navbar {{ class }}" aria-label="Primary"><a class="lcars-brand" href="/"><span class="lcars-mark lcars-mark-square" aria-hidden="true"></span>{% if logoType == "image" and logo %}{% img logo alt=alt|default:"Home" class="lcars-brand-logo" %}{% else %}<span>{{ logoText|get:"text"|default:logoText|default:context.site.title|default:"Studio" }}</span>{% endif %}</a><div class="lcars-nav-links">{% for item in menu.items %}<a class="lcars-nav-link" href="{{ item.url }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}>{{ item.label|default:item.title }}</a>{% endfor %}{% if cta.text and cta.url %}<a class="lcars-btn-primary lcars-btn-sm" href="{{ cta.url }}">{{ cta.text }}</a>{% endif %}</div><input type="checkbox" id="lcars-nav-toggle-cb" class="lcars-nav-cb" style="display:none;"><label for="lcars-nav-toggle-cb" class="lcars-nav-toggle lcars-btn-outline lcars-btn-sm" aria-label="Toggle menu"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#menu"/></svg></label><div class="lcars-nav-drawer">{% for item in menu.items %}<a href="{{ item.url }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}>{{ item.label|default:item.title }}</a>{% endfor %}{% if cta.text and cta.url %}<a href="{{ cta.url }}" class="lcars-btn-primary lcars-btn-sm" style="margin-top:0.75rem;">{{ cta.text }}</a>{% endif %}</div><style>.lcars-nav-cb:checked ~ .lcars-nav-drawer{display:flex;}</style></nav>

View File

@ -1 +1 @@
<section class="lcars-section {{ class }}" data-block="lcars:page-suggestions"><div class="lcars-content-well"><div class="lcars-measure lcars-stack"><span class="lcars-mark lcars-mark-triangle" aria-hidden="true"></span><h2 class="lcars-heading" style="font-size: clamp(1.5rem, 2.5vw, 2rem); margin: 0;"><span class="lcars-heading-h2-accent">{{ title|default:"Were you looking for..." }}</span></h2>{% if suggestions %}<ul class="lcars-stack-sm" style="list-style: none; margin: 0; padding: 0;">{% for s in suggestions %}<li><a class="lcars-sidebar-link" href="/{{ s.slug }}" style="display: block;"><span class="lcars-post-title" style="font-size: 1rem;">{{ s.title }}</span>{% if showDescription and s.excerpt %}<span class="lcars-text" style="display: block; font-size: 0.875rem; color: hsl(var(--muted-foreground));">{{ s.excerpt }}</span>{% endif %}</a></li>{% endfor %}</ul>{% else %}{% if emptyMessage %}<p class="lcars-text" style="margin: 0; color: hsl(var(--muted-foreground));">{{ emptyMessage }}</p>{% endif %}<div class="lcars-btn-row"><a class="lcars-btn-outline lcars-btn-sm" href="/">::lucide:home:sm::Home</a><a class="lcars-btn-outline lcars-btn-sm" href="/blog">::lucide:newspaper:sm::Blog</a></div>{% endif %}</div></div></section> <section class="lcars-section {{ class }}" data-block="lcars:page-suggestions"><div class="lcars-content-well"><div class="lcars-measure lcars-stack"><span class="lcars-mark lcars-mark-triangle" aria-hidden="true"></span><h2 class="lcars-heading" style="font-size: clamp(1.5rem, 2.5vw, 2rem); margin: 0;"><span class="lcars-heading-h2-accent">{{ title|default:"Were you looking for..." }}</span></h2>{% if suggestions %}<ul class="lcars-stack-sm" style="list-style: none; margin: 0; padding: 0;">{% for s in suggestions %}<li><a class="lcars-sidebar-link" href="/{{ s.slug }}" style="display: block;"><span class="lcars-post-title" style="font-size: 1rem;">{{ s.title }}</span>{% if showDescription and s.excerpt %}<span class="lcars-text" style="display: block; font-size: 0.875rem; color: hsl(var(--muted-foreground));">{{ s.excerpt }}</span>{% endif %}</a></li>{% endfor %}</ul>{% else %}{% if emptyMessage %}<p class="lcars-text" style="margin: 0; color: hsl(var(--muted-foreground));">{{ emptyMessage }}</p>{% endif %}<div class="lcars-btn-row"><a class="lcars-btn-outline lcars-btn-sm" href="/"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#home"/></svg>Home</a><a class="lcars-btn-outline lcars-btn-sm" href="/blog"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#newspaper"/></svg>Blog</a></div>{% endif %}</div></div></section>

View File

@ -7,5 +7,5 @@
<div class="lcars-field lcars-field--full"><label class="lcars-label" for="lcars-reset-email">Email</label><input class="lcars-input" type="email" name="email" id="lcars-reset-email" required></div> <div class="lcars-field lcars-field--full"><label class="lcars-label" for="lcars-reset-email">Email</label><input class="lcars-input" type="email" name="email" id="lcars-reset-email" required></div>
<button type="submit" class="lcars-btn-primary" hx-disabled-elt="this" style="width:100%; justify-content:center;">Send reset link</button> <button type="submit" class="lcars-btn-primary" hx-disabled-elt="this" style="width:100%; justify-content:center;">Send reset link</button>
</form> </form>
<a class="lcars-btn-ghost lcars-btn-sm" href="/login" style="align-self: flex-start;">::lucide:arrow-left:sm::Back to sign in</a> <a class="lcars-btn-ghost lcars-btn-sm" href="/login" style="align-self: flex-start;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#arrow-left"/></svg>Back to sign in</a>
</div> </div>

View File

@ -7,7 +7,7 @@
{% if tier.name %}<h3 class="lcars-feature-title" style="margin: 0;">{{ tier.name }}</h3>{% endif %} {% if tier.name %}<h3 class="lcars-feature-title" style="margin: 0;">{{ tier.name }}</h3>{% endif %}
<p style="display: flex; align-items: baseline; gap: 0.25rem; margin: 1rem 0 0 0;"><span class="lcars-price numeric-tabular" style="font-family: var(--font-mono, ui-monospace, monospace); font-size: clamp(2rem, 4vw, 2.75rem); font-weight: 500; line-height: 1; color: hsl(var(--foreground));">{% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }}</span>{% if tier.period %}<span class="lcars-price-period lcars-stat-label" style="margin-top: 0;">{{ tier.period }}</span>{% endif %}</p> <p style="display: flex; align-items: baseline; gap: 0.25rem; margin: 1rem 0 0 0;"><span class="lcars-price numeric-tabular" style="font-family: var(--font-mono, ui-monospace, monospace); font-size: clamp(2rem, 4vw, 2.75rem); font-weight: 500; line-height: 1; color: hsl(var(--foreground));">{% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }}</span>{% if tier.period %}<span class="lcars-price-period lcars-stat-label" style="margin-top: 0;">{{ tier.period }}</span>{% endif %}</p>
{% if tier.description %}<p class="lcars-text" style="font-size: 0.9375rem; color: hsl(var(--muted-foreground)); margin-top: 0.75rem;">{{ tier.description }}</p>{% endif %} {% if tier.description %}<p class="lcars-text" style="font-size: 0.9375rem; color: hsl(var(--muted-foreground)); margin-top: 0.75rem;">{{ tier.description }}</p>{% endif %}
{% if tier.features %}<ul class="lcars-stack-sm" style="list-style: none; padding: 0; margin: 1.5rem 0 0 0; display: flex; flex-direction: column; gap: 0.625rem; flex: 1;">{% for feature in tier.features %}<li class="lcars-check" style="display: flex; gap: 0.5rem; align-items: flex-start; font-size: 0.9375rem; color: hsl(var(--foreground));"><span style="color: hsl(var(--accent)); flex: none;">::lucide:check:sm::</span><span>{{ feature }}</span></li>{% endfor %}</ul>{% endif %} {% if tier.features %}<ul class="lcars-stack-sm" style="list-style: none; padding: 0; margin: 1.5rem 0 0 0; display: flex; flex-direction: column; gap: 0.625rem; flex: 1;">{% for feature in tier.features %}<li class="lcars-check" style="display: flex; gap: 0.5rem; align-items: flex-start; font-size: 0.9375rem; color: hsl(var(--foreground));"><span style="color: hsl(var(--accent)); flex: none;"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#check"/></svg></span><span>{{ feature }}</span></li>{% endfor %}</ul>{% endif %}
{% if tier.ctaUrl and tier.ctaLabel %}{% if tier.highlighted %}<a class="lcars-btn-primary" href="{{ tier.ctaUrl }}" style="margin-top: 1.5rem; width: 100%; box-sizing: border-box; text-align: center;">{{ tier.ctaLabel }}</a>{% else %}<a class="lcars-btn-outline" href="{{ tier.ctaUrl }}" style="margin-top: 1.5rem; width: 100%; box-sizing: border-box; text-align: center;">{{ tier.ctaLabel }}</a>{% endif %}{% endif %} {% if tier.ctaUrl and tier.ctaLabel %}{% if tier.highlighted %}<a class="lcars-btn-primary" href="{{ tier.ctaUrl }}" style="margin-top: 1.5rem; width: 100%; box-sizing: border-box; text-align: center;">{{ tier.ctaLabel }}</a>{% else %}<a class="lcars-btn-outline" href="{{ tier.ctaUrl }}" style="margin-top: 1.5rem; width: 100%; box-sizing: border-box; text-align: center;">{{ tier.ctaLabel }}</a>{% endif %}{% endif %}
</div>{% endfor %}</div>{% endif %} </div>{% endfor %}</div>{% endif %}
{% if billingNote %}<p class="lcars-stat-label" style="text-align: center; margin-top: 2rem;">{{ billingNote }}</p>{% endif %} {% if billingNote %}<p class="lcars-stat-label" style="text-align: center; margin-top: 2rem;">{{ billingNote }}</p>{% endif %}

View File

@ -4,7 +4,7 @@
{% if eyebrow %}<p class="lcars-eyebrow">{{ eyebrow }}</p>{% endif %} {% if eyebrow %}<p class="lcars-eyebrow">{{ eyebrow }}</p>{% endif %}
{% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 1rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %} {% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 1rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %}
{% if body %}<div class="lcars-text" style="color: hsl(var(--muted-foreground)); line-height: 1.7;">{{ body|safe }}</div>{% endif %} {% if body %}<div class="lcars-text" style="color: hsl(var(--muted-foreground)); line-height: 1.7;">{{ body|safe }}</div>{% endif %}
{% if ctaUrl and ctaLabel %}<a class="lcars-btn-ghost" href="{{ ctaUrl }}" style="margin-top: 1.5rem;">{{ ctaLabel }}::lucide:arrow-right:sm::</a>{% endif %} {% if ctaUrl and ctaLabel %}<a class="lcars-btn-ghost" href="{{ ctaUrl }}" style="margin-top: 1.5rem;">{{ ctaLabel }}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"/></svg></a>{% endif %}
</div> </div>
<div class="lcars-media-frame" style="aspect-ratio: 4 / 3; background: hsl(var(--muted)); border: 1px solid hsl(var(--border)); overflow: hidden; {% if mediaPosition == "left" %}order: -1;{% endif %}">{% if media %}{% img media alt=mediaAlt class="lcars-rich-media" %}{% endif %}</div> <div style="{% if mediaPosition == "left" %}order: -1;{% endif %}">{% if media %}<div class="lcars-media-frame" style="aspect-ratio: 4 / 3; background: hsl(var(--muted)); border: 1px solid hsl(var(--border)); overflow: hidden;">{% img media alt=mediaAlt class="lcars-rich-media" %}</div>{% else %}<div class="lcars-console-art"><span class="lcars-console-art-label">No signal</span><span class="lcars-console-art-scope" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></span></div>{% endif %}</div>
</div></div></section> </div></div></section>

View File

@ -1,3 +1,3 @@
<nav class="{{ class }}" data-block="lcars:sidebar-nav" style="{% if showBorder %}border-right: 1px solid hsl(var(--border)); padding-right: 1rem;{% endif %}">{% if title %}<h3 class="lcars-kicker" style="margin-top: 0;">{{ title }}</h3>{% endif %}<ul class="lcars-stack-sm" style="list-style: none; margin: 0; padding: 0;">{% for item in menu.items %}<li><a class="lcars-sidebar-link" 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>{% if item.icon %}<svg class="lcars-icon" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"/></svg>{% endif %}{{ item.label }}</a></li>{% endfor %}</ul>{% if highlightCurrent %}<script> <nav class="{{ class }}" data-block="lcars:sidebar-nav" style="{% if showBorder %}border-right: 1px solid hsl(var(--border)); padding-right: 1rem;{% endif %}">{% if title %}<h3 class="lcars-kicker" style="margin-top: 0;">{{ title }}</h3>{% endif %}<ul class="lcars-stack-sm" style="list-style: none; margin: 0; padding: 0;">{% for item in menu.items %}<li><a class="lcars-sidebar-link" 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>{% if item.icon %}<svg class="lcars-icon" width="16" height="16" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"/></svg>{% endif %}{{ item.label }}</a></li>{% endfor %}</ul>{% if highlightCurrent %}<script>
(function(){var p=window.location.pathname;document.querySelectorAll('[data-bn-sidebar-link]').forEach(function(a){if(a.getAttribute('href')===p){a.setAttribute('aria-current','page');}});})(); (function(){var p=window.location.pathname;document.querySelectorAll('[data-bn-sidebar-link]').forEach(function(a){if(a.getAttribute('href')===p){a.setAttribute('aria-current','page');}});})();
</script>{% endif %}</nav> </script>{% endif %}</nav>

View File

@ -2,6 +2,6 @@
<div class="{{ class }}"> <div class="{{ class }}">
{% if heading %}<p class="lcars-stat-label" style="margin:0 0 0.75rem 0;">{{ heading }}</p>{% endif %} {% if heading %}<p class="lcars-stat-label" style="margin:0 0 0.75rem 0;">{{ heading }}</p>{% endif %}
<ul class="lcars-social-row" style="list-style:none;margin:0;padding:0;{% if style == "stack" %}display:flex;flex-direction:column;gap:0.5rem;{% else %}display:flex;flex-wrap:wrap;align-items:center;gap:0.75rem;{% endif %}"> <ul class="lcars-social-row" style="list-style:none;margin:0;padding:0;{% if style == "stack" %}display:flex;flex-direction:column;gap:0.5rem;{% else %}display:flex;flex-wrap:wrap;align-items:center;gap:0.75rem;{% endif %}">
{% for link in links %}{% if link.url %}<li><a href="{{ link.url }}" target="_blank" rel="noopener noreferrer" aria-label="{{ link.label|default:link.network }}" class="lcars-social-link" style="display:inline-flex;align-items:center;gap:0.5rem;border:1px solid hsl(var(--border));border-radius:4px;color:hsl(var(--foreground));text-decoration:none;{% if style == "stack" %}padding:0.5rem 1rem;{% else %}padding:0.5rem;{% endif %}">{% if link.network %}::{{ link.network }}:sm::{% endif %}{% if style == "stack" and link.label %}<span style="font-size:0.875rem;font-weight:500;">{{ link.label }}</span>{% endif %}</a></li>{% endif %}{% endfor %} {% for link in links %}{% if link.url %}<li><a href="{{ link.url }}" target="_blank" rel="noopener noreferrer" aria-label="{{ link.label|default:link.network }}" class="lcars-social-link" style="display:inline-flex;align-items:center;gap:0.5rem;border:1px solid hsl(var(--border));border-radius:4px;color:hsl(var(--foreground));text-decoration:none;{% if style == "stack" %}padding:0.5rem 1rem;{% else %}padding:0.5rem;{% endif %}">{% if link.network %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ link.network|split:":"|first }}.svg#{{ link.network|split:":"|last }}"/></svg>{% endif %}{% if style == "stack" and link.label %}<span style="font-size:0.875rem;font-weight:500;">{{ link.label }}</span>{% endif %}</a></li>{% endif %}{% endfor %}
</ul> </ul>
</div> </div>

View File

@ -7,6 +7,6 @@
{% if member.name %}<h3 class="lcars-feature-title" style="margin: 0;">{{ member.name }}</h3>{% endif %} {% if member.name %}<h3 class="lcars-feature-title" style="margin: 0;">{{ member.name }}</h3>{% endif %}
{% if member.role %}<div class="lcars-stat-label" style="margin-top: 0.25rem;">{{ member.role }}</div>{% endif %} {% if member.role %}<div class="lcars-stat-label" style="margin-top: 0.25rem;">{{ member.role }}</div>{% endif %}
{% if member.bio %}<p class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground)); margin-top: 0.75rem;">{{ member.bio }}</p>{% endif %} {% if member.bio %}<p class="lcars-text" style="font-size: 0.9375rem; line-height: 1.6; color: hsl(var(--muted-foreground)); margin-top: 0.75rem;">{{ member.bio }}</p>{% endif %}
{% if member.socials %}<div class="lcars-btn-row" style="display: flex; gap: 0.75rem; margin-top: 1rem;">{% for social in member.socials %}{% if social.url %}<a href="{{ social.url }}" aria-label="Profile link" style="color: hsl(var(--muted-foreground));">::{{ social.icon }}:sm::</a>{% endif %}{% endfor %}</div>{% endif %} {% if member.socials %}<div class="lcars-btn-row" style="display: flex; gap: 0.75rem; margin-top: 1rem;">{% for social in member.socials %}{% if social.url %}<a href="{{ social.url }}" aria-label="Profile link" style="color: hsl(var(--muted-foreground));"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ social.icon|split:":"|first }}.svg#{{ social.icon|split:":"|last }}"/></svg></a>{% endif %}{% endfor %}</div>{% endif %}
</div>{% endfor %}</div>{% endif %} </div>{% endfor %}</div>{% endif %}
</div></section> </div></section>

View File

@ -2,7 +2,7 @@
<section class="lcars-section {{ class }}"><div class="lcars-content-well"> <section class="lcars-section {{ class }}"><div class="lcars-content-well">
{% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 2.5rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %} {% if heading %}<h2 class="lcars-heading" style="font-size: clamp(1.75rem, 3vw, 2.25rem); margin: 0 0 2.5rem 0;"><span class="lcars-heading-h2-accent">{{ heading }}</span></h2>{% endif %}
<div class="{% if layout == "single" %}lcars-measure{% else %}lcars-grid lcars-grid-3{% endif %}">{% for q in quotes %}<figure class="lcars-quote-block lcars-card" style="margin: 0; display: flex; flex-direction: column;"> <div class="{% if layout == "single" %}lcars-measure{% else %}lcars-grid lcars-grid-3{% endif %}">{% for q in quotes %}<figure class="lcars-quote-block lcars-card" style="margin: 0; display: flex; flex-direction: column;">
{% if q.rating %}<div class="lcars-rating" aria-label="Rated {{ q.rating }} out of 5" style="display: flex; gap: 0.125rem; margin-bottom: 0.75rem;"><span style="color: {% if q.rating >= 1 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};">::lucide:star:sm::</span><span style="color: {% if q.rating >= 2 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};">::lucide:star:sm::</span><span style="color: {% if q.rating >= 3 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};">::lucide:star:sm::</span><span style="color: {% if q.rating >= 4 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};">::lucide:star:sm::</span><span style="color: {% if q.rating >= 5 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};">::lucide:star:sm::</span></div>{% endif %} {% if q.rating %}<div class="lcars-rating" aria-label="Rated {{ q.rating }} out of 5" style="display: flex; gap: 0.125rem; margin-bottom: 0.75rem;"><span style="color: {% if q.rating >= 1 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#star"/></svg></span><span style="color: {% if q.rating >= 2 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#star"/></svg></span><span style="color: {% if q.rating >= 3 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#star"/></svg></span><span style="color: {% if q.rating >= 4 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#star"/></svg></span><span style="color: {% if q.rating >= 5 %}hsl(var(--accent)){% else %}hsl(var(--muted-foreground) / 0.35){% endif %};"><svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#star"/></svg></span></div>{% endif %}
{% if q.quote %}<blockquote class="lcars-pull-quote" style="flex: 1; margin: 0;">{{ q.quote }}</blockquote>{% endif %} {% if q.quote %}<blockquote class="lcars-pull-quote" style="flex: 1; margin: 0;">{{ q.quote }}</blockquote>{% endif %}
<figcaption class="lcars-quote-cite" style="display: flex; align-items: center; gap: 0.75rem; margin-top: 1.25rem;">{% if q.avatar %}<span class="lcars-avatar" style="width: 2.75rem; height: 2.75rem; border-radius: 9999px; overflow: hidden; background: hsl(var(--muted)); display: inline-flex; flex: none;">{% img q.avatar alt=q.name class="lcars-avatar-img" %}</span>{% endif %}<span>{% if q.name %}<span class="lcars-feature-title" style="display: block; font-size: 0.9375rem;">{{ q.name }}</span>{% endif %}{% if q.role %}<span class="lcars-stat-label" style="margin-top: 0;">{{ q.role }}</span>{% endif %}</span></figcaption> <figcaption class="lcars-quote-cite" style="display: flex; align-items: center; gap: 0.75rem; margin-top: 1.25rem;">{% if q.avatar %}<span class="lcars-avatar" style="width: 2.75rem; height: 2.75rem; border-radius: 9999px; overflow: hidden; background: hsl(var(--muted)); display: inline-flex; flex: none;">{% img q.avatar alt=q.name class="lcars-avatar-img" %}</span>{% endif %}<span>{% if q.name %}<span class="lcars-feature-title" style="display: block; font-size: 0.9375rem;">{{ q.name }}</span>{% endif %}{% if q.role %}<span class="lcars-stat-label" style="margin-top: 0;">{{ q.role }}</span>{% endif %}</span></figcaption>
</figure>{% endfor %}</div> </figure>{% endfor %}</div>

View File

@ -1,6 +1,6 @@
{# utility-bar override — thin Swiss top strip; left/right item groups; icon-picker fields render via ::pack:name:: shorthand. #} {# utility-bar override — thin Swiss top strip; left/right item groups; icon-picker fields render via ::pack:name:: shorthand. #}
{% if variant == "primary" %}{% set ubvar = "lcars-utility-bar--primary" %}{% set ubsty = "background:hsl(var(--primary));color:hsl(var(--primary-foreground));" %}{% elif variant == "dark" %}{% set ubvar = "lcars-utility-bar--dark" %}{% set ubsty = "background:hsl(var(--foreground));color:hsl(var(--background));" %}{% else %}{% set ubvar = "lcars-utility-bar--muted" %}{% set ubsty = "background:hsl(var(--muted));color:hsl(var(--muted-foreground));border-bottom:1px solid hsl(var(--border));" %}{% endif %} {% if variant == "primary" %}{% set ubvar = "lcars-utility-bar--primary" %}{% set ubsty = "background:hsl(var(--primary));color:hsl(var(--primary-foreground));" %}{% elif variant == "dark" %}{% set ubvar = "lcars-utility-bar--dark" %}{% set ubsty = "background:hsl(var(--foreground));color:hsl(var(--background));" %}{% else %}{% set ubvar = "lcars-utility-bar--muted" %}{% set ubsty = "background:hsl(var(--muted));color:hsl(var(--muted-foreground));border-bottom:1px solid hsl(var(--border));" %}{% endif %}
{% macro ubitem(it) %}{% if it.link %}<a href="{{ it.link }}" class="lcars-utility-item" style="display:inline-flex;align-items:center;gap:0.375rem;color:inherit;text-decoration:none;">{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</a>{% else %}<span class="lcars-utility-item" style="display:inline-flex;align-items:center;gap:0.375rem;">{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</span>{% endif %}{% endmacro %} {% macro ubitem(it) %}{% if it.link %}<a href="{{ it.link }}" class="lcars-utility-item" style="display:inline-flex;align-items:center;gap:0.375rem;color:inherit;text-decoration:none;">{% if it.icon %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"/></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</a>{% else %}<span class="lcars-utility-item" style="display:inline-flex;align-items:center;gap:0.375rem;">{% if it.icon %}<svg width="16" height="16" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/{{ it.icon|split:":"|first }}.svg#{{ it.icon|split:":"|last }}"/></svg>{% endif %}{% if it.label %}<span>{{ it.label }}</span>{% endif %}</span>{% endif %}{% endmacro %}
<div class="lcars-utility-bar {{ ubvar }} {{ class }}" style="{{ ubsty }}font-size:0.75rem;font-family:var(--font-body, 'Antonio', system-ui, sans-serif);"> <div class="lcars-utility-bar {{ ubvar }} {{ class }}" style="{{ ubsty }}font-size:0.75rem;font-family:var(--font-body, 'Antonio', system-ui, sans-serif);">
<div class="lcars-content-well lcars-utility-row" style="display:flex;align-items:center;justify-content:space-between;gap:1rem;min-height:2.25rem;"> <div class="lcars-content-well lcars-utility-row" style="display:flex;align-items:center;justify-content:space-between;gap:1rem;min-height:2.25rem;">
<div class="lcars-utility-group" style="display:flex;align-items:center;gap:1.25rem;flex-wrap:wrap;">{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}</div> <div class="lcars-utility-group" style="display:flex;align-items:center;gap:1.25rem;flex-wrap:wrap;">{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}</div>

View File

@ -4,7 +4,7 @@
<div class="lcars-video-frame" data-bn-video data-video-url="{{ url|default:'' }}" data-video-media="{% if media %}{{ media|mediaURL }}{% endif %}" style="position:relative;width:100%;overflow:hidden;border:1px solid hsl(var(--border));border-radius:4px;background:hsl(var(--muted));aspect-ratio:{{ vratio }};"> <div class="lcars-video-frame" data-bn-video data-video-url="{{ url|default:'' }}" data-video-media="{% if media %}{{ media|mediaURL }}{% endif %}" style="position:relative;width:100%;overflow:hidden;border:1px solid hsl(var(--border));border-radius:4px;background:hsl(var(--muted));aspect-ratio:{{ vratio }};">
<button type="button" data-bn-video-play class="lcars-video-play" aria-label="Play video{% if title %}: {{ title }}{% endif %}" style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;width:100%;height:100%;border:0;background:none;cursor:pointer;"> <button type="button" data-bn-video-play class="lcars-video-play" aria-label="Play video{% if title %}: {{ title }}{% endif %}" style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;width:100%;height:100%;border:0;background:none;cursor:pointer;">
{% if poster %}{% img poster alt=title|default:"" class="lcars-video-poster" %}{% endif %} {% if poster %}{% img poster alt=title|default:"" class="lcars-video-poster" %}{% endif %}
<span class="lcars-video-play-badge" style="position:relative;display:inline-flex;align-items:center;justify-content:center;width:4rem;height:4rem;border-radius:4px;background:hsl(var(--accent));color:hsl(var(--accent-foreground));">::lucide:play:lg::</span> <span class="lcars-video-play-badge" style="position:relative;display:inline-flex;align-items:center;justify-content:center;width:4rem;height:4rem;border-radius:4px;background:hsl(var(--accent));color:hsl(var(--accent-foreground));"><svg width="28" height="28" class="lcars-inline-icon" aria-hidden="true"><use href="/icons/lucide.svg#play"/></svg></span>
</button> </button>
</div> </div>
{% if caption %}<figcaption class="lcars-stat-label" style="margin-top:0.5rem;text-align:center;">{{ caption }}</figcaption>{% endif %} {% if caption %}<figcaption class="lcars-stat-label" style="margin-top:0.5rem;text-align:center;">{{ caption }}</figcaption>{% endif %}