Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
120bc07
feat: upgrade DocBlocks with new components and icon support
crypropro1-cmd Apr 23, 2026
a9511b9
fix: use item.text as stable key in DocFeatureGrid
crypropro1-cmd Apr 23, 2026
4fb3aaa
fix: reset blog/sign-in/download to dark OLED emerald theme
crypropro1-cmd Apr 23, 2026
952bc9d
fix: sign-in button type submit
crypropro1-cmd Apr 23, 2026
3e00ece
feat: enrich doc pages with DocFeatureGrid and labels
crypropro1-cmd Apr 23, 2026
0dcfcb9
feat: enrich DocBlocks with feature grids
crypropro1-cmd Apr 23, 2026
88e180d
feat: enrich doc pages with DocFeatureGrid and DocStat
crypropro1-cmd Apr 23, 2026
757f50d
fix: apply DocFeatureGrid and DocSectionLabel to security-model
crypropro1-cmd Apr 23, 2026
34e9a69
fix: escape quotes in vpn-servers JSX text
crypropro1-cmd Apr 23, 2026
972878c
feat(docs): enrich partners, support, what-is-my-ip with DocFeatureGrid
crypropro1-cmd Apr 23, 2026
f47bf4e
feat(cta): clipboard install flow with Win+R/Ctrl+V/Enter keystrokes
crypropro1-cmd Apr 23, 2026
1b2b699
docs(cta): hero + vertical stepper redesign spec
crypropro1-cmd Apr 23, 2026
3484053
docs(cta): absolute-grade appendix from 4 specialist passes
crypropro1-cmd Apr 23, 2026
5ddffc0
docs(cta): implementation plan for hero + vertical stepper
crypropro1-cmd Apr 23, 2026
bcd3583
style(cta): replace violet mesh orb with emerald-700
crypropro1-cmd Apr 23, 2026
781d8ca
refactor(cta): demote VPNOrbit to atmosphere with acknowledge flash
crypropro1-cmd Apr 23, 2026
e143203
feat(cta): add AuroraBacklight atmosphere layer
crypropro1-cmd Apr 23, 2026
3ee3afe
feat(cta): mount AuroraBacklight inside modal shell
crypropro1-cmd Apr 23, 2026
fd96aad
feat(cta): add HeroButton primary CTA
crypropro1-cmd Apr 23, 2026
63aa974
feat(cta): add LaunchedChip, SectionDivider, StepCard, StepperConnector
crypropro1-cmd Apr 23, 2026
4371062
chore(cta): retune stepper cascade delayChildren
crypropro1-cmd Apr 23, 2026
5219151
refactor(cta): swap TryFreeCard+StepRow for HeroButton+StepCard layout
crypropro1-cmd Apr 23, 2026
1c346c3
refactor(cta): remove unused TryFreeCard, StepRow, KeyCap, ConfettiBu…
crypropro1-cmd Apr 23, 2026
ee7ccdb
fix(cta): replace Russian text with English (UI + comments)
crypropro1-cmd Apr 23, 2026
94fbc3c
fix(cta): hero always clickable + styled section divider
crypropro1-cmd Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
983 changes: 983 additions & 0 deletions docs/superpowers/plans/2026-04-24-ctamodal-hero-ribbon.md

Large diffs are not rendered by default.

321 changes: 321 additions & 0 deletions docs/superpowers/specs/2026-04-24-ctamodal-hero-ribbon-design.md

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions src/app/(site)/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { DocCallout, DocInlineLink } from "@/components/proton/DocBlocks";
import { docMetadata } from "@/lib/page-meta";
import { BLOG_POSTS } from "@/lib/blog-posts";
import { ROUTES } from "@/lib/site-routes";
import { syne } from "@/lib/proton-fonts";
import { cn } from "@/lib/utils";
import { ArrowLeft } from "lucide-react";
import Link from "next/link";

export const metadata = docMetadata(
"Blog",
"/blog",
"Security guides, audits, and product deep dives.",
);

export default function BlogIndexPage() {
const entries = Object.entries(BLOG_POSTS);
return (
<div className="relative mx-auto max-w-3xl px-4 py-14 md:px-8 md:py-20 xl:px-16">
<div
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[300px] bg-[radial-gradient(ellipse_60%_60%_at_50%_0%,rgb(16_185_129/_0.06),transparent_75%)]"
/>

<nav aria-label="Breadcrumb" className="mb-8 text-sm">
<Link
href={ROUTES.home}
className="group/back inline-flex items-center gap-1.5 font-medium text-zinc-400 transition-colors hover:text-emerald-300"
>
<ArrowLeft
className="size-3.5 transition-transform duration-200 group-hover/back:-translate-x-0.5"
strokeWidth={2.2}
/>
Home
</Link>
</nav>

<h1
className={cn(
syne.className,
"text-4xl font-semibold tracking-tight text-zinc-50 sm:text-[40px]",
)}
>
Blog
</h1>
<p className="mt-6 text-[17px] leading-relaxed text-zinc-400">
Longer articles live on their own URLs inside this demo. Topics cover
audits, open source, browser extensions, mobile privacy, and kill
switch behaviour — all scoped to the VPN product line.
</p>

<DocCallout title="Editorial note">
<p className="text-sm leading-relaxed">
Replace or extend posts in{" "}
<code className="rounded bg-white/[0.08] px-1.5 py-0.5 text-xs text-zinc-300">
src/lib/blog-posts.ts
</code>
. For MDX later, swap the dynamic route to read from the filesystem.
</p>
</DocCallout>

<ul className="mt-10 space-y-4">
{entries.map(([slug, post]) => (
<li key={slug}>
<Link
href={`${ROUTES.blog}/${slug}`}
className="group block rounded-2xl border border-white/[0.06] bg-white/[0.02] p-6 backdrop-blur-sm transition-all duration-300 hover:-translate-y-0.5 hover:border-emerald-400/20 hover:bg-white/[0.04]"
>
<h2 className="text-[17px] font-semibold text-zinc-50 transition-colors group-hover:text-emerald-300">
{post.title}
</h2>
<p className="mt-2 text-[14px] leading-relaxed text-zinc-400">
{post.excerpt}
</p>
<span className="mt-3 inline-block text-[13px] font-medium text-emerald-400">
Read article →
</span>
</Link>
</li>
))}
</ul>

<p className="mt-10 text-center text-sm text-zinc-500">
More to explore:{" "}
<DocInlineLink href={ROUTES.support}>Support</DocInlineLink>
{" · "}
<DocInlineLink href={ROUTES.features}>Features</DocInlineLink>
</p>
</div>
);
}
72 changes: 72 additions & 0 deletions src/app/(site)/business/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
DocCallout,
DocFeatureGrid,
DocH2,
DocInlineLink,
DocSectionLabel,
} from "@/components/proton/DocBlocks";
import { SimpleDocPage } from "@/components/proton/SimpleDocPage";
import { docMetadata } from "@/lib/page-meta";
import { ROUTES } from "@/lib/site-routes";
import {
Banknote,
GitBranch,
Headphones,
Server,
UserCheck,
} from "lucide-react";

export const metadata = docMetadata(
"Business VPN",
"/business",
"VPN for teams: deployment, billing, and support.",
);

export default function BusinessPage() {
return (
<SimpleDocPage
title="Business VPN"
description="Give every employee encrypted egress without shipping hardware VPN concentrators. Central dashboards help IT provision tokens, revoke leavers, and prove coverage during audits."
>
<DocSectionLabel>Enterprise features</DocSectionLabel>
<DocH2 icon={UserCheck}>Common requirements</DocH2>
<DocFeatureGrid
items={[
{
icon: UserCheck,
text: "SSO or directory sync for onboarding at scale.",
},
{
icon: Banknote,
text: "Invoice-friendly billing and optional purchase orders.",
},
{
icon: Server,
text: "Dedicated gateways or static egress IPs for allow-lists.",
},
{
icon: Headphones,
text: "Priority support SLAs and named customer success for larger seats.",
},
]}
/>
<DocH2 icon={GitBranch}>Rollout pattern</DocH2>
<p>
Pilot on a single team, gather latency feedback, then expand with MDM
packages for macOS and Windows and managed app configs for mobile. Use
the{" "}
<DocInlineLink href={ROUTES.download}>Download</DocInlineLink> page to
deep-link installers per platform.
</p>
<DocCallout title="Talk to sales">
<p className="text-sm leading-relaxed">
<DocInlineLink href={ROUTES.businessContact}>
Business contact
</DocInlineLink>{" "}
— demo form placeholder. For quotes, attach expected seat count and
regions.
</p>
</DocCallout>
</SimpleDocPage>
);
}
62 changes: 62 additions & 0 deletions src/app/(site)/contact/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
DocCallout,
DocFeatureGrid,
DocH2,
DocInlineLink,
DocSectionLabel,
} from "@/components/proton/DocBlocks";
import { SimpleDocPage } from "@/components/proton/SimpleDocPage";
import { docMetadata } from "@/lib/page-meta";
import { ROUTES } from "@/lib/site-routes";
import { Bug, ExternalLink, Newspaper, Wrench } from "lucide-react";

export const metadata = docMetadata(
"Contact",
"/contact",
"Press, partnerships, and general inquiries.",
);

export default function ContactPage() {
return (
<SimpleDocPage
title="Contact us"
description="Route requests to the right inbox: press teams need fact sheets, affiliates need programme rules, and users with broken installs should start in Support so engineers see structured tickets."
>
<DocSectionLabel>Routing guide</DocSectionLabel>
<DocH2 icon={ExternalLink}>Before you write</DocH2>
<DocFeatureGrid
items={[
{
icon: Wrench,
text: "Connection problems — start with Support and the FAQ so logs can be attached.",
},
{
icon: Newspaper,
text: "Press / media — include outlet, deadline, and languages required.",
},
{
icon: Bug,
text: "Security research — use the vendor’s published disclosure address.",
},
]}
/>
<DocH2>Faster self-serve links</DocH2>
<p>
<DocInlineLink href={ROUTES.support}>Help and support</DocInlineLink>
{" · "}
<DocInlineLink href={ROUTES.faq}>FAQ</DocInlineLink>
{" · "}
<DocInlineLink href={ROUTES.partners}>Partners</DocInlineLink>
</p>
<DocCallout title="Demo">
<p className="text-sm">
Embed HubSpot, Formspree, or a simple{" "}
<code className="rounded bg-white/[0.08] px-1.5 py-0.5 text-xs text-zinc-300">
mailto:
</code>{" "}
button on this route when you deploy.
</p>
</DocCallout>
</SimpleDocPage>
);
}
Loading