diff --git a/blocks/episode_console.ninjatpl b/blocks/episode_console.ninjatpl index 96d20d9..4938ab7 100644 --- a/blocks/episode_console.ninjatpl +++ b/blocks/episode_console.ninjatpl @@ -1,13 +1,13 @@
-{% if cover %}
{% img cover alt=title|default:"Episode cover" %}
{% else %}{% endif %} +{% if cover %}
{% img cover alt=title|default:"Episode cover" %}
{% else %}
No cover art
{% endif %}
{% if eyebrow %}{{ eyebrow }}{% else %}Now Broadcasting{% endif %}
{% if episodeNumber %}EP {{ episodeNumber }}{% endif %}{% if stardate %}Stardate {{ stardate }}{% endif %}{% if duration %}{{ duration }}{% endif %}
{% if title %}

{{ title }}

{% endif %} {% if description %}

{{ description }}

{% endif %} -
{% if listenUrl %}::lucide:play:sm::{{ listenLabel|default:"Listen now" }}{% endif %}{% for p in platforms %}{{ p.label }}{% endfor %}
+
{% if listenUrl %}{{ listenLabel|default:"Listen now" }}{% endif %}{% for p in platforms %}{{ p.label }}{% endfor %}
diff --git a/manifest.yaml b/manifest.yaml index 17a7f84..f298278 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -197,6 +197,9 @@ css: .lcars-btn-lg { padding: 0.75rem 1.75rem; font-size: 1.0625rem; } .lcars-btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; } .lcars-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.125em; } + /* Sized 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 --- */ .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 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; } - /* Graceful empty-media state: an on-brand LCARS readout panel that stays - compact instead of ballooning into a blank square when no cover ships. */ - .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; } + /* Graceful empty-media state: an on-brand LCARS readout panel with a status + label, shown instead of a bare grey rectangle when no image ships. Stays + 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 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)); } diff --git a/seed/media/console.jpg b/seed/media/console.jpg new file mode 100644 index 0000000..af2e846 Binary files /dev/null and b/seed/media/console.jpg differ diff --git a/seed/media/control-buttons.jpg b/seed/media/control-buttons.jpg new file mode 100644 index 0000000..2561f77 Binary files /dev/null and b/seed/media/control-buttons.jpg differ diff --git a/seed/media/deep-space.jpg b/seed/media/deep-space.jpg new file mode 100644 index 0000000..4c23f3c Binary files /dev/null and b/seed/media/deep-space.jpg differ diff --git a/seed/media/milky-way.jpg b/seed/media/milky-way.jpg new file mode 100644 index 0000000..9ea21b8 Binary files /dev/null and b/seed/media/milky-way.jpg differ diff --git a/seed/media/nebula.jpg b/seed/media/nebula.jpg new file mode 100644 index 0000000..e5ff344 Binary files /dev/null and b/seed/media/nebula.jpg differ diff --git a/seed/media/starfield.jpg b/seed/media/starfield.jpg new file mode 100644 index 0000000..3e4d70e Binary files /dev/null and b/seed/media/starfield.jpg differ diff --git a/seed/seed.json b/seed/seed.json index e804541..925d212 100644 --- a/seed/seed.json +++ b/seed/seed.json @@ -6,6 +6,14 @@ "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": [ { "key": "hail_signals", @@ -27,8 +35,8 @@ "template_key": "full-width", "reconcile_blocks": true, "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": "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": "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", "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": "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" } } @@ -42,8 +50,9 @@ "blocks": [ { "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": "

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.

" } }, - { "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": "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": "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: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", "reconcile_blocks": true, "blocks": [ - { "block_key": "card", "title": "Episode 48", "slot": "main", "sort_order": 1, "content": { "title": "First contact was a podcast", "text": "

If a signal reached us tomorrow, who would answer, and what would we say back.

", "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": "

A propulsion engineer walks us through what the math actually allows.

", "link": "/episodes/warp-honestly", "linkLabel": "Listen" } }, - { "block_key": "card", "title": "Episode 46", "slot": "main", "sort_order": 3, "content": { "title": "Terraforming on a budget", "text": "

What it would really take to make one small world a little more livable.

", "link": "/episodes/terraforming", "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": "

If a signal reached us tomorrow, who would answer, and what would we say back.

", "link": "/episodes/first-contact", "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": "

A propulsion engineer walks us through what the math actually allows.

", "link": "/episodes/warp-honestly", "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": "

What it would really take to make one small world a little more livable.

", "link": "/episodes/terraforming", "linkLabel": "Listen" } } ] }, { @@ -65,7 +74,7 @@ "reconcile_blocks": true, "blocks": [ { "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": "

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.

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.

" } } + { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

" } } ] }, { @@ -76,7 +85,7 @@ "reconcile_blocks": true, "blocks": [ { "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": "

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.

The short version is that the energy budget is the whole story. Everything else is set dressing until you solve for that.

" } } + { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "

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.

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.

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.

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.

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.

" } } ] }, { @@ -87,7 +96,7 @@ "reconcile_blocks": true, "blocks": [ { "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": "

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.

The answer is not domes or rockets. It is patience, pressure, and a very long supply of the right microbes.

" } } + { "block_key": "text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "text": "

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?

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.

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.

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.

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.

" } } ] }, { diff --git a/templates/overrides/lcars/announcement-bar.ninjatpl b/templates/overrides/lcars/announcement-bar.ninjatpl index 54d3ab8..3ae2dda 100644 --- a/templates/overrides/lcars/announcement-bar.ninjatpl +++ b/templates/overrides/lcars/announcement-bar.ninjatpl @@ -3,6 +3,6 @@

{{ message }}{% if linkText and linkUrl %} {{ linkText }}{% endif %}

-{% if dismissable %}{% endif %} +{% if dismissable %}{% endif %}
diff --git a/templates/overrides/lcars/audio-embed.ninjatpl b/templates/overrides/lcars/audio-embed.ninjatpl index 3f5425c..dd86bc1 100644 --- a/templates/overrides/lcars/audio-embed.ninjatpl +++ b/templates/overrides/lcars/audio-embed.ninjatpl @@ -6,8 +6,8 @@ {% if title %}

{{ title }}

{% endif %} {% if artist %}

{{ artist }}

{% endif %}
- -{% if download %}::lucide:download:sm:: Download{% endif %} + +{% if download %} Download{% endif %}
diff --git a/templates/overrides/lcars/author-bio-hero.ninjatpl b/templates/overrides/lcars/author-bio-hero.ninjatpl index 894f9e0..1eceffd 100644 --- a/templates/overrides/lcars/author-bio-hero.ninjatpl +++ b/templates/overrides/lcars/author-bio-hero.ninjatpl @@ -1 +1 @@ -{% if context.currentAuthor %}
{% if showAvatar and context.currentAuthor.avatarUrl %}{{ context.currentAuthor.displayName }}{% else %}{% endif %}

{{ context.currentAuthor.displayName }}

{% if context.currentAuthor.bio %}

{{ context.currentAuthor.bio }}

{% endif %}{% if showSocial %}
{% if context.currentAuthor.websiteUrl %}{% endif %}{% if context.currentAuthor.twitterHandle %}{% endif %}{% if context.currentAuthor.linkedinUrl %}{% endif %}
{% endif %}
{% endif %} +{% if context.currentAuthor %}
{% if showAvatar and context.currentAuthor.avatarUrl %}{{ context.currentAuthor.displayName }}{% else %}{% endif %}

{{ context.currentAuthor.displayName }}

{% if context.currentAuthor.bio %}

{{ context.currentAuthor.bio }}

{% endif %}{% if showSocial %}
{% if context.currentAuthor.websiteUrl %}{% endif %}{% if context.currentAuthor.twitterHandle %}{% endif %}{% if context.currentAuthor.linkedinUrl %}{% endif %}
{% endif %}
{% endif %} diff --git a/templates/overrides/lcars/button.ninjatpl b/templates/overrides/lcars/button.ninjatpl index 25c69b2..774d724 100644 --- a/templates/overrides/lcars/button.ninjatpl +++ b/templates/overrides/lcars/button.ninjatpl @@ -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 %} {% set sizeClass = "" %} {% if size == "sm" %}{% set sizeClass = "lcars-btn-sm" %}{% elif size == "lg" %}{% set sizeClass = "lcars-btn-lg" %}{% endif %} -
{% if newTab %}{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}{% else %}{% if icon and iconPosition != "right" %}::{{ icon }}:sm::{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}::{{ icon }}:sm::{% endif %}{% endif %}
+
{% if newTab %}{% if icon and iconPosition != "right" %}{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}{% endif %}{% else %}{% if icon and iconPosition != "right" %}{% endif %}{{ label|default:"Learn more" }}{% if icon and iconPosition == "right" %}{% endif %}{% endif %}
diff --git a/templates/overrides/lcars/card.ninjatpl b/templates/overrides/lcars/card.ninjatpl index 8fba679..a30698f 100644 --- a/templates/overrides/lcars/card.ninjatpl +++ b/templates/overrides/lcars/card.ninjatpl @@ -1 +1 @@ -
{% if media %}
{% img media alt=title|default:"" class="lcars-card-media" %}
{% endif %}{% if title %}

{{ title }}

{% endif %}{% if text %}
{{ text|safe }}
{% endif %}{% if linkLabel and link %}{{ linkLabel }}::lucide:arrow-right:sm::{% endif %}
+
{% if media %}
{% img media alt=title|default:"" class="lcars-card-media" %}
{% endif %}{% if title %}

{{ title }}

{% endif %}{% if text %}
{{ text|safe }}
{% endif %}{% if linkLabel and link %}{{ linkLabel }}{% endif %}
diff --git a/templates/overrides/lcars/contact-card.ninjatpl b/templates/overrides/lcars/contact-card.ninjatpl index 7cb8140..f16bfd2 100644 --- a/templates/overrides/lcars/contact-card.ninjatpl +++ b/templates/overrides/lcars/contact-card.ninjatpl @@ -4,7 +4,7 @@ {% if description %}

{{ description }}

{% endif %}
{% for channel in channels %}
-{% if channel.icon %}::{{ channel.icon }}:sm::{% endif %} +{% if channel.icon %}{% endif %}
{% if channel.label %}
{{ channel.label }}
{% endif %} {% if channel.value %}
{% if channel.link %}{{ channel.value }}{% else %}{{ channel.value }}{% endif %}
{% endif %} diff --git a/templates/overrides/lcars/divider.ninjatpl b/templates/overrides/lcars/divider.ninjatpl index ad9e2b5..ec57e36 100644 --- a/templates/overrides/lcars/divider.ninjatpl +++ b/templates/overrides/lcars/divider.ninjatpl @@ -1,2 +1,2 @@ {# divider override — plain hairline / thick spacer rule / centered ornament between two hairlines. #} -{% if variant == "ornament" %}{% elif variant == "spacer-rule" %}{% else %}{% endif %} +{% if variant == "ornament" %}{% elif variant == "spacer-rule" %}{% else %}{% endif %} diff --git a/templates/overrides/lcars/event-list.ninjatpl b/templates/overrides/lcars/event-list.ninjatpl index 4d6f77a..784c839 100644 --- a/templates/overrides/lcars/event-list.ninjatpl +++ b/templates/overrides/lcars/event-list.ninjatpl @@ -11,7 +11,7 @@

{{ event.title }}

{% if event.venue %}

{{ event.venue }}

{% endif %} {% if event.description %}

{{ event.description }}

{% endif %} -{% if event.link %}{{ event.linkLabel|default:"Details" }}::lucide:arrow-right:sm::{% endif %} +{% if event.link %}{{ event.linkLabel|default:"Details" }}{% endif %}
{% endif %}{% endfor %}
diff --git a/templates/overrides/lcars/faq.ninjatpl b/templates/overrides/lcars/faq.ninjatpl index 0d8feaa..85eeaed 100644 --- a/templates/overrides/lcars/faq.ninjatpl +++ b/templates/overrides/lcars/faq.ninjatpl @@ -2,5 +2,5 @@
{% if heading %}

{{ heading }}

{% endif %} {% if intro %}

{{ intro }}

{% endif %} -{% if items %}
{% for item in items %}
{{ item.question }}
{{ item.answer|safe }}
{% endfor %}
{% endif %} +{% if items %}
{% for item in items %}
{{ item.question }}
{{ item.answer|safe }}
{% endfor %}
{% endif %}
diff --git a/templates/overrides/lcars/feature-grid.ninjatpl b/templates/overrides/lcars/feature-grid.ninjatpl index b1544de..2b4cddd 100644 --- a/templates/overrides/lcars/feature-grid.ninjatpl +++ b/templates/overrides/lcars/feature-grid.ninjatpl @@ -3,5 +3,5 @@ {% if eyebrow %}

{{ eyebrow }}

{% endif %} {% if heading %}

{{ heading }}

{% endif %} {% if intro %}

{{ intro }}

{% endif %} -{% if items %}
{% for item in items %}
{% if item.icon %}{% else %}{% endif %}{% if item.title %}

{% if item.linkUrl %}{{ item.title }}{% else %}{{ item.title }}{% endif %}

{% endif %}{% if item.text %}

{{ item.text }}

{% endif %}{% if item.linkUrl and item.linkLabel %}{{ item.linkLabel }}::lucide:arrow-right:sm::{% endif %}
{% endfor %}
{% endif %} +{% if items %}
{% for item in items %}
{% if item.icon %}{% else %}{% endif %}{% if item.title %}

{% if item.linkUrl %}{{ item.title }}{% else %}{{ item.title }}{% endif %}

{% endif %}{% if item.text %}

{{ item.text }}

{% endif %}{% if item.linkUrl and item.linkLabel %}{{ item.linkLabel }}{% endif %}
{% endfor %}
{% endif %}
diff --git a/templates/overrides/lcars/footer.ninjatpl b/templates/overrides/lcars/footer.ninjatpl index 91a65f5..8851299 100644 --- a/templates/overrides/lcars/footer.ninjatpl +++ b/templates/overrides/lcars/footer.ninjatpl @@ -12,6 +12,6 @@ diff --git a/templates/overrides/lcars/hours-location.ninjatpl b/templates/overrides/lcars/hours-location.ninjatpl index 2b7a76a..1955f47 100644 --- a/templates/overrides/lcars/hours-location.ninjatpl +++ b/templates/overrides/lcars/hours-location.ninjatpl @@ -7,11 +7,11 @@ {% if specialHoursNote %}

{{ specialHoursNote }}

{% endif %} {% if address %}
Address
{{ address }}
{% endif %} {% if phone %}
Phone
{{ phone }}
{% endif %} -{% if directionsUrl %}::lucide:navigation:sm::Get directions{% endif %} +{% if directionsUrl %}Get directions{% endif %} {% if mapEmbedUrl %}
- +
{% endif %} diff --git a/templates/overrides/lcars/navbar.ninjatpl b/templates/overrides/lcars/navbar.ninjatpl index 9895039..817c65d 100644 --- a/templates/overrides/lcars/navbar.ninjatpl +++ b/templates/overrides/lcars/navbar.ninjatpl @@ -1 +1 @@ - + diff --git a/templates/overrides/lcars/page-suggestions.ninjatpl b/templates/overrides/lcars/page-suggestions.ninjatpl index dc46e2b..18aa08a 100644 --- a/templates/overrides/lcars/page-suggestions.ninjatpl +++ b/templates/overrides/lcars/page-suggestions.ninjatpl @@ -1 +1 @@ -

{{ title|default:"Were you looking for..." }}

{% if suggestions %}{% else %}{% if emptyMessage %}

{{ emptyMessage }}

{% endif %}{% endif %}
+

{{ title|default:"Were you looking for..." }}

{% if suggestions %}{% else %}{% if emptyMessage %}

{{ emptyMessage }}

{% endif %}{% endif %}
diff --git a/templates/overrides/lcars/password-reset-form.ninjatpl b/templates/overrides/lcars/password-reset-form.ninjatpl index fac3360..72e8400 100644 --- a/templates/overrides/lcars/password-reset-form.ninjatpl +++ b/templates/overrides/lcars/password-reset-form.ninjatpl @@ -7,5 +7,5 @@
- ::lucide:arrow-left:sm::Back to sign in + Back to sign in diff --git a/templates/overrides/lcars/pricing.ninjatpl b/templates/overrides/lcars/pricing.ninjatpl index ac0ab4f..e0f75fa 100644 --- a/templates/overrides/lcars/pricing.ninjatpl +++ b/templates/overrides/lcars/pricing.ninjatpl @@ -7,7 +7,7 @@ {% if tier.name %}

{{ tier.name }}

{% endif %}

{% if currency %}{{ currency }}{% else %}${% endif %}{{ tier.price }}{% if tier.period %}{{ tier.period }}{% endif %}

{% if tier.description %}

{{ tier.description }}

{% endif %} -{% if tier.features %}{% endif %} +{% if tier.features %}{% endif %} {% if tier.ctaUrl and tier.ctaLabel %}{% if tier.highlighted %}{{ tier.ctaLabel }}{% else %}{{ tier.ctaLabel }}{% endif %}{% endif %} {% endfor %}{% endif %} {% if billingNote %}

{{ billingNote }}

{% endif %} diff --git a/templates/overrides/lcars/rich-section.ninjatpl b/templates/overrides/lcars/rich-section.ninjatpl index baa7b17..fb504cb 100644 --- a/templates/overrides/lcars/rich-section.ninjatpl +++ b/templates/overrides/lcars/rich-section.ninjatpl @@ -4,7 +4,7 @@ {% if eyebrow %}

{{ eyebrow }}

{% endif %} {% if heading %}

{{ heading }}

{% endif %} {% if body %}
{{ body|safe }}
{% endif %} -{% if ctaUrl and ctaLabel %}{{ ctaLabel }}::lucide:arrow-right:sm::{% endif %} +{% if ctaUrl and ctaLabel %}{{ ctaLabel }}{% endif %} -
{% if media %}{% img media alt=mediaAlt class="lcars-rich-media" %}{% endif %}
+
{% if media %}
{% img media alt=mediaAlt class="lcars-rich-media" %}
{% else %}
No signal
{% endif %}
diff --git a/templates/overrides/lcars/sidebar-nav.ninjatpl b/templates/overrides/lcars/sidebar-nav.ninjatpl index 423bdf8..cccdb16 100644 --- a/templates/overrides/lcars/sidebar-nav.ninjatpl +++ b/templates/overrides/lcars/sidebar-nav.ninjatpl @@ -1,3 +1,3 @@ - diff --git a/templates/overrides/lcars/social-links.ninjatpl b/templates/overrides/lcars/social-links.ninjatpl index efc81ac..75d8008 100644 --- a/templates/overrides/lcars/social-links.ninjatpl +++ b/templates/overrides/lcars/social-links.ninjatpl @@ -2,6 +2,6 @@
{% if heading %}

{{ heading }}

{% endif %}
diff --git a/templates/overrides/lcars/team.ninjatpl b/templates/overrides/lcars/team.ninjatpl index 3f1616b..99a215e 100644 --- a/templates/overrides/lcars/team.ninjatpl +++ b/templates/overrides/lcars/team.ninjatpl @@ -7,6 +7,6 @@ {% if member.name %}

{{ member.name }}

{% endif %} {% if member.role %}
{{ member.role }}
{% endif %} {% if member.bio %}

{{ member.bio }}

{% endif %} -{% if member.socials %}
{% for social in member.socials %}{% if social.url %}::{{ social.icon }}:sm::{% endif %}{% endfor %}
{% endif %} +{% if member.socials %}
{% for social in member.socials %}{% if social.url %}{% endif %}{% endfor %}
{% endif %} {% endfor %}{% endif %} diff --git a/templates/overrides/lcars/testimonial.ninjatpl b/templates/overrides/lcars/testimonial.ninjatpl index c1ff75f..8ba3dcb 100644 --- a/templates/overrides/lcars/testimonial.ninjatpl +++ b/templates/overrides/lcars/testimonial.ninjatpl @@ -2,7 +2,7 @@
{% if heading %}

{{ heading }}

{% endif %}
{% for q in quotes %}
-{% if q.rating %}
::lucide:star:sm::::lucide:star:sm::::lucide:star:sm::::lucide:star:sm::::lucide:star:sm::
{% endif %} +{% if q.rating %}
{% endif %} {% if q.quote %}
{{ q.quote }}
{% endif %}
{% if q.avatar %}{% img q.avatar alt=q.name class="lcars-avatar-img" %}{% endif %}{% if q.name %}{{ q.name }}{% endif %}{% if q.role %}{{ q.role }}{% endif %}
{% endfor %}
diff --git a/templates/overrides/lcars/utility-bar.ninjatpl b/templates/overrides/lcars/utility-bar.ninjatpl index b8f2771..1863880 100644 --- a/templates/overrides/lcars/utility-bar.ninjatpl +++ b/templates/overrides/lcars/utility-bar.ninjatpl @@ -1,6 +1,6 @@ {# 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 %} -{% macro ubitem(it) %}{% if it.link %}{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% else %}{% if it.icon %}::{{ it.icon }}:sm::{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% endif %}{% endmacro %} +{% macro ubitem(it) %}{% if it.link %}{% if it.icon %}{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% else %}{% if it.icon %}{% endif %}{% if it.label %}{{ it.label }}{% endif %}{% endif %}{% endmacro %}
{% for it in leftItems %}{{ ubitem(it) }}{% endfor %}
diff --git a/templates/overrides/lcars/video-embed.ninjatpl b/templates/overrides/lcars/video-embed.ninjatpl index 28e4a14..5086ed0 100644 --- a/templates/overrides/lcars/video-embed.ninjatpl +++ b/templates/overrides/lcars/video-embed.ninjatpl @@ -4,7 +4,7 @@
{% if caption %}
{{ caption }}
{% endif %}