Compare commits

..

No commits in common. "ffdd627192098d75f6e59af7eabc778cd8c9fe37" and "1f74c5ac063abf6b29648afb9d569fef622c20a9" have entirely different histories.

34 changed files with 48 additions and 51 deletions

View File

@ -7,7 +7,7 @@
<div class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"> <div class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{% for member in members %} {% for member in members %}
<div class="hud-frame flex items-center gap-4 rounded-md border border-primary/40 bg-card p-5 text-card-foreground neon-edge-magenta"> <div class="hud-frame flex items-center gap-4 rounded-md border border-primary/40 bg-card p-5 text-card-foreground neon-edge-magenta">
{% if member.avatar %}<span class="clip-cut h-14 w-14 shrink-0 overflow-hidden rounded-md border border-primary/40 bg-muted">{% img member.avatar alt=member.name class="h-full w-full object-cover" %}</span>{% else %}<span class="clip-cut flex h-14 w-14 shrink-0 items-center justify-center rounded-md border border-primary/40 bg-primary/10 text-primary"><svg width="24" height="24" class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#user"></use></svg></span>{% endif %} {% if member.avatar %}<span class="clip-cut h-14 w-14 shrink-0 overflow-hidden rounded-md border border-primary/40 bg-muted">{% img member.avatar alt=member.name class="h-full w-full object-cover" %}</span>{% else %}<span class="clip-cut flex h-14 w-14 shrink-0 items-center justify-center rounded-md border border-primary/40 bg-primary/10 text-primary"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#user"></use></svg></span>{% endif %}
<div class="min-w-0"> <div class="min-w-0">
{% if member.name %}<h3 class="cyberpunk-display text-base font-semibold leading-tight">{{ member.name }}</h3>{% endif %} {% if member.name %}<h3 class="cyberpunk-display text-base font-semibold leading-tight">{{ member.name }}</h3>{% endif %}
{% if member.handle %}<p class="cyberpunk-mono text-sm text-primary">{{ member.handle }}</p>{% endif %} {% if member.handle %}<p class="cyberpunk-mono text-sm text-primary">{{ member.handle }}</p>{% endif %}

View File

@ -293,17 +293,15 @@ css:
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 1;
} }
/* Inset 5px so the L-brackets clear any rounded / overflow-hidden panel
corner (e.g. the code_neon figure) instead of being sliced by it. */
.hud-frame::before { .hud-frame::before {
top: 5px; top: 0;
left: 5px; left: 0;
border-top: 2px solid hsl(var(--primary)); border-top: 2px solid hsl(var(--primary));
border-left: 2px solid hsl(var(--primary)); border-left: 2px solid hsl(var(--primary));
} }
.hud-frame::after { .hud-frame::after {
bottom: 5px; bottom: 0;
right: 5px; right: 0;
border-bottom: 2px solid hsl(var(--accent)); border-bottom: 2px solid hsl(var(--accent));
border-right: 2px solid hsl(var(--accent)); border-right: 2px solid hsl(var(--accent));
} }

View File

@ -2,7 +2,7 @@
name = "cyberpunk" name = "cyberpunk"
display_name = "Cyberpunk" display_name = "Cyberpunk"
scope = "@themes" scope = "@themes"
version = "0.4.0" version = "0.3.0"
description = "Neon-on-black BlockNinja theme with glitch motifs, monospace accents, and magenta/cyan/lime tri-accent palette for SaaS, dev tools, and crypto." description = "Neon-on-black BlockNinja theme with glitch motifs, monospace accents, and magenta/cyan/lime tri-accent palette for SaaS, dev tools, and crypto."
kind = "theme" kind = "theme"
categories = ["templates"] categories = ["templates"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -114,10 +114,10 @@
"template_key": "default", "template_key": "default",
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The studio", "level": 1 } }, { "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The studio", "level": 1 } },
{ "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "<p>Neon Forge started as a build tool for a game that shipped two years late. The game came and went. The tool outlived it. We kept sharpening it in the dark between projects, then built more games to prove it could take the punishment.</p><p>Now we run both halves at once. The engine and the live service on one side, the games that stress-test them on the other. Nothing ships to a player before it has shipped to us first, on the same pipeline, under the same load.</p><p>We are a small crew by design. Fourteen people who would rather own the whole stack than manage a hundred who own slices of it. Everyone here writes code that runs in production, and everyone here has been paged at 3am by something they wrote. That keeps us honest.</p><p>The look of this place is not an accident either. Neon on black, mono readouts, a little glitch in the type. It is how our tools have always looked on the wall of screens in the build room, and we never saw a reason to dress it up for the website.</p>" } }, { "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "<p>Neon Forge started as a build tool for a game that shipped late. The tool outlived the game. We kept building it, then built more games to prove it out.</p><p>Now we run both. The engine and live service on one side, the games that stress test them on the other. Everything we make, we run in production first.</p>" } },
{ "block_key": "cyberpunk:code_neon", "title": "Quickstart", "slot": "main", "sort_order": 3, "content": { "language": "bash", "code": "npm install @neon-forge/sdk\nnpx neon-forge init my-game\nnpx neon-forge ship --stage prod", "copy": "on" } }, { "block_key": "cyberpunk:code_neon", "title": "Quickstart", "slot": "main", "sort_order": 3, "content": { "language": "bash", "code": "npm install @neon-forge/sdk\nnpx neon-forge init my-game\nnpx neon-forge ship --stage prod", "copy": "on" } },
{ "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "line", "weight": "medium" } }, { "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "line", "weight": "medium" } },
{ "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 5, "content": { "style": "pull", "quote": "Build the tool. Ship the game. Run both in production before you trust either.", "attribution": "Nova Reyes", "role": "Engine lead, Neon Forge" } } { "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 5, "content": { "style": "pull", "quote": "Build the tool. Ship the game. Repeat.", "attribution": "The studio" } }
] ]
}, },
{ {
@ -137,7 +137,7 @@
"parent_slug": "/blog", "parent_slug": "/blog",
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Making it rain", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Making it rain", "level": 1 } },
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>The hero on our home page runs a digital-rain canvas. No libraries, no sprite sheets, no video. Just a few dozen lines that draw falling glyphs onto a single <code>&lt;canvas&gt;</code> and never touch the network again.</p><p>We wanted the front door of the studio to feel like the wall of screens in our build room: green-on-black readouts, columns of characters sliding down, the faint sense that something is compiling behind the glass. A GIF would have looked dead. A video would have cost a megabyte and stuttered on the first scroll. So we drew it live.</p><p>The whole effect is one idea repeated: divide the width into columns, give each column a <em>drop</em> that falls one row per tick, and paint a random glyph wherever that drop currently sits. When a drop runs off the bottom, roll a die and occasionally send it back to the top. That randomness is what stops the rain from marching in lockstep.</p><p>The trick that makes it read as rain instead of confetti is the fade. Every frame we do not clear the canvas. We paint a translucent rectangle of the background colour over the whole thing, just barely opaque, then draw the new glyphs on top. Yesterday's characters do not vanish; they dim, one step per frame, leaving a comet tail behind each drop. Clear the canvas outright and you get sharp dots with no soul. Fade it and you get rain.</p><p>Colour comes from the theme, not from a hex code baked into the script. On boot we read the CSS custom properties off the document root, the primary and accent channels, and pick one of them at random per glyph. Retheme the site and the rain retints itself for free. That single decision is why the effect survives every palette we throw at it.</p><p>Performance was the part we actually sweated. A canvas that repaints as fast as the browser allows will happily cook a laptop fan for a background nobody is looking at. So we cap the loop at roughly eighteen frames a second. Rain does not need sixty. The <code>requestAnimationFrame</code> callback fires as often as the display wants, but we bail early unless enough milliseconds have passed since the last real paint. Half the frames do nothing but check a clock.</p><p>We also refused to let it run when it should not. The canvas only wakes up once it scrolls into view, wired through an <code>IntersectionObserver</code>, so a page that never shows the hero never spends a cycle on it. If the visitor has asked for reduced motion, we skip the animation entirely and let a static neon gradient stand in. The rain is a flourish, never a requirement.</p><p>Sizing is handled the boring, correct way. A <code>ResizeObserver</code> watches the hero and rebuilds the column list whenever the box changes, multiplying the backing store by the device pixel ratio so the glyphs stay crisp on retina panels without rendering four times the pixels on a phone. Resize the window and the rain reflows mid-fall.</p><p>None of this is clever, and that is the point. The failure mode of a signature animation is a dependency you have to keep patched and a bundle that grows every time someone adds a feature. This one has no dependencies, ships as inline script inside the theme, and has not changed since the day it worked. It will still run when the framework it was born next to is three major versions gone.</p><p>If you are building your own, start with the fade and the frame cap. Everything else is decoration. Get a single column falling with a trailing tail at a sane frame rate, and you already have the effect. The rest is just more columns.</p>" } } { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>The hero on our home page runs a digital-rain canvas. No libraries, no images, just a small script that draws falling glyphs.</p><p>The trick is to fade the last frame instead of clearing it. That leaves a trail. Cap the frame rate and it stays cheap, even on a laptop.</p>" } }
] ]
}, },
{ {
@ -147,7 +147,7 @@
"parent_slug": "/blog", "parent_slug": "/blog",
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Caching shaders across branches", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Caching shaders across branches", "level": 1 } },
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Every branch used to recompile the whole shader set from scratch. That is minutes per build, times every push, times every engineer. On a busy day the build farm spent more time on shaders nobody had touched than on the code that changed.</p><p>The insight was embarrassingly simple once we saw it. A shader does not know what branch it lives on. If the source bytes are identical, the compiled output is identical. So we keyed the cache on a hash of the shader source and its compile flags, not on the branch name.</p><p>Now two branches that share a shader share the compile. The first branch to build a given shader pays for it; everyone after pulls the artifact from the cache in milliseconds. A feature branch that only touches gameplay code inherits every shader the mainline already compiled.</p><p>Green builds went from tens of minutes back down to single digits. The farm stopped melting under merge storms. Nobody has thought about shader compile times since, which is the highest compliment we can pay a piece of infrastructure.</p>" } } { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Every branch used to recompile the whole shader set. That is minutes per build, times every push.</p><p>We keyed the cache on the shader source, not the branch. Two branches that share a shader now share the compile. Builds got short again.</p>" } }
] ]
}, },
{ {
@ -157,7 +157,7 @@
"parent_slug": "/blog", "parent_slug": "/blog",
"blocks": [ "blocks": [
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Netcode on bad links", "level": 1 } }, { "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Netcode on bad links", "level": 1 } },
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Players on slow connections kept desyncing, and the complaints all rhymed: the world would freeze for a beat, then snap somewhere they did not expect. Rewriting the simulation to be network-native was a six-month job we did not have. We needed a fix that lived on top of the sim we already trusted.</p><p>So we added client prediction with a short rollback window. The client stops waiting for the server to bless every input and starts guessing. Press dash, and you dash now, locally, immediately. The input also goes to the server, which is still the only authority that counts.</p><p>When the server's version of events comes back, the client compares it against what it predicted. Most of the time they agree and nothing happens. When they disagree, the client quietly rewinds the last few frames, replays them with the corrected state, and rolls forward again, all inside a window short enough that the eye never catches the seam.</p><p>The result is a game that feels instant on a bad link and stays authoritative on the server. Desync on two-hundred-millisecond connections dropped to something players stopped reporting. The simulation never changed. We just stopped making it wait.</p>" } } { "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Players on slow connections kept desyncing. Rewriting the simulation was off the table.</p><p>We added client prediction with a short rollback window. The client guesses, the server corrects, and the gap closes before anyone notices.</p>" } }
] ]
}, },
{ {

View File

@ -4,7 +4,7 @@
<div data-bn-announcement data-bn-annkey="{{ variant|default:'info' }}:{{ message|slugify }}" class="bn-announcement w-full {{ anncls }} {{ class }}"> <div data-bn-announcement data-bn-annkey="{{ variant|default:'info' }}:{{ message|slugify }}" class="bn-announcement w-full {{ anncls }} {{ class }}">
<div class="max-w-7xl mx-auto px-10 py-2 relative flex items-center justify-center gap-2 text-sm text-center"> <div class="max-w-7xl mx-auto px-10 py-2 relative flex items-center justify-center gap-2 text-sm text-center">
<p class="cyberpunk-mono uppercase tracking-wide font-medium">{{ message }}{% if linkText and linkUrl %} <a href="{{ linkUrl }}" class="underline underline-offset-2 hover:opacity-80">{{ linkText }}</a>{% endif %}</p> <p class="cyberpunk-mono uppercase tracking-wide font-medium">{{ message }}{% if linkText and linkUrl %} <a href="{{ linkUrl }}" class="underline underline-offset-2 hover:opacity-80">{{ linkText }}</a>{% endif %}</p>
{% if dismissable %}<button type="button" data-bn-ann-dismiss aria-label="Dismiss announcement" class="absolute right-3 top-1/2 -translate-y-1/2 inline-flex items-center justify-center p-1 rounded hover:bg-black/10 transition-colors"><svg width="16" height="16" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></button>{% endif %} {% if dismissable %}<button type="button" data-bn-ann-dismiss aria-label="Dismiss announcement" class="absolute right-3 top-1/2 -translate-y-1/2 inline-flex items-center justify-center p-1 rounded hover:bg-black/10 transition-colors"><svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></button>{% endif %}
</div> </div>
</div> </div>
{% if dismissable %}<script> {% if dismissable %}<script>

View File

@ -30,8 +30,8 @@
</script>{% endmacro %} </script>{% endmacro %}
{% macro social() %}{% if show_social != false and (context.site.google_oauth_client_id or context.site.facebook_app_id) %}<div class="auth-social my-4"> {% macro social() %}{% if show_social != false and (context.site.google_oauth_client_id or context.site.facebook_app_id) %}<div class="auth-social my-4">
<div class="relative my-4"><hr class="border-border"/><span class="cyberpunk-mono absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-background px-3 text-xs uppercase tracking-widest text-muted-foreground">or</span></div> <div class="relative my-4"><hr class="border-border"/><span class="cyberpunk-mono absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-background px-3 text-xs uppercase tracking-widest text-muted-foreground">or</span></div>
{% if context.site.google_oauth_client_id %}<a href="/api/auth/google/start" class="cyberpunk-mono mb-2 flex w-full items-center justify-center gap-3 rounded-md border border-border px-4 py-2.5 uppercase tracking-wide transition-colors hover:bg-accent/10"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#google"></use></svg><span class="text-sm font-medium text-foreground/80">Continue with Google</span></a>{% endif %} {% if context.site.google_oauth_client_id %}<a href="/api/auth/google/start" class="cyberpunk-mono mb-2 flex w-full items-center justify-center gap-3 rounded-md border border-border px-4 py-2.5 uppercase tracking-wide transition-colors hover:bg-accent/10"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#google"></use></svg><span class="text-sm font-medium text-foreground/80">Continue with Google</span></a>{% endif %}
{% if context.site.facebook_app_id %}<a href="/api/auth/facebook/start" class="cyberpunk-mono flex w-full items-center justify-center gap-3 rounded-md border border-border px-4 py-2.5 uppercase tracking-wide transition-colors hover:bg-accent/10"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#facebook"></use></svg><span class="text-sm font-medium text-foreground/80">Continue with Facebook</span></a>{% endif %} {% if context.site.facebook_app_id %}<a href="/api/auth/facebook/start" class="cyberpunk-mono flex w-full items-center justify-center gap-3 rounded-md border border-border px-4 py-2.5 uppercase tracking-wide transition-colors hover:bg-accent/10"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/simple-icons.svg#facebook"></use></svg><span class="text-sm font-medium text-foreground/80">Continue with Facebook</span></a>{% endif %}
</div>{% endif %}{% endmacro %} </div>{% endif %}{% endmacro %}
<div class="auth-form hud-frame mx-auto max-w-md rounded-md border border-primary/40 bg-card p-6 text-card-foreground neon-edge-magenta"> <div class="auth-form hud-frame mx-auto max-w-md rounded-md border border-primary/40 bg-card p-6 text-card-foreground neon-edge-magenta">
<div id="auth-message"></div> <div id="auth-message"></div>

View File

@ -10,9 +10,9 @@
</div>{% endif %} </div>{% endif %}
<div class="auth-status relative"> <div class="auth-status relative">
<button type="button" onclick="this.nextElementSibling.classList.toggle('hidden')" class="flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium opacity-90 transition-colors hover:bg-primary/10 hover:opacity-100"> <button type="button" onclick="this.nextElementSibling.classList.toggle('hidden')" class="flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium opacity-90 transition-colors hover:bg-primary/10 hover:opacity-100">
<span class="clip-cut flex h-7 w-7 items-center justify-center rounded-md bg-accent text-accent-foreground"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#user"></use></svg></span> <span class="clip-cut flex h-7 w-7 items-center justify-center rounded-md bg-accent text-accent-foreground"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#user"></use></svg></span>
<span class="cyberpunk-mono uppercase tracking-wide">{{ context.publicDisplayName|default:context.publicUsername }}</span> <span class="cyberpunk-mono uppercase tracking-wide">{{ context.publicDisplayName|default:context.publicUsername }}</span>
<svg width="16" height="16" class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg> <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg>
</button> </button>
<div id="auth-dropdown-menu" class="hud-frame hidden absolute right-0 top-full mt-1 w-48 rounded-md border border-primary/40 bg-card py-1 text-card-foreground neon-edge-magenta z-50"> <div id="auth-dropdown-menu" class="hud-frame hidden absolute right-0 top-full mt-1 w-48 rounded-md border border-primary/40 bg-card py-1 text-card-foreground neon-edge-magenta z-50">
<a href="/account" class="cyberpunk-mono block px-4 py-2 text-sm uppercase tracking-wide text-card-foreground hover:bg-primary/10">My Profile</a> <a href="/account" class="cyberpunk-mono block px-4 py-2 text-sm uppercase tracking-wide text-card-foreground hover:bg-primary/10">My Profile</a>

View File

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

View File

@ -7,7 +7,7 @@
{% if showHome %}<li class="flex items-center"><a href="/" class="text-accent transition-colors hover:text-primary">{{ homeLabel|default:"Home" }}</a></li>{% endif %} {% if showHome %}<li class="flex items-center"><a href="/" class="text-accent transition-colors hover:text-primary">{{ homeLabel|default:"Home" }}</a></li>{% endif %}
{% for item in breadcrumbs %} {% for item in breadcrumbs %}
<li class="flex items-center"> <li class="flex items-center">
{% if showHome or not forloop.First %}{% if arrows %}<svg width="16" height="16" class="mx-2 h-4 w-4 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>{% else %}<span class="mx-2 text-primary">{{ separator|default:"/" }}</span>{% endif %}{% endif %} {% if showHome or not forloop.First %}{% if arrows %}<svg class="mx-2 h-4 w-4 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>{% else %}<span class="mx-2 text-primary">{{ separator|default:"/" }}</span>{% endif %}{% endif %}
{% if item.is_current %}{% if showCurrent %}<span class="font-medium text-foreground" aria-current="page">{{ item.label }}</span>{% endif %}{% else %}<a href="{{ item.url }}" class="text-accent transition-colors hover:text-primary">{{ item.label }}</a>{% endif %} {% if item.is_current %}{% if showCurrent %}<span class="font-medium text-foreground" aria-current="page">{{ item.label }}</span>{% endif %}{% else %}<a href="{{ item.url }}" class="text-accent transition-colors hover:text-primary">{{ item.label }}</a>{% endif %}
</li> </li>
{% endfor %} {% endfor %}

View File

@ -6,7 +6,7 @@
<div class="mt-10 grid grid-cols-1 gap-4 {% if columns == 3 %}sm:grid-cols-2 lg:grid-cols-3{% elif columns == 1 %}{% else %}sm:grid-cols-2{% endif %}"> <div class="mt-10 grid grid-cols-1 gap-4 {% if columns == 3 %}sm:grid-cols-2 lg:grid-cols-3{% elif columns == 1 %}{% else %}sm:grid-cols-2{% endif %}">
{% for channel in channels %} {% for channel in channels %}
<div class="hud-frame flex items-start gap-4 rounded-md border border-primary/40 bg-card p-5 text-card-foreground neon-edge-magenta"> <div class="hud-frame flex items-start gap-4 rounded-md border border-primary/40 bg-card p-5 text-card-foreground neon-edge-magenta">
{% if channel.icon %}<span class="clip-cut inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary"><svg width="20" height="20" class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"></use></svg></span>{% endif %} {% if channel.icon %}<span class="clip-cut inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary"><svg class="h-5 w-5" aria-hidden="true"><use href="/icons/{{ channel.icon|split:":"|first }}.svg#{{ channel.icon|split:":"|last }}"></use></svg></span>{% endif %}
<div class="min-w-0"> <div class="min-w-0">
{% if channel.label %}<div class="cyberpunk-mono text-sm font-medium uppercase tracking-wide text-accent">{{ channel.label }}</div>{% endif %} {% if channel.label %}<div class="cyberpunk-mono text-sm font-medium uppercase tracking-wide text-accent">{{ channel.label }}</div>{% endif %}
{% if channel.value %}<div class="mt-0.5 break-words font-medium">{% if channel.link %}<a href="{{ channel.link }}" class="transition-colors hover:text-primary">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %} {% if channel.value %}<div class="mt-0.5 break-words font-medium">{% if channel.link %}<a href="{{ channel.link }}" class="transition-colors hover:text-primary">{{ channel.value }}</a>{% else %}{{ channel.value }}{% endif %}</div>{% endif %}

View File

@ -4,7 +4,7 @@
<div class="mx-auto max-w-2xl px-4"> <div class="mx-auto max-w-2xl px-4">
{% if form.submitted %} {% if form.submitted %}
<div class="hud-frame rounded-md border border-primary/50 bg-card p-8 text-center text-card-foreground neon-edge-magenta"> <div class="hud-frame rounded-md border border-primary/50 bg-card p-8 text-center text-card-foreground neon-edge-magenta">
<div class="clip-cut mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-md bg-primary/10 text-primary"><svg width="24" height="24" class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg></div> <div class="clip-cut mx-auto mb-4 inline-flex h-12 w-12 items-center justify-center rounded-md bg-primary/10 text-primary"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg></div>
<p class="cyberpunk-display text-lg font-medium">{{ form.message|default:successMessage|default:"Thanks — your message has been sent." }}</p> <p class="cyberpunk-display text-lg font-medium">{{ form.message|default:successMessage|default:"Thanks — your message has been sent." }}</p>
</div> </div>
{% else %} {% else %}

View File

@ -13,7 +13,7 @@
</div> </div>
<div class="mt-8 hidden" data-countdown-expired> <div class="mt-8 hidden" data-countdown-expired>
<p class="cyberpunk-display text-xl font-medium">{{ expiredMessage|default:"This has started." }}</p> <p class="cyberpunk-display text-xl font-medium">{{ expiredMessage|default:"This has started." }}</p>
{% if expiredUrl and expiredLabel %}<a href="{{ expiredUrl }}" class="cyberpunk-mono clip-cut rgb-split mt-4 inline-flex items-center gap-2 rounded-md bg-primary px-5 py-3 font-semibold uppercase tracking-wider text-primary-foreground transition-opacity hover:opacity-90">{{ expiredLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %} {% if expiredUrl and expiredLabel %}<a href="{{ expiredUrl }}" class="cyberpunk-mono clip-cut rgb-split mt-4 inline-flex items-center gap-2 rounded-md bg-primary px-5 py-3 font-semibold uppercase tracking-wider text-primary-foreground transition-opacity hover:opacity-90">{{ expiredLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div> </div>
</div> </div>
<noscript><p class="mt-6 text-muted-foreground">Counting down to <time datetime="{{ target }}">{{ target }}</time>.</p></noscript> <noscript><p class="mt-6 text-muted-foreground">Counting down to <time datetime="{{ target }}">{{ target }}</time>.</p></noscript>

View File

@ -8,7 +8,7 @@
{% if text %}<p class="mt-3 text-lg {% if background == "band" %}text-primary-foreground/80{% else %}text-muted-foreground{% endif %}">{{ text }}</p>{% endif %} {% if text %}<p class="mt-3 text-lg {% if background == "band" %}text-primary-foreground/80{% else %}text-muted-foreground{% endif %}">{{ text }}</p>{% endif %}
</div> </div>
<div class="flex flex-wrap items-center justify-center gap-3 {% if background != "split" %}mt-8{% else %}shrink-0{% endif %}"> <div class="flex flex-wrap items-center justify-center gap-3 {% if background != "split" %}mt-8{% else %}shrink-0{% endif %}">
{% if primaryUrl and primaryLabel %}<a href="{{ primaryUrl }}" class="cyberpunk-mono clip-cut rgb-split inline-flex items-center gap-2 rounded-md px-6 py-3 font-semibold uppercase tracking-wider transition-opacity hover:opacity-90 {% if background == "band" %}bg-background text-foreground{% else %}bg-primary text-primary-foreground{% endif %}">{{ primaryLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %} {% if primaryUrl and primaryLabel %}<a href="{{ primaryUrl }}" class="cyberpunk-mono clip-cut rgb-split inline-flex items-center gap-2 rounded-md px-6 py-3 font-semibold uppercase tracking-wider transition-opacity hover:opacity-90 {% if background == "band" %}bg-background text-foreground{% else %}bg-primary text-primary-foreground{% endif %}">{{ primaryLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
{% if secondaryUrl and secondaryLabel %}<a href="{{ secondaryUrl }}" class="cyberpunk-mono inline-flex items-center rounded-md border px-6 py-3 font-semibold uppercase tracking-wider transition-colors {% if background == "band" %}border-primary-foreground/40 text-primary-foreground hover:bg-primary-foreground/10{% else %}border-accent/60 text-accent hover:bg-accent/10{% endif %}">{{ secondaryLabel }}</a>{% endif %} {% if secondaryUrl and secondaryLabel %}<a href="{{ secondaryUrl }}" class="cyberpunk-mono inline-flex items-center rounded-md border px-6 py-3 font-semibold uppercase tracking-wider transition-colors {% if background == "band" %}border-primary-foreground/40 text-primary-foreground hover:bg-primary-foreground/10{% else %}border-accent/60 text-accent hover:bg-accent/10{% endif %}">{{ secondaryLabel }}</a>{% endif %}
</div> </div>
</div> </div>

View File

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

View File

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

View File

@ -8,10 +8,10 @@
<div class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}"> <div class="mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 {% if columns == 2 %}lg:grid-cols-2{% elif columns == 4 %}lg:grid-cols-4{% else %}lg:grid-cols-3{% endif %}">
{% for item in items %} {% for item in items %}
<div class="{% if layout == "card" %}hud-frame rounded-md border border-primary/40 bg-card p-6 text-card-foreground neon-edge-magenta transition-transform hover:-translate-y-0.5{% elif layout == "centered" %}text-center{% endif %}"> <div class="{% if layout == "card" %}hud-frame rounded-md border border-primary/40 bg-card p-6 text-card-foreground neon-edge-magenta transition-transform hover:-translate-y-0.5{% elif layout == "centered" %}text-center{% endif %}">
{% if item.icon %}<div class="clip-cut mb-4 inline-flex h-11 w-11 items-center justify-center rounded-md bg-primary/10 text-primary{% if layout == "centered" %} mx-auto{% endif %}"><svg width="24" height="24" class="h-6 w-6" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg></div>{% endif %} {% if item.icon %}<div class="clip-cut mb-4 inline-flex h-11 w-11 items-center justify-center rounded-md bg-primary/10 text-primary{% if layout == "centered" %} mx-auto{% endif %}"><svg class="h-6 w-6" aria-hidden="true"><use href="/icons/{{ item.icon|split:":"|first }}.svg#{{ item.icon|split:":"|last }}"></use></svg></div>{% endif %}
<h3 class="cyberpunk-display text-lg font-semibold">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" class="transition-colors hover:text-primary">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3> <h3 class="cyberpunk-display text-lg font-semibold">{% if item.linkUrl %}<a href="{{ item.linkUrl }}" class="transition-colors hover:text-primary">{{ item.title }}</a>{% else %}{{ item.title }}{% endif %}</h3>
{% if item.text %}<p class="mt-2 text-muted-foreground">{{ item.text }}</p>{% endif %} {% if item.text %}<p class="mt-2 text-muted-foreground">{{ item.text }}</p>{% endif %}
{% if item.linkUrl and item.linkLabel %}<a href="{{ item.linkUrl }}" class="cyberpunk-mono uppercase tracking-wide mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline">{{ item.linkLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %} {% if item.linkUrl and item.linkLabel %}<a href="{{ item.linkUrl }}" class="cyberpunk-mono uppercase tracking-wide mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline">{{ item.linkLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -60,8 +60,7 @@
if(W===0||H===0)return; if(W===0||H===0)return;
cv.width=W*dpr;cv.height=H*dpr;ctx.setTransform(dpr,0,0,dpr,0,0); cv.width=W*dpr;cv.height=H*dpr;ctx.setTransform(dpr,0,0,dpr,0,0);
cols=Math.max(1,Math.floor(W/fontSize)); cols=Math.max(1,Math.floor(W/fontSize));
var rows=Math.max(1,Math.floor(H/fontSize)); drops=[];for(var i=0;i<cols;i++)drops[i]=Math.random()*-50;
drops=[];for(var i=0;i<cols;i++)drops[i]=Math.random()*rows;
} }
resize(); resize();
var last=0,fps=1000/18; var last=0,fps=1000/18;

View File

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

View File

@ -10,7 +10,7 @@
{% set bg = backgroundColor|default:"bg-background" %} {% set bg = backgroundColor|default:"bg-background" %}
{% macro navlink(item) %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} class="cyberpunk-mono uppercase tracking-wider px-3 py-2 text-xs font-medium text-foreground/80 hover:text-primary transition-colors {{ item.css_class }}">{{ item.label }}</a>{% endmacro %} {% macro navlink(item) %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %}{% if item.title %} title="{{ item.title }}"{% endif %} class="cyberpunk-mono uppercase tracking-wider px-3 py-2 text-xs font-medium text-foreground/80 hover:text-primary transition-colors {{ item.css_class }}">{{ item.label }}</a>{% endmacro %}
{% macro dropdown(item) %}<div class="relative group"> {% macro dropdown(item) %}<div class="relative group">
<button type="button" class="cyberpunk-mono uppercase tracking-wider px-3 py-2 text-xs font-medium text-foreground/80 hover:text-primary transition-colors inline-flex items-center gap-1">{{ item.label }}<svg width="16" height="16" class="h-4 w-4 transition-transform group-hover:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></button> <button type="button" class="cyberpunk-mono uppercase tracking-wider px-3 py-2 text-xs font-medium text-foreground/80 hover:text-primary transition-colors inline-flex items-center gap-1">{{ item.label }}<svg class="h-4 w-4 transition-transform group-hover:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></button>
{% if use_mega %}<div class="absolute left-1/2 -translate-x-1/2 mt-1 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="p-6 bg-card border border-primary/40 neon-edge-magenta rounded-md shadow-xl grid gap-8" style="grid-template-columns:repeat({{ item.children|length|default:1 }},minmax(10rem,1fr));min-width:min(90vw,42rem)">{% for child in item.children %}<div class="space-y-1">{% if child.item_type == "header" %}<div class="cyberpunk-mono px-2 py-1 text-xs font-semibold text-accent uppercase tracking-widest border-b border-primary/40 mb-2">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 rounded hover:bg-accent transition-colors {{ child.css_class }}">{% if child.icon %}<span class="mr-1.5 text-primary">::{{ child.icon }}::</span>{% endif %}<span class="text-sm font-medium text-foreground">{{ child.label }}</span>{% if child.description %}<span class="block text-xs text-muted-foreground mt-0.5">{{ child.description }}</span>{% endif %}</a>{% endif %}</div>{% endfor %}</div></div> {% if use_mega %}<div class="absolute left-1/2 -translate-x-1/2 mt-1 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="p-6 bg-card border border-primary/40 neon-edge-magenta rounded-md shadow-xl grid gap-8" style="grid-template-columns:repeat({{ item.children|length|default:1 }},minmax(10rem,1fr));min-width:min(90vw,42rem)">{% for child in item.children %}<div class="space-y-1">{% if child.item_type == "header" %}<div class="cyberpunk-mono px-2 py-1 text-xs font-semibold text-accent uppercase tracking-widest border-b border-primary/40 mb-2">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 rounded hover:bg-accent transition-colors {{ child.css_class }}">{% if child.icon %}<span class="mr-1.5 text-primary">::{{ child.icon }}::</span>{% endif %}<span class="text-sm font-medium text-foreground">{{ child.label }}</span>{% if child.description %}<span class="block text-xs text-muted-foreground mt-0.5">{{ child.description }}</span>{% endif %}</a>{% endif %}</div>{% endfor %}</div></div>
{% else %}<div class="absolute left-0 mt-1 w-56 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="py-2 bg-card border border-primary/40 neon-edge-cyan rounded-md shadow-lg">{% for child in item.children %}{% if child.item_type == "header" %}<div class="cyberpunk-mono px-4 py-2 text-xs font-semibold text-accent uppercase tracking-widest">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-4 py-2 text-sm text-foreground hover:bg-accent transition-colors {{ child.css_class }}">{{ child.label }}</a>{% endif %}{% endfor %}</div></div>{% endif %} {% else %}<div class="absolute left-0 mt-1 w-56 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50"><div class="py-2 bg-card border border-primary/40 neon-edge-cyan rounded-md shadow-lg">{% for child in item.children %}{% if child.item_type == "header" %}<div class="cyberpunk-mono px-4 py-2 text-xs font-semibold text-accent uppercase tracking-widest">{{ child.label }}</div>{% else %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-4 py-2 text-sm text-foreground hover:bg-accent transition-colors {{ child.css_class }}">{{ child.label }}</a>{% endif %}{% endfor %}</div></div>{% endif %}
</div>{% endmacro %} </div>{% endmacro %}
@ -33,7 +33,7 @@
<div class="hidden md:flex items-center gap-1">{% for item in menu.items %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endfor %}{{ ctabtn("ml-3") }}</div> <div class="hidden md:flex items-center gap-1">{% for item in menu.items %}{% if item.children %}{{ dropdown(item) }}{% else %}{{ navlink(item) }}{% endif %}{% endfor %}{{ ctabtn("ml-3") }}</div>
{% endif %} {% endif %}
<div class="flex items-center md:hidden"> <div class="flex items-center md:hidden">
<label for="bn-navbar-toggle" data-bn-nav-open aria-controls="bn-navbar-drawer" aria-expanded="false" class="inline-flex items-center justify-center p-2 rounded-md cursor-pointer hover:bg-accent/50 transition-colors"><span class="sr-only">Open menu</span><svg width="24" height="24" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></label> <label for="bn-navbar-toggle" data-bn-nav-open aria-controls="bn-navbar-drawer" aria-expanded="false" class="inline-flex items-center justify-center p-2 rounded-md cursor-pointer hover:bg-accent/50 transition-colors"><span class="sr-only">Open menu</span><svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/></svg></label>
</div> </div>
</div> </div>
</div> </div>
@ -41,8 +41,8 @@
<input type="checkbox" id="bn-navbar-toggle" class="bn-navbar-toggle" aria-hidden="true"/> <input type="checkbox" id="bn-navbar-toggle" class="bn-navbar-toggle" aria-hidden="true"/>
<label for="bn-navbar-toggle" class="bn-navbar-overlay fixed inset-0 bg-black/50 z-40 md:hidden" aria-hidden="true"></label> <label for="bn-navbar-toggle" class="bn-navbar-overlay fixed inset-0 bg-black/50 z-40 md:hidden" aria-hidden="true"></label>
<div id="bn-navbar-drawer" class="bn-navbar-drawer fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-background text-foreground z-50 shadow-xl md:hidden flex flex-col" role="dialog" aria-modal="true" aria-label="Site menu"> <div id="bn-navbar-drawer" class="bn-navbar-drawer fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-background text-foreground z-50 shadow-xl md:hidden flex flex-col" role="dialog" aria-modal="true" aria-label="Site menu">
<div class="flex items-center justify-between p-4 border-b border-primary/30">{{ brand("h-8") }}<label for="bn-navbar-toggle" data-bn-nav-close class="p-2 rounded-md cursor-pointer text-muted-foreground hover:text-primary hover:bg-accent"><span class="sr-only">Close menu</span><svg width="24" height="24" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></label></div> <div class="flex items-center justify-between p-4 border-b border-primary/30">{{ brand("h-8") }}<label for="bn-navbar-toggle" data-bn-nav-close class="p-2 rounded-md cursor-pointer text-muted-foreground hover:text-primary hover:bg-accent"><span class="sr-only">Close menu</span><svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg></label></div>
<nav class="flex-1 overflow-y-auto py-4" aria-label="Mobile">{% for item in menu.items %}{% if item.children %}<details class="group/acc"><summary class="cyberpunk-mono uppercase tracking-wide flex items-center justify-between px-6 py-3 text-sm font-medium cursor-pointer hover:bg-accent transition-colors list-none">{{ item.label }}<svg width="16" height="16" class="h-4 w-4 transition-transform group-open/acc:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></summary><div class="pl-8 pb-2">{% for child in item.children %}{% if child.item_type != "header" %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 text-sm text-muted-foreground hover:text-primary transition-colors">{{ child.label }}</a>{% endif %}{% endfor %}</div></details>{% else %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="cyberpunk-mono uppercase tracking-wide block px-6 py-3 text-sm font-medium hover:bg-accent transition-colors">{{ item.label }}</a>{% endif %}{% endfor %}</nav> <nav class="flex-1 overflow-y-auto py-4" aria-label="Mobile">{% for item in menu.items %}{% if item.children %}<details class="group/acc"><summary class="cyberpunk-mono uppercase tracking-wide flex items-center justify-between px-6 py-3 text-sm font-medium cursor-pointer hover:bg-accent transition-colors list-none">{{ item.label }}<svg class="h-4 w-4 transition-transform group-open/acc:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/></svg></summary><div class="pl-8 pb-2">{% for child in item.children %}{% if child.item_type != "header" %}<a href="{{ child.url|default:'#' }}"{% if child.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="block px-2 py-2 text-sm text-muted-foreground hover:text-primary transition-colors">{{ child.label }}</a>{% endif %}{% endfor %}</div></details>{% else %}<a href="{{ item.url|default:'#' }}"{% if item.open_in_new_tab %} target="_blank" rel="noopener"{% endif %} class="cyberpunk-mono uppercase tracking-wide block px-6 py-3 text-sm font-medium hover:bg-accent transition-colors">{{ item.label }}</a>{% endif %}{% endfor %}</nav>
{% if cta_text %}<div class="p-4 border-t border-primary/30"><a href="{{ cta_url|default:'#' }}" class="cyberpunk-mono uppercase tracking-wider clip-cut block w-full text-center rounded-none bg-primary px-4 py-3 text-base font-semibold text-primary-foreground hover:bg-primary/90 transition-colors">{{ cta_text }}</a></div>{% endif %} {% if cta_text %}<div class="p-4 border-t border-primary/30"><a href="{{ cta_url|default:'#' }}" class="cyberpunk-mono uppercase tracking-wider clip-cut block w-full text-center rounded-none bg-primary px-4 py-3 text-base font-semibold text-primary-foreground hover:bg-primary/90 transition-colors">{{ cta_text }}</a></div>{% endif %}
</div> </div>
</nav> </nav>

View File

@ -7,7 +7,7 @@
<p class="mt-4 text-lg text-muted-foreground">{{ emptyMessage|default:"That route returned nothing. The page moved, shipped, or never existed." }}</p> <p class="mt-4 text-lg text-muted-foreground">{{ emptyMessage|default:"That route returned nothing. The page moved, shipped, or never existed." }}</p>
{% if context.path %}<p class="cyberpunk-mono mt-3 text-sm text-muted-foreground">requested: <span class="text-primary">{{ context.path }}</span></p>{% endif %} {% if context.path %}<p class="cyberpunk-mono mt-3 text-sm text-muted-foreground">requested: <span class="text-primary">{{ context.path }}</span></p>{% endif %}
<div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
<a href="/" class="cyberpunk-mono clip-cut rgb-split inline-flex items-center gap-2 rounded-md bg-primary px-6 py-3 font-semibold uppercase tracking-wider text-primary-foreground transition-opacity hover:opacity-90"><svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg>Back to home</a> <a href="/" class="cyberpunk-mono clip-cut rgb-split inline-flex items-center gap-2 rounded-md bg-primary px-6 py-3 font-semibold uppercase tracking-wider text-primary-foreground transition-opacity hover:opacity-90"><svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg>Back to home</a>
</div> </div>
</div> </div>
</section> </section>

View File

@ -15,7 +15,7 @@
</p> </p>
{% if tier.description %}<p class="mt-3 text-sm text-muted-foreground">{{ tier.description }}</p>{% endif %} {% if tier.description %}<p class="mt-3 text-sm text-muted-foreground">{{ tier.description }}</p>{% endif %}
{% if tier.features %}<ul class="mt-6 flex-1 space-y-3 text-sm"> {% if tier.features %}<ul class="mt-6 flex-1 space-y-3 text-sm">
{% for feature in tier.features %}<li class="flex items-start gap-2"><svg width="16" height="16" class="mt-0.5 h-4 w-4 shrink-0 text-primary" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg><span>{{ feature }}</span></li>{% endfor %} {% for feature in tier.features %}<li class="flex items-start gap-2"><svg class="mt-0.5 h-4 w-4 shrink-0 text-primary" aria-hidden="true"><use href="/icons/lucide.svg#check"></use></svg><span>{{ feature }}</span></li>{% endfor %}
</ul>{% endif %} </ul>{% endif %}
{% if tier.ctaUrl and tier.ctaLabel %}<a href="{{ tier.ctaUrl }}" class="cyberpunk-mono uppercase tracking-wider clip-cut mt-8 inline-flex w-full items-center justify-center rounded-none px-5 py-3 font-semibold transition-opacity hover:opacity-90 {% if tier.highlighted %}rgb-split bg-primary text-primary-foreground{% else %}border border-primary/40 bg-background text-foreground hover:bg-muted{% endif %}">{{ tier.ctaLabel }}</a>{% endif %} {% if tier.ctaUrl and tier.ctaLabel %}<a href="{{ tier.ctaUrl }}" class="cyberpunk-mono uppercase tracking-wider clip-cut mt-8 inline-flex w-full items-center justify-center rounded-none px-5 py-3 font-semibold transition-opacity hover:opacity-90 {% if tier.highlighted %}rgb-split bg-primary text-primary-foreground{% else %}border border-primary/40 bg-background text-foreground hover:bg-muted{% endif %}">{{ tier.ctaLabel }}</a>{% endif %}
</div> </div>

View File

@ -5,7 +5,7 @@
{% if eyebrow %}<p class="cyberpunk-mono text-xs font-semibold uppercase tracking-widest text-accent">{{ eyebrow }}</p>{% endif %} {% if eyebrow %}<p class="cyberpunk-mono text-xs font-semibold uppercase tracking-widest text-accent">{{ eyebrow }}</p>{% endif %}
{% if heading %}<h2 class="cyberpunk-display glitch mt-2 text-3xl font-semibold tracking-tight md:text-4xl" data-text="{{ heading }}">{{ heading }}</h2>{% endif %} {% if heading %}<h2 class="cyberpunk-display glitch mt-2 text-3xl font-semibold tracking-tight md:text-4xl" data-text="{{ heading }}">{{ heading }}</h2>{% endif %}
{% if body %}<div class="mt-4 space-y-4 text-lg text-muted-foreground [&_a]:text-primary [&_a]:underline [&_strong]:text-foreground">{{ body|safe }}</div>{% endif %} {% if body %}<div class="mt-4 space-y-4 text-lg text-muted-foreground [&_a]:text-primary [&_a]:underline [&_strong]:text-foreground">{{ body|safe }}</div>{% endif %}
{% if ctaUrl and ctaLabel %}<a href="{{ ctaUrl }}" class="cyberpunk-mono uppercase tracking-wider clip-cut rgb-split mt-6 inline-flex items-center gap-2 rounded-none bg-primary px-5 py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90">{{ ctaLabel }}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %} {% if ctaUrl and ctaLabel %}<a href="{{ ctaUrl }}" class="cyberpunk-mono uppercase tracking-wider clip-cut rgb-split mt-6 inline-flex items-center gap-2 rounded-none bg-primary px-5 py-3 font-semibold text-primary-foreground transition-opacity hover:opacity-90">{{ ctaLabel }}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#arrow-right"></use></svg></a>{% endif %}
</div> </div>
<div class="{% if mediaPosition == "left" %}md:order-1{% else %}md:order-2{% endif %}"> <div class="{% if mediaPosition == "left" %}md:order-1{% else %}md:order-2{% endif %}">
{% if media %}<div class="hud-frame overflow-hidden rounded-md border border-dashed border-primary/50 neon-edge-cyan">{% img media alt=mediaAlt class="w-full h-auto object-cover" %}</div>{% endif %} {% if media %}<div class="hud-frame overflow-hidden rounded-md border border-dashed border-primary/50 neon-edge-cyan">{% img media alt=mediaAlt class="w-full h-auto object-cover" %}</div>{% endif %}

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@
{% for step in steps %} {% for step in steps %}
<li class="{% if orientation == "horizontal" %}text-center{% else %}relative pl-14{% endif %}"> <li class="{% if orientation == "horizontal" %}text-center{% else %}relative pl-14{% endif %}">
<span class="clip-cut flex h-8 w-8 items-center justify-center rounded-md bg-primary text-sm font-semibold text-primary-foreground cyberpunk-mono {% if orientation == "horizontal" %}mx-auto{% else %}absolute left-0 top-0 ring-4 ring-background{% endif %}"> <span class="clip-cut flex h-8 w-8 items-center justify-center rounded-md bg-primary text-sm font-semibold text-primary-foreground cyberpunk-mono {% if orientation == "horizontal" %}mx-auto{% else %}absolute left-0 top-0 ring-4 ring-background{% endif %}">
{% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}<span class="h-2 w-2 rounded-full bg-primary-foreground"></span>{% else %}<svg width="16" height="16" class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#flag"></use></svg>{% endif %} {% if marker == "numbered" %}{{ forloop.counter }}{% elif marker == "dot" %}<span class="h-2 w-2 rounded-full bg-primary-foreground"></span>{% else %}<svg class="h-4 w-4" aria-hidden="true"><use href="/icons/lucide.svg#flag"></use></svg>{% endif %}
</span> </span>
<div class="{% if orientation == "horizontal" %}mt-4{% else %}pt-1{% endif %}"> <div class="{% if orientation == "horizontal" %}mt-4{% else %}pt-1{% endif %}">
{% if step.label %}<p class="cyberpunk-mono text-xs font-semibold uppercase tracking-widest text-accent">{{ step.label }}</p>{% endif %} {% if step.label %}<p class="cyberpunk-mono text-xs font-semibold uppercase tracking-widest text-accent">{{ step.label }}</p>{% endif %}