feat: flatten routes and merge marketing and onboarding directories

This commit is contained in:
2026-06-06 18:52:03 -07:00
parent 47417d13a0
commit 0480b306f1
139 changed files with 36409 additions and 229 deletions

View File

@@ -0,0 +1,333 @@
// The Journey — 4 steps from idea → first 100 customers. A visual marker shows
// where most tools stop. Each step shows a tiny "demo" snippet of what Vibn does.
const JOURNEY_STEPS = [
{
num: "01",
title: "You describe it.",
sub: "The AI builds it.",
body: "Talk to it like you'd talk to a friend who codes. It builds the screens, the buttons, the logic — whatever your idea needs.",
demo: "describe",
},
{
num: "02",
title: "It goes live.",
sub: "The AI puts it online.",
body: "Logins, saving your stuff, hosting — handled. You get a live link from minute one. Share it. Show your friends. It just works.",
demo: "live",
},
{
num: "03",
title: "It gets seen.",
sub: "The AI markets it.",
body: "Posts, emails, social — written, scheduled, and shipped on autopilot. The tone matches your brand because you trained it talking to your AI.",
demo: "seen",
},
{
num: "04",
title: "It gets customers.",
sub: "Your first 100.",
body: "Through our Google partnership, Vibn helps the right people find your product when they're searching for what you built.",
demo: "customers",
},
];
function Journey() {
return (
<section className="section journey" id="how">
<style>{`
.journey { padding-block: clamp(80px, 11vh, 140px); }
.journey-head { text-align: center; max-width: 820px; margin: 0 auto 64px; }
.journey-title {
font-size: clamp(36px, 4.8vw, 64px);
font-weight: 500; letter-spacing: -0.025em; line-height: 1.02;
text-wrap: balance;
}
.journey-title .accent { color: var(--accent); }
.journey-sub {
margin-top: 20px;
color: var(--fg-mute); font-size: 17px;
text-wrap: balance;
}
.journey-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
position: relative;
}
@media (max-width: 1080px) { .journey-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .journey-grid { grid-template-columns: 1fr; } }
.step {
position: relative;
padding: 24px 24px 0;
border-radius: 16px;
background: linear-gradient(180deg, oklch(0.20 0.009 60 / 0.55), oklch(0.17 0.008 60 / 0.55));
border: 1px solid var(--hairline);
display: flex; flex-direction: column;
min-height: 380px;
overflow: hidden;
isolation: isolate;
}
.step::before {
/* Top accent line that varies by step */
content: "";
position: absolute; top: 0; left: 0; right: 0; height: 1px;
background: linear-gradient(90deg, transparent, var(--accent) 50%, transparent);
opacity: 0;
}
.step.active::before { opacity: .7; }
.step.stopped {
opacity: 0.46;
}
.step.stopped::after {
content: "";
position: absolute; inset: 0;
background: linear-gradient(180deg, transparent 40%, oklch(0.155 0.008 60 / 0.6));
pointer-events: none;
}
.step-num {
font-family: var(--font-mono);
font-size: 11px;
color: var(--fg-faint);
letter-spacing: 0.08em;
}
.step-title {
margin-top: 12px;
font-size: 22px; font-weight: 500;
letter-spacing: -0.018em;
}
.step-sub {
margin-top: 4px;
color: var(--accent);
font-size: 15px;
font-weight: 500;
}
.step.stopped .step-sub { color: var(--fg-mute); }
.step-body {
margin-top: 12px;
color: var(--fg-dim);
font-size: 14px;
line-height: 1.55;
}
.step-demo {
margin-top: auto;
margin-inline: -24px; margin-bottom: 0;
padding: 16px 18px;
border-top: 1px solid var(--hairline);
background: oklch(0.16 0.008 60 / 0.6);
font-family: var(--font-mono);
font-size: 12px; line-height: 1.55;
color: var(--fg-dim);
min-height: 116px;
display: flex; flex-direction: column;
gap: 7px;
}
/* Visual marker: where other tools stop */
.stop-marker {
position: absolute;
left: calc(50% - 8px);
top: 0; bottom: 0;
width: 16px;
display: flex; flex-direction: column; align-items: center;
pointer-events: none;
z-index: 2;
}
@media (max-width: 1080px) { .stop-marker { display: none; } }
.stop-marker .line {
flex: 1; width: 1px;
background: repeating-linear-gradient(180deg, var(--accent) 0 6px, transparent 6px 12px);
opacity: .7;
}
.stop-label {
font-family: var(--font-mono);
font-size: 10px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent);
background: var(--bg);
padding: 6px 12px;
border-radius: 999px;
border: 1px solid oklch(0.74 0.175 35 / 0.5);
white-space: nowrap;
box-shadow: 0 0 24px var(--accent-glow);
transform: translateY(-1px);
}
/* Demo blocks */
.demo-row { display: flex; gap: 8px; align-items: flex-start; }
.demo-tag {
font-family: var(--font-mono); font-size: 10px;
padding: 1px 6px; border-radius: 4px;
color: var(--fg-faint);
background: oklch(0.22 0.01 60);
letter-spacing: 0.04em;
flex-shrink: 0;
margin-top: 1px;
}
.demo-tag.you { color: oklch(0.85 0.06 250); background: oklch(0.28 0.04 250); }
.demo-tag.ai { color: var(--accent); background: oklch(0.35 0.10 35 / 0.4); }
.demo-line { color: var(--fg-dim); }
.demo-ok { color: var(--ok); }
.demo-host {
display: inline-flex; align-items: center; gap: 6px;
color: var(--fg-dim);
}
.demo-host i {
width: 6px; height: 6px; border-radius: 50%;
background: var(--ok);
box-shadow: 0 0 6px oklch(0.78 0.16 155 / 0.6);
}
.demo-progress {
height: 4px; border-radius: 999px;
background: oklch(0.25 0.01 60);
overflow: hidden;
position: relative;
}
.demo-progress span {
position: absolute; inset: 0;
background: var(--accent);
width: 64%;
box-shadow: 0 0 8px var(--accent-glow);
}
.demo-customer {
display: flex; align-items: center; gap: 8px;
}
.demo-customer .av {
width: 16px; height: 16px; border-radius: 50%;
flex-shrink: 0;
}
.demo-num {
font-family: var(--font-mono); font-size: 22px;
color: var(--accent);
letter-spacing: -0.02em;
font-weight: 500;
}
.demo-num small {
color: var(--fg-mute); font-size: 11px;
font-weight: 400;
margin-left: 4px;
}
.journey-foot {
margin-top: 48px;
text-align: center;
color: var(--fg-mute);
font-size: 15px;
text-wrap: balance;
}
.journey-foot b {
color: var(--fg);
font-weight: 500;
}
`}</style>
<div className="wrap">
<div className="journey-head">
<Eyebrow>The journey</Eyebrow>
<h2 className="journey-title" style={{ marginTop: 18 }}>
From idea to first 100 customers.
<br/><span className="accent">In one chat.</span>
</h2>
<p className="journey-sub">
Other tools take you to step two and wave goodbye. Vibn keeps building with you.
</p>
</div>
<div className="journey-grid">
{/* "Where everyone else stops" marker, sits over the gap between cards 2 and 3 */}
<div className="stop-marker" style={{ left: "calc(50% - 1px)" }}>
<div className="line" />
<span className="stop-label"> Where every other tool stops</span>
<div className="line" />
</div>
{JOURNEY_STEPS.map((step, i) => (
<StepCard key={step.num} step={step} stopped={i >= 2} />
))}
</div>
<p className="journey-foot">
<b>One tool. One chat.</b> From "wouldn't it be cool if…" to <b>real customers paying you money.</b>
</p>
</div>
</section>
);
}
function StepCard({ step, stopped }) {
return (
<div className={`step${stopped ? "" : " active"}`}>
<div>
<div className="step-num">{step.num}</div>
<h3 className="step-title">{step.title}</h3>
<div className="step-sub">{step.sub}</div>
<p className="step-body">{step.body}</p>
</div>
<StepDemo demo={step.demo} />
</div>
);
}
function StepDemo({ demo }) {
if (demo === "describe") {
return (
<div className="step-demo">
<div className="demo-row"><span className="demo-tag you">YOU</span><span className="demo-line">build a booking site for my dog grooming biz</span></div>
<div className="demo-row"><span className="demo-tag ai">VIBN</span><span className="demo-line">on it designing screens</span></div>
<div className="demo-row" style={{ alignItems: "center" }}>
<span className="demo-tag ai">VIBN</span>
<span className="demo-ok"> booking flow ready</span>
</div>
</div>
);
}
if (demo === "live") {
return (
<div className="step-demo">
<div className="demo-row" style={{ alignItems: "center" }}>
<span className="demo-tag ai">VIBN</span>
<span className="demo-line">put it online</span>
</div>
<div className="demo-progress"><span /></div>
<div className="demo-row" style={{ alignItems: "center", marginTop: 2 }}>
<span className="demo-host"><i /> pawsandposh.vibn.app</span>
</div>
<div className="demo-row"><span className="demo-ok"> logins · saving · live</span></div>
</div>
);
}
if (demo === "seen") {
return (
<div className="step-demo">
<div className="demo-row"><span className="demo-tag ai">VIBN</span><span className="demo-line">draft a launch post for Instagram + email blast</span></div>
<div className="demo-row" style={{ color: "var(--fg-faint)" }}> scheduled for Tue 9:00 AM</div>
<div className="demo-row" style={{ color: "var(--fg-faint)" }}> scheduled for Thu 6:00 PM</div>
<div className="demo-row"><span className="demo-ok"> 3 channels on autopilot</span></div>
</div>
);
}
if (demo === "customers") {
return (
<div className="step-demo">
<div className="demo-row" style={{ alignItems: "center" }}>
<span className="demo-num">+47<small>this week</small></span>
</div>
<div className="demo-customer">
<span className="av" style={{ background: "oklch(0.55 0.14 35)" }} />
<span className="av" style={{ background: "oklch(0.55 0.14 260)" }} />
<span className="av" style={{ background: "oklch(0.55 0.14 155)" }} />
<span className="av" style={{ background: "oklch(0.55 0.14 80)" }} />
<span style={{ color: "var(--fg-mute)" }}>found you via Google</span>
</div>
<div className="demo-row"><span className="demo-ok"> tracking toward 100</span></div>
</div>
);
}
return null;
}
Object.assign(window, { Journey });