Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

landing-v2.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

landing-v2.tsxBlame1447 lines · 1 contributor
11c3ab6ccanty labs1import type { FC } from "hono/jsx";
2
3export interface LandingPageProps {
4 stats?: {
5 publicRepos?: number;
6 users?: number;
7 };
8}
9
10const demoAllEvents = [
11 { title: "Push received", time: "now", dot: "#16181d", body: "feat/repair-sandbox-loop — gates fire at the wire, not in a queue." },
12 { title: "Sonnet 5 review posted", time: "now", dot: "#4353c9", body: "Line-level comments, one risk flag, verdict: approve pending gates." },
13 { title: "Gate failed — repair engaged", time: "now", dot: "#b45309", body: "2 tests red. The agent attached to the PR sandbox and reproduced both in isolation." },
14 { title: "Patch drafted, gates re-run", time: "now", dot: "#b45309", body: "Bounded the repair loop, threaded the sandbox session. All 412 tests green." },
15 { title: "Merged & deployed", time: "now", dot: "#1e7f5c", body: "One human approval, then auto-merge and deploy. Fully reversible in one click." },
16];
17
18const tickerItems = [
19 { dot: "#1e7f5c", text: "auto-merge · northwind-labs/api №341 — gates green" },
20 { dot: "#b45309", text: "repair · acme-tools/web №88 — attempt 2 of 5" },
21 { dot: "#4353c9", text: "review · Sonnet 5 posted 6 comments on helvetia/core №129" },
22 { dot: "#1e7f5c", text: "deploy · gluecron 82321e8 → production, 41s" },
23 { dot: "#1e7f5c", text: "fleet · auth-header rename merged atomically across 4 repos" },
24 { dot: "#4353c9", text: "sandbox · pr-220.preview booted" },
25 { dot: "#1e7f5c", text: "flaky test assassinated · sandbox-boot.test.ts fixed after bisect" },
26 { dot: "#b45309", text: "advisory · transitive CVE patched, exposure 19 min" },
27 { dot: "#1e7f5c", text: "auto-merge · northwind-labs/api №341 — gates green" },
28 { dot: "#b45309", text: "repair · acme-tools/web №88 — attempt 2 of 5" },
29 { dot: "#4353c9", text: "review · Sonnet 5 posted 6 comments on helvetia/core №129" },
30 { dot: "#1e7f5c", text: "deploy · gluecron 82321e8 → production, 41s" },
31 { dot: "#1e7f5c", text: "fleet · auth-header rename merged atomically across 4 repos" },
32 { dot: "#4353c9", text: "sandbox · pr-220.preview booted" },
33 { dot: "#1e7f5c", text: "flaky test assassinated · sandbox-boot.test.ts fixed after bisect" },
34 { dot: "#b45309", text: "advisory · transitive CVE patched, exposure 19 min" },
35];
36
37const stageData = [
38 { name: "Push", desc: "Git-native Smart HTTP. Your existing workflow, unchanged.", meta: "no queue, ever" },
39 { name: "Gate", desc: "Security, tests, types — enforced at the moment of push.", meta: "before the branch moves" },
40 { name: "Review", desc: "Sonnet 5 reviews the instant the PR opens. Line-level, auditable.", meta: "the model devs trust" },
41 { name: "Repair", desc: "Red gate? The agent fixes it inside an isolated sandbox.", meta: "93.5% self-heal" },
42 { name: "Merge", desc: "Green across the board merges immediately — with your approval policy.", meta: "you set the policy" },
43 { name: "Deploy", desc: "Streams live to the dashboard. One-click rollback, always.", meta: "reversible by design" },
44];
45
46const heroFeatures = [
47 {
48 href: "/",
49 eyebrow: "01 · The autonomous repair loop",
50 title: "Failures fix themselves — and show their work.",
51 body: "When a gate goes red, the repair engine attaches to the PR's own sandbox, reproduces the failure, drafts a bounded patch, and re-runs the gates. Every attempt is recorded to the flywheel with the failing gate, the diff, and the outcome. You watch it happen live, interrupt any time, or take the keyboard yourself.",
52 cta: "Watch a live repair session",
53 mock: [
54 { dot: "#b42318", color: "#b42318", text: "✗ gate: tests — 2 failing" },
55 { dot: "#b45309", color: "#b45309", text: "agent attached · sandbox pr-218" },
56 { dot: "#b45309", color: "#b45309", text: "patch drafted · +9 −3 · bounded loop" },
57 { dot: "#1e7f5c", color: "#1e7f5c", text: "✓ gates re-run — 412 passing" },
58 { dot: "#1e7f5c", color: "#8a8d99", text: "waiting on your approval" },
59 ],
60 },
61 {
62 href: "/",
63 eyebrow: "02 · Live sandbox isolation",
64 title: "Every PR gets its own instant, disposable environment.",
65 body: "The moment a PR opens, an isolated environment boots on your hardware: preview URL, shared terminal, real data shape. Reviewers click a link instead of pulling a branch. Agents repair inside the same box they broke nothing in. It expires on merge and leaves an audit trail behind.",
66 cta: "See a PR with its sandbox",
67 mock: [
68 { dot: "#1e7f5c", color: "#1e7f5c", text: "pr-218.preview.gluecron.com · live" },
69 { dot: "#c4c6cf", color: "#8a8d99", text: "isolated · branch-scoped · your metal" },
70 { dot: "#4353c9", color: "#4353c9", text: "reviewer joined the shared terminal" },
71 { dot: "#c4c6cf", color: "#8a8d99", text: "expires on merge · audit retained" },
72 ],
73 },
74 {
75 href: "/",
76 eyebrow: "03 · Multiplayer IDE workspaces",
77 title: "You and the agent, side by side, in your editor.",
78 body: "The VS Code and JetBrains extensions join the same live session: you see the agent's cursor, it sees your edits, and either of you can take over. Prefer to fly solo? Observe-only mode turns the agent into a silent reviewer in your gutter. The browser becomes optional.",
79 cta: "See the editor session",
80 mock: [
81 { dot: "#4353c9", color: "#4353c9", text: "you: the loop needs an upper bound" },
82 { dot: "#1e7f5c", color: "#1e7f5c", text: "claude: agreed — typing lines 151–154" },
83 { dot: "#1e7f5c", color: "#d6d8e0", text: "+ for (let i = 0; i < MAX_ATTEMPTS; i++)" },
84 { dot: "#c4c6cf", color: "#8a8d99", text: "mode: suggest → you accept · or observe-only" },
85 ],
86 },
87];
88
89const capabilities = [
90 { group: "Code hosting", items: ["Git Smart HTTP", "SSH, PATs, OAuth2 provider", "Forks, stars, templates, mirrors", "Releases & protected tags", "Push policy rulesets"] },
91 { group: "Collaboration", items: ["Issues, labels, milestones", "Inline review & draft PRs", "Merge queues", "Discussions, wikis, projects", "Gists & reactions"] },
92 { group: "AI-native", items: ["Sonnet 5 code review", "Security review + secret scanner", "Auto-repair engine", "Spec-to-PR with plan approval", "Merge-conflict resolver", "Org memory & archaeology"] },
93 { group: "Automation", items: ["Push-time gates", "Workflow runner, zero YAML", "HMAC webhooks", "Dependency updater", "CODEOWNERS auto-sync"] },
94 { group: "Platform", items: ["Orgs, teams, roles", "2FA, passkeys, OIDC SSO", "npm package registry", "Static pages hosting", "REST + GraphQL + MCP"] },
95 { group: "Sovereignty", items: ["Self-host anywhere Bun runs", "Local LLM routing", "Air-gapped region sync", "Own-edge Caddy ingress", "Data-region residency"] },
96 { group: "Observability", items: ["Request-ID tracing", "Audit log, 100% coverage", "Traffic analytics", "Org insights & green rate", "Health scores"] },
97 { group: "Trust", items: ["Live public quality metrics", "Blast radius before approval", "One-click reversal", "Zero irreversible auto-actions", "Manual twin for every surface"] },
98];
99
100const sovereignLayerNames = [
101 "Frontend foundation", "APIs & backend logic", "Database & storage", "Auth & permissions",
102 "Hosting & deployment", "Cloud & compute", "CI/CD & version control", "Security & RLS",
103 "Rate limiting", "Caching & CDN", "Load balancing & scaling", "Error tracking & logs",
104 "Availability & recovery",
105];
106
107export const LandingPageV2: FC<LandingPageProps> = (_props) => {
108 return (
109 <>
110 <style dangerouslySetInnerHTML={{ __html: css }} />
111
112 {/* Nav */}
113 <header class="lv-nav">
114 <div class="lv-nav-inner">
115 <a href="/" class="lv-logo">
116 <span class="lv-logo-mark"></span>gluecron
117 </a>
118 <nav class="lv-nav-links">
119 <a href="#loop" class="lv-nav-link">The loop</a>
120 <a href="#platform" class="lv-nav-link">Platform</a>
121 <a href="#sovereign" class="lv-nav-link">Sovereignty</a>
122 <a href="/trust" class="lv-nav-link">Trust</a>
123 </nav>
124 <div class="lv-nav-ctas">
125 <a href="/login" class="lv-btn-secondary">Sign in</a>
126 <a href="/register" class="lv-btn-primary">Start building</a>
127 </div>
128 </div>
129 </header>
130
131 {/* Hero */}
132 <section class="lv-hero">
133 <div class="lv-hero-glow"></div>
134 <div class="lv-hero-inner">
135 <div class="lv-hero-badge">
136 <span class="lv-dot lv-dot-green lv-pulse"></span>
137 Live: a repair loop converged on pr-218 while you read this
138 </div>
139 <h1 class="lv-h1">Your PR is done before the dinosaurs finish booting.</h1>
140 <p class="lv-hero-sub">
141 No CI queue. No pipeline warm-up. Gates fire <strong class="lv-strong">at the moment of push</strong>, <strong class="lv-strong">Claude Sonnet 5</strong> reviews the instant your PR opens, failures repair themselves in isolated sandboxes, and clean work merges immediately. You stay in flow — and the manual path is always one click away.
142 </p>
143 <div class="lv-hero-actions">
144 <a href="/register" class="lv-cta-primary">Start building — free →</a>
145 <a href="/" class="lv-cta-secondary">Watch a live repair</a>
146 </div>
147 <div class="lv-hero-tag">Self-hosted · Git-native · Sonnet 5 reviews · Manual-always-possible</div>
148
149 {/* Live product window */}
150 <div class="lv-demo-window">
151 <div class="lv-demo-bar">
152 <span class="lv-demo-dot"></span>
153 <span class="lv-demo-dot"></span>
154 <span class="lv-demo-dot"></span>
155 <span class="lv-demo-url">gluecron.com / ccantynz-alt / gluecron · PR №218 · live</span>
156 <span class="lv-demo-live">
157 <span class="lv-dot lv-dot-green lv-pulse" style="width:6px;height:6px"></span>
158 LIVE
159 </span>
160 </div>
161 <div class="lv-demo-body" id="lv-demo-body">
162 {/* Events rendered by JS */}
163 {demoAllEvents.slice(0, 1).map((e, i) => (
164 <div class="lv-demo-event" key={i}>
165 <div class="lv-demo-event-track">
166 <span class="lv-dot lv-pulse" style={`width:8px;height:8px;background:${e.dot}`}></span>
167 <span class="lv-demo-line" style="display:none"></span>
168 </div>
169 <div class="lv-demo-event-content">
170 <div class="lv-demo-event-header">
171 <span class="lv-demo-event-title">{e.title}</span>
172 <span class="lv-demo-event-time">{e.time}</span>
173 </div>
174 <div class="lv-demo-event-body">{e.body}</div>
175 </div>
176 </div>
177 ))}
178 </div>
179 </div>
180 </div>
181
182 {/* Activity ticker */}
183 <div class="lv-ticker-wrap">
184 <div class="lv-ticker-track">
185 {tickerItems.map((t, i) => (
186 <span class="lv-ticker-item" key={i}>
187 <span class="lv-dot" style={`width:6px;height:6px;background:${t.dot}`}></span>
188 {t.text}
189 </span>
190 ))}
191 </div>
192 </div>
193 </section>
194
195 {/* Stat band */}
196 <section class="lv-stats">
197 <div class="lv-stats-inner">
198 <div class="lv-stat">
199 <div class="lv-stat-num">Sonnet 5</div>
200 <div class="lv-stat-label">reviews every pull request — the model developers trust</div>
201 </div>
202 <div class="lv-stat">
203 <div class="lv-stat-num">93.5%</div>
204 <div class="lv-stat-label">of failures self-repair without a human</div>
205 </div>
206 <div class="lv-stat">
207 <div class="lv-stat-num">1.9%</div>
208 <div class="lv-stat-label">AI merges reverted — published live</div>
209 </div>
210 <div class="lv-stat">
211 <div class="lv-stat-num">0</div>
212 <div class="lv-stat-label">irreversible actions taken autonomously</div>
213 </div>
214 </div>
215 </section>
216
217 {/* The loop */}
218 <section id="loop" class="lv-loop">
219 <div class="lv-loop-inner">
220 <div class="lv-section-header">
221 <div class="lv-eyebrow lv-eyebrow-indigo">The closed loop — running now</div>
222 <h2 class="lv-h2">Push. Gate. Review. Repair. Merge. Deploy.</h2>
223 <p class="lv-section-sub">Six stages, zero YAML, full audit trail. The highlighted stage is cycling live — this is the pipeline, not a diagram of one.</p>
224 </div>
225 <div class="lv-stages" id="lv-stages">
226 {stageData.map((s, i) => (
227 <div class={`lv-stage-card${i === 0 ? " lv-stage-active" : ""}`} key={i} data-stage={i}>
228 <div class="lv-stage-header">
229 <span class={`lv-dot${i === 0 ? " lv-dot-indigo lv-pulse" : " lv-dot-idle"}`} style="width:7px;height:7px"></span>
230 <span class="lv-stage-n">0{i + 1}</span>
231 </div>
232 <div class="lv-stage-name">{s.name}</div>
233 <div class="lv-stage-desc">{s.desc}</div>
234 <div class={`lv-stage-meta${i === 0 ? " lv-stage-meta-active" : ""}`}>{s.meta}</div>
235 </div>
236 ))}
237 </div>
238 </div>
239 </section>
240
241 {/* Three heroes */}
242 <section class="lv-heroes">
243 <div class="lv-heroes-inner">
244 <div class="lv-heroes-header">
245 <div class="lv-eyebrow lv-eyebrow-indigo">Three things nobody else has</div>
246 <h2 class="lv-h2">Legacy hosts store code.<br />Gluecron finishes it.</h2>
247 </div>
248 <div class="lv-heroes-list">
249 {heroFeatures.map((h, i) => (
250 <a href={h.href} class="lv-hero-card" key={i}>
251 <div class="lv-hero-card-left">
252 <div class="lv-eyebrow">{h.eyebrow}</div>
253 <h3 class="lv-hero-card-title">{h.title}</h3>
254 <p class="lv-hero-card-body">{h.body}</p>
255 <span class="lv-hero-card-cta">{h.cta} →</span>
256 </div>
257 <div class="lv-terminal">
258 {h.mock.map((m, j) => (
259 <div class="lv-terminal-line" key={j}>
260 <span class="lv-dot" style={`width:6px;height:6px;background:${m.dot};flex-shrink:0`}></span>
261 <span style={`color:${m.color};overflow:hidden;text-overflow:ellipsis`}>{m.text}</span>
262 </div>
263 ))}
264 </div>
265 </a>
266 ))}
267 </div>
268 </div>
269 </section>
270
271 {/* Everything grid */}
272 <section id="platform" class="lv-platform">
273 <div class="lv-platform-inner">
274 <div class="lv-section-header lv-section-header-center">
275 <div class="lv-eyebrow lv-eyebrow-indigo">The whole platform, day one</div>
276 <h2 class="lv-h2">Everything you'd assemble from five vendors. Built in.</h2>
277 <p class="lv-section-sub">No marketplace scavenger hunt. Every capability below ships with your first push — on by default, opt out per feature.</p>
278 </div>
279 <div class="lv-cap-grid">
280 {capabilities.map((c, i) => (
281 <div class="lv-cap-col" key={i}>
282 <div class="lv-cap-group">{c.group}</div>
283 <div class="lv-cap-items">
284 {c.items.map((item, j) => (
285 <div class="lv-cap-item" key={j}>{item}</div>
286 ))}
287 </div>
288 </div>
289 ))}
290 </div>
291 </div>
292 </section>
293
294 {/* Sovereignty band */}
295 <section id="sovereign" class="lv-sovereign">
296 <div class="lv-sovereign-grid-bg"></div>
297 <div class="lv-sovereign-inner">
298 <div class="lv-section-header lv-section-header-center lv-section-header-dark">
299 <div class="lv-eyebrow lv-eyebrow-light">Infrastructure sovereignty</div>
300 <h2 class="lv-h2-dark">Your code. Your servers. Your models. Your keys.</h2>
301 <p class="lv-section-sub-dark">Thirteen production layers with zero external runtime dependencies — no magic edge proxies, no third-party CDN in the serving path. Route AI to local models, burst to private cloud, or run fully air-gapped on bare metal.</p>
302 </div>
303 <div class="lv-layers-grid">
304 {sovereignLayerNames.map((name, i) => (
305 <div class="lv-layer-chip" key={i}>
306 <div class="lv-layer-n">{String(i + 1).padStart(2, "0")}</div>
307 <div class="lv-layer-name">{name}</div>
308 </div>
309 ))}
310 <a href="/" class="lv-layer-chip lv-layer-cta">
311 <div class="lv-layer-cta-text">All self-owned →</div>
312 </a>
313 </div>
314 <div class="lv-sovereign-feats">
315 <div class="lv-sovereign-feat">
316 <div class="lv-sovereign-feat-title">Local inference first</div>
317 <div class="lv-sovereign-feat-sub">your hardware, private cloud only on burst</div>
318 </div>
319 <div class="lv-sovereign-feat">
320 <div class="lv-sovereign-feat-title">Air-gapped sync</div>
321 <div class="lv-sovereign-feat-sub">repos, indices, and registries to bare metal</div>
322 </div>
323 <div class="lv-sovereign-feat">
324 <div class="lv-sovereign-feat-title">Self-healing infra</div>
325 <div class="lv-sovereign-feat-sub">the platform repairs itself with the same engine</div>
326 </div>
327 </div>
328 </div>
329 </section>
330
331 {/* Manual-first + reversibility */}
332 <section class="lv-twin">
333 <div class="lv-twin-inner">
334 <div class="lv-twin-card">
335 <div class="lv-eyebrow">Manual-first, always</div>
336 <h3 class="lv-twin-title">Every AI surface has a manual twin.</h3>
337 <p class="lv-twin-body">Pull up the raw diff. Work the merge by hand. Set agents to observe-only, per repo or per developer. The manual path is the same first-class UI — never a degraded fallback. Developers who never touch AI get the best git host they've ever used.</p>
338 </div>
339 <div class="lv-twin-card">
340 <div class="lv-eyebrow">The reversibility guarantee</div>
341 <h3 class="lv-twin-title">One click undoes anything the AI did.</h3>
342 <p class="lv-twin-body">Every autonomous merge, repair, and deploy shows its blast radius before you approve and reverses in one click after. If it can't be reversed, it isn't done autonomously — policy, not promise. Our quality numbers are published live, unedited.</p>
343 <a href="/trust" class="lv-twin-link">See the live trust report →</a>
344 </div>
345 </div>
346 </section>
347
348 {/* Quote */}
349 <section class="lv-quote">
350 <div class="lv-quote-inner">
351 <p class="lv-quote-text">
352 "GitHub gives you a place to <em class="lv-em">store</em> code.<br />
353 Gluecron is where code gets <em class="lv-em">finished</em>."
354 </p>
355 </div>
356 </section>
357
358 {/* CTA */}
359 <section class="lv-cta-section">
360 <div class="lv-cta-card">
361 <div class="lv-cta-glow"></div>
362 <h2 class="lv-cta-h2">The next decade of shipping starts with one push.</h2>
363 <p class="lv-cta-sub">Migrate from GitHub in one click — continuous two-way mirror, zero cutover risk, leave whenever you want.</p>
364 <div class="lv-cta-actions">
365 <a href="/register" class="lv-cta-primary">Create your account →</a>
366 <a href="/" class="lv-cta-secondary">Migrate from GitHub</a>
367 </div>
368 <div class="lv-cta-fine">free for individuals · internal orgs never billed · try without signing up at /play</div>
369 </div>
370 </section>
371
372 {/* Footer */}
373 <footer class="lv-footer">
374 <div class="lv-footer-inner">
375 <div class="lv-footer-brand">
376 <a href="/" class="lv-logo">
377 <span class="lv-logo-mark"></span>gluecron
378 </a>
379 <p class="lv-footer-tagline">The AI-native git host. Self-hosted, auditable, reversible — and fully manual whenever you want it.</p>
380 </div>
381 <div class="lv-footer-cols">
382 <div class="lv-footer-col">
383 <h4 class="lv-footer-col-head">Product</h4>
384 <a href="/" class="lv-footer-link">Agent workspace</a>
385 <a href="/" class="lv-footer-link">Fleet refactors</a>
386 <a href="/" class="lv-footer-link">Org memory</a>
387 <a href="/" class="lv-footer-link">IDE extensions</a>
388 </div>
389 <div class="lv-footer-col">
390 <h4 class="lv-footer-col-head">Platform</h4>
391 <a href="/" class="lv-footer-link">Production layers</a>
392 <a href="/trust" class="lv-footer-link">Trust report</a>
393 <a href="/" class="lv-footer-link">Docs</a>
394 <a href="/" class="lv-footer-link">Status</a>
395 </div>
396 <div class="lv-footer-col">
397 <h4 class="lv-footer-col-head">Company</h4>
398 <a href="/" class="lv-footer-link">About</a>
399 <a href="/" class="lv-footer-link">Pricing</a>
400 <a href="/" class="lv-footer-link">Enterprise</a>
401 </div>
402 </div>
403 </div>
404 <div class="lv-footer-bar">
405 <span>© 2026 Gluecron</span>
406 <span class="lv-footer-stack">Self-hosted · Git-native · Sonnet 5 · Reversible</span>
407 </div>
408 </footer>
409
410 <script dangerouslySetInnerHTML={{ __html: clientScript }} />
411 </>
412 );
413};
414
415export const LandingPage = LandingPageV2;
416export default LandingPageV2;
417
418const clientScript = `
419(function() {
420 var demoAll = [
421 { title: "Push received", time: "now", dot: "#16181d", body: "feat/repair-sandbox-loop — gates fire at the wire, not in a queue." },
422 { title: "Sonnet 5 review posted", time: "now", dot: "#4353c9", body: "Line-level comments, one risk flag, verdict: approve pending gates." },
423 { title: "Gate failed — repair engaged", time: "now", dot: "#b45309", body: "2 tests red. The agent attached to the PR sandbox and reproduced both in isolation." },
424 { title: "Patch drafted, gates re-run", time: "now", dot: "#b45309", body: "Bounded the repair loop, threaded the sandbox session. All 412 tests green." },
425 { title: "Merged & deployed", time: "now", dot: "#1e7f5c", body: "One human approval, then auto-merge and deploy. Fully reversible in one click." },
426 ];
427
428 var demoStep = 0;
429 var stage = 0;
430
431 function renderDemo() {
432 var container = document.getElementById('lv-demo-body');
433 if (!container) return;
434 var visible = demoAll.slice(0, demoStep + 1);
435 container.innerHTML = visible.map(function(e, i) {
436 var isLast = i === visible.length - 1;
437 var pulse = isLast && demoStep < 4 ? 'lv-pulse' : '';
438 return '<div class="lv-demo-event">' +
439 '<div class="lv-demo-event-track">' +
440 '<span class="lv-dot ' + pulse + '" style="width:8px;height:8px;background:' + e.dot + '"></span>' +
441 '<span class="lv-demo-line" style="display:' + (isLast ? 'none' : 'block') + '"></span>' +
442 '</div>' +
443 '<div class="lv-demo-event-content">' +
444 '<div class="lv-demo-event-header">' +
445 '<span class="lv-demo-event-title">' + e.title + '</span>' +
446 '<span class="lv-demo-event-time">' + e.time + '</span>' +
447 '</div>' +
448 '<div class="lv-demo-event-body">' + e.body + '</div>' +
449 '</div>' +
450 '</div>';
451 }).join('');
452 }
453
454 function renderStages() {
455 var cards = document.querySelectorAll('.lv-stage-card');
456 cards.forEach(function(card, i) {
457 var dot = card.querySelector('.lv-dot');
458 var meta = card.querySelector('.lv-stage-meta');
459 if (i === stage) {
460 card.classList.add('lv-stage-active');
461 if (dot) {
462 dot.classList.remove('lv-dot-idle');
463 dot.classList.add('lv-dot-indigo', 'lv-pulse');
464 }
465 if (meta) meta.classList.add('lv-stage-meta-active');
466 } else {
467 card.classList.remove('lv-stage-active');
468 if (dot) {
469 dot.classList.add('lv-dot-idle');
470 dot.classList.remove('lv-dot-indigo', 'lv-pulse');
471 }
472 if (meta) meta.classList.remove('lv-stage-meta-active');
473 }
474 });
475 }
476
477 renderDemo();
478
479 setInterval(function() {
480 demoStep = (demoStep + 1) % 5;
481 renderDemo();
482 }, 3600);
483
484 setInterval(function() {
485 stage = (stage + 1) % 6;
486 renderStages();
487 }, 2200);
488})();
489`;
490
491const css = `
492@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;450;500;600;700&family=Inter+Tight:wght@500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
493
494*, *::before, *::after { box-sizing: border-box; }
495
496body {
497 margin: 0;
498 background: #fcfcfd;
499 -webkit-font-smoothing: antialiased;
500 text-rendering: optimizeLegibility;
501 font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
502 font-size: 15px;
503 line-height: 1.6;
504 letter-spacing: -0.008em;
505 color: #16181d;
506}
507
508@keyframes gcPulse {
509 0%, 100% { opacity: 1; }
510 50% { opacity: 0.35; }
511}
512
513@keyframes gcTicker {
514 0% { transform: translateX(0); }
515 100% { transform: translateX(-50%); }
516}
517
518/* Shared utilities */
519.lv-dot {
520 display: inline-block;
521 border-radius: 50%;
522}
523.lv-dot-green { background: #1e7f5c; }
524.lv-dot-indigo { background: #4353c9; }
525.lv-dot-idle { background: #c4c6cf; }
526.lv-pulse { animation: gcPulse 1.4s ease-in-out infinite; }
527
528.lv-strong { color: #16181d; font-weight: 600; }
529
530.lv-eyebrow {
531 font-family: 'JetBrains Mono', monospace;
532 font-size: 11px;
533 letter-spacing: 0.12em;
534 text-transform: uppercase;
535 color: #8a8d99;
536 font-weight: 500;
537 margin-bottom: 12px;
538}
539.lv-eyebrow-indigo { color: #4353c9; font-size: 11.5px; margin-bottom: 16px; }
540.lv-eyebrow-light { color: #a9b4ee; font-size: 11.5px; margin-bottom: 16px; }
541
542.lv-h1 {
543 font-family: 'Inter Tight', sans-serif;
544 font-weight: 700;
545 letter-spacing: -0.035em;
546 font-size: clamp(44px, 7vw, 84px);
547 line-height: 0.98;
548 margin: 30px auto 0;
549 max-width: 14ch;
550 color: #111318;
551}
552
553.lv-h2 {
554 font-family: 'Inter Tight', sans-serif;
555 font-weight: 700;
556 letter-spacing: -0.028em;
557 font-size: clamp(30px, 4.4vw, 48px);
558 line-height: 1.05;
559 margin: 0;
560 color: #111318;
561}
562
563.lv-h2-dark {
564 font-family: 'Inter Tight', sans-serif;
565 font-weight: 700;
566 letter-spacing: -0.028em;
567 font-size: clamp(30px, 4.6vw, 52px);
568 line-height: 1.05;
569 margin: 0;
570 color: #fff;
571}
572
573.lv-section-header {
574 max-width: 640px;
575 margin: 0 auto 56px;
576}
577
578.lv-section-header-center {
579 text-align: center;
580}
581
582.lv-section-sub {
583 color: #6b7080;
584 font-size: 17px;
585 margin: 18px auto 0;
586 max-width: 52ch;
587}
588
589.lv-section-sub-dark {
590 color: rgba(255,255,255,0.72);
591 font-size: 17px;
592 margin: 18px auto 0;
593 max-width: 56ch;
594}
595
596/* Nav */
597.lv-nav {
598 position: sticky;
599 top: 0;
600 z-index: 60;
601 backdrop-filter: saturate(180%) blur(14px);
602 -webkit-backdrop-filter: saturate(180%) blur(14px);
603 background: rgba(252,252,253,0.8);
604 border-bottom: 1px solid rgba(22,24,29,0.07);
605}
606
607.lv-nav-inner {
608 max-width: 1200px;
609 margin: 0 auto;
610 padding: 14px 28px;
611 display: flex;
612 align-items: center;
613 gap: 28px;
614}
615
616.lv-logo {
617 display: inline-flex;
618 align-items: center;
619 gap: 9px;
620 font-family: 'Inter Tight', sans-serif;
621 font-weight: 700;
622 font-size: 17px;
623 letter-spacing: -0.02em;
624 color: #16181d;
625 text-decoration: none;
626}
627
628.lv-logo-mark {
629 width: 17px;
630 height: 17px;
631 border-radius: 5px;
632 background: #4353c9;
633 display: inline-block;
634 flex-shrink: 0;
635}
636
637.lv-nav-links {
638 display: flex;
639 gap: 24px;
640 font-size: 13.5px;
641 font-weight: 500;
642}
643
644.lv-nav-link {
645 color: #6b7080;
646 text-decoration: none;
647 transition: color 0.15s;
648}
649.lv-nav-link:hover { color: #16181d; }
650
651.lv-nav-ctas {
652 margin-left: auto;
653 display: flex;
654 align-items: center;
655 gap: 10px;
656}
657
658.lv-btn-secondary {
659 padding: 8px 15px;
660 border-radius: 8px;
661 font-size: 13.5px;
662 font-weight: 500;
663 color: #16181d;
664 border: 1px solid rgba(22,24,29,0.12);
665 background: #ffffff;
666 text-decoration: none;
667 white-space: nowrap;
668 transition: border-color 0.15s;
669}
670.lv-btn-secondary:hover { border-color: rgba(22,24,29,0.28); }
671
672.lv-btn-primary {
673 padding: 8px 15px;
674 border-radius: 8px;
675 font-size: 13.5px;
676 font-weight: 600;
677 background: #16181d;
678 color: #fff;
679 text-decoration: none;
680 white-space: nowrap;
681 transition: box-shadow 0.15s;
682}
683.lv-btn-primary:hover { box-shadow: 0 8px 22px rgba(22,24,29,0.18); }
684
685/* Hero */
686.lv-hero {
687 position: relative;
688 overflow: hidden;
689 padding: 88px 0 0;
690}
691
692.lv-hero-glow {
693 position: absolute;
694 inset: -10% 0 auto 0;
695 height: 640px;
696 pointer-events: none;
697 background: radial-gradient(55% 55% at 50% 0%, rgba(67,83,201,0.06), transparent 70%);
698}
699
700.lv-hero-inner {
701 position: relative;
702 max-width: 1200px;
703 margin: 0 auto;
704 padding: 0 28px;
705 text-align: center;
706}
707
708.lv-hero-badge {
709 display: inline-flex;
710 align-items: center;
711 gap: 9px;
712 font-size: 12.5px;
713 font-weight: 600;
714 color: #3a3d45;
715 background: #ffffff;
716 border: 1px solid rgba(22,24,29,0.10);
717 border-radius: 9999px;
718 padding: 7px 16px;
719 box-shadow: 0 1px 2px rgba(22,24,29,0.04);
720}
721
722.lv-hero-sub {
723 font-size: clamp(16px, 2vw, 19px);
724 color: #6b7080;
725 max-width: 60ch;
726 margin: 24px auto 0;
727 font-weight: 450;
728 line-height: 1.65;
729}
730
731.lv-hero-actions {
732 display: flex;
733 gap: 12px;
734 justify-content: center;
735 flex-wrap: wrap;
736 margin-top: 32px;
737}
738
739.lv-cta-primary {
740 padding: 13px 24px;
741 border-radius: 11px;
742 font-size: 15.5px;
743 font-weight: 600;
744 background: #16181d;
745 color: #fff;
746 text-decoration: none;
747 white-space: nowrap;
748 transition: box-shadow 0.15s;
749}
750.lv-cta-primary:hover { box-shadow: 0 10px 26px rgba(22,24,29,0.22); }
751
752.lv-cta-secondary {
753 padding: 13px 24px;
754 border-radius: 11px;
755 font-size: 15.5px;
756 font-weight: 600;
757 color: #16181d;
758 border: 1px solid rgba(22,24,29,0.14);
759 background: #ffffff;
760 text-decoration: none;
761 white-space: nowrap;
762 transition: border-color 0.15s;
763}
764.lv-cta-secondary:hover { border-color: rgba(22,24,29,0.30); }
765
766.lv-hero-tag {
767 margin-top: 18px;
768 font-family: 'JetBrains Mono', monospace;
769 font-size: 11.5px;
770 letter-spacing: 0.08em;
771 text-transform: uppercase;
772 color: #8a8d99;
773}
774
775/* Demo window */
776.lv-demo-window {
777 margin: 56px auto 0;
778 max-width: 860px;
779 text-align: left;
780 background: #ffffff;
781 border: 1px solid rgba(22,24,29,0.09);
782 border-radius: 18px;
783 box-shadow: 0 40px 90px -40px rgba(22,24,29,0.30), 0 1px 2px rgba(22,24,29,0.04);
784 overflow: hidden;
785}
786
787.lv-demo-bar {
788 display: flex;
789 align-items: center;
790 gap: 7px;
791 padding: 12px 18px;
792 border-bottom: 1px solid rgba(22,24,29,0.07);
793 background: #fcfcfd;
794}
795
796.lv-demo-dot {
797 width: 10px;
798 height: 10px;
799 border-radius: 50%;
800 background: #e4e5ea;
801}
802
803.lv-demo-url {
804 margin-left: 10px;
805 font-family: 'JetBrains Mono', monospace;
806 font-size: 12px;
807 color: #6b7080;
808}
809
810.lv-demo-live {
811 margin-left: auto;
812 display: inline-flex;
813 align-items: center;
814 gap: 6px;
815 font-size: 11px;
816 font-weight: 600;
817 color: #1e7f5c;
818}
819
820.lv-demo-body {
821 padding: 22px 24px;
822}
823
824.lv-demo-event {
825 display: grid;
826 grid-template-columns: 18px minmax(0, 1fr);
827 gap: 14px;
828 padding-bottom: 20px;
829 position: relative;
830}
831.lv-demo-event:last-child { padding-bottom: 0; }
832
833.lv-demo-event-track {
834 display: flex;
835 flex-direction: column;
836 align-items: center;
837}
838
839.lv-demo-line {
840 width: 1px;
841 flex: 1;
842 background: rgba(22,24,29,0.08);
843 margin-top: 5px;
844 min-height: 20px;
845}
846
847.lv-demo-event-content {}
848
849.lv-demo-event-header {
850 display: flex;
851 align-items: baseline;
852 gap: 10px;
853}
854
855.lv-demo-event-title {
856 font-size: 13.5px;
857 font-weight: 600;
858 color: #16181d;
859}
860
861.lv-demo-event-time {
862 font-family: 'JetBrains Mono', monospace;
863 font-size: 11px;
864 color: #8a8d99;
865}
866
867.lv-demo-event-body {
868 font-size: 13px;
869 color: #6b7080;
870 margin-top: 2px;
871}
872
873/* Ticker */
874.lv-ticker-wrap {
875 border-top: 1px solid rgba(22,24,29,0.07);
876 border-bottom: 1px solid rgba(22,24,29,0.07);
877 background: #ffffff;
878 margin-top: 64px;
879 overflow: hidden;
880 white-space: nowrap;
881 position: relative;
882}
883
884.lv-ticker-track {
885 display: inline-flex;
886 animation: gcTicker 40s linear infinite;
887 padding: 11px 0;
888}
889
890.lv-ticker-item {
891 display: inline-flex;
892 align-items: center;
893 gap: 8px;
894 font-family: 'JetBrains Mono', monospace;
895 font-size: 11.5px;
896 color: #6b7080;
897 padding: 0 28px;
898 border-right: 1px solid rgba(22,24,29,0.06);
899}
900
901/* Stats */
902.lv-stats {
903 background: #fcfcfd;
904}
905
906.lv-stats-inner {
907 max-width: 1200px;
908 margin: 0 auto;
909 display: grid;
910 grid-template-columns: repeat(4, 1fr);
911 gap: 24px;
912 padding: 52px 28px;
913}
914
915.lv-stat {
916 text-align: center;
917}
918
919.lv-stat-num {
920 font-family: 'Inter Tight', sans-serif;
921 font-weight: 700;
922 font-size: clamp(30px, 4vw, 44px);
923 letter-spacing: -0.025em;
924 color: #111318;
925}
926
927.lv-stat-label {
928 font-size: 13px;
929 color: #6b7080;
930 margin-top: 4px;
931}
932
933/* Loop */
934.lv-loop {
935 padding: 96px 0;
936 background: #ffffff;
937 border-top: 1px solid rgba(22,24,29,0.07);
938 border-bottom: 1px solid rgba(22,24,29,0.07);
939}
940
941.lv-loop-inner {
942 max-width: 1200px;
943 margin: 0 auto;
944 padding: 0 28px;
945}
946
947.lv-stages {
948 display: grid;
949 grid-template-columns: repeat(6, 1fr);
950 gap: 12px;
951}
952
953.lv-stage-card {
954 border: 1px solid rgba(22,24,29,0.08);
955 border-radius: 14px;
956 background: #ffffff;
957 padding: 20px 18px;
958 transition: border-color 0.3s, background 0.3s;
959}
960
961.lv-stage-card.lv-stage-active {
962 border-color: rgba(67,83,201,0.45);
963 background: rgba(67,83,201,0.03);
964}
965
966.lv-stage-header {
967 display: flex;
968 align-items: center;
969 gap: 8px;
970 margin-bottom: 10px;
971}
972
973.lv-stage-n {
974 font-family: 'JetBrains Mono', monospace;
975 font-size: 10.5px;
976 letter-spacing: 0.1em;
977 text-transform: uppercase;
978 color: #8a8d99;
979}
980
981.lv-stage-name {
982 font-family: 'Inter Tight', sans-serif;
983 font-size: 16px;
984 font-weight: 600;
985 letter-spacing: -0.01em;
986 color: #16181d;
987 margin-bottom: 5px;
988}
989
990.lv-stage-desc {
991 font-size: 12px;
992 color: #6b7080;
993 line-height: 1.55;
994}
995
996.lv-stage-meta {
997 font-family: 'JetBrains Mono', monospace;
998 font-size: 10.5px;
999 color: #8a8d99;
1000 margin-top: 10px;
1001 transition: color 0.3s;
1002}
1003
1004.lv-stage-meta.lv-stage-meta-active {
1005 color: #4353c9;
1006}
1007
1008/* Heroes */
1009.lv-heroes {
1010 padding: 96px 0;
1011 background: #fcfcfd;
1012}
1013
1014.lv-heroes-inner {
1015 max-width: 1200px;
1016 margin: 0 auto;
1017 padding: 0 28px;
1018}
1019
1020.lv-heroes-header {
1021 max-width: 640px;
1022 margin-bottom: 56px;
1023}
1024
1025.lv-heroes-list {
1026 display: flex;
1027 flex-direction: column;
1028 gap: 20px;
1029}
1030
1031.lv-hero-card {
1032 display: grid;
1033 grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
1034 gap: 48px;
1035 align-items: center;
1036 border: 1px solid rgba(22,24,29,0.08);
1037 border-radius: 20px;
1038 background: #ffffff;
1039 padding: 44px 48px;
1040 text-decoration: none;
1041 transition: border-color 0.2s, box-shadow 0.2s;
1042}
1043.lv-hero-card:hover {
1044 border-color: rgba(22,24,29,0.22);
1045 box-shadow: 0 24px 60px -36px rgba(22,24,29,0.24);
1046}
1047
1048.lv-hero-card-left {}
1049
1050.lv-hero-card-title {
1051 font-family: 'Inter Tight', sans-serif;
1052 font-size: 26px;
1053 font-weight: 600;
1054 letter-spacing: -0.022em;
1055 line-height: 1.15;
1056 color: #16181d;
1057 margin: 0 0 12px;
1058}
1059
1060.lv-hero-card-body {
1061 font-size: 14.5px;
1062 color: #6b7080;
1063 margin: 0 0 18px;
1064 line-height: 1.65;
1065}
1066
1067.lv-hero-card-cta {
1068 font-size: 13.5px;
1069 font-weight: 600;
1070 color: #4353c9;
1071}
1072
1073.lv-terminal {
1074 border: 1px solid rgba(22,24,29,0.07);
1075 border-radius: 14px;
1076 background: #fcfcfd;
1077 padding: 20px 22px;
1078 font-family: 'JetBrains Mono', monospace;
1079 font-size: 12px;
1080 line-height: 1.9;
1081 overflow: hidden;
1082}
1083
1084.lv-terminal-line {
1085 display: flex;
1086 align-items: center;
1087 gap: 10px;
1088 white-space: nowrap;
1089 overflow: hidden;
1090 text-overflow: ellipsis;
1091}
1092
1093/* Platform */
1094.lv-platform {
1095 padding: 96px 0;
1096 background: #ffffff;
1097 border-top: 1px solid rgba(22,24,29,0.07);
1098}
1099
1100.lv-platform-inner {
1101 max-width: 1200px;
1102 margin: 0 auto;
1103 padding: 0 28px;
1104}
1105
1106.lv-cap-grid {
1107 display: grid;
1108 grid-template-columns: repeat(4, 1fr);
1109 gap: 24px 32px;
1110}
1111
1112.lv-cap-col {}
1113
1114.lv-cap-group {
1115 font-family: 'JetBrains Mono', monospace;
1116 font-size: 10.5px;
1117 letter-spacing: 0.12em;
1118 text-transform: uppercase;
1119 color: #8a8d99;
1120 font-weight: 500;
1121 margin-bottom: 12px;
1122 padding-bottom: 8px;
1123 border-bottom: 1px solid rgba(22,24,29,0.07);
1124}
1125
1126.lv-cap-items {
1127 display: flex;
1128 flex-direction: column;
1129 gap: 7px;
1130}
1131
1132.lv-cap-item {
1133 font-size: 12.5px;
1134 color: #3a3d45;
1135 line-height: 1.45;
1136}
1137
1138/* Sovereignty */
1139.lv-sovereign {
1140 position: relative;
1141 overflow: hidden;
1142 padding: 104px 0;
1143 color: #fff;
1144 background: radial-gradient(130% 130% at 50% -10%, #1b2030 0%, #12151f 45%, #0b0d13 100%);
1145}
1146
1147.lv-sovereign-grid-bg {
1148 position: absolute;
1149 inset: 0;
1150 opacity: 0.4;
1151 background-image: linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px);
1152 background-size: 56px 56px;
1153 -webkit-mask-image: radial-gradient(80% 80% at 50% 0%, #000, transparent 78%);
1154 mask-image: radial-gradient(80% 80% at 50% 0%, #000, transparent 78%);
1155}
1156
1157.lv-sovereign-inner {
1158 position: relative;
1159 max-width: 1200px;
1160 margin: 0 auto;
1161 padding: 0 28px;
1162}
1163
1164.lv-section-header-dark {
1165 max-width: 680px;
1166 margin: 0 auto 48px;
1167 text-align: center;
1168}
1169
1170.lv-layers-grid {
1171 display: grid;
1172 grid-template-columns: repeat(4, 1fr);
1173 gap: 10px;
1174 max-width: 980px;
1175 margin: 0 auto;
1176}
1177
1178.lv-layer-chip {
1179 border: 1px solid rgba(255,255,255,0.10);
1180 border-radius: 10px;
1181 padding: 12px 16px;
1182 background: rgba(255,255,255,0.03);
1183}
1184
1185.lv-layer-cta {
1186 border-color: rgba(169,180,238,0.30);
1187 background: rgba(169,180,238,0.06);
1188 display: flex;
1189 align-items: center;
1190 text-decoration: none;
1191 transition: background 0.15s;
1192}
1193.lv-layer-cta:hover { background: rgba(169,180,238,0.10); }
1194
1195.lv-layer-cta-text {
1196 font-size: 13px;
1197 font-weight: 500;
1198 color: #a9b4ee;
1199}
1200
1201.lv-layer-n {
1202 font-family: 'JetBrains Mono', monospace;
1203 font-size: 10px;
1204 color: rgba(255,255,255,0.4);
1205 margin-bottom: 3px;
1206}
1207
1208.lv-layer-name {
1209 font-size: 13px;
1210 font-weight: 500;
1211 color: rgba(255,255,255,0.92);
1212}
1213
1214.lv-sovereign-feats {
1215 display: flex;
1216 gap: 44px;
1217 justify-content: center;
1218 flex-wrap: wrap;
1219 margin-top: 52px;
1220 text-align: center;
1221}
1222
1223.lv-sovereign-feat {}
1224
1225.lv-sovereign-feat-title {
1226 font-family: 'Inter Tight', sans-serif;
1227 font-size: 20px;
1228 font-weight: 700;
1229 color: #fff;
1230}
1231
1232.lv-sovereign-feat-sub {
1233 color: rgba(255,255,255,0.55);
1234 font-size: 13px;
1235 margin-top: 2px;
1236}
1237
1238/* Twin cards */
1239.lv-twin {
1240 padding: 96px 0;
1241 background: #fcfcfd;
1242}
1243
1244.lv-twin-inner {
1245 max-width: 1200px;
1246 margin: 0 auto;
1247 padding: 0 28px;
1248 display: grid;
1249 grid-template-columns: 1fr 1fr;
1250 gap: 24px;
1251}
1252
1253.lv-twin-card {
1254 border: 1px solid rgba(22,24,29,0.08);
1255 border-radius: 20px;
1256 background: #ffffff;
1257 padding: 44px 48px;
1258}
1259
1260.lv-twin-title {
1261 font-family: 'Inter Tight', sans-serif;
1262 font-size: 24px;
1263 font-weight: 600;
1264 letter-spacing: -0.02em;
1265 line-height: 1.2;
1266 margin: 0 0 12px;
1267 color: #16181d;
1268}
1269
1270.lv-twin-body {
1271 font-size: 14.5px;
1272 color: #6b7080;
1273 margin: 0 0 16px;
1274 line-height: 1.7;
1275}
1276
1277.lv-twin-link {
1278 font-size: 13.5px;
1279 font-weight: 600;
1280 color: #4353c9;
1281 text-decoration: none;
1282}
1283.lv-twin-link:hover { text-decoration: underline; }
1284
1285/* Quote */
1286.lv-quote {
1287 padding: 40px 0 96px;
1288 background: #fcfcfd;
1289}
1290
1291.lv-quote-inner {
1292 max-width: 980px;
1293 margin: 0 auto;
1294 padding: 0 28px;
1295 text-align: center;
1296}
1297
1298.lv-quote-text {
1299 font-family: 'Inter Tight', sans-serif;
1300 font-weight: 600;
1301 font-size: clamp(26px, 3.8vw, 42px);
1302 line-height: 1.2;
1303 letter-spacing: -0.025em;
1304 margin: 0;
1305 color: #111318;
1306}
1307
1308.lv-em {
1309 font-style: normal;
1310 color: #4353c9;
1311}
1312
1313/* CTA */
1314.lv-cta-section {
1315 padding: 0 0 104px;
1316 background: #fcfcfd;
1317}
1318
1319.lv-cta-card {
1320 max-width: 820px;
1321 margin: 0 auto;
1322 padding: 64px 40px;
1323 text-align: center;
1324 background: #ffffff;
1325 border: 1px solid rgba(22,24,29,0.08);
1326 border-radius: 26px;
1327 box-shadow: 0 30px 80px -50px rgba(22,24,29,0.28);
1328 position: relative;
1329 overflow: hidden;
1330}
1331
1332.lv-cta-glow {
1333 position: absolute;
1334 inset: -40% 0 auto 0;
1335 height: 280px;
1336 background: radial-gradient(50% 60% at 50% 0%, rgba(67,83,201,0.06), transparent 70%);
1337 pointer-events: none;
1338}
1339
1340.lv-cta-h2 {
1341 font-family: 'Inter Tight', sans-serif;
1342 font-weight: 700;
1343 letter-spacing: -0.028em;
1344 font-size: clamp(30px, 4.6vw, 48px);
1345 margin: 0;
1346 position: relative;
1347 color: #111318;
1348}
1349
1350.lv-cta-sub {
1351 color: #6b7080;
1352 font-size: 17px;
1353 margin: 16px 0 30px;
1354 position: relative;
1355}
1356
1357.lv-cta-actions {
1358 display: flex;
1359 gap: 12px;
1360 justify-content: center;
1361 flex-wrap: wrap;
1362 position: relative;
1363}
1364
1365.lv-cta-fine {
1366 margin-top: 20px;
1367 font-family: 'JetBrains Mono', monospace;
1368 font-size: 11px;
1369 color: #8a8d99;
1370 position: relative;
1371}
1372
1373/* Footer */
1374.lv-footer {
1375 border-top: 1px solid rgba(22,24,29,0.07);
1376 background: #ffffff;
1377 padding: 56px 0 30px;
1378}
1379
1380.lv-footer-inner {
1381 max-width: 1200px;
1382 margin: 0 auto;
1383 padding: 0 28px;
1384 display: flex;
1385 gap: 48px;
1386 flex-wrap: wrap;
1387 justify-content: space-between;
1388}
1389
1390.lv-footer-brand {}
1391
1392.lv-footer-tagline {
1393 color: #6b7080;
1394 font-size: 13.5px;
1395 margin: 12px 0 0;
1396 max-width: 32ch;
1397 line-height: 1.6;
1398}
1399
1400.lv-footer-cols {
1401 display: flex;
1402 gap: 64px;
1403 flex-wrap: wrap;
1404}
1405
1406.lv-footer-col {
1407 display: flex;
1408 flex-direction: column;
1409 gap: 9px;
1410}
1411
1412.lv-footer-col-head {
1413 font-family: 'JetBrains Mono', monospace;
1414 font-size: 11px;
1415 text-transform: uppercase;
1416 letter-spacing: 0.1em;
1417 color: #8a8d99;
1418 margin: 0 0 4px;
1419 font-weight: 500;
1420}
1421
1422.lv-footer-link {
1423 color: #3a3d45;
1424 font-size: 13.5px;
1425 text-decoration: none;
1426 transition: color 0.15s;
1427}
1428.lv-footer-link:hover { color: #16181d; }
1429
1430.lv-footer-bar {
1431 max-width: 1200px;
1432 margin: 44px auto 0;
1433 padding: 22px 28px 0;
1434 border-top: 1px solid rgba(22,24,29,0.06);
1435 display: flex;
1436 justify-content: space-between;
1437 flex-wrap: wrap;
1438 gap: 8px;
1439 color: #8a8d99;
1440 font-size: 12.5px;
1441}
1442
1443.lv-footer-stack {
1444 font-family: 'JetBrains Mono', monospace;
1445 font-size: 11px;
1446}
1447`;