Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

landing-pro.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-pro.tsxBlame1284 lines · 1 contributor
f8e5feaccanty labs1import type { FC } from "hono/jsx";
2import type { PublicStats } from "../lib/public-stats";
3import type {
4 QueuedAiBuildIssue,
5 RecentAutoMerge,
6 RecentAiReview,
7 DemoActivityEntry,
8} from "../lib/demo-activity";
9import { DEMO_USERNAME } from "../lib/demo-seed";
10
11export interface LandingProLiveFeed {
12 queued: QueuedAiBuildIssue[];
13 merges: RecentAutoMerge[];
14 reviews: RecentAiReview[];
15 reviewCount: number;
16 feed: DemoActivityEntry[];
17}
18
19export interface LandingProProps {
20 stats?: { publicRepos?: number; users?: number };
21 publicStats?: PublicStats | null;
22 liveFeed?: LandingProLiveFeed | null;
23}
24
25export function relTime(
26 value: string | Date | null | undefined,
27 now: number = Date.now()
28): string {
29 if (value === null || value === undefined) return "just now";
30 const t = value instanceof Date ? value.getTime() : new Date(value).getTime();
31 if (!Number.isFinite(t)) return "just now";
32 const d = now - t;
33 if (d < 0) return "just now";
34 const s = Math.floor(d / 1000);
35 if (s < 60) return "just now";
36 const m = Math.floor(s / 60);
37 if (m < 60) return `${m}m ago`;
38 const h = Math.floor(m / 60);
39 if (h < 24) return `${h}h ago`;
40 return `${Math.floor(h / 24)}d ago`;
41}
42
54f2e2accanty labs43// ─── inline SVG icon helper ────────────────────────────────────────
44
45function icon(paths: string, color = "#4353c9", size = 20) {
46 return `<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${color}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths}</svg>`;
47}
48
49const ICONS: Record<string, string> = {
50 code: icon('<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>'),
51 fork: icon('<circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><line x1="6" y1="9" x2="6" y2="15"/><path d="M18 9V7a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2"/><path d="M18 15a3 3 0 0 0 0-6"/>'),
52 ai: icon('<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>', "#7c3aed"),
53 shield: icon('<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>', "#059669"),
54 workflow: icon('<circle cx="12" cy="12" r="3"/><path d="M12 3v3"/><path d="M12 18v3"/><path d="M4.22 4.22l2.12 2.12"/><path d="M17.66 17.66l2.12 2.12"/><path d="M3 12h3"/><path d="M18 12h3"/><path d="M4.22 19.78l2.12-2.12"/><path d="M17.66 6.34l2.12-2.12"/>', "#b45309"),
55 grid: icon('<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>', "#475569"),
56 chart: icon('<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>', "#0891b2"),
57 link: icon('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>', "#dc2626"),
58 team: icon('<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>', "#0d9488"),
59};
60
f8e5feaccanty labs61// ─── page ──────────────────────────────────────────────────────────
62
63export const LandingProPage: FC<LandingProProps> = ({
64 publicStats,
65 liveFeed,
66} = {}) => {
67 const title = "Gluecron — The AI-native git platform";
68 const desc =
69 "The git platform that does the work. AI code review on every PR, secrets scanned at push, features built from plain-English issues. Self-hosted, git-native, Claude-first.";
70
71 const liveQueued = liveFeed?.queued ?? [];
72 const liveMerges = liveFeed?.merges ?? [];
73 const liveReviews = liveFeed?.reviews ?? [];
74 const liveReviewCount = liveFeed?.reviewCount ?? 0;
75 const liveEntries = liveFeed?.feed ?? [];
76
77 return (
78 <html lang="en">
79 <head>
80 <meta charset="UTF-8" />
81 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
82 <meta name="theme-color" content="#ffffff" />
83 <title>{title}</title>
84 <meta name="description" content={desc} />
85 <meta property="og:title" content={title} />
86 <meta property="og:description" content={desc} />
87 <meta property="og:type" content="website" />
88 <meta name="twitter:card" content="summary_large_image" />
89 <link rel="icon" type="image/svg+xml" href="/icon.svg" />
90 <link rel="preconnect" href="https://fonts.googleapis.com" />
91 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />
54f2e2accanty labs92 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;450;500;600&family=Inter+Tight:wght@600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" />
f8e5feaccanty labs93 <style dangerouslySetInnerHTML={{ __html: css }} />
94 </head>
95 <body>
96
54f2e2accanty labs97 {/* ── Nav ── */}
f8e5feaccanty labs98 <header class="lp-nav" id="lp-nav">
99 <div class="lp-nav-in">
100 <a href="/" class="lp-logo" aria-label="Gluecron home">
101 <span class="lp-logo-mark" aria-hidden="true" />
102 gluecron
103 </a>
104 <nav class="lp-nav-links" aria-label="Primary">
105 <a href="#platform">Platform</a>
106 <a href="#ai">AI suite</a>
107 <a href="#security">Security</a>
108 <a href="/pricing">Pricing</a>
109 <a href="/explore">Explore</a>
110 </nav>
111 <div class="lp-nav-ctas">
112 <a href="/login" class="lp-btn lp-btn-ghost">Sign in</a>
113 <a href="/register" class="lp-btn lp-btn-solid">Start building</a>
114 </div>
115 </div>
116 </header>
117
54f2e2accanty labs118 {/* ── Hero ── */}
f8e5feaccanty labs119 <section class="lp-hero">
120 <div class="lp-wrap lp-hero-in">
121 <div class="lp-hero-text">
122 <div class="lp-kicker">The AI-native git platform</div>
54f2e2accanty labs123 <h1 class="lp-h1">The platform<br />that does the work.</h1>
f8e5feaccanty labs124 <p class="lp-hero-sub">
125 AI code review on every PR. Secrets scanned at push.
54f2e2accanty labs126 Features built from plain-English issues. Gluecron closes
127 the loop from spec to deployed code — while you focus on
128 what matters.
f8e5feaccanty labs129 </p>
130 <div class="lp-hero-ctas">
54f2e2accanty labs131 <a href="/register" class="lp-btn lp-btn-solid lp-btn-lg">Sign up free</a>
132 <a href="/import" class="lp-btn lp-btn-outline lp-btn-lg">Migrate from GitHub</a>
f8e5feaccanty labs133 </div>
134 <div class="lp-hero-links">
135 <a href="/demo">Try the live demo</a>
136 <span aria-hidden="true">·</span>
137 <a href="/vs-github">Compare to GitHub</a>
138 <span aria-hidden="true">·</span>
139 <a href="/pricing">See pricing</a>
140 </div>
141
142 {publicStats && (
143 <dl class="lp-hero-stats">
144 <div class="lp-hero-stat">
54f2e2accanty labs145 <dt
146 class="lp-counter"
147 data-counter-target={String(publicStats.weeklyPrsAutoMerged)}
148 >
149 {publicStats.weeklyPrsAutoMerged.toLocaleString()}
150 </dt>
f8e5feaccanty labs151 <dd>PRs auto-merged this week</dd>
152 </div>
153 <div class="lp-hero-stat">
54f2e2accanty labs154 <dt
155 class="lp-counter"
156 data-counter-target={String(publicStats.weeklyIssuesBuiltByAi)}
157 >
158 {publicStats.weeklyIssuesBuiltByAi.toLocaleString()}
159 </dt>
f8e5feaccanty labs160 <dd>issues built by AI</dd>
161 </div>
162 <div class="lp-hero-stat">
54f2e2accanty labs163 <dt
164 class="lp-counter"
165 data-counter-target={String(Math.round(publicStats.weeklyHoursSaved))}
166 data-counter-suffix="h"
167 >
168 {`~${Math.round(publicStats.weeklyHoursSaved)}h`}
169 </dt>
f8e5feaccanty labs170 <dd>saved by AI this week</dd>
171 </div>
172 <div class="lp-hero-stat">
54f2e2accanty labs173 <dt
174 class="lp-counter"
175 data-counter-target={String(publicStats.weeklyDeploysShipped)}
176 >
177 {publicStats.weeklyDeploysShipped.toLocaleString()}
178 </dt>
f8e5feaccanty labs179 <dd>deploys shipped</dd>
180 </div>
181 </dl>
182 )}
183 </div>
184
54f2e2accanty labs185 {/* Rich PR review mock card */}
f8e5feaccanty labs186 <div class="lp-hero-card" aria-hidden="true">
54f2e2accanty labs187 <div class="lp-hc-chrome">
188 <span class="lp-hc-dot lp-hc-dot-r" />
189 <span class="lp-hc-dot lp-hc-dot-y" />
190 <span class="lp-hc-dot lp-hc-dot-g" />
191 <span class="lp-hc-path">auth/middleware.ts · PR #128 · main</span>
192 </div>
193 <div class="lp-hc-pr-row">
194 <span class="lp-badge lp-badge-merged">Merged</span>
195 <span class="lp-hc-pr-title">Harden token validation</span>
f8e5feaccanty labs196 </div>
54f2e2accanty labs197 <div class="lp-diff">
198 <div class="lp-diff-line lp-diff-add">
199 <span class="lp-ln">80</span>
200 <span class="lp-op">+</span>
201 <code><span class="lp-kw">const</span> validateToken = <span class="lp-kw">async</span> (token: <span class="lp-ty">string</span>) =&gt; {"{"}</code>
f8e5feaccanty labs202 </div>
54f2e2accanty labs203 <div class="lp-diff-line lp-diff-add lp-diff-focus">
204 <span class="lp-ln">81</span>
205 <span class="lp-op">+</span>
206 <code>{" "}<span class="lp-kw">const</span> hash = <span class="lp-kw">await</span> <span class="lp-fn">sha256</span>(token);</code>
f8e5feaccanty labs207 </div>
54f2e2accanty labs208 <div class="lp-diff-line lp-diff-add">
209 <span class="lp-ln">82</span>
210 <span class="lp-op">+</span>
211 <code>{" "}<span class="lp-kw">const</span> user = <span class="lp-kw">await</span> db.<span class="lp-fn">findByHash</span>(hash);</code>
f8e5feaccanty labs212 </div>
54f2e2accanty labs213 <div class="lp-diff-line lp-diff-add">
214 <span class="lp-ln">83</span>
215 <span class="lp-op">+</span>
216 <code>{" "}<span class="lp-kw">if</span> (!user) <span class="lp-kw">throw new</span> <span class="lp-ty">AuthError</span>(<span class="lp-str">"invalid"</span>);</code>
f8e5feaccanty labs217 </div>
218 </div>
54f2e2accanty labs219 <div class="lp-inline-comment">
220 <div class="lp-ic-ava">C</div>
221 <div class="lp-ic-body">
222 <div class="lp-ic-head">Claude <span class="lp-ic-loc">middleware.ts:81</span></div>
223 <div class="lp-ic-text">SHA-256 via Web Crypto — constant-time, no timing-attack surface. Correct approach. ✓</div>
224 </div>
225 </div>
226 <div class="lp-gates">
227 <span class="lp-gate lp-gate-ok">✓ Security</span>
228 <span class="lp-gate lp-gate-ok">✓ Tests (412)</span>
229 <span class="lp-gate lp-gate-ok">✓ Claude review</span>
230 <span class="lp-gate lp-gate-spin">⊙ Deploying</span>
231 </div>
232 <div class="lp-automerge-bar">Auto-merging to main · deploy in ~4s</div>
f8e5feaccanty labs233 </div>
234 </div>
235 </section>
236
54f2e2accanty labs237 {/* ── Trust strip ── */}
f8e5feaccanty labs238 <div class="lp-trust-strip">
239 <div class="lp-wrap lp-trust-in">
240 <span>Self-hosted on your hardware</span>
241 <span class="lp-sep" aria-hidden="true" />
242 <span>Git-native · Smart HTTP + SSH</span>
243 <span class="lp-sep" aria-hidden="true" />
244 <span>Claude-powered AI review</span>
245 <span class="lp-sep" aria-hidden="true" />
54f2e2accanty labs246 <span>MCP-native for Claude Code</span>
f8e5feaccanty labs247 <span class="lp-sep" aria-hidden="true" />
248 <span>Free to start</span>
249 </div>
250 </div>
251
54f2e2accanty labs252 {/* ── Impact stat band ── */}
253 <div class="lp-impact-band">
254 <div class="lp-wrap lp-impact-in">
255 <div class="lp-impact-stat lp-reveal">
256 <span class="lp-impact-n">2<span class="lp-impact-x">×</span></span>
257 <span class="lp-impact-label">faster dev velocity</span>
258 </div>
259 <div class="lp-impact-sep" aria-hidden="true" />
260 <div class="lp-impact-stat lp-reveal">
261 <span class="lp-impact-n">100<span class="lp-impact-x">%</span></span>
262 <span class="lp-impact-label">audit log coverage</span>
263 </div>
264 <div class="lp-impact-sep" aria-hidden="true" />
265 <div class="lp-impact-stat lp-reveal">
266 <span class="lp-impact-n">&lt;30<span class="lp-impact-x">s</span></span>
267 <span class="lp-impact-label">AI review latency</span>
268 </div>
269 </div>
270 </div>
271
272 {/* ── Live-now ── */}
f8e5feaccanty labs273 <section class="lp-sec lp-sec-soft" aria-labelledby="lp-live-h">
274 <div class="lp-wrap">
275 <div class="lp-sec-head">
276 <div class="lp-kicker">
277 <span class="lp-live-dot" aria-hidden="true">●</span> Live now
278 </div>
54f2e2accanty labs279 <h2 id="lp-live-h" class="lp-h2">Claude is working on demo repos as you read this.</h2>
280 <p class="lp-sub">Real data from the public <code>{DEMO_USERNAME}/*</code> repos. Refreshes every 30 seconds.</p>
f8e5feaccanty labs281 </div>
282
283 <div class="lp-live-grid" data-livenow-grid>
54f2e2accanty labs284 <LiveCard title="Issues queued for AI" variant="violet">
f8e5feaccanty labs285 <ul class="lp-live-list" data-livecard="queued">
286 {liveQueued.length === 0 ? (
287 <li class="lp-live-empty">Quiet right now.</li>
54f2e2accanty labs288 ) : liveQueued.slice(0, 3).map((i) => (
289 <li class="lp-live-row" data-row-id={`queued|${i.repo}|${i.number}`}>
290 <a href={`/${DEMO_USERNAME}/${i.repo}/issues/${i.number}`} class="lp-live-link">
291 <span class="lp-live-num">#{i.number}</span> {i.title}
292 </a>
293 <span class="lp-live-meta">{i.repo}</span>
294 </li>
295 ))}
f8e5feaccanty labs296 </ul>
297 </LiveCard>
298
54f2e2accanty labs299 <LiveCard title="Recently merged by AI" variant="green">
f8e5feaccanty labs300 <ul class="lp-live-list" data-livecard="merges">
301 {liveMerges.length === 0 ? (
302 <li class="lp-live-empty">No auto-merges in the last 24h.</li>
54f2e2accanty labs303 ) : liveMerges.slice(0, 3).map((m) => (
304 <li class="lp-live-row" data-row-id={`merges|${m.repo}|${m.number}`}>
305 <a href={`/${DEMO_USERNAME}/${m.repo}/pulls/${m.number}`} class="lp-live-link">
306 <span class="lp-live-num">#{m.number}</span> {m.title}
307 </a>
308 <span class="lp-live-meta">
309 {m.repo} · <span data-rel={m.mergedAt instanceof Date ? m.mergedAt.toISOString() : String(m.mergedAt)}>{relTime(m.mergedAt)}</span>
310 </span>
311 </li>
312 ))}
f8e5feaccanty labs313 </ul>
314 </LiveCard>
315
54f2e2accanty labs316 <LiveCard title="AI reviews posted" variant="brand">
f8e5feaccanty labs317 <div class="lp-live-bignum">
54f2e2accanty labs318 <span data-livecard-count="reviews">{liveReviewCount}</span>
f8e5feaccanty labs319 <span class="lp-live-bignum-label">today</span>
320 </div>
321 <ul class="lp-live-list" data-livecard="reviews">
322 {liveReviews.length === 0 ? (
323 <li class="lp-live-empty">No reviews in the last 24h.</li>
54f2e2accanty labs324 ) : liveReviews.slice(0, 2).map((r) => (
325 <li class="lp-live-row" data-row-id={`reviews|${r.repo}|${r.prNumber}`}>
326 <a href={`/${DEMO_USERNAME}/${r.repo}/pulls/${r.prNumber}`} class="lp-live-link">
327 <span class="lp-live-num">#{r.prNumber}</span> {r.commentSnippet}
328 </a>
329 <span class="lp-live-meta">{r.repo}</span>
330 </li>
331 ))}
f8e5feaccanty labs332 </ul>
333 </LiveCard>
334
54f2e2accanty labs335 <LiveCard title="Activity feed" variant="neutral">
f8e5feaccanty labs336 <ul class="lp-live-list" data-livecard="feed">
337 {liveEntries.length === 0 ? (
338 <li class="lp-live-empty">Quiet right now — check back in a minute.</li>
54f2e2accanty labs339 ) : liveEntries.slice(0, 6).map((e) => {
340 const path = e.ref.type === "pr" ? "pulls" : "issues";
341 const kindLabel = e.kind === "auto_merge.merged" ? "auto-merged" : e.kind === "ai_build.dispatched" ? "AI-built" : "AI review";
342 const id = `${e.kind}|${e.repo}|${e.ref.type}|${e.ref.number}`;
343 return (
344 <li class="lp-live-feedrow" data-row-id={id}>
345 <span class={`lp-feed-kind lp-feed-kind-${e.kind.replace(/\./g, "-")}`}>{kindLabel}</span>
346 {" "}<a class="lp-live-link" href={`/${DEMO_USERNAME}/${e.repo}/${path}/${e.ref.number}`}>{e.repo} #{e.ref.number}</a>
347 {" "}<span class="lp-live-rel" data-rel={e.at instanceof Date ? e.at.toISOString() : String(e.at)}>{relTime(e.at)}</span>
348 </li>
349 );
350 })}
f8e5feaccanty labs351 </ul>
352 </LiveCard>
353 </div>
354
355 <div class="lp-live-cta">
356 <a href="/register" class="lp-btn lp-btn-solid">Sign up free</a>
357 <a href="/demo" class="lp-text-link">Open the live demo →</a>
358 </div>
359 </div>
360 <script dangerouslySetInnerHTML={{ __html: liveNowJs }} />
361 </section>
362
54f2e2accanty labs363 {/* ── Platform breadth ── */}
f8e5feaccanty labs364 <section class="lp-sec" id="platform" aria-labelledby="lp-platform-h">
365 <div class="lp-wrap">
366 <div class="lp-sec-head">
367 <div class="lp-kicker">The platform</div>
54f2e2accanty labs368 <h2 id="lp-platform-h" class="lp-h2">Everything your team needs.<br />Nothing you don't.</h2>
369 <p class="lp-sub">Gluecron ships the surfaces GitHub charges extra for — and the ones it never built. AI is a first-class contributor, not a plugin.</p>
f8e5feaccanty labs370 </div>
371
372 <div class="lp-platform-grid">
54f2e2accanty labs373 <PlatformGroup icon={ICONS.code} iconColor="#4353c9" title="Code hosting">
f8e5feaccanty labs374 {["Git Smart HTTP · SSH keys", "Forks · Stars · Topics", "Templates · Mirroring", "Releases · Protected tags", "Push policy rulesets", "Commit signature verify"]}
375 </PlatformGroup>
54f2e2accanty labs376 <PlatformGroup icon={ICONS.team} iconColor="#0d9488" title="Collaboration">
f8e5feaccanty labs377 {["Issues · PRs · Inline review", "Draft PRs · Merge queues", "Discussions · Wikis", "Projects / kanban", "Gists · Reactions", "Mentions · Notifications"]}
378 </PlatformGroup>
54f2e2accanty labs379 <PlatformGroup icon={ICONS.ai} iconColor="#7c3aed" title="AI suite">
380 {["Spec-to-PR from plain English", "AI code review on every PR", "AI auto-merge when gates pass", "Sleep Mode — ships overnight", "Auto-repair on gate failure", "AI changelog · AI test stubs"]}
f8e5feaccanty labs381 </PlatformGroup>
54f2e2accanty labs382 <PlatformGroup icon={ICONS.shield} iconColor="#059669" title="Security">
f8e5feaccanty labs383 {["Secret scanner (15 patterns)", "AI semantic security review", "GateTest integration", "Dependency CVE alerts", "2FA · Passkeys · SAML SSO", "Audit log (100% coverage)"]}
384 </PlatformGroup>
54f2e2accanty labs385 <PlatformGroup icon={ICONS.workflow} iconColor="#b45309" title="CI / CD">
f8e5feaccanty labs386 {["Workflow runner (YAML-native)", "Cron triggers · Secrets", "Branch protection · Gates", "Required status checks", "Auto-repair on gate failure", "Protected tags enforcement"]}
387 </PlatformGroup>
54f2e2accanty labs388 <PlatformGroup icon={ICONS.grid} iconColor="#475569" title="Platform">
f8e5feaccanty labs389 {["Organizations · Teams · Roles", "npm package registry", "Pages / static hosting", "App marketplace", "Protected environments", "Billing · Quotas"]}
390 </PlatformGroup>
54f2e2accanty labs391 <PlatformGroup icon={ICONS.chart} iconColor="#0891b2" title="Observability">
f8e5feaccanty labs392 {["DORA metrics dashboard", "Developer velocity", "Repository health score", "Hot files heatmap", "Traffic analytics", "Org insights"]}
393 </PlatformGroup>
54f2e2accanty labs394 <PlatformGroup icon={ICONS.link} iconColor="#dc2626" title="Integrations">
f8e5feaccanty labs395 {["REST API v2 · GraphQL", "MCP server (Claude, Cursor)", "Official CLI · VS Code ext", "Webhooks (HMAC-signed)", "OAuth provider · GitHub Apps", "GitHub import (single + bulk)"]}
396 </PlatformGroup>
397 </div>
398 </div>
399 </section>
400
54f2e2accanty labs401 {/* ── Developer painkiller ── */}
f8e5feaccanty labs402 <section class="lp-sec lp-sec-soft">
403 <div class="lp-wrap">
404 <div class="lp-sec-head">
405 <div class="lp-kicker">Why developers switch</div>
406 <h2 class="lp-h2">Pain out. Productivity in.</h2>
54f2e2accanty labs407 <p class="lp-sub">Every friction point in modern development has a specific answer in Gluecron.</p>
f8e5feaccanty labs408 </div>
409 <div class="lp-pain-table">
54f2e2accanty labs410 <PainRow problem="Waiting on CI to queue before a gate runs" fix="Gates fire at the moment of push — before the branch even moves" />
411 <PainRow problem="Manual code review as a bottleneck" fix="AI reviews every PR in under 30 seconds, line-level, with risk flags" />
412 <PainRow problem="A failed gate halts your whole day" fix="Auto-repair tries to fix it, re-runs the gate, continues — you may never see it" />
413 <PainRow problem="AI as a sidebar you talk at" fix="Claude has a bot account, makes commits, appears in your git history like a teammate" />
414 <PainRow problem="Platform lock-in and surprise bills" fix="Self-hosted, single Bun binary, git-native — run it on a $6 VPS" />
415 <PainRow problem="Dependency CVEs discovered after merge" fix="CVE scanner runs on every push touching a manifest; opens issues automatically" />
f8e5feaccanty labs416 </div>
417 </div>
418 </section>
419
54f2e2accanty labs420 {/* ── AI showcase ── */}
f8e5feaccanty labs421 <section class="lp-sec" id="ai" aria-labelledby="lp-ai-h">
422 <div class="lp-wrap">
423 <div class="lp-sec-head">
424 <div class="lp-kicker">AI-native, not AI-bolted-on</div>
54f2e2accanty labs425 <h2 id="lp-ai-h" class="lp-h2">Claude does the work.<br />You stay in control.</h2>
426 <p class="lp-sub">Every AI action is attributed, auditable, and reversible. The manual path is always one click away.</p>
f8e5feaccanty labs427 </div>
428
429 <div class="lp-ai-features">
54f2e2accanty labs430 <AiFeatureCard
f8e5feaccanty labs431 n="01"
432 title="Spec-to-PR"
433 body="Describe a feature in plain English — or just label an issue ai:build. Claude opens a branch, writes the change, and submits a draft PR against your gates. Spec to PR in under 90 seconds."
434 link={{ href: "/demo", label: "Try on a live repo" }}
54f2e2accanty labs435 mock={
436 <div class="lp-review-mock">
437 <div class="lp-rm-header">
438 <span class="lp-rm-label">Issue #42 · labelled <code>ai:build</code></span>
439 <span class="lp-badge lp-badge-ai">AI</span>
440 </div>
441 <div class="lp-rm-steps">
442 <div class="lp-rm-step lp-rm-done"><span class="lp-rm-icon">✓</span> Branch opened: <code>feat/add-auth-provider</code></div>
443 <div class="lp-rm-step lp-rm-done"><span class="lp-rm-icon">✓</span> Files written: <code>auth/provider.ts</code>, <code>auth/types.ts</code></div>
444 <div class="lp-rm-step lp-rm-active"><span class="lp-rm-icon">⊙</span> PR #43 open — awaiting your review</div>
445 </div>
446 <div class="lp-rm-time">Spec → draft PR in 74s</div>
447 </div>
448 }
f8e5feaccanty labs449 />
450
54f2e2accanty labs451 <AiFeatureCard
f8e5feaccanty labs452 n="02"
453 title="AI code review on every PR"
454 body="The moment a PR opens, Claude reviews the diff: line-level comments, security flags, logic issues, and a verdict. Under 30 seconds. Every PR, every time, before a human has to look."
455 link={{ href: "/vs-github", label: "Compare to Copilot" }}
456 reverse
54f2e2accanty labs457 mock={
458 <div class="lp-review-mock">
459 <div class="lp-rm-header">
460 <span class="lp-rm-label">PR #128 · Claude review</span>
461 <span class="lp-badge lp-badge-approved">Approved</span>
462 </div>
463 <div class="lp-rm-comment">
464 <div class="lp-rm-ava">C</div>
465 <div class="lp-rm-bubble">
466 <div class="lp-rm-file">auth/middleware.ts:81</div>
467 SHA-256 via Web Crypto — constant-time, no timing-attack surface. Correct approach.
468 </div>
469 </div>
470 <div class="lp-rm-verdict">
471 <span class="lp-rm-v-ok">✓ No security issues · Approved for auto-merge</span>
472 </div>
473 <div class="lp-rm-time">Review posted in 28s</div>
474 </div>
475 }
f8e5feaccanty labs476 />
477
54f2e2accanty labs478 <AiFeatureCard
f8e5feaccanty labs479 n="03"
480 title="Sleep Mode"
54f2e2accanty labs481 body="Enable Sleep Mode and set your wake-up hour. Gluecron's autopilot works overnight: merging ready PRs, building labelled issues, repairing failed gates, fixing secrets. You wake up to a digest."
f8e5feaccanty labs482 link={{ href: "/sleep-mode", label: "See Sleep Mode" }}
54f2e2accanty labs483 mock={
484 <div class="lp-review-mock lp-digest-mock">
485 <div class="lp-rm-header">
486 <span class="lp-rm-label">Overnight digest · 9:04 AM</span>
487 </div>
488 <div class="lp-digest-rows">
489 <div class="lp-digest-row"><span class="lp-digest-ok">✓</span> 3 PRs auto-merged to main</div>
490 <div class="lp-digest-row"><span class="lp-digest-ok">✓</span> Issue #37 built and in review</div>
491 <div class="lp-digest-row"><span class="lp-digest-ok">✓</span> 2 secrets auto-repaired before push</div>
492 <div class="lp-digest-row"><span class="lp-digest-ok">✓</span> 1 failing gate repaired, re-run green</div>
493 </div>
494 <div class="lp-rm-time">While you slept · 0 pages sent</div>
495 </div>
496 }
f8e5feaccanty labs497 />
498
54f2e2accanty labs499 <AiFeatureCard
f8e5feaccanty labs500 n="04"
501 title="Auto-repair on gate failure"
54f2e2accanty labs502 body="When a gate fails, auto-repair reads the failure, drafts a fix, commits it with a bot account, and re-runs the gate. If it can't fix it, it opens an incident issue with a root-cause summary."
f8e5feaccanty labs503 link={{ href: "/demo", label: "Watch a live repair" }}
504 reverse
54f2e2accanty labs505 mock={
506 <div class="lp-review-mock">
507 <div class="lp-rm-header">
508 <span class="lp-rm-label">Gate: tests · 2 failing</span>
509 <span class="lp-badge lp-badge-warn">Repairing</span>
510 </div>
511 <div class="lp-rm-steps">
512 <div class="lp-rm-step lp-rm-done"><span class="lp-rm-icon lp-rm-fail">✗</span> gate:tests — 2 assertions failed</div>
513 <div class="lp-rm-step lp-rm-done"><span class="lp-rm-icon">✓</span> Patch drafted: <code>+9 −3</code></div>
514 <div class="lp-rm-step lp-rm-active"><span class="lp-rm-icon">⊙</span> Re-running gate · 412 passing</div>
515 </div>
516 <div class="lp-rm-verdict">
517 <span class="lp-rm-v-ok">✓ All gates green · Proceeding to merge</span>
518 </div>
519 </div>
520 }
f8e5feaccanty labs521 />
522 </div>
523 </div>
524 </section>
525
54f2e2accanty labs526 {/* ── Security ── */}
527 <section class="lp-sec lp-sec-soft" id="security" aria-labelledby="lp-secsec-h">
f8e5feaccanty labs528 <div class="lp-wrap">
529 <div class="lp-sec-head">
530 <div class="lp-kicker">Security</div>
54f2e2accanty labs531 <h2 id="lp-secsec-h" class="lp-h2">Secure by default at every layer.</h2>
532 <p class="lp-sub">Security isn't a settings toggle. On Gluecron it runs automatically on every push, every PR, and every dependency update.</p>
f8e5feaccanty labs533 </div>
534 <div class="lp-security-grid">
54f2e2accanty labs535 <SecurityCard title="Push-time secret scanner" body="15 regex patterns + AI semantic scan runs before the branch moves. AWS keys, GitHub tokens, private keys, database URLs — stopped cold." />
536 <SecurityCard title="AI security review" body="Claude reviews every diff for SSRF, SQL injection, XSS, and unsafe deserialization patterns. Line-level findings posted as PR comments." />
537 <SecurityCard title="Dependency CVE alerts" body="Scans package.json, go.mod, Cargo.toml, requirements.txt on every push. Critical findings open issues automatically." />
538 <SecurityCard title="Push policy rulesets" body="Enforce commit message patterns, block file paths, cap file sizes, forbid force-pushes — enforced at the HTTP layer, not advisory." />
539 <SecurityCard title="Commit signature verify" body="GPG and SSH key registration with Verified badges on every commit. Full OpenPGP packet parsing, SSHSIG support." />
540 <SecurityCard title="Enterprise auth" body="TOTP 2FA, passkeys (WebAuthn), SAML/OIDC SSO (Okta, Azure AD, Google Workspace), personal access tokens, OAuth provider." />
f8e5feaccanty labs541 </div>
542 </div>
543 </section>
544
54f2e2accanty labs545 {/* ── For teams ── */}
f8e5feaccanty labs546 <section class="lp-sec">
547 <div class="lp-wrap">
548 <div class="lp-sec-head">
549 <div class="lp-kicker">For teams</div>
550 <h2 class="lp-h2">Built for organisations, not just solo developers.</h2>
54f2e2accanty labs551 <p class="lp-sub">Everything a growing engineering team needs — including the parts enterprise platforms charge separately for.</p>
f8e5feaccanty labs552 </div>
553 <div class="lp-teams-grid">
54f2e2accanty labs554 <TeamCard title="Organizations &amp; teams" items={["Org-owned repositories", "Team-based CODEOWNERS (@org/team)", "Role-based access (read / write / admin)", "Per-repo collaborator invites", "Org-wide secrets manager (AES-256-GCM)"]} />
555 <TeamCard title="Enterprise auth" items={["SAML/OIDC SSO (Okta, Azure AD, Google)", "TOTP 2FA + recovery codes", "Passkeys / WebAuthn", "Email-domain allowlists", "Auto-provision on first SSO login"]} />
556 <TeamCard title="Compliance &amp; audit" items={["100% audit log coverage", "Per-repo + org-level audit views", "Signed commits with Verified badges", "Protected environments (reviewer-gated)", "DORA metrics for engineering health"]} />
557 <TeamCard title="Developer insights" items={["DORA metrics (deploy freq, lead time, MTTR)", "Developer velocity dashboard", "Repository health score (0–100)", "Hot files heatmap (churn-based risk tiers)", "Org-wide green rate and PR activity"]} />
f8e5feaccanty labs558 </div>
559 </div>
560 </section>
561
54f2e2accanty labs562 {/* ── Ecosystem ── */}
f8e5feaccanty labs563 <section class="lp-sec lp-sec-soft">
564 <div class="lp-wrap">
565 <div class="lp-sec-head">
566 <div class="lp-kicker">Developer ecosystem</div>
567 <h2 class="lp-h2">Meet developers where they work.</h2>
568 </div>
569 <div class="lp-eco-grid">
54f2e2accanty labs570 <EcoCard title="Official CLI" sub="gluecron repo ls · gluecron issues · gluecron gql" body="A Bun-compiled single binary. Login, repo CRUD, issue listing, GraphQL queries, and server info from your terminal." link="/install" />
571 <EcoCard title="VS Code extension" sub="Explain · Semantic search · Generate tests · Open on web" body="Four commands wired to your active Gluecron remote. AI explain-this-file and test generation without leaving the editor." link="/vscode" />
572 <EcoCard title="MCP server" sub="Claude Code · Claude Desktop · Cursor" body="Model Context Protocol tools for repo search, file reads, issue and PR management — all natively available to Claude and Cursor." link="/mcp" />
573 <EcoCard title="Full API surface" sub="REST v2 · GraphQL · Webhooks" body="A comprehensive REST API v2, a GraphQL mirror, HMAC-signed webhook delivery, and an OAuth 2.0 provider for third-party apps." link="/api" />
f8e5feaccanty labs574 </div>
575 </div>
576 </section>
577
54f2e2accanty labs578 {/* ── Comparison ── */}
f8e5feaccanty labs579 <section class="lp-sec">
580 <div class="lp-wrap">
581 <div class="lp-sec-head">
582 <div class="lp-kicker">vs the incumbent</div>
583 <h2 class="lp-h2">Everything GitHub charges for.<br />And the parts they never built.</h2>
584 </div>
585 <div class="lp-compare">
586 <div class="lp-compare-head" aria-hidden="true">
587 <div />
588 <div>GitHub</div>
589 <div>Gluecron</div>
590 </div>
591 <CompareRow feature="Git hosting + Smart HTTP push" them="✓" us="✓" />
592 <CompareRow feature="Issues, PRs, code review" them="✓" us="✓" />
593 <CompareRow feature="Workflow runner" them="Metered minutes" us="Self-hosted, unmetered" ours />
594 <CompareRow feature="AI code review on every PR" them="Copilot subscription" us="Built in, always on" ours />
595 <CompareRow feature="Spec-to-PR (issue → draft PR)" them="—" us="✓" ours />
596 <CompareRow feature="Auto-repair on gate failure" them="—" us="✓" ours />
597 <CompareRow feature="Secret scanner on push" them="Paid add-on" us="Built in" ours />
598 <CompareRow feature="MCP server (Claude / Cursor)" them="—" us="✓" ours />
599 <CompareRow feature="DORA metrics + velocity dashboard" them="Paid add-on" us="Built in" ours />
600 <CompareRow feature="Self-host on your own hardware" them="Enterprise tier" us="Single binary, free" ours />
601 <CompareRow feature="npm package registry" them="✓" us="✓" />
602 <CompareRow feature="Pre-receive policy enforcement" them="GitHub Enterprise" us="✓ on all plans" ours />
603 </div>
604 <div class="lp-compare-foot">
605 <a href="/vs-github" class="lp-text-link">See the full 26-row comparison →</a>
606 </div>
607 </div>
608 </section>
609
54f2e2accanty labs610 {/* ── Pricing ── */}
f8e5feaccanty labs611 <section class="lp-sec lp-sec-soft">
612 <div class="lp-wrap">
613 <div class="lp-sec-head">
614 <div class="lp-kicker">Pricing</div>
615 <h2 class="lp-h2">Free to start. Honest at scale.</h2>
54f2e2accanty labs616 <p class="lp-sub">Self-hosting is free forever. Hosted plans price the AI calls, not the seats. You own your data either way.</p>
f8e5feaccanty labs617 </div>
618 <div class="lp-price-grid">
54f2e2accanty labs619 <PricingCard tier="Free" price="$0" cadence="forever" desc="For personal projects and open source. Public and private repos, full AI suite, fair quotas." features={["Unlimited public repos", "3 private repos", "5K AI calls / month", "Community support"]} cta="Start free" href="/register" />
620 <PricingCard tier="Pro" price="$12" cadence="per user / month" desc="For working developers. Lifts every quota, adds priority routing, no Gluecron branding on deploys." features={["Unlimited private repos", "100K AI calls / month", "Priority queue", "Custom domains"]} cta="Go Pro" href="/settings/billing" highlight />
621 <PricingCard tier="Team" price="Talk to us" cadence="custom" desc="For orgs running production on Gluecron. SSO, audit retention, enterprise SLA, on-prem." features={["SSO + SCIM", "On-prem deploy", "Dedicated capacity", "24/7 incident response"]} cta="Contact us" href="mailto:hello@gluecron.com" />
f8e5feaccanty labs622 </div>
623 <div class="lp-price-foot">
624 <a href="/pricing" class="lp-text-link">Full pricing details →</a>
625 </div>
626 </div>
627 </section>
628
54f2e2accanty labs629 {/* ── Install ── */}
f8e5feaccanty labs630 <section class="lp-sec">
631 <div class="lp-wrap lp-install-wrap">
632 <div class="lp-install-text">
633 <div class="lp-kicker">One command to start</div>
54f2e2accanty labs634 <h2 class="lp-h2 lp-h2-tight">Already on GitHub?<br />Migrate in 30 seconds.</h2>
635 <p class="lp-sub">Signs you in, mints a PAT, imports your repo, wires the Claude Desktop MCP server, and drops the Gluecron skill files — all in one shot.</p>
636 <a href="/import" class="lp-btn lp-btn-solid lp-btn-lg" style="margin-top:20px">Or import a single repo →</a>
f8e5feaccanty labs637 </div>
54f2e2accanty labs638 <div class="lp-install-terminal">
f8e5feaccanty labs639 <div class="lp-term-bar">
640 <span class="lp-term-dot" /><span class="lp-term-dot" /><span class="lp-term-dot" />
641 <span class="lp-term-title">Terminal</span>
642 </div>
643 <div class="lp-term-body">
644 <div class="lp-term-line">
645 <span class="lp-term-prompt">$</span>
646 <span id="lp-install-cmd">curl -sSL gluecron.com/install | bash</span>
54f2e2accanty labs647 <button type="button" class="lp-copy-btn" data-copy-target="lp-install-cmd" aria-label="Copy install command">Copy</button>
f8e5feaccanty labs648 </div>
649 <div class="lp-term-out lp-term-ok">✓ signed in as you@example.com</div>
650 <div class="lp-term-out lp-term-ok">✓ PAT created (admin scope)</div>
651 <div class="lp-term-out lp-term-ok">✓ your-repo imported from GitHub</div>
652 <div class="lp-term-out lp-term-ok">✓ MCP server added to Claude Desktop</div>
653 <div class="lp-term-out lp-term-ok">✓ gluecron-pr, gluecron-issue skills ready</div>
654 </div>
655 </div>
656 </div>
657 </section>
658
54f2e2accanty labs659 {/* ── Dark CTA ── */}
660 <section class="lp-cta-dark">
f8e5feaccanty labs661 <div class="lp-wrap lp-cta-in">
54f2e2accanty labs662 <div class="lp-kicker lp-kicker-dark">Ready when you are</div>
f8e5feaccanty labs663 <h2 class="lp-cta-h">Stop managing the platform.<br />Start shipping the product.</h2>
54f2e2accanty labs664 <p class="lp-cta-sub">Free to start. Self-hosted-friendly. MCP-native. Migrate from GitHub in one command.</p>
f8e5feaccanty labs665 <div class="lp-cta-btns">
54f2e2accanty labs666 <a href="/register" class="lp-btn lp-btn-cta-solid lp-btn-xl">Create your account</a>
667 <a href="/import" class="lp-btn lp-btn-cta-outline lp-btn-xl">Migrate a repo</a>
f8e5feaccanty labs668 </div>
54f2e2accanty labs669 <div class="lp-cta-links lp-cta-links-dark">
f8e5feaccanty labs670 <a href="/demo">Try the live demo</a>
671 <span aria-hidden="true">·</span>
672 <a href="/vs-github">Compare to GitHub</a>
673 <span aria-hidden="true">·</span>
674 <a href="/pricing">See pricing</a>
675 </div>
676 </div>
677 </section>
678
54f2e2accanty labs679 {/* ── Footer ── */}
f8e5feaccanty labs680 <footer class="lp-footer">
681 <div class="lp-wrap lp-footer-in">
682 <div class="lp-footer-brand">
54f2e2accanty labs683 <a href="/" class="lp-logo lp-logo-light">
f8e5feaccanty labs684 <span class="lp-logo-mark" aria-hidden="true" />
685 gluecron
686 </a>
54f2e2accanty labs687 <p class="lp-footer-tag">The AI-native git platform.<br />Self-hosted, auditable, git-native.</p>
f8e5feaccanty labs688 </div>
689 <div class="lp-footer-cols">
690 <div class="lp-footer-col">
691 <h4>Product</h4>
692 <a href="#platform">Features</a>
693 <a href="#ai">AI suite</a>
694 <a href="#security">Security</a>
695 <a href="/pricing">Pricing</a>
696 <a href="/vs-github">vs GitHub</a>
697 <a href="/sleep-mode">Sleep Mode</a>
698 </div>
699 <div class="lp-footer-col">
700 <h4>Platform</h4>
701 <a href="/explore">Explore repos</a>
702 <a href="/demo">Live demo</a>
703 <a href="/marketplace">Marketplace</a>
704 <a href="/install">Install script</a>
705 <a href="/api">API docs</a>
706 <a href="/mcp">MCP server</a>
707 </div>
708 <div class="lp-footer-col">
709 <h4>Developers</h4>
710 <a href="/install">CLI install</a>
711 <a href="/vscode">VS Code ext</a>
712 <a href="/api/graphql">GraphQL explorer</a>
713 <a href="/help">Migration guide</a>
714 <a href="/import">Import from GitHub</a>
715 <a href="/connect/claude-guide">Claude Code guide</a>
716 </div>
717 <div class="lp-footer-col">
718 <h4>Account</h4>
719 <a href="/login">Sign in</a>
720 <a href="/register">Register</a>
721 <a href="/settings">Settings</a>
722 <a href="/settings/billing">Billing</a>
723 <a href="/settings/tokens">API tokens</a>
724 <a href="/status">Platform status</a>
725 </div>
726 </div>
727 </div>
728 <div class="lp-footer-bottom">
729 <div class="lp-wrap lp-footer-bottom-in">
730 <span>© {new Date().getFullYear()} Gluecron</span>
731 <span>Self-hosted · Git-native · Claude-first</span>
732 </div>
733 </div>
734 </footer>
735
54f2e2accanty labs736 <script dangerouslySetInnerHTML={{ __html: pageJs }} />
f8e5feaccanty labs737 </body>
738 </html>
739 );
740};
741
742// ─── sub-components ────────────────────────────────────────────────
743
54f2e2accanty labs744const LiveCard: FC<{ title: string; variant: "violet"|"green"|"brand"|"neutral"; children?: any }> = ({ title, variant, children }) => (
745 <article class={`lp-live-card lp-live-card-${variant} lp-reveal`}>
f8e5feaccanty labs746 <h3 class="lp-live-card-title">{title}</h3>
747 {children}
748 </article>
749);
750
54f2e2accanty labs751const PlatformGroup: FC<{ icon: string; iconColor: string; title: string; children: string[] }> = ({ icon: iconHtml, title, children }) => (
752 <div class="lp-plat-group lp-reveal">
753 <div class="lp-plat-header">
754 <span class="lp-plat-icon" dangerouslySetInnerHTML={{ __html: iconHtml }} />
755 <h3 class="lp-plat-title">{title}</h3>
756 </div>
f8e5feaccanty labs757 <ul class="lp-plat-list">
54f2e2accanty labs758 {children.map((item) => <li>{item}</li>)}
f8e5feaccanty labs759 </ul>
760 </div>
761);
762
763const PainRow: FC<{ problem: string; fix: string }> = ({ problem, fix }) => (
54f2e2accanty labs764 <div class="lp-pain-row lp-reveal">
f8e5feaccanty labs765 <div class="lp-pain-problem">
54f2e2accanty labs766 <span class="lp-pain-icon lp-pain-no" aria-label="Before">✗</span>{problem}
f8e5feaccanty labs767 </div>
768 <div class="lp-pain-arrow" aria-hidden="true">→</div>
769 <div class="lp-pain-fix">
54f2e2accanty labs770 <span class="lp-pain-icon lp-pain-yes" aria-label="After">✓</span>{fix}
f8e5feaccanty labs771 </div>
772 </div>
773);
774
54f2e2accanty labs775const AiFeatureCard: FC<{
776 n: string; title: string; body: string;
f8e5feaccanty labs777 link: { href: string; label: string };
54f2e2accanty labs778 mock: any; reverse?: boolean;
f8e5feaccanty labs779}> = ({ n, title, body, link, mock, reverse }) => (
54f2e2accanty labs780 <div class={`lp-ai-feature lp-reveal${reverse ? " lp-ai-feature-rev" : ""}`}>
f8e5feaccanty labs781 <div class="lp-ai-text">
782 <div class="lp-ai-n">{n}</div>
783 <h3 class="lp-ai-title">{title}</h3>
784 <p class="lp-ai-body">{body}</p>
785 <a href={link.href} class="lp-text-link">{link.label} →</a>
786 </div>
54f2e2accanty labs787 <div class="lp-ai-mock" aria-hidden="true">{mock}</div>
f8e5feaccanty labs788 </div>
789);
790
791const SecurityCard: FC<{ title: string; body: string }> = ({ title, body }) => (
54f2e2accanty labs792 <div class="lp-sec-card lp-reveal">
f8e5feaccanty labs793 <h3 class="lp-sec-card-title">{title}</h3>
794 <p class="lp-sec-card-body">{body}</p>
795 </div>
796);
797
798const TeamCard: FC<{ title: string; items: string[] }> = ({ title, items }) => (
54f2e2accanty labs799 <div class="lp-team-card lp-reveal">
f8e5feaccanty labs800 <h3 class="lp-team-title">{title}</h3>
801 <ul class="lp-team-list">
54f2e2accanty labs802 {items.map((item) => <li><span aria-hidden="true">✓</span>{item}</li>)}
f8e5feaccanty labs803 </ul>
804 </div>
805);
806
54f2e2accanty labs807const EcoCard: FC<{ title: string; sub: string; body: string; link: string }> = ({ title, sub, body, link }) => (
808 <div class="lp-eco-card lp-reveal">
f8e5feaccanty labs809 <h3 class="lp-eco-title">{title}</h3>
810 <div class="lp-eco-sub">{sub}</div>
811 <p class="lp-eco-body">{body}</p>
812 <a href={link} class="lp-text-link">Learn more →</a>
813 </div>
814);
815
54f2e2accanty labs816const CompareRow: FC<{ feature: string; them: string; us: string; ours?: boolean }> = ({ feature, them, us, ours }) => (
f8e5feaccanty labs817 <div class={`lp-cmp-row${ours ? " lp-cmp-ours" : ""}`}>
818 <div class="lp-cmp-feature">{feature}</div>
819 <div class="lp-cmp-them">{them}</div>
820 <div class={`lp-cmp-us${ours ? " lp-cmp-us-hl" : ""}`}>{us}</div>
821 </div>
822);
823
824const PricingCard: FC<{
825 tier: string; price: string; cadence: string; desc: string;
826 features: string[]; cta: string; href: string; highlight?: boolean;
827}> = ({ tier, price, cadence, desc, features, cta, href, highlight }) => (
54f2e2accanty labs828 <div class={`lp-price-card lp-reveal${highlight ? " lp-price-hl" : ""}`}>
f8e5feaccanty labs829 {highlight && <div class="lp-price-badge">Most popular</div>}
830 <div class="lp-price-tier">{tier}</div>
831 <div class="lp-price-amount">
832 <span class="lp-price-num">{price}</span>
833 <span class="lp-price-cad">{cadence}</span>
834 </div>
835 <p class="lp-price-desc">{desc}</p>
836 <ul class="lp-price-features">
837 {features.map((f) => <li><span aria-hidden="true">✓</span>{f}</li>)}
838 </ul>
54f2e2accanty labs839 <a href={href} class={`lp-btn ${highlight ? "lp-btn-solid" : "lp-btn-outline"} lp-btn-block`}>{cta}</a>
f8e5feaccanty labs840 </div>
841);
842
843// ─── JavaScript ────────────────────────────────────────────────────
844
845const liveNowJs = `
846(function(){
847try{
848 var DEMO=${JSON.stringify(DEMO_USERNAME)};
849 var INTERVAL=30000;
850 function esc(s){return String(s==null?'':s).replace(/[&<>"']/g,function(c){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c];});}
851 function rel(v){
852 if(v==null) return 'just now';
54f2e2accanty labs853 var t=(typeof v==='number'?v:new Date(v).getTime());
f8e5feaccanty labs854 if(!isFinite(t)) return 'just now';
855 var d=Date.now()-t;if(d<0) return 'just now';
856 var s=Math.floor(d/1000);if(s<60) return 'just now';
857 var m=Math.floor(s/60);if(m<60) return m+'m ago';
858 var h=Math.floor(m/60);if(h<24) return h+'h ago';
859 return Math.floor(h/24)+'d ago';
860 }
861 function diffMount(ul,newHtml){
862 if(!ul) return;
863 var prev={};
864 ul.querySelectorAll('[data-row-id]').forEach(function(n){prev[n.getAttribute('data-row-id')]=true;});
865 ul.innerHTML=newHtml;
866 ul.querySelectorAll('[data-row-id]').forEach(function(n){
54f2e2accanty labs867 if(!prev[n.getAttribute('data-row-id')]){
868 n.style.transition='none';n.style.background='rgba(67,83,201,.07)';
869 setTimeout(function(){n.style.transition='background .8s';n.style.background='';},50);
870 }
f8e5feaccanty labs871 });
872 }
54f2e2accanty labs873 function pollQueued(){fetch('/api/v2/demo/queued',{credentials:'omit'}).then(function(r){return r.json();}).then(function(d){var ul=document.querySelector('[data-livecard="queued"]');if(!ul) return;var items=(d&&d.items)||[];if(!items.length){ul.innerHTML='<li class="lp-live-empty">Quiet right now.</li>';return;}diffMount(ul,items.slice(0,3).map(function(i){var id='queued|'+i.repo+'|'+i.number;return'<li class="lp-live-row" data-row-id="'+esc(id)+'"><a href="/'+esc(DEMO)+'/'+esc(i.repo)+'/issues/'+i.number+'" class="lp-live-link"><span class="lp-live-num">#'+i.number+'</span> '+esc(i.title)+'</a><span class="lp-live-meta">'+esc(i.repo)+'</span></li>';}).join(''));}).catch(function(){});}
874 function pollMerges(){fetch('/api/v2/demo/merges',{credentials:'omit'}).then(function(r){return r.json();}).then(function(d){var ul=document.querySelector('[data-livecard="merges"]');if(!ul) return;var items=(d&&d.items)||[];if(!items.length){ul.innerHTML='<li class="lp-live-empty">No auto-merges in the last 24h.</li>';return;}diffMount(ul,items.slice(0,3).map(function(m){var id='merges|'+m.repo+'|'+m.number;return'<li class="lp-live-row" data-row-id="'+esc(id)+'"><a href="/'+esc(DEMO)+'/'+esc(m.repo)+'/pulls/'+m.number+'" class="lp-live-link"><span class="lp-live-num">#'+m.number+'</span> '+esc(m.title)+'</a><span class="lp-live-meta">'+esc(m.repo)+' <span data-rel="'+esc(m.mergedAt)+'">'+esc(rel(m.mergedAt))+'</span></span></li>';}).join(''));}).catch(function(){});}
875 function pollReviews(){fetch('/api/v2/demo/reviews',{credentials:'omit'}).then(function(r){return r.json();}).then(function(d){var ul=document.querySelector('[data-livecard="reviews"]');if(!ul) return;var cnt=document.querySelector('[data-livecard-count="reviews"]');if(cnt&&typeof d.count==='number') cnt.textContent=d.count;var items=(d&&d.items)||[];if(!items.length){ul.innerHTML='<li class="lp-live-empty">No reviews in the last 24h.</li>';return;}diffMount(ul,items.slice(0,2).map(function(r){var id='reviews|'+r.repo+'|'+r.prNumber;return'<li class="lp-live-row" data-row-id="'+esc(id)+'"><a href="/'+esc(DEMO)+'/'+esc(r.repo)+'/pulls/'+r.prNumber+'" class="lp-live-link"><span class="lp-live-num">#'+r.prNumber+'</span> '+esc(r.commentSnippet)+'</a><span class="lp-live-meta">'+esc(r.repo)+'</span></li>';}).join(''));}).catch(function(){});}
876 function pollFeed(){fetch('/api/v2/demo/activity',{credentials:'omit'}).then(function(r){return r.json();}).then(function(d){var ul=document.querySelector('[data-livecard="feed"]');if(!ul) return;var entries=(d&&d.entries)||[];if(!entries.length){ul.innerHTML='<li class="lp-live-empty">Quiet right now.</li>';return;}diffMount(ul,entries.slice(0,6).map(function(e){var path=(e.ref&&e.ref.type==='pr')?'pulls':'issues';var num=(e.ref&&e.ref.number)||0;var label=e.kind==='auto_merge.merged'?'auto-merged':e.kind==='ai_build.dispatched'?'AI-built':'AI review';var kc=String(e.kind||'').replace(/\\./g,'-');var id=e.kind+'|'+e.repo+'|'+(e.ref&&e.ref.type)+'|'+num;return'<li class="lp-live-feedrow" data-row-id="'+esc(id)+'"><span class="lp-feed-kind lp-feed-kind-'+esc(kc)+'">'+esc(label)+'</span> <a class="lp-live-link" href="/'+esc(DEMO)+'/'+esc(e.repo)+'/'+path+'/'+num+'">'+esc(e.repo)+' #'+num+'</a> <span data-rel="'+esc(e.at)+'">'+esc(rel(e.at))+'</span></li>';}).join(''));}).catch(function(){});}
877 function refreshRel(){document.querySelectorAll('[data-rel]').forEach(function(el){el.textContent=rel(el.getAttribute('data-rel'));});}
f8e5feaccanty labs878 function tick(){pollQueued();pollMerges();pollReviews();pollFeed();}
54f2e2accanty labs879 setInterval(tick,INTERVAL);setInterval(refreshRel,60000);
880}catch(err){}
881})();
882`;
883
884const pageJs = `
885(function(){
886/* ── copy button ── */
887document.addEventListener('click',function(e){
888 var btn=e.target.closest('[data-copy-target]');
889 if(!btn) return;
890 var el=document.getElementById(btn.getAttribute('data-copy-target'));
891 if(!el) return;
892 navigator.clipboard.writeText(el.textContent.trim()).then(function(){
893 var o=btn.textContent;btn.textContent='Copied!';
894 setTimeout(function(){btn.textContent=o;},1500);
895 }).catch(function(){});
896});
897
898/* ── scroll reveal ── */
899try{
900 var obs=new IntersectionObserver(function(entries){
901 entries.forEach(function(e){
902 if(e.isIntersecting){e.target.classList.add('lp-visible');obs.unobserve(e.target);}
903 });
904 },{threshold:0.08,rootMargin:'0px 0px -40px 0px'});
905 document.querySelectorAll('.lp-reveal').forEach(function(el){obs.observe(el);});
906}catch(err){}
907
908/* ── counter animation ── */
909try{
910 function animCount(el,target,dur){
911 var start=performance.now();
912 var suffix=el.getAttribute('data-counter-suffix')||'';
913 function step(now){
914 var p=Math.min((now-start)/dur,1);
915 var ease=1-Math.pow(1-p,3);
916 var v=Math.round(ease*target);
917 el.textContent=(v>=1000?(v/1000).toFixed(v>=10000?0:1)+'k':String(v))+suffix;
918 if(p<1) requestAnimationFrame(step);
919 else el.textContent=target>=1000?(target/1000).toFixed(target>=10000?0:1)+'k'+suffix:String(target)+suffix;
920 }
921 requestAnimationFrame(step);
922 }
923 var cObs=new IntersectionObserver(function(entries){
924 entries.forEach(function(e){
925 if(e.isIntersecting){
926 var t=parseInt(e.target.getAttribute('data-counter-target')||'0',10);
927 if(t>0) animCount(e.target,t,1200);
928 cObs.unobserve(e.target);
929 }
930 });
931 },{threshold:0.5});
932 document.querySelectorAll('[data-counter-target]').forEach(function(el){cObs.observe(el);});
933}catch(err){}
934
935/* ── nav scroll class ── */
936try{
937 var nav=document.getElementById('lp-nav');
938 window.addEventListener('scroll',function(){
939 nav&&nav.classList.toggle('lp-stuck',window.scrollY>20);
940 },{passive:true});
f8e5feaccanty labs941}catch(err){}
942})();
943`;
944
945// ─── CSS ───────────────────────────────────────────────────────────
946
947const css = `
54f2e2accanty labs948/* ── tokens ── */
f8e5feaccanty labs949:root{
54f2e2accanty labs950 --lp-brand:#4353c9;--lp-brand-h:#3848b6;
951 --lp-bg:#ffffff;--lp-soft:#fafafb;
952 --lp-ink:#0a0b0d;--lp-ink-2:#3a3d45;--lp-muted:#6b7280;
953 --lp-border:rgba(0,0,0,.08);
954 --lp-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 20px rgba(0,0,0,.06);
955 --lp-shadow-lg:0 4px 12px rgba(0,0,0,.07),0 24px 48px rgba(0,0,0,.09);
956 --lp-green:#059669;--lp-red:#dc2626;--lp-violet:#7c3aed;--lp-amber:#b45309;
957 --lp-max:1200px;--lp-r:10px;
958 --lp-navy:#0a0d1a;
f8e5feaccanty labs959}
960*{box-sizing:border-box;margin:0;padding:0}
54f2e2accanty labs961html{scroll-behavior:smooth;font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
962body{background:var(--lp-bg);color:var(--lp-ink);font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif}
f8e5feaccanty labs963a{color:inherit;text-decoration:none}
964
54f2e2accanty labs965/* ── scroll reveal ── */
966.lp-reveal{opacity:0;transform:translateY(16px);transition:opacity .5s ease,transform .5s ease}
967.lp-reveal.lp-visible{opacity:1;transform:none}
968
969/* ── layout ── */
f8e5feaccanty labs970.lp-wrap{max-width:var(--lp-max);margin:0 auto;padding:0 24px}
971.lp-sec{padding:96px 0}
972.lp-sec-soft{background:var(--lp-soft)}
973
54f2e2accanty labs974/* ── typography ── */
975.lp-h1{font-family:'Inter Tight','Inter',sans-serif;font-weight:800;font-size:clamp(42px,6.5vw,76px);line-height:1.02;letter-spacing:-.03em;color:var(--lp-ink)}
976.lp-h2{font-family:'Inter Tight','Inter',sans-serif;font-weight:700;font-size:clamp(30px,4vw,50px);line-height:1.08;letter-spacing:-.022em;color:var(--lp-ink)}
977.lp-h2-tight{font-size:clamp(26px,3.2vw,40px)}
978.lp-kicker{font-size:12.5px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--lp-brand);margin-bottom:12px}
f8e5feaccanty labs979.lp-sub{font-size:18px;color:var(--lp-ink-2);line-height:1.65;max-width:60ch}
980.lp-text-link{color:var(--lp-brand);font-size:15px;font-weight:500}
981.lp-text-link:hover{color:var(--lp-brand-h);text-decoration:underline}
54f2e2accanty labs982code{font-family:'JetBrains Mono',ui-monospace,monospace;font-size:.86em;background:rgba(0,0,0,.05);padding:2px 5px;border-radius:4px}
983
984/* ── buttons ── */
985.lp-btn{display:inline-flex;align-items:center;gap:6px;font-family:inherit;font-weight:600;font-size:15px;border-radius:var(--lp-r);padding:10px 18px;border:1.5px solid transparent;cursor:pointer;text-decoration:none;transition:transform .15s,box-shadow .2s,background .15s,border-color .15s,color .15s;white-space:nowrap}
f8e5feaccanty labs986.lp-btn:hover{transform:translateY(-1px)}
987.lp-btn-solid{background:var(--lp-ink);color:#fff;border-color:var(--lp-ink)}
54f2e2accanty labs988.lp-btn-solid:hover{box-shadow:0 8px 24px rgba(10,11,13,.25)}
f8e5feaccanty labs989.lp-btn-outline{color:var(--lp-ink);border-color:rgba(0,0,0,.2)}
990.lp-btn-outline:hover{border-color:var(--lp-ink);background:rgba(0,0,0,.03)}
991.lp-btn-ghost{color:var(--lp-ink-2);border-color:var(--lp-border)}
992.lp-btn-ghost:hover{color:var(--lp-ink);border-color:rgba(0,0,0,.2)}
993.lp-btn-lg{padding:13px 22px;font-size:16px;border-radius:12px}
54f2e2accanty labs994.lp-btn-xl{padding:15px 30px;font-size:17px;border-radius:14px}
f8e5feaccanty labs995.lp-btn-block{width:100%;justify-content:center}
54f2e2accanty labs996/* dark section buttons */
997.lp-btn-cta-solid{background:#fff;color:var(--lp-navy);border-color:#fff}
998.lp-btn-cta-solid:hover{background:#f1f5f9;box-shadow:0 8px 24px rgba(0,0,0,.35)}
999.lp-btn-cta-outline{color:rgba(255,255,255,.9);border-color:rgba(255,255,255,.28)}
1000.lp-btn-cta-outline:hover{border-color:rgba(255,255,255,.6);background:rgba(255,255,255,.07)}
1001
1002/* ── badges ── */
1003.lp-badge{display:inline-flex;align-items:center;font-size:11.5px;font-weight:700;padding:3px 8px;border-radius:6px}
f8e5feaccanty labs1004.lp-badge-merged{color:var(--lp-green);background:rgba(5,150,105,.1)}
54f2e2accanty labs1005.lp-badge-approved{color:var(--lp-green);background:rgba(5,150,105,.1)}
1006.lp-badge-ai{color:var(--lp-violet);background:rgba(124,58,237,.1)}
1007.lp-badge-warn{color:var(--lp-amber);background:rgba(180,83,9,.1)}
f8e5feaccanty labs1008
54f2e2accanty labs1009/* ── nav ── */
1010.lp-nav{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.88);backdrop-filter:blur(14px) saturate(180%);border-bottom:1px solid transparent;transition:border-color .2s}
1011.lp-nav.lp-stuck{border-bottom-color:var(--lp-border)}
1012.lp-nav-in{max-width:var(--lp-max);margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:20px}
1013.lp-logo{display:inline-flex;align-items:center;gap:9px;font-family:'Inter Tight',sans-serif;font-weight:700;font-size:18px;letter-spacing:-.02em;color:var(--lp-ink)}
1014.lp-logo-light{color:rgba(255,255,255,.9)}
1015.lp-logo-mark{width:18px;height:18px;border-radius:6px;background:var(--lp-brand);display:inline-block;flex-shrink:0}
f8e5feaccanty labs1016.lp-nav-links{display:flex;gap:24px;margin-left:10px}
1017.lp-nav-links a{font-size:15px;font-weight:500;color:var(--lp-ink-2);transition:color .15s}
1018.lp-nav-links a:hover{color:var(--lp-ink)}
1019.lp-nav-ctas{margin-left:auto;display:flex;align-items:center;gap:10px}
1020@media(max-width:720px){.lp-nav-links{display:none}.lp-nav-ctas .lp-btn-ghost{display:none}}
1021
54f2e2accanty labs1022/* ── hero ── */
f8e5feaccanty labs1023.lp-hero{padding:80px 0 60px;border-bottom:1px solid var(--lp-border)}
1024.lp-hero-in{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
54f2e2accanty labs1025.lp-hero-text{display:flex;flex-direction:column}
f8e5feaccanty labs1026.lp-hero-text .lp-kicker{margin-bottom:16px}
1027.lp-hero-sub{font-size:18px;color:var(--lp-ink-2);line-height:1.65;margin:20px 0 0}
1028.lp-hero-ctas{display:flex;gap:12px;flex-wrap:wrap;margin-top:28px}
1029.lp-hero-links{display:flex;gap:10px;align-items:center;margin-top:14px;font-size:14px;color:var(--lp-muted)}
1030.lp-hero-links a{color:var(--lp-brand);font-weight:500}
1031.lp-hero-links span{color:var(--lp-border)}
54f2e2accanty labs1032.lp-hero-stats{display:flex;gap:28px;margin-top:32px;padding-top:24px;border-top:1px solid var(--lp-border);list-style:none;flex-wrap:wrap}
1033.lp-hero-stat dt{font-family:'Inter Tight',sans-serif;font-weight:700;font-size:22px;color:var(--lp-ink);letter-spacing:-.01em}
1034.lp-hero-stat dd{font-size:12.5px;color:var(--lp-muted);margin-top:2px}
1035@media(max-width:900px){.lp-hero-in{grid-template-columns:1fr}.lp-hero-card{order:-1}}
1036
1037/* ── hero PR mock card ── */
1038.lp-hero-card{background:#fff;border:1px solid var(--lp-border);border-radius:16px;box-shadow:var(--lp-shadow-lg);overflow:hidden;font-size:13px}
1039.lp-hc-chrome{display:flex;align-items:center;gap:6px;padding:10px 14px;background:var(--lp-soft);border-bottom:1px solid var(--lp-border)}
1040.lp-hc-dot{width:11px;height:11px;border-radius:50%}
1041.lp-hc-dot-r{background:#ff5f57}
1042.lp-hc-dot-y{background:#ffbd2e}
1043.lp-hc-dot-g{background:#28c840}
1044.lp-hc-path{margin-left:8px;font-family:'JetBrains Mono',monospace;font-size:11.5px;color:var(--lp-muted)}
1045.lp-hc-pr-row{display:flex;align-items:center;gap:10px;padding:12px 16px;border-bottom:1px solid var(--lp-border)}
1046.lp-hc-pr-title{font-size:13.5px;font-weight:600;color:var(--lp-ink)}
1047/* diff */
1048.lp-diff{font-family:'JetBrains Mono',monospace;font-size:12.5px;background:#fafafa;border-bottom:1px solid var(--lp-border)}
1049.lp-diff-line{display:flex;align-items:baseline;gap:0;line-height:1.7;padding:0 0}
1050.lp-diff-add{background:rgba(5,150,105,.07)}
1051.lp-diff-focus{background:rgba(5,150,105,.13)}
1052.lp-ln{width:36px;text-align:right;color:#9ca3af;padding-right:8px;user-select:none;font-size:11px}
1053.lp-op{width:16px;text-align:center;color:var(--lp-green);font-weight:700;flex-shrink:0}
1054.lp-diff-line code{font-family:'JetBrains Mono',monospace;font-size:12px;background:none;padding:0;color:#1f2937}
1055.lp-kw{color:#7c3aed;font-style:italic}
1056.lp-ty{color:#059669}
1057.lp-fn{color:#2563eb}
1058.lp-str{color:#d97706}
1059/* inline comment */
1060.lp-inline-comment{display:flex;gap:10px;padding:12px 16px;background:rgba(67,83,201,.04);border-bottom:1px solid rgba(67,83,201,.12)}
1061.lp-ic-ava{width:26px;height:26px;border-radius:50%;background:var(--lp-brand);color:#fff;font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px}
1062.lp-ic-head{font-size:12px;font-weight:600;color:var(--lp-ink-2);margin-bottom:3px}
1063.lp-ic-loc{color:var(--lp-brand);font-family:'JetBrains Mono',monospace;font-size:11px}
1064.lp-ic-text{font-size:13px;color:var(--lp-ink-2);line-height:1.5}
1065/* gates */
1066.lp-gates{display:flex;gap:6px;flex-wrap:wrap;padding:10px 16px;border-bottom:1px solid var(--lp-border)}
1067.lp-gate{font-size:11.5px;font-weight:600;padding:3px 9px;border-radius:20px}
1068.lp-gate-ok{color:var(--lp-green);background:rgba(5,150,105,.09)}
1069.lp-gate-spin{color:var(--lp-brand);background:rgba(67,83,201,.09)}
1070/* auto-merge banner */
1071.lp-automerge-bar{background:var(--lp-brand);color:#fff;font-size:12px;font-weight:600;text-align:center;padding:8px;letter-spacing:.01em}
1072
1073/* ── trust strip ── */
f8e5feaccanty labs1074.lp-trust-strip{border-bottom:1px solid var(--lp-border);padding:14px 0;background:var(--lp-soft)}
54f2e2accanty labs1075.lp-trust-in{display:flex;align-items:center;gap:20px;flex-wrap:wrap;font-size:13.5px;font-weight:500;color:var(--lp-muted);justify-content:center}
f8e5feaccanty labs1076.lp-sep{width:1px;height:14px;background:var(--lp-border)}
1077
54f2e2accanty labs1078/* ── impact band ── */
1079.lp-impact-band{padding:52px 0;border-bottom:1px solid var(--lp-border)}
1080.lp-impact-in{display:flex;align-items:center;justify-content:center;gap:0}
1081.lp-impact-stat{text-align:center;padding:0 60px;display:flex;flex-direction:column;align-items:center;gap:6px}
1082.lp-impact-n{font-family:'Inter Tight',sans-serif;font-size:clamp(40px,6vw,68px);font-weight:800;color:var(--lp-ink);letter-spacing:-.03em;line-height:1}
1083.lp-impact-x{color:var(--lp-brand);font-size:.7em}
1084.lp-impact-label{font-size:13.5px;color:var(--lp-muted);font-weight:500}
1085.lp-impact-sep{width:1px;height:64px;background:var(--lp-border);flex-shrink:0}
1086@media(max-width:600px){.lp-impact-in{flex-direction:column;gap:32px}.lp-impact-sep{width:64px;height:1px}.lp-impact-stat{padding:0}}
1087
1088/* ── section header ── */
f8e5feaccanty labs1089.lp-sec-head{max-width:680px;margin-bottom:52px}
1090.lp-sec-head .lp-h2{margin:8px 0 16px}
1091
54f2e2accanty labs1092/* ── live-now ── */
1093.lp-live-dot{color:var(--lp-brand);font-size:9px;margin-right:4px}
f8e5feaccanty labs1094.lp-live-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:32px}
1095@media(max-width:1000px){.lp-live-grid{grid-template-columns:repeat(2,1fr)}}
1096@media(max-width:560px){.lp-live-grid{grid-template-columns:1fr}}
54f2e2accanty labs1097.lp-live-card{background:#fff;border:1px solid var(--lp-border);border-radius:var(--lp-r);padding:20px;box-shadow:var(--lp-shadow);border-left:3px solid transparent;transition:transform .18s,box-shadow .2s}
1098.lp-live-card:hover{transform:translateY(-2px);box-shadow:var(--lp-shadow-lg)}
1099.lp-live-card-violet{border-left-color:rgba(124,58,237,.4);background:rgba(124,58,237,.02)}
1100.lp-live-card-green{border-left-color:rgba(5,150,105,.4);background:rgba(5,150,105,.02)}
1101.lp-live-card-brand{border-left-color:rgba(67,83,201,.4);background:rgba(67,83,201,.02)}
1102.lp-live-card-neutral{border-left-color:var(--lp-border)}
1103.lp-live-card-title{font-size:12.5px;font-weight:700;color:var(--lp-ink-2);text-transform:uppercase;letter-spacing:.05em;margin-bottom:14px}
f8e5feaccanty labs1104.lp-live-list{list-style:none;display:flex;flex-direction:column;gap:10px}
1105.lp-live-empty{font-size:13.5px;color:var(--lp-muted)}
54f2e2accanty labs1106.lp-live-row{display:flex;flex-direction:column;gap:3px;transition:background .3s}
f8e5feaccanty labs1107.lp-live-link{font-size:13.5px;color:var(--lp-ink);font-weight:500;line-height:1.4}
1108.lp-live-link:hover{color:var(--lp-brand)}
1109.lp-live-num{font-family:'JetBrains Mono',monospace;font-size:11.5px;color:var(--lp-muted)}
1110.lp-live-meta{font-size:12px;color:var(--lp-muted)}
1111.lp-live-bignum{display:flex;align-items:baseline;gap:6px;margin-bottom:10px}
54f2e2accanty labs1112.lp-live-bignum span:first-child{font-family:'Inter Tight',sans-serif;font-size:32px;font-weight:700;color:var(--lp-ink)}
f8e5feaccanty labs1113.lp-live-bignum-label{font-size:13.5px;color:var(--lp-muted)}
54f2e2accanty labs1114.lp-live-feedrow{display:flex;align-items:baseline;gap:5px;flex-wrap:wrap;font-size:13px;line-height:1.5}
1115.lp-live-rel{color:var(--lp-muted)}
f8e5feaccanty labs1116.lp-feed-kind{font-size:11.5px;font-weight:600;padding:2px 6px;border-radius:4px}
1117.lp-feed-kind-auto_merge-merged{color:var(--lp-green);background:rgba(5,150,105,.09)}
1118.lp-feed-kind-ai_build-dispatched{color:var(--lp-brand);background:rgba(67,83,201,.09)}
54f2e2accanty labs1119.lp-feed-kind-ai_review-posted{color:var(--lp-violet);background:rgba(124,58,237,.09)}
f8e5feaccanty labs1120.lp-live-cta{display:flex;align-items:center;gap:16px}
1121
54f2e2accanty labs1122/* ── platform grid ── */
1123.lp-platform-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:2px;border:1px solid var(--lp-border);border-radius:14px;overflow:hidden;background:var(--lp-border)}
f8e5feaccanty labs1124@media(max-width:900px){.lp-platform-grid{grid-template-columns:repeat(2,1fr)}}
1125@media(max-width:500px){.lp-platform-grid{grid-template-columns:1fr}}
54f2e2accanty labs1126.lp-plat-group{background:#fff;padding:22px;display:flex;flex-direction:column;gap:12px;transition:background .15s}
1127.lp-plat-group:hover{background:#fafbff}
1128.lp-plat-header{display:flex;align-items:center;gap:8px;margin-bottom:2px}
1129.lp-plat-icon{display:flex;flex-shrink:0}
1130.lp-plat-icon svg{display:block}
1131.lp-plat-title{font-size:13px;font-weight:700;color:var(--lp-ink)}
1132.lp-plat-list{list-style:none;display:flex;flex-direction:column;gap:5px}
1133.lp-plat-list li{font-size:13px;color:var(--lp-ink-2)}
1134
1135/* ── pain table ── */
1136.lp-pain-table{display:flex;flex-direction:column;border:1px solid var(--lp-border);border-radius:14px;overflow:hidden}
1137.lp-pain-row{display:grid;grid-template-columns:1fr 40px 1fr;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--lp-border);transition:background .15s}
f8e5feaccanty labs1138.lp-pain-row:last-child{border-bottom:0}
1139.lp-pain-row:hover{background:var(--lp-soft)}
54f2e2accanty labs1140.lp-pain-problem{display:flex;align-items:flex-start;gap:10px;font-size:15px;color:#6b7280}
f8e5feaccanty labs1141.lp-pain-fix{display:flex;align-items:flex-start;gap:10px;font-size:15px;color:var(--lp-ink);font-weight:500}
1142.lp-pain-arrow{font-size:18px;color:var(--lp-muted);text-align:center}
54f2e2accanty labs1143.lp-pain-icon{font-size:12.5px;font-weight:700;margin-top:3px;flex-shrink:0}
1144.lp-pain-no{color:#b91c1c}
f8e5feaccanty labs1145.lp-pain-yes{color:var(--lp-green)}
54f2e2accanty labs1146@media(max-width:700px){.lp-pain-row{grid-template-columns:1fr;gap:8px}.lp-pain-arrow{display:none}}
f8e5feaccanty labs1147
54f2e2accanty labs1148/* ── AI features ── */
1149.lp-ai-features{display:flex;flex-direction:column;gap:72px}
f8e5feaccanty labs1150.lp-ai-feature{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
1151.lp-ai-feature-rev{direction:rtl}
1152.lp-ai-feature-rev>*{direction:ltr}
1153@media(max-width:800px){.lp-ai-feature,.lp-ai-feature-rev{grid-template-columns:1fr;direction:ltr}}
54f2e2accanty labs1154.lp-ai-n{font-family:'JetBrains Mono',monospace;font-size:11px;font-weight:500;color:var(--lp-muted);margin-bottom:10px;letter-spacing:.04em}
1155.lp-ai-title{font-family:'Inter Tight',sans-serif;font-weight:700;font-size:clamp(22px,3vw,30px);line-height:1.12;letter-spacing:-.018em;color:var(--lp-ink);margin-bottom:14px}
f8e5feaccanty labs1156.lp-ai-body{font-size:16px;color:var(--lp-ink-2);line-height:1.65;margin-bottom:18px}
54f2e2accanty labs1157.lp-ai-mock{background:#fff;border:1px solid var(--lp-border);border-radius:14px;overflow:hidden;box-shadow:var(--lp-shadow-lg)}
1158/* review mock */
1159.lp-review-mock{display:flex;flex-direction:column;gap:0;font-size:13.5px}
1160.lp-rm-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--lp-border);background:var(--lp-soft)}
1161.lp-rm-label{font-size:12.5px;font-weight:600;color:var(--lp-ink-2)}
1162.lp-rm-steps{padding:14px 16px;display:flex;flex-direction:column;gap:10px}
1163.lp-rm-step{display:flex;align-items:flex-start;gap:10px;font-size:13px;color:var(--lp-ink-2);line-height:1.45}
1164.lp-rm-icon{font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--lp-green);flex-shrink:0;width:14px}
1165.lp-rm-fail{color:var(--lp-red)}
1166.lp-rm-done{opacity:.7}
1167.lp-rm-active{color:var(--lp-ink);font-weight:500}
1168.lp-rm-time{padding:8px 16px;font-size:11.5px;color:var(--lp-muted);border-top:1px solid var(--lp-border);font-family:'JetBrains Mono',monospace}
1169.lp-rm-comment{display:flex;gap:10px;padding:12px 16px;background:rgba(67,83,201,.03)}
1170.lp-rm-ava{width:28px;height:28px;border-radius:50%;background:var(--lp-brand);color:#fff;font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px}
1171.lp-rm-bubble{flex:1;font-size:13px;color:var(--lp-ink-2);line-height:1.5}
1172.lp-rm-file{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--lp-brand);margin-bottom:4px}
1173.lp-rm-verdict{padding:10px 16px;border-top:1px solid var(--lp-border)}
1174.lp-rm-v-ok{font-size:13px;font-weight:600;color:var(--lp-green)}
1175/* digest mock */
1176.lp-digest-rows{padding:14px 16px;display:flex;flex-direction:column;gap:9px}
1177.lp-digest-row{display:flex;align-items:flex-start;gap:8px;font-size:13.5px;color:var(--lp-ink-2)}
1178.lp-digest-ok{color:var(--lp-green);font-weight:700;flex-shrink:0}
1179
1180/* ── security cards ── */
f8e5feaccanty labs1181.lp-security-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
1182@media(max-width:900px){.lp-security-grid{grid-template-columns:repeat(2,1fr)}}
1183@media(max-width:560px){.lp-security-grid{grid-template-columns:1fr}}
54f2e2accanty labs1184.lp-sec-card{background:#fff;border:1px solid var(--lp-border);border-radius:var(--lp-r);padding:24px;box-shadow:var(--lp-shadow);transition:transform .18s,box-shadow .2s}
1185.lp-sec-card:hover{transform:translateY(-3px);box-shadow:var(--lp-shadow-lg)}
f8e5feaccanty labs1186.lp-sec-card-title{font-size:15px;font-weight:700;color:var(--lp-ink);margin-bottom:10px}
54f2e2accanty labs1187.lp-sec-card-body{font-size:13.5px;color:var(--lp-ink-2);line-height:1.6}
f8e5feaccanty labs1188
54f2e2accanty labs1189/* ── teams ── */
f8e5feaccanty labs1190.lp-teams-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
1191@media(max-width:1000px){.lp-teams-grid{grid-template-columns:repeat(2,1fr)}}
1192@media(max-width:560px){.lp-teams-grid{grid-template-columns:1fr}}
54f2e2accanty labs1193.lp-team-card{background:#fff;border:1px solid var(--lp-border);border-radius:var(--lp-r);padding:24px;box-shadow:var(--lp-shadow);transition:transform .18s,box-shadow .2s}
1194.lp-team-card:hover{transform:translateY(-3px);box-shadow:var(--lp-shadow-lg)}
1195.lp-team-title{font-size:14.5px;font-weight:700;color:var(--lp-ink);margin-bottom:14px;padding-bottom:12px;border-bottom:1px solid var(--lp-border)}
f8e5feaccanty labs1196.lp-team-list{list-style:none;display:flex;flex-direction:column;gap:8px}
54f2e2accanty labs1197.lp-team-list li{display:flex;align-items:flex-start;gap:8px;font-size:13.5px;color:var(--lp-ink-2);line-height:1.4}
f8e5feaccanty labs1198.lp-team-list li span{color:var(--lp-green);font-size:12px;margin-top:2px;flex-shrink:0}
1199
54f2e2accanty labs1200/* ── ecosystem ── */
f8e5feaccanty labs1201.lp-eco-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
1202@media(max-width:900px){.lp-eco-grid{grid-template-columns:repeat(2,1fr)}}
1203@media(max-width:500px){.lp-eco-grid{grid-template-columns:1fr}}
54f2e2accanty labs1204.lp-eco-card{background:#fff;border:1px solid var(--lp-border);border-radius:var(--lp-r);padding:24px;box-shadow:var(--lp-shadow);display:flex;flex-direction:column;gap:10px;transition:transform .18s,box-shadow .2s}
1205.lp-eco-card:hover{transform:translateY(-3px);box-shadow:var(--lp-shadow-lg)}
f8e5feaccanty labs1206.lp-eco-title{font-size:15px;font-weight:700;color:var(--lp-ink)}
54f2e2accanty labs1207.lp-eco-sub{font-family:'JetBrains Mono',monospace;font-size:11.5px;color:var(--lp-brand)}
1208.lp-eco-body{font-size:13.5px;color:var(--lp-ink-2);line-height:1.6;flex:1}
f8e5feaccanty labs1209
54f2e2accanty labs1210/* ── comparison ── */
f8e5feaccanty labs1211.lp-compare{border:1px solid var(--lp-border);border-radius:14px;overflow:hidden}
54f2e2accanty labs1212.lp-compare-head{display:grid;grid-template-columns:1fr 160px 160px;padding:12px 20px;background:var(--lp-soft);font-size:12.5px;font-weight:700;color:var(--lp-muted);text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--lp-border)}
1213.lp-cmp-row{display:grid;grid-template-columns:1fr 160px 160px;padding:14px 20px;border-bottom:1px solid var(--lp-border);font-size:14px;align-items:center;transition:background .15s}
f8e5feaccanty labs1214.lp-cmp-row:last-child{border-bottom:0}
1215.lp-cmp-ours{background:rgba(67,83,201,.025)}
54f2e2accanty labs1216.lp-cmp-ours:hover{background:rgba(67,83,201,.04)}
f8e5feaccanty labs1217.lp-cmp-feature{color:var(--lp-ink-2)}
54f2e2accanty labs1218.lp-cmp-them{color:var(--lp-muted);font-size:13.5px}
1219.lp-cmp-us{color:var(--lp-muted);font-size:13.5px}
1220.lp-cmp-us-hl{color:var(--lp-green);font-weight:700}
f8e5feaccanty labs1221.lp-compare-foot{margin-top:16px}
54f2e2accanty labs1222@media(max-width:700px){.lp-compare-head,.lp-cmp-row{grid-template-columns:1fr 90px 90px;font-size:12.5px}}
f8e5feaccanty labs1223
54f2e2accanty labs1224/* ── pricing ── */
f8e5feaccanty labs1225.lp-price-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
1226@media(max-width:800px){.lp-price-grid{grid-template-columns:1fr}}
54f2e2accanty labs1227.lp-price-card{background:#fff;border:1px solid var(--lp-border);border-radius:14px;padding:28px;box-shadow:var(--lp-shadow);display:flex;flex-direction:column;gap:0;position:relative;transition:transform .18s,box-shadow .2s}
1228.lp-price-card:hover{transform:translateY(-3px);box-shadow:var(--lp-shadow-lg)}
1229.lp-price-hl{border-color:var(--lp-brand);box-shadow:0 0 0 1px var(--lp-brand),var(--lp-shadow)}
1230.lp-price-badge{position:absolute;top:-13px;left:50%;transform:translateX(-50%);background:var(--lp-brand);color:#fff;font-size:11.5px;font-weight:700;padding:4px 14px;border-radius:999px}
1231.lp-price-tier{font-size:12.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--lp-brand);margin-bottom:12px}
f8e5feaccanty labs1232.lp-price-amount{display:flex;align-items:baseline;gap:6px;margin-bottom:12px}
54f2e2accanty labs1233.lp-price-num{font-family:'Inter Tight',sans-serif;font-size:36px;font-weight:800;color:var(--lp-ink);letter-spacing:-.02em}
1234.lp-price-cad{font-size:13.5px;color:var(--lp-muted)}
1235.lp-price-desc{font-size:13.5px;color:var(--lp-ink-2);line-height:1.6;margin-bottom:20px}
1236.lp-price-features{list-style:none;display:flex;flex-direction:column;gap:8px;margin-bottom:24px;flex:1}
1237.lp-price-features li{display:flex;align-items:flex-start;gap:8px;font-size:13.5px;color:var(--lp-ink-2)}
f8e5feaccanty labs1238.lp-price-features li span{color:var(--lp-green);font-size:12px;margin-top:2px}
1239.lp-price-foot{margin-top:16px}
1240
54f2e2accanty labs1241/* ── install ── */
f8e5feaccanty labs1242.lp-install-wrap{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
1243@media(max-width:800px){.lp-install-wrap{grid-template-columns:1fr}}
1244.lp-install-text{display:flex;flex-direction:column}
1245.lp-install-text .lp-kicker{margin-bottom:16px}
54f2e2accanty labs1246.lp-install-terminal{background:#fff;border:1px solid var(--lp-border);border-radius:14px;overflow:hidden;box-shadow:var(--lp-shadow-lg)}
1247.lp-term-bar{display:flex;align-items:center;gap:6px;padding:10px 16px;background:var(--lp-soft);border-bottom:1px solid var(--lp-border)}
f8e5feaccanty labs1248.lp-term-dot{width:10px;height:10px;border-radius:50%;background:#d1d5db}
1249.lp-term-title{margin-left:8px;font-size:12px;color:var(--lp-muted);font-family:'JetBrains Mono',monospace}
1250.lp-term-body{padding:16px;display:flex;flex-direction:column;gap:8px}
1251.lp-term-line{display:flex;align-items:center;gap:10px;font-family:'JetBrains Mono',monospace;font-size:13px}
1252.lp-term-prompt{color:var(--lp-brand);font-weight:500}
54f2e2accanty labs1253.lp-term-out{font-family:'JetBrains Mono',monospace;font-size:12.5px;color:var(--lp-muted);padding-left:20px}
f8e5feaccanty labs1254.lp-term-ok{color:var(--lp-green)}
54f2e2accanty labs1255.lp-copy-btn{margin-left:auto;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;padding:4px 10px;border:1px solid var(--lp-border);border-radius:6px;background:#fff;color:var(--lp-ink-2);cursor:pointer;transition:background .15s,color .15s}
f8e5feaccanty labs1256.lp-copy-btn:hover{background:var(--lp-soft);color:var(--lp-ink)}
1257
54f2e2accanty labs1258/* ── dark CTA ── */
1259.lp-cta-dark{background:var(--lp-navy);padding:96px 0;border-top:1px solid rgba(255,255,255,.06)}
1260.lp-cta-in{text-align:center;display:flex;flex-direction:column;align-items:center}
1261.lp-kicker-dark{color:rgba(163,178,238,.9)}
1262.lp-cta-h{font-family:'Inter Tight',sans-serif;font-weight:800;font-size:clamp(32px,5vw,56px);line-height:1.06;letter-spacing:-.025em;color:#fff;margin:12px 0 18px}
1263.lp-cta-sub{font-size:18px;color:rgba(255,255,255,.65);max-width:52ch;margin-bottom:36px}
1264.lp-cta-btns{display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-bottom:24px}
1265.lp-cta-links-dark{display:flex;gap:12px;align-items:center;font-size:14px}
1266.lp-cta-links-dark a{color:rgba(163,178,238,.85);font-weight:500}
1267.lp-cta-links-dark a:hover{color:#fff}
1268.lp-cta-links-dark span{color:rgba(255,255,255,.2)}
1269
1270/* ── footer ── */
1271.lp-footer{background:var(--lp-navy);border-top:1px solid rgba(255,255,255,.07);padding:64px 0 0}
1272.lp-footer-in{display:grid;grid-template-columns:260px 1fr;gap:64px;margin-bottom:48px}
f8e5feaccanty labs1273@media(max-width:800px){.lp-footer-in{grid-template-columns:1fr;gap:32px}}
1274.lp-footer-brand{display:flex;flex-direction:column;gap:12px}
54f2e2accanty labs1275.lp-footer-tag{font-size:13.5px;color:rgba(255,255,255,.4);line-height:1.6}
f8e5feaccanty labs1276.lp-footer-cols{display:grid;grid-template-columns:repeat(4,1fr);gap:32px}
1277@media(max-width:700px){.lp-footer-cols{grid-template-columns:repeat(2,1fr)}}
1278.lp-footer-col{display:flex;flex-direction:column;gap:10px}
54f2e2accanty labs1279.lp-footer-col h4{font-size:12.5px;font-weight:700;color:rgba(255,255,255,.9);text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px}
1280.lp-footer-col a{font-size:13.5px;color:rgba(255,255,255,.45);transition:color .15s}
1281.lp-footer-col a:hover{color:rgba(255,255,255,.9)}
1282.lp-footer-bottom{border-top:1px solid rgba(255,255,255,.07);padding:20px 0}
1283.lp-footer-bottom-in{display:flex;justify-content:space-between;align-items:center;font-size:13px;color:rgba(255,255,255,.3)}
f8e5feaccanty labs1284`;