chore: clean up root directory, move docs to /docs and legacy plans to /docs_archive

This commit is contained in:
2026-05-07 15:05:34 -07:00
parent dc60e1fdf5
commit 3563b98de1
65 changed files with 1 additions and 40164 deletions

View File

@@ -1,61 +0,0 @@
# Continue Configuration for Product OS
# https://docs.continue.dev/reference/config
name: Product OS
# Models - using Gemini via your Control Plane
models:
- name: Gemini (Product OS)
provider: openai # Continue uses OpenAI-compatible API format
model: gemini-1.5-flash
apiBase: http://localhost:8080 # Your Control Plane
apiKey: not-needed # Auth handled by Control Plane
# Default model for chat
model: Gemini (Product OS)
# MCP Servers - your Product OS tools
experimental:
modelContextProtocolServers:
- name: productos
command: npx
args:
- tsx
- /Users/markhenderson/Cursor Projects/Master Biz AI/platform/backend/mcp-adapter/src/index.ts
env:
CONTROL_PLANE_URL: http://localhost:8080
TENANT_ID: t_continue
# Context providers
contextProviders:
- name: code
params:
nFinal: 5
nRetrieve: 10
- name: docs
- name: terminal
- name: problems
# Slash commands
slashCommands:
- name: deploy
description: Deploy a service to Cloud Run
- name: analytics
description: Get funnel analytics
- name: marketing
description: Generate marketing content
# Custom instructions for the AI
systemMessage: |
You are Product OS, an AI assistant for building and operating SaaS products on Google Cloud.
You have access to these tools via MCP:
- deploy_service: Deploy Cloud Run services
- get_service_status: Check deployment health
- get_funnel_analytics: Analyze conversion funnels
- get_top_drivers: Understand what drives metrics
- generate_marketing_posts: Create social media content
- chat_with_gemini: General AI conversation
When users ask to deploy, analyze, or generate content, use the appropriate tool.
Always confirm before deploying to production.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,33 +0,0 @@
# Coolify White Label — Vibn Branding
Users never see the Coolify UI directly (it's backend infrastructure), but if you
want the admin panel to match, add these to the Coolify `.env` on the server.
## Steps
```bash
# SSH into the server
gcloud compute ssh coolify-server-mtl --zone=northamerica-northeast1-a
# Edit the Coolify env file
sudo nano /data/coolify/source/.env
```
## Add These Lines
```env
COOLIFY_WHITE_LABELED=true
COOLIFY_WHITE_LABELED_ICON=https://vibnai.com/vibn-icon.png
```
The icon URL must be publicly accessible. Once your logo is live on vibnai.com,
point this to the 180×180 PNG version.
## Apply Changes
```bash
cd /data/coolify/source
docker compose down && docker compose up -d
```
Note: These settings are lost on Coolify upgrades — re-apply if you update Coolify.

View File

@@ -1,10 +0,0 @@
; Vibn branding overrides for Gitea
; These settings go in $GITEA_CUSTOM/conf/app.ini
; On the server this is at: /data/gitea/data/gitea/custom/conf/app.ini
[ui]
SITE_TITLE = Vibn
[server]
; Optional: change the landing page description meta tag
LANDING_PAGE = home

View File

@@ -1,34 +0,0 @@
# Gitea Brand Assets — Drop Files Here
Place the following files in this directory, then copy them to the server at:
`/data/gitea/data/gitea/custom/public/assets/img/`
Then restart Gitea for changes to take effect.
## Required Files
| File | Format | Dimensions | Purpose |
|---|---|---|---|
| `logo.svg` | SVG | Vector | Main nav logo |
| `logo.png` | PNG | 512×512 | Open Graph previews |
| `favicon.svg` | SVG | Vector | Browser tab (primary) |
| `favicon.png` | PNG | 180×180 | Browser tab (fallback) |
| `apple-touch-icon.png` | PNG | 180×180 | iOS bookmark icon |
| `avatar_default.png` | PNG | 200×200 | Default user avatar |
## How to Deploy
```bash
# From local machine:
gcloud compute scp branding/gitea/public/assets/img/* \
coolify-server-mtl:/data/gitea/data/gitea/custom/public/assets/img/ \
--zone=northamerica-northeast1-a
gcloud compute scp branding/gitea/conf/app.ini \
coolify-server-mtl:/data/gitea/data/gitea/custom/conf/app.ini \
--zone=northamerica-northeast1-a
# Then restart Gitea:
gcloud compute ssh coolify-server-mtl --zone=northamerica-northeast1-a \
--command="sudo docker restart gitea-bcc4k0kog0w4ckkskg8gwggc"
```

View File

@@ -1,242 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vibn — Homepage</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#444441;--mid:#6B7280;--muted:#9CA3AF;--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#f7f4ee;--white:#FFFFFF;--border:#E5E7EB;--serif:'Lora',Georgia,serif;--sans:'Inter',sans-serif;}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFA,#F3F7F5);min-height:100vh;color:var(--ink);}
.f{font-family:var(--serif);}
nav{background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 52px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;}
.logo-box{width:30px;height:30px;background:var(--ink);border-radius:7px;display:flex;align-items:center;justify-content:center;}
.btn-ink{background:linear-gradient(135deg,#1F3D2B,#2F6F4F);color:#FFFFFF;border:none;border-radius:8px;padding:9px 22px;font-family:var(--sans);font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(31,61,43,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink:hover{box-shadow:0 10px 25px rgba(31,61,43,0.15),0 0 0 6px rgba(47,111,79,0.2);transform:translateY(-1px);}
.btn-ink-lg{background:linear-gradient(135deg,#1F3D2B,#2F6F4F);color:#FFFFFF;border:none;border-radius:10px;padding:15px 36px;font-family:var(--sans);font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(31,61,43,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink-lg:hover{box-shadow:0 10px 25px rgba(31,61,43,0.15),0 0 0 6px rgba(47,111,79,0.2);transform:translateY(-1px);}
.gradient-em{background:linear-gradient(to right,#2F6F4F,#6FAF8F);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-style:italic;}
.gradient-text{background:linear-gradient(to right,#2F6F4F,#6FAF8F);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.gradient-num{background:linear-gradient(135deg,#1F3D2B,#2F6F4F);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.empathy-card{background:var(--white);border:1px solid var(--border);border-left:3px solid rgba(47,111,79,0.8);border-radius:12px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;box-shadow:0 10px 30px rgba(31,61,43,0.05);transition:border-color 0.2s ease,background 0.2s ease;}
.empathy-card:hover{border-color:#2F6F4F;background:#F3F7F5;}
</style>
</head>
<body>
<nav>
<div style="display:flex;align-items:center;gap:10px;">
<div class="logo-box"><span class="f" style="font-size:15px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:19px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<div style="display:flex;gap:32px;align-items:center;">
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Product</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Stories</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Blog</a>
</div>
<div style="display:flex;align-items:center;gap:12px;">
<a href="02_signup.html" style="font-size:14px;color:var(--muted);text-decoration:none;">Log in</a>
<a href="02_signup.html"><button class="btn-ink">Get started free</button></a>
</div>
</nav>
<!-- HERO -->
<section style="max-width:980px;margin:0 auto;padding:88px 52px 72px;">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:96px;align-items:center;">
<!-- Left: copy -->
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:22px;">For non-technical founders</div>
<h1 class="f" style="font-size:58px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.06;margin-bottom:28px;">
You have the idea.<br>We handle<br><em class="gradient-em">everything else.</em>
</h1>
<p style="font-size:17px;color:var(--mid);line-height:1.75;">You describe it. Vibn builds it, launches it, and markets it. From idea to <strong style="color:var(--ink);">live</strong> product in <strong style="color:var(--ink);">72 hours</strong> — no code, no agencies, no waiting.</p>
</div>
<!-- Right: product moment card -->
<div style="flex-shrink:0;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 20px 60px rgba(31,61,43,0.05);">
<!-- Input area -->
<div style="padding:24px 26px 20px;background:#FAFAFA;border-bottom:1px solid var(--border);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:12px;">Your idea</div>
<p class="f" style="font-size:15px;font-style:italic;color:var(--ink);line-height:1.65;margin-bottom:14px;">"I want to build a booking tool for independent personal trainers."</p>
<div style="display:flex;justify-content:flex-end;">
<span style="font-size:11px;color:var(--muted);background:var(--white);border:1px solid var(--border);border-radius:5px;padding:3px 9px;letter-spacing:0.04em;">↵ Enter</span>
</div>
</div>
<!-- Output area -->
<div style="padding:20px 26px 24px;background:var(--white);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">vibn generated</div>
<div style="display:flex;flex-direction:column;gap:0;">
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Pages</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Landing, Dashboard, Booking, Payments</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Stack</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Auth, database, payments — handled</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Revenue</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Subscription · $29 / mo</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Status</span>
<span style="font-size:13px;font-weight:600;color:#2F6F4F;">&nbsp; Ready to build</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CTA row -->
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;margin-top:52px;">
<a href="02_signup.html"><button class="btn-ink-lg">Start free — no code needed</button></a>
<span style="font-size:13.5px;color:#6FAF8F;">★★★★★</span><span style="font-size:13.5px;color:var(--stone);">&nbsp;&nbsp;280 founders launched</span>
<p style="font-size:12px;color:#9CA3AF;">No credit card required · Free forever plan</p>
<a href="#how-it-works" style="font-size:13.5px;color:#2F6F4F;text-decoration:none;font-weight:500;margin-top:4px;">See how it works →</a>
</div>
</section>
<!-- EMPATHY -->
<section style="border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:80px 52px;">
<div style="max-width:980px;margin:0 auto;display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center;">
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:18px;">Sound familiar?</div>
<h2 class="f" style="font-size:36px;font-weight:700;color:#1A1A1A;line-height:1.18;margin-bottom:24px;letter-spacing:-0.02em;">The idea is the hard part. <span class="gradient-text">Everything else shouldn't be.</span></h2>
<p style="font-size:15px;color:var(--mid);line-height:1.82;margin-bottom:20px;">You know exactly what you want to build and who it's for. But the moment you think about servers, databases, deployment pipelines, SEO — the whole thing stalls.</p>
<p style="font-size:15px;color:var(--mid);line-height:1.82;">vibn exists to remove all of that. Not abstract it — <em class="f" style="font-style:italic;">remove it entirely.</em></p>
</div>
<div style="display:flex;flex-direction:column;gap:14px;">
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(47,111,79,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6FAF8F;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I need to hire a developer first"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">vibn is your developer. Start building the moment you have an idea.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(47,111,79,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6FAF8F;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more staring at a blank marketing calendar</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">AI generates and publishes your content every single week.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(47,111,79,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6FAF8F;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I'll launch when it's ready"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">Most founders ship their first version in under 72 hours.</div></div></div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section id="how-it-works" style="max-width:980px;margin:0 auto;padding:84px 52px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">How it works</div>
<h2 class="f" style="font-size:42px;font-weight:700;color:#1A1A1A;letter-spacing:-0.02em;margin-bottom:54px;max-width:480px;line-height:1.15;">Four phases. One <span class="gradient-text">complete</span> product.</h2>
<div style="display:grid;grid-template-columns:1fr 1fr;border:1px solid rgba(47,111,79,0.2);border-radius:14px;overflow:hidden;">
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(47,111,79,0.2);border-bottom:1px solid rgba(47,111,79,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(47,111,79,0.7);margin-bottom:14px;">01 — Discover</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Define your idea</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon.</p></div>
<div style="padding:40px 44px;background:var(--white);border-bottom:1px solid rgba(47,111,79,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(47,111,79,0.7);margin-bottom:14px;">02 — Design</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Choose your style</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Pick a visual style and see your exact site and emails live before a single line of code is written.</p></div>
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(47,111,79,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(47,111,79,0.7);margin-bottom:14px;">03 — Build</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Your app, live</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English.</p></div>
<div style="padding:40px 44px;background:var(--white);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(47,111,79,0.7);margin-bottom:14px;">04 — Grow</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Market &amp; automate</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on users.</p></div>
</div>
</section>
<!-- WHAT YOU GET -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div style="max-width:980px;margin:0 auto;padding:0 52px;display:grid;grid-template-columns:1fr 1fr 1fr;">
<div style="padding:44px 40px 44px 0;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#2F6F4F;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A live, working product</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Not a prototype. Real auth, real payments, real database — on your own URL from day one.</p>
</div>
<div style="padding:44px 40px;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#2F6F4F;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A full marketing engine</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Blog posts, onboarding emails, and social content — written and published automatically every week.</p>
</div>
<div style="padding:44px 0 44px 40px;">
<div style="font-size:13px;font-weight:700;color:#2F6F4F;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A product that evolves</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Describe changes in plain English. Vibn handles the code so your product grows as fast as your ideas.</p>
</div>
</div>
</section>
<!-- QUOTE BAND -->
<section style="background:#1A1A1A;padding:32px 52px 28px;">
<div style="max-width:980px;margin:0 auto;">
<!-- Carousel track -->
<div style="display:grid;grid-template-columns:1fr 1.6fr 1fr;gap:28px;align-items:center;margin-bottom:20px;">
<!-- Left: supporting quote -->
<div style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6FAF8F;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Alex K., founder of Taskly</span>
</div>
</div>
<!-- Center: dominant quote -->
<div style="background:rgba(255,255,255,0.05);border-radius:12px;padding:22px 26px;">
<div style="width:3px;height:16px;background:#6FAF8F;border-radius:2px;margin-bottom:12px;opacity:0.7;"></div>
<p class="f" style="font-size:16px;color:#FFFFFF;line-height:1.7;font-style:italic;margin-bottom:12px;">"I have zero coding experience. Three weeks in, I have 300 paying users. That's entirely because of vibn."</p>
<span style="font-size:11px;color:var(--muted);font-weight:600;">— Marcus L., founder of Flowmatic</span>
</div>
<!-- Right: supporting quote -->
<div style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6FAF8F;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"The marketing autopilot saved me ten hours a week. My blog runs itself. I just focus on product."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Sara R., founder of Nudge</span>
</div>
</div>
</div>
<!-- Pagination dots -->
<div style="display:flex;justify-content:center;gap:7px;">
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
<div style="width:16px;height:5px;border-radius:3px;background:#FFFFFF;"></div>
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
</div>
</div>
</section>
<!-- STATS -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div style="max-width:980px;margin:0 auto;padding:0 52px;display:grid;grid-template-columns:1fr 1fr 1fr 1fr;">
<div style="padding:40px 0;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">280+</div><div style="font-size:13px;color:var(--muted);">founders launched</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">72h</div><div style="font-size:13px;color:var(--muted);">average time to first version</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">4.9★</div><div style="font-size:13px;color:var(--muted);">average rating</div></div>
<div style="padding:40px 0 40px 36px;"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">3×</div><div style="font-size:13px;color:var(--muted);">faster than hiring a developer</div></div>
</div>
</section>
<!-- CTA -->
<section style="padding:80px 52px;text-align:center;">
<div style="max-width:680px;margin:0 auto;background:#FFFFFF;border-radius:20px;padding:64px 52px;box-shadow:0 0 0 1px rgba(47,111,79,0.15),0 20px 60px rgba(31,61,43,0.08);">
<h2 class="f" style="font-size:48px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.1;margin-bottom:20px;">Your idea deserves to exist.</h2>
<p style="font-size:16px;color:var(--mid);line-height:1.75;margin-bottom:38px;">Thousands of ideas never make it past a spreadsheet. Yours doesn't have to be one of them.</p>
<a href="02_signup.html"><button class="btn-ink-lg" style="margin-bottom:16px;">Build my product — free</button></a>
<div style="font-size:12.5px;color:var(--muted);">Joins 280+ non-technical founders already live</div>
</div>
</section>
<!-- FOOTER -->
<footer style="background:rgba(250,250,250,0.95);border-top:1px solid var(--border);padding:32px 52px;display:flex;align-items:center;justify-content:space-between;">
<span class="f" style="font-size:16px;font-weight:700;color:var(--ink);">vibn</span>
<div style="display:flex;gap:28px;">
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Product</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Privacy</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Terms</a>
</div>
<span style="font-size:12.5px;color:var(--muted);">© 2026 vibn</span>
</footer>
</body>
</html>

View File

@@ -1,242 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vibn — Homepage</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#444441;--mid:#6B7280;--muted:#9CA3AF;--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#f7f4ee;--white:#FFFFFF;--border:#E5E7EB;--serif:'Lora',Georgia,serif;--sans:'Inter',sans-serif;}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFE,#F0EEFF);min-height:100vh;color:var(--ink);}
.f{font-family:var(--serif);}
nav{background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 52px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;}
.logo-box{width:30px;height:30px;background:var(--ink);border-radius:7px;display:flex;align-items:center;justify-content:center;}
.btn-ink{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:8px;padding:9px 22px;font-family:var(--sans);font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.btn-ink-lg{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:10px;padding:15px 36px;font-family:var(--sans);font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink-lg:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.gradient-em{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-style:italic;}
.gradient-text{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.gradient-num{background:linear-gradient(135deg,#2E2A5E,#4338CA);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.empathy-card{background:var(--white);border:1px solid var(--border);border-left:3px solid rgba(99,102,241,0.8);border-radius:12px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;box-shadow:0 10px 30px rgba(30,27,75,0.05);transition:border-color 0.2s ease,background 0.2s ease;}
.empathy-card:hover{border-color:#6366F1;background:#FAFAFF;}
</style>
</head>
<body>
<nav>
<div style="display:flex;align-items:center;gap:10px;">
<div class="logo-box"><span class="f" style="font-size:15px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:19px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<div style="display:flex;gap:32px;align-items:center;">
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Product</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Stories</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Blog</a>
</div>
<div style="display:flex;align-items:center;gap:12px;">
<a href="02_signup.html" style="font-size:14px;color:var(--muted);text-decoration:none;">Log in</a>
<a href="02_signup.html"><button class="btn-ink">Get started free</button></a>
</div>
</nav>
<!-- HERO -->
<section style="max-width:980px;margin:0 auto;padding:88px 52px 72px;">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:96px;align-items:center;">
<!-- Left: copy -->
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:22px;">For non-technical founders</div>
<h1 class="f" style="font-size:58px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.06;margin-bottom:28px;">
You have the idea.<br>We handle<br><em class="gradient-em">everything else.</em>
</h1>
<p style="font-size:17px;color:var(--mid);line-height:1.75;">You describe it. Vibn builds it, launches it, and markets it. From idea to <strong style="color:var(--ink);">live</strong> product in <strong style="color:var(--ink);">72 hours</strong> — no code, no agencies, no waiting.</p>
</div>
<!-- Right: product moment card -->
<div style="flex-shrink:0;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 20px 60px rgba(30,27,75,0.05);">
<!-- Input area -->
<div style="padding:24px 26px 20px;background:#FCFCFF;border-bottom:1px solid var(--border);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:12px;">Your idea</div>
<p class="f" style="font-size:15px;font-style:italic;color:var(--ink);line-height:1.65;margin-bottom:14px;">"I want to build a booking tool for independent personal trainers."</p>
<div style="display:flex;justify-content:flex-end;">
<span style="font-size:11px;color:var(--muted);background:var(--white);border:1px solid var(--border);border-radius:5px;padding:3px 9px;letter-spacing:0.04em;">↵ Enter</span>
</div>
</div>
<!-- Output area -->
<div style="padding:20px 26px 24px;background:var(--white);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">vibn generated</div>
<div style="display:flex;flex-direction:column;gap:0;">
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Pages</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Landing, Dashboard, Booking, Payments</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Stack</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Auth, database, payments — handled</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Revenue</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Subscription · $29 / mo</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Status</span>
<span style="font-size:13px;font-weight:600;color:#6366F1;">&nbsp; Ready to build</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CTA row -->
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;margin-top:52px;">
<a href="02_signup.html"><button class="btn-ink-lg">Start free — no code needed</button></a>
<span style="font-size:13.5px;color:#818CF8;">★★★★★</span><span style="font-size:13.5px;color:var(--stone);">&nbsp;&nbsp;280 founders launched</span>
<p style="font-size:12px;color:#9CA3AF;">No credit card required · Free forever plan</p>
<a href="#how-it-works" style="font-size:13.5px;color:#6366F1;text-decoration:none;font-weight:500;margin-top:4px;">See how it works →</a>
</div>
</section>
<!-- EMPATHY -->
<section style="border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:80px 52px;">
<div style="max-width:980px;margin:0 auto;display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center;">
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:18px;">Sound familiar?</div>
<h2 class="f" style="font-size:36px;font-weight:700;color:#1A1A1A;line-height:1.18;margin-bottom:24px;letter-spacing:-0.02em;">The idea is the hard part. <span class="gradient-text">Everything else shouldn't be.</span></h2>
<p style="font-size:15px;color:var(--mid);line-height:1.82;margin-bottom:20px;">You know exactly what you want to build and who it's for. But the moment you think about servers, databases, deployment pipelines, SEO — the whole thing stalls.</p>
<p style="font-size:15px;color:var(--mid);line-height:1.82;">vibn exists to remove all of that. Not abstract it — <em class="f" style="font-style:italic;">remove it entirely.</em></p>
</div>
<div style="display:flex;flex-direction:column;gap:14px;">
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I need to hire a developer first"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">vibn is your developer. Start building the moment you have an idea.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more staring at a blank marketing calendar</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">AI generates and publishes your content every single week.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I'll launch when it's ready"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">Most founders ship their first version in under 72 hours.</div></div></div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section id="how-it-works" style="max-width:980px;margin:0 auto;padding:84px 52px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">How it works</div>
<h2 class="f" style="font-size:42px;font-weight:700;color:#1A1A1A;letter-spacing:-0.02em;margin-bottom:54px;max-width:480px;line-height:1.15;">Four phases. One <span class="gradient-text">complete</span> product.</h2>
<div style="display:grid;grid-template-columns:1fr 1fr;border:1px solid rgba(99,102,241,0.2);border-radius:14px;overflow:hidden;">
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">01 — Discover</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Define your idea</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon.</p></div>
<div style="padding:40px 44px;background:var(--white);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">02 — Design</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Choose your style</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Pick a visual style and see your exact site and emails live before a single line of code is written.</p></div>
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">03 — Build</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Your app, live</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English.</p></div>
<div style="padding:40px 44px;background:var(--white);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">04 — Grow</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Market &amp; automate</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on users.</p></div>
</div>
</section>
<!-- WHAT YOU GET -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div style="max-width:980px;margin:0 auto;padding:0 52px;display:grid;grid-template-columns:1fr 1fr 1fr;">
<div style="padding:44px 40px 44px 0;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A live, working product</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Not a prototype. Real auth, real payments, real database — on your own URL from day one.</p>
</div>
<div style="padding:44px 40px;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A full marketing engine</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Blog posts, onboarding emails, and social content — written and published automatically every week.</p>
</div>
<div style="padding:44px 0 44px 40px;">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A product that evolves</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Describe changes in plain English. Vibn handles the code so your product grows as fast as your ideas.</p>
</div>
</div>
</section>
<!-- QUOTE BAND -->
<section style="background:#1A1A1A;padding:32px 52px 28px;">
<div style="max-width:980px;margin:0 auto;">
<!-- Carousel track -->
<div style="display:grid;grid-template-columns:1fr 1.6fr 1fr;gap:28px;align-items:center;margin-bottom:20px;">
<!-- Left: supporting quote -->
<div style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Alex K., founder of Taskly</span>
</div>
</div>
<!-- Center: dominant quote -->
<div style="background:rgba(255,255,255,0.05);border-radius:12px;padding:22px 26px;">
<div style="width:3px;height:16px;background:#6366F1;border-radius:2px;margin-bottom:12px;opacity:0.7;"></div>
<p class="f" style="font-size:16px;color:#FFFFFF;line-height:1.7;font-style:italic;margin-bottom:12px;">"I have zero coding experience. Three weeks in, I have 300 paying users. That's entirely because of vibn."</p>
<span style="font-size:11px;color:var(--muted);font-weight:600;">— Marcus L., founder of Flowmatic</span>
</div>
<!-- Right: supporting quote -->
<div style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"The marketing autopilot saved me ten hours a week. My blog runs itself. I just focus on product."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Sara R., founder of Nudge</span>
</div>
</div>
</div>
<!-- Pagination dots -->
<div style="display:flex;justify-content:center;gap:7px;">
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
<div style="width:16px;height:5px;border-radius:3px;background:#FFFFFF;"></div>
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
</div>
</div>
</section>
<!-- STATS -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div style="max-width:980px;margin:0 auto;padding:0 52px;display:grid;grid-template-columns:1fr 1fr 1fr 1fr;">
<div style="padding:40px 0;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">280+</div><div style="font-size:13px;color:var(--muted);">founders launched</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">72h</div><div style="font-size:13px;color:var(--muted);">average time to first version</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">4.9★</div><div style="font-size:13px;color:var(--muted);">average rating</div></div>
<div style="padding:40px 0 40px 36px;"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">3×</div><div style="font-size:13px;color:var(--muted);">faster than hiring a developer</div></div>
</div>
</section>
<!-- CTA -->
<section style="padding:80px 52px;text-align:center;">
<div style="max-width:680px;margin:0 auto;background:#FFFFFF;border-radius:20px;padding:64px 52px;box-shadow:0 0 0 1px rgba(99,102,241,0.15),0 20px 60px rgba(30,27,75,0.08);">
<h2 class="f" style="font-size:48px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.1;margin-bottom:20px;">Your idea deserves to exist.</h2>
<p style="font-size:16px;color:var(--mid);line-height:1.75;margin-bottom:38px;">Thousands of ideas never make it past a spreadsheet. Yours doesn't have to be one of them.</p>
<a href="02_signup.html"><button class="btn-ink-lg" style="margin-bottom:16px;">Build my product — free</button></a>
<div style="font-size:12.5px;color:var(--muted);">Joins 280+ non-technical founders already live</div>
</div>
</section>
<!-- FOOTER -->
<footer style="background:rgba(250,250,250,0.95);border-top:1px solid var(--border);padding:32px 52px;display:flex;align-items:center;justify-content:space-between;">
<span class="f" style="font-size:16px;font-weight:700;color:var(--ink);">vibn</span>
<div style="display:flex;gap:28px;">
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Product</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Privacy</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Terms</a>
</div>
<span style="font-size:12.5px;color:var(--muted);">© 2026 vibn</span>
</footer>
</body>
</html>

1
dyad

Submodule dyad deleted from f86b78bba3

View File

@@ -1,26 +0,0 @@
/* vibn Design Tokens — Ink & Parchment */
/* Import this in any HTML file or reference these values */
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
:root {
--ink: #1a1510;
--ink2: #2c2c2a;
--ink3: #444441;
--mid: #5f5e5a;
--muted: #888780;
--stone: #b4b2a9;
--parch: #d3d1c7;
--cream: #f1efe8;
--paper: #f7f4ee;
--white: #fdfcfa;
--border: #e8e2d9;
--serif: 'Lora', Georgia, serif;
--sans: 'Inter', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--sans); background: var(--paper); color: var(--ink); }
.f { font-family: var(--serif); }
.s { font-family: var(--sans); }

View File

@@ -1,335 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>vibn — Homepage</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#444441;--mid:#6B7280;--muted:#9CA3AF;--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#f7f4ee;--white:#FFFFFF;--border:#E5E7EB;--serif:'Plus Jakarta Sans',sans-serif;--sans:'Plus Jakarta Sans',sans-serif;}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFE,#F0EEFF);min-height:100vh;color:var(--ink);}
.f{font-family:var(--serif);}
nav{background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 52px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;}
.nav-links{display:flex;gap:32px;align-items:center;}
.btn-ink{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:8px;padding:9px 22px;font-family:var(--sans);font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.btn-ink-lg{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:10px;padding:15px 36px;font-family:var(--sans);font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink-lg:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.gradient-em{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-style:italic;}
.gradient-text{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.gradient-num{background:linear-gradient(135deg,#2E2A5E,#4338CA);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.empathy-card{background:var(--white);border:1px solid var(--border);border-left:3px solid rgba(99,102,241,0.8);border-radius:12px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;box-shadow:0 10px 30px rgba(30,27,75,0.05);transition:border-color 0.2s ease,background 0.2s ease;}
.empathy-card:hover{border-color:#6366F1;background:#FAFAFF;}
/* ── Layout grid classes (for responsive overrides) ── */
.hero-grid{display:grid;grid-template-columns:1fr 1fr;gap:96px;align-items:center;}
.empathy-grid{display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center;}
.phase-grid{display:grid;grid-template-columns:1fr 1fr;border:1px solid rgba(99,102,241,0.2);border-radius:14px;overflow:hidden;}
.wyg-grid{display:grid;grid-template-columns:1fr 1fr 1fr;}
.quote-grid{display:grid;grid-template-columns:1fr 1.6fr 1fr;gap:28px;align-items:center;margin-bottom:20px;}
.stats-grid{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;}
.footer-tagline{display:block;font-size:12px;color:var(--muted);margin-top:4px;font-family:var(--sans);}
/* ── Hamburger ── */
.hamburger{display:none;flex-direction:column;gap:5px;background:none;border:none;cursor:pointer;padding:6px;}
.hamburger span{display:block;width:22px;height:2px;background:var(--ink);border-radius:2px;transition:transform 0.25s ease,opacity 0.25s ease;}
.hamburger.open span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.hamburger.open span:nth-child(2){opacity:0;}
.hamburger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}
/* Mobile drawer */
.mobile-menu{display:none;position:fixed;top:62px;left:0;right:0;background:rgba(250,250,250,0.98);border-bottom:1px solid var(--border);padding:20px 24px 28px;z-index:49;flex-direction:column;gap:0;box-shadow:0 8px 24px rgba(30,27,75,0.08);}
.mobile-menu.open{display:flex;}
.mobile-menu a{font-size:15px;color:var(--ink);text-decoration:none;padding:13px 0;border-bottom:1px solid var(--border);font-weight:500;}
.mobile-menu a:last-of-type{border-bottom:none;}
.mobile-menu .mobile-menu-cta{margin-top:18px;}
/* ── Mobile ── */
@media (max-width:768px){
nav{padding:0 20px;}
.nav-links{display:none;}
.hamburger{display:flex;}
.nav-right-btns{display:none;}
.hero-grid{grid-template-columns:1fr;gap:44px;}
.hero-section{padding:52px 24px 48px !important;}
.empathy-section{padding:56px 24px !important;}
.empathy-grid{grid-template-columns:1fr;gap:36px;}
.how-section{padding:64px 24px !important;}
.phase-grid{grid-template-columns:1fr;}
.phase-grid > div{border-right:none !important;padding:28px 24px !important;}
.wyg-grid{grid-template-columns:1fr;}
.wyg-grid > div{border-right:none !important;border-bottom:1px solid var(--border);padding:32px 24px !important;}
.wyg-grid > div:last-child{border-bottom:none;}
.wyg-section{padding:0 24px !important;}
.quote-grid{grid-template-columns:1fr;}
.quote-side{display:none !important;}
.quote-section{padding:32px 24px 28px !important;}
.stats-grid{grid-template-columns:1fr 1fr;}
.stats-grid > div{padding:28px 16px !important;}
.stats-grid > div:nth-child(odd){padding-left:0 !important;}
.stats-grid > div:nth-child(3),.stats-grid > div:nth-child(4){border-top:1px solid var(--border);}
.stats-grid > div:nth-child(even){border-right:none !important;}
.stats-section{padding:0 24px !important;}
.cta-section{padding:56px 20px !important;}
.cta-card{padding:44px 28px !important;}
.hero-h1{font-size:40px !important;line-height:1.1 !important;}
.hero-sub{font-size:15px !important;}
footer{flex-direction:column;gap:20px;text-align:center;padding:32px 24px !important;}
.footer-links{flex-wrap:wrap;justify-content:center;}
}
</style>
</head>
<body>
<nav>
<div style="display:flex;align-items:center;gap:10px;">
<div class="logo-box" style="width:30px;height:30px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:7px;display:flex;align-items:center;justify-content:center;"><span class="f" style="font-size:15px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:19px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<div class="nav-links">
<a href="#how-it-works" style="font-size:14px;color:var(--muted);text-decoration:none;">How it works</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Stories</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Blog</a>
</div>
<div class="nav-right-btns" style="display:flex;align-items:center;gap:12px;">
<a href="03_dashboard.html" style="font-size:14px;color:#6366F1;font-weight:600;text-decoration:none;">Log in</a>
<a href="02_signup.html"><button class="btn-ink">Get started free</button></a>
</div>
<button class="hamburger" id="hamburger" aria-label="Open menu" onclick="toggleMenu()">
<span></span><span></span><span></span>
</button>
</nav>
<!-- Mobile drawer -->
<div class="mobile-menu" id="mobile-menu">
<a href="#how-it-works" onclick="closeMenu()">How it works</a>
<a href="#" onclick="closeMenu()">Pricing</a>
<a href="#" onclick="closeMenu()">Stories</a>
<a href="#" onclick="closeMenu()">Blog</a>
<a href="03_dashboard.html" style="color:#6366F1;font-weight:600;" onclick="closeMenu()">Log in</a>
<div class="mobile-menu-cta">
<a href="02_signup.html"><button class="btn-ink-lg" style="width:100%;">Get started free</button></a>
</div>
</div>
<!-- HERO -->
<section class="hero-section" style="max-width:980px;margin:0 auto;padding:88px 52px 72px;">
<div class="hero-grid">
<!-- Left: copy -->
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:22px;">For non-technical founders</div>
<h1 class="f hero-h1" style="font-size:58px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.06;margin-bottom:28px;">
You have the idea.<br>We handle<br><em class="gradient-em">everything else.</em>
</h1>
<p class="hero-sub" style="font-size:17px;color:var(--mid);line-height:1.75;">You describe it. Vibn builds it, launches it, and markets it. From idea to <strong style="color:var(--ink);">live</strong> product in <strong style="color:var(--ink);">72 hours</strong> — no code, no agencies, no waiting.</p>
</div>
<!-- Right: product moment card -->
<div style="flex-shrink:0;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 20px 60px rgba(30,27,75,0.05);">
<!-- Input area -->
<div style="padding:24px 26px 20px;background:#FCFCFF;border-bottom:1px solid var(--border);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:12px;">Your idea</div>
<p class="f" style="font-size:15px;font-style:italic;color:var(--ink);line-height:1.65;margin-bottom:14px;">"I want to build a booking tool for independent personal trainers."</p>
<div style="display:flex;justify-content:flex-end;">
<span style="font-size:11px;color:var(--muted);background:var(--white);border:1px solid var(--border);border-radius:5px;padding:3px 9px;letter-spacing:0.04em;">↵ Enter</span>
</div>
</div>
<!-- Output area -->
<div style="padding:20px 26px 24px;background:var(--white);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">vibn generated</div>
<div style="display:flex;flex-direction:column;gap:0;">
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Pages</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Landing, Dashboard, Booking, Payments</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Stack</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Auth, database, payments — handled</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Revenue</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Subscription · $29 / mo</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Status</span>
<span style="font-size:13px;font-weight:600;color:#6366F1;">&nbsp; Ready to build</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CTA row -->
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;margin-top:52px;">
<a href="02_signup.html"><button class="btn-ink-lg">Start free — no code needed</button></a>
<div><span style="font-size:13.5px;color:#818CF8;">★★★★★</span><span style="font-size:13.5px;color:var(--stone);">&nbsp;&nbsp;280 founders launched</span></div>
<p style="font-size:12px;color:#9CA3AF;">No credit card required · Free forever plan</p>
<a href="#how-it-works" style="font-size:13.5px;color:#6366F1;text-decoration:none;font-weight:500;margin-top:4px;">See how it works →</a>
</div>
</section>
<!-- EMPATHY -->
<section class="empathy-section" style="border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:80px 52px;">
<div style="max-width:980px;margin:0 auto;">
<div class="empathy-grid">
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:18px;">Sound familiar?</div>
<h2 class="f" style="font-size:36px;font-weight:700;color:#1A1A1A;line-height:1.18;margin-bottom:24px;letter-spacing:-0.02em;">The idea is the hard part. <span class="gradient-text">Everything else shouldn't be.</span></h2>
<p style="font-size:15px;color:var(--mid);line-height:1.82;margin-bottom:20px;">You know exactly what you want to build and who it's for. But the moment you think about servers, databases, deployment pipelines, SEO — the whole thing stalls.</p>
<p style="font-size:15px;color:var(--mid);line-height:1.82;">vibn exists to remove all of that. Not abstract it — <em class="f" style="font-style:italic;">remove it entirely.</em></p>
</div>
<div style="display:flex;flex-direction:column;gap:14px;">
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I need to hire a developer first"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">vibn is your developer. Start building the moment you have an idea.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more staring at a blank marketing calendar</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">AI generates and publishes your content every single week.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I'll launch when it's ready"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">Most founders ship their first version in under 72 hours.</div></div></div>
</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section id="how-it-works" class="how-section" style="max-width:980px;margin:0 auto;padding:84px 52px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">How it works</div>
<h2 class="f" style="font-size:42px;font-weight:700;color:#1A1A1A;letter-spacing:-0.02em;margin-bottom:54px;max-width:480px;line-height:1.15;">Four phases. One <span class="gradient-text">complete</span> product.</h2>
<div class="phase-grid">
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">01 — Discover</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Define your idea</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon.</p></div>
<div style="padding:40px 44px;background:var(--white);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">02 — Design</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Choose your style</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Pick a visual style and see your exact site and emails live before a single line of code is written.</p></div>
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">03 — Build</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Your app, live</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English.</p></div>
<div style="padding:40px 44px;background:var(--white);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">04 — Grow</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Market &amp; automate</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on users.</p></div>
</div>
</section>
<!-- WHAT YOU GET -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div class="wyg-grid wyg-section" style="max-width:980px;margin:0 auto;padding:0 52px;">
<div style="padding:44px 40px 44px 0;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A live, working product</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Not a prototype. Real auth, real payments, real database — on your own URL from day one.</p>
<p style="font-size:12px;color:var(--muted);line-height:1.6;text-align:center;margin-top:10px;">Runs on your own servers — your data, your infrastructure, no lock-in.</p>
</div>
<div style="padding:44px 40px;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A full marketing engine</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Blog posts, onboarding emails, and social content — written and published automatically every week.</p>
</div>
<div style="padding:44px 0 44px 40px;">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A product that evolves</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Describe changes in plain English. Vibn handles the code so your product grows as fast as your ideas.</p>
</div>
</div>
</section>
<!-- QUOTE BAND -->
<section class="quote-section" style="background:#1A1A1A;padding:32px 52px 28px;">
<div style="max-width:980px;margin:0 auto;">
<div class="quote-grid">
<!-- Left: supporting quote -->
<div class="quote-side" style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Alex K., founder of Taskly</span>
</div>
</div>
<!-- Center: dominant quote -->
<div style="background:rgba(255,255,255,0.05);border-radius:12px;padding:22px 26px;">
<div style="width:3px;height:16px;background:#6366F1;border-radius:2px;margin-bottom:12px;opacity:0.7;"></div>
<p class="f" style="font-size:16px;color:#FFFFFF;line-height:1.7;font-style:italic;margin-bottom:12px;">"I have zero coding experience. Three weeks in, I have 300 paying users. That's entirely because of vibn."</p>
<span style="font-size:11px;color:var(--muted);font-weight:600;">— Marcus L., founder of Flowmatic</span>
</div>
<!-- Right: supporting quote -->
<div class="quote-side" style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"The marketing autopilot saved me ten hours a week. My blog runs itself. I just focus on product."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Sara R., founder of Nudge</span>
</div>
</div>
</div>
<!-- Pagination dots -->
<div style="display:flex;justify-content:center;gap:7px;">
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
<div style="width:16px;height:5px;border-radius:3px;background:#FFFFFF;"></div>
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
</div>
</div>
</section>
<!-- STATS -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div class="stats-grid stats-section" style="max-width:980px;margin:0 auto;padding:0 52px;">
<div style="padding:40px 0;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">280+</div><div style="font-size:13px;color:var(--muted);">founders launched</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">72h</div><div style="font-size:13px;color:var(--muted);">average time to first version</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">4.9★</div><div style="font-size:13px;color:var(--muted);">average rating</div></div>
<div style="padding:40px 0 40px 36px;"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">3×</div><div style="font-size:13px;color:var(--muted);">faster than hiring a developer</div></div>
</div>
</section>
<!-- CTA -->
<section class="cta-section" style="padding:80px 52px;text-align:center;">
<div class="cta-card" style="max-width:680px;margin:0 auto;background:#FFFFFF;border-radius:20px;padding:64px 52px;box-shadow:0 0 0 1px rgba(99,102,241,0.15),0 20px 60px rgba(30,27,75,0.08);">
<h2 class="f" style="font-size:48px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.1;margin-bottom:20px;">Your idea deserves to exist.</h2>
<p style="font-size:16px;color:var(--mid);line-height:1.75;margin-bottom:38px;">Thousands of ideas never make it past a spreadsheet. Yours doesn't have to be one of them.</p>
<a href="02_signup.html"><button class="btn-ink-lg" style="margin-bottom:16px;">Build my product — free</button></a>
<div style="font-size:12.5px;color:var(--muted);">Joins 280+ non-technical founders already live</div>
</div>
</section>
<!-- FOOTER -->
<footer style="background:rgba(250,250,250,0.95);border-top:1px solid var(--border);padding:32px 52px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;">
<div>
<span class="f" style="font-size:16px;font-weight:700;color:var(--ink);">vibn</span>
<span class="footer-tagline">The fastest way from idea to product.</span>
</div>
<div class="footer-links" style="display:flex;gap:28px;">
<a href="#how-it-works" style="font-size:13px;color:var(--muted);text-decoration:none;">How it works</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Privacy</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Terms</a>
</div>
<span style="font-size:12.5px;color:var(--muted);text-align:right;display:block;">© 2026 vibn</span>
</footer>
<script>
function toggleMenu(){
var btn=document.getElementById('hamburger');
var menu=document.getElementById('mobile-menu');
var open=menu.classList.toggle('open');
btn.classList.toggle('open',open);
document.body.style.overflow=open?'hidden':'';
}
function closeMenu(){
document.getElementById('hamburger').classList.remove('open');
document.getElementById('mobile-menu').classList.remove('open');
document.body.style.overflow='';
}
// Close on anchor click (for same-page links like #how-it-works)
document.querySelectorAll('.mobile-menu a[href^="#"]').forEach(function(a){
a.addEventListener('click',closeMenu);
});
</script>
</body>
</html>

View File

@@ -1,329 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>vibn — Sign up</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{
--ink:#1A1A1A;
--mid:#6B7280;
--muted:#9CA3AF;
--border:#E5E7EB;
--white:#FFFFFF;
--soft:#F5F3FF;
--hover:#FAFAFF;
--serif:'Plus Jakarta Sans',sans-serif;
--sans:'Plus Jakarta Sans',sans-serif;
}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);min-height:100vh;display:flex;flex-direction:column;color:var(--ink);}
.f{font-family:var(--serif);}
/* Inputs */
input::placeholder{color:var(--muted);}
input{width:100%;border:1px solid var(--border);border-radius:8px;padding:10px 13px;font-family:var(--sans);font-size:14px;color:var(--ink);background:#FAFAFA;outline:none;transition:border-color 0.15s,box-shadow 0.15s;}
input:focus{border-color:#6366F1;box-shadow:0 0 0 3px rgba(99,102,241,0.12);}
input.error{border-color:#F87171;}
/* Primary button */
.btn{width:100%;background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:10px;padding:13px;font-family:var(--sans);font-size:14px;font-weight:600;cursor:pointer;margin-top:4px;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.btn:disabled{opacity:0.4;cursor:default;transform:none;box-shadow:0 10px 25px rgba(30,27,75,0.15);}
/* Mode option cards */
.mode-opt{border:1px solid var(--border);background:transparent;border-radius:10px;padding:16px;cursor:pointer;margin-bottom:10px;display:flex;align-items:center;gap:12px;transition:all 0.15s;}
.mode-opt:hover{border-color:#6366F1;background:var(--hover);}
.mode-opt.selected{border-color:#6366F1;background:var(--hover);box-shadow:0 0 0 3px rgba(99,102,241,0.1);}
/* Password strength */
.strength-bar{display:flex;gap:4px;margin-top:8px;}
.strength-seg{flex:1;height:3px;border-radius:2px;background:var(--border);transition:background 0.2s ease;}
.strength-label{font-size:11px;color:var(--muted);margin-top:5px;min-height:16px;}
/* Password toggle */
.pwd-wrap{position:relative;}
.pwd-wrap input{padding-right:40px;}
.pwd-toggle{position:absolute;right:11px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:var(--muted);padding:4px;display:flex;align-items:center;transition:color 0.15s;}
.pwd-toggle:hover{color:var(--ink);}
/* Google button */
.btn-google{width:100%;background:transparent;border:1px solid var(--border);color:var(--ink);border-radius:10px;padding:11px;font-family:var(--sans);font-size:13.5px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:9px;transition:border-color 0.15s,background 0.15s;}
.btn-google:hover{border-color:#6366F1;background:var(--hover);}
/* Billing notice — animated */
.billing-notice{overflow:hidden;max-height:0;opacity:0;transition:max-height 0.3s ease,opacity 0.25s ease,margin-bottom 0.3s ease;margin-bottom:0;}
.billing-notice.visible{max-height:140px;opacity:1;margin-bottom:20px;}
/* Experience hint */
.mode-hint{text-align:center;font-size:12px;color:var(--muted);margin-top:10px;min-height:18px;transition:opacity 0.2s ease;}
.exp-feedback{overflow:hidden;max-height:0;opacity:0;transition:max-height 0.3s ease,opacity 0.25s ease,margin-bottom 0.3s ease;margin-bottom:0;border-radius:10px;padding:0 16px;}
.exp-feedback.visible{max-height:80px;opacity:1;margin-bottom:4px;padding:13px 16px;}
</style>
</head>
<body>
<nav style="background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 40px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;">
<div style="display:flex;align-items:center;gap:9px;">
<div style="width:28px;height:28px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:7px;display:flex;align-items:center;justify-content:center;"><span class="f" style="font-size:14px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<span style="font-size:13.5px;color:var(--muted);">Already have an account? <a href="03_dashboard.html" style="color:#6366F1;font-weight:600;text-decoration:none;">Log in</a></span>
</nav>
<div style="flex:1;display:flex;align-items:center;justify-content:center;padding:40px 24px;">
<div style="width:100%;max-width:440px;">
<!-- Step indicator -->
<div id="steps" style="display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:32px;">
<div style="display:flex;align-items:center;gap:6px;" id="s1">
<div id="s1c" style="width:24px;height:24px;border-radius:50%;background:#6366F1;display:flex;align-items:center;justify-content:center;font-size:11px;color:#FFFFFF;font-weight:700;">1</div>
<span style="font-size:12.5px;font-weight:600;color:var(--ink);">Account</span>
</div>
<div style="width:28px;height:1px;background:var(--border);"></div>
<div style="display:flex;align-items:center;gap:6px;opacity:0.35;" id="s2">
<div id="s2c" style="width:24px;height:24px;border-radius:50%;background:var(--border);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted);font-weight:700;">2</div>
<span id="s2l" style="font-size:12.5px;color:var(--muted);">Your experience</span>
</div>
<div style="width:28px;height:1px;background:var(--border);"></div>
<div style="display:flex;align-items:center;gap:6px;opacity:0.35;" id="s3">
<div id="s3c" style="width:24px;height:24px;border-radius:50%;background:var(--border);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted);font-weight:700;">3</div>
<span id="s3l" style="font-size:12.5px;color:var(--muted);">Ready</span>
</div>
</div>
<!-- STEP 1 -->
<div id="step1" style="background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<h2 class="f" style="font-size:23px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:6px;">Let's build your first product.</h2>
<p style="font-size:14px;color:var(--muted);margin-bottom:22px;">Free to start · No credit card needed</p>
<!-- Google first -->
<button onclick="openGoogleAuth()" class="btn-google" style="margin-bottom:20px;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
Continue with Google
</button>
<div style="margin-bottom:20px;display:flex;align-items:center;gap:12px;">
<div style="flex:1;height:1px;background:var(--border);"></div>
<span style="font-size:12px;color:var(--muted);">or continue with email</span>
<div style="flex:1;height:1px;background:var(--border);"></div>
</div>
<!-- Email form -->
<div style="display:flex;flex-direction:column;gap:15px;">
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Full name</label>
<input type="text" id="inp-name" placeholder="Jane Smith" oninput="validateStep1()"/>
</div>
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Email</label>
<input type="email" id="inp-email" placeholder="jane@studio.com" oninput="validateStep1()"/>
</div>
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Password</label>
<div class="pwd-wrap">
<input type="password" id="pwd" placeholder="8+ characters" oninput="checkStrength(this.value);validateStep1()"/>
<button type="button" class="pwd-toggle" onclick="togglePwd()" id="pwd-toggle-btn" aria-label="Show password">
<svg id="eye-open" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
<svg id="eye-closed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none;"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
</button>
</div>
<div class="strength-bar"><div class="strength-seg" id="seg1"></div><div class="strength-seg" id="seg2"></div><div class="strength-seg" id="seg3"></div></div>
<div class="strength-label" id="strength-label"></div>
</div>
<!-- Social proof above button -->
<p style="text-align:center;font-size:12px;color:var(--muted);margin-bottom:-4px;">Joining 280+ founders already building</p>
<button id="step1btn" class="btn" onclick="goStep(2)" disabled>Continue →</button>
<p style="text-align:center;font-size:11.5px;color:var(--muted);margin-top:2px;">By continuing you agree to our <a href="#" style="color:var(--muted);text-decoration:underline;">Terms</a> and <a href="#" style="color:var(--muted);text-decoration:underline;">Privacy Policy</a></p>
</div>
</div>
<!-- STEP 2 -->
<div id="step2" style="display:none;background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<h2 class="f" style="font-size:23px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:6px;">How experienced are you?</h2>
<p style="font-size:14px;color:var(--muted);margin-bottom:24px;">Just so we know who we're building with</p>
<div id="modes">
<div class="mode-opt" onclick="selectExperience('beginner',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">First time</div><div style="font-size:12.5px;color:var(--muted);">I've never shipped a product before</div></div>
</div>
<div class="mode-opt" onclick="selectExperience('some',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Some experience</div><div style="font-size:12.5px;color:var(--muted);">I've built things before</div></div>
</div>
<div class="mode-opt" onclick="selectExperience('experienced',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Experienced</div><div style="font-size:12.5px;color:var(--muted);">I ship products regularly</div></div>
</div>
</div>
<!-- Contextual feedback — animated -->
<div id="exp-feedback" class="exp-feedback" style="background:var(--soft);border:1px solid rgba(99,102,241,0.2);">
<div id="exp-feedback-text" style="font-size:13px;color:#4338CA;line-height:1.6;"></div>
</div>
<button id="step2btn" class="btn" style="margin-top:20px;" onclick="goStep(3)" disabled>Set up my workspace →</button>
<p class="mode-hint" id="mode-hint">Select an option above to continue</p>
<p style="text-align:center;margin-top:6px;"><a onclick="goStep(1)" style="font-size:13px;color:var(--muted);text-decoration:none;cursor:pointer;">← Back</a></p>
</div>
<!-- STEP 3 -->
<div id="step3" style="display:none;background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<div style="display:flex;align-items:center;gap:12px;margin-bottom:6px;">
<div style="width:36px;height:36px;background:var(--soft);border:1px solid rgba(99,102,241,0.25);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;color:#6366F1;"></div>
<h2 class="f" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">You're in. Got an idea?</h2>
</div>
<p id="done-msg" style="font-size:14px;color:var(--muted);line-height:1.7;margin-bottom:20px;padding-left:48px;">Describe it in one sentence and we'll carry it straight into your workspace.</p>
<!-- Seed input -->
<textarea id="seed-idea" placeholder="e.g. A booking tool for independent personal trainers." style="width:100%;border:1px solid var(--border);border-radius:8px;padding:11px 13px;font-family:var(--sans);font-size:14px;color:var(--ink);background:#FAFAFA;outline:none;resize:none;height:88px;line-height:1.6;transition:border-color 0.15s,box-shadow 0.15s;margin-bottom:16px;" onfocus="this.style.borderColor='#6366F1';this.style.boxShadow='0 0 0 3px rgba(99,102,241,0.12)';" onblur="this.style.borderColor='#E5E7EB';this.style.boxShadow='none';"></textarea>
<button id="dash-btn" class="btn" style="margin-top:0;" onclick="openDashboard()">Start building →</button>
<p style="text-align:center;margin-top:14px;">
<a onclick="goToDashboard()" style="font-size:13px;color:var(--muted);text-decoration:none;cursor:pointer;">I'll do this later — take me to the dashboard</a>
</p>
<p style="text-align:center;margin-top:10px;"><a onclick="goStep(2)" style="font-size:12px;color:var(--muted);text-decoration:none;cursor:pointer;opacity:0.6;">← Back</a></p>
</div>
</div>
</div>
<script>
/* Google auth popup */
function openGoogleAuth(){
var w=500,h=600;
var left=(screen.width/2)-(w/2);
var top=(screen.height/2)-(h/2);
window.open('google-auth-popup.html','google-auth','width='+w+',height='+h+',left='+left+',top='+top+',toolbar=no,menubar=no,scrollbars=no');
window.addEventListener('message',function(e){
if(e.data&&e.data.type==='google-auth-success'){
goStep(2);
}
},{once:true});
}
var mode=null;
var EXP_FEEDBACK={
beginner:"We've got you — we'll explain every step clearly, no jargon, no assumptions. You'll have a product live before you know it.",
some:"Great! You know the ropes — let's move fast and make something great.",
experienced:"You know the process. We'll keep things efficient and get straight to the point."
};
var EXP_DONE={
beginner:"Everything is in place. We'll guide you every step of the way.",
some:"Everything is in place. Let's get straight to building.",
experienced:"Everything is in place. Let's move fast."
};
/* Step navigation */
function goStep(n){
[1,2,3].forEach(function(i){
document.getElementById('step'+i).style.display=i===n?'block':'none';
var s=document.getElementById('s'+i);
if(s) s.style.opacity=i<=n?'1':'0.35';
var c=document.getElementById('s'+i+'c');
if(c){
c.style.background=i<n?'#4338CA':i===n?'#6366F1':'#E5E7EB';
c.style.color=i<=n?'#FFFFFF':'#9CA3AF';
c.textContent=i<n?'✓':String(i);
}
});
}
/* Step 1 — form validation */
function validateStep1(){
var name=document.getElementById('inp-name').value.trim();
var email=document.getElementById('inp-email').value.trim();
var pwd=document.getElementById('pwd').value;
var emailOk=/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
var pwdOk=pwd.length>=8;
document.getElementById('step1btn').disabled=!(name.length>0 && emailOk && pwdOk);
}
/* Password show / hide */
function togglePwd(){
var input=document.getElementById('pwd');
var eyeOpen=document.getElementById('eye-open');
var eyeClosed=document.getElementById('eye-closed');
var isHidden=input.type==='password';
input.type=isHidden?'text':'password';
eyeOpen.style.display=isHidden?'none':'block';
eyeClosed.style.display=isHidden?'block':'none';
}
/* Password strength */
function checkStrength(v){
var segs=['seg1','seg2','seg3'];
var labelEl=document.getElementById('strength-label');
if(v.length===0){
segs.forEach(function(id){document.getElementById(id).style.background='#E5E7EB';});
labelEl.textContent='';
return;
}
if(v.length<8){
segs.forEach(function(id){document.getElementById(id).style.background='#E5E7EB';});
document.getElementById('seg1').style.background='#F87171';
labelEl.textContent='Not enough characters — 8 minimum';
labelEl.style.color='#F87171';
return;
}
var score=1;
if(/[A-Z]/.test(v)&&/[0-9]/.test(v)) score++;
if(/[^A-Za-z0-9]/.test(v)||v.length>=12) score++;
var colors=['#E5E7EB','#E5E7EB','#E5E7EB'];
var label='';
if(score===1){colors[0]='#F87171';label='Weak';}
else if(score===2){colors[0]='#FBBF24';colors[1]='#FBBF24';label='Fair';}
else{colors[0]='#4338CA';colors[1]='#6366F1';colors[2]='#818CF8';label='Strong';}
segs.forEach(function(id,i){document.getElementById(id).style.background=colors[i];});
labelEl.textContent=label;
labelEl.style.color=score===1?'#F87171':score===2?'#FBBF24':'#6366F1';
}
/* Step 2 — experience selection */
function selectExperience(level,el){
mode=level;
document.querySelectorAll('.mode-opt').forEach(function(d){d.classList.remove('selected');});
el.classList.add('selected');
// Show contextual feedback
var feedback=document.getElementById('exp-feedback');
var feedbackText=document.getElementById('exp-feedback-text');
feedbackText.textContent=EXP_FEEDBACK[level];
feedback.classList.add('visible');
// Enable button + hide hint
document.getElementById('step2btn').disabled=false;
document.getElementById('mode-hint').style.opacity='0';
document.getElementById('done-msg').textContent=EXP_DONE[level];
}
/* Step 3 — start building (carries seed idea to Describe) */
function openDashboard(){
var btn=document.getElementById('dash-btn');
btn.textContent='Setting up…';
btn.disabled=true;
var idea=(document.getElementById('seed-idea').value||'').trim();
setTimeout(function(){
try {
sessionStorage.setItem('vibn_new_project','1');
if(idea) sessionStorage.setItem('vibn_seed_idea', idea);
} catch(e){}
window.location.href='05_describe.html';
},800);
}
/* Step 3 — skip to dashboard */
function goToDashboard(){
window.location.href='03_dashboard.html';
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,589 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>vibn — Architect</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{
--ink:#1A1A1A;--mid:#6B7280;--muted:#9CA3AF;
--border:#E5E7EB;--cream:#FAFAFF;--paper:#F5F3FF;--white:#FFFFFF;
--indigo:#6366F1;--indigo-dark:#4338CA;--indigo-deep:#2E2A5E;
--indigo-soft:rgba(99,102,241,0.08);--indigo-ring:rgba(99,102,241,0.12);
}
body{font-family:'Plus Jakarta Sans',sans-serif;background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);display:flex;flex-direction:column;height:100vh;overflow:hidden;}
.f{font-family:'Plus Jakarta Sans',sans-serif;}
/* ── Dark mode — exact match to Describe ── */
[data-theme="dark"]{
--ink:#ECE9F5;--ink2:#C8C4D8;--ink3:#A0A0B8;
--mid:#9AA3BC;--muted:#6A7490;--border:#3A4260;
--cream:#2A3250;--paper:#2A3250;--white:#2A3250;
--indigo:#818CF8;--indigo-dark:#A5B4FC;--indigo-deep:#6366F1;
--indigo-soft:rgba(99,102,241,0.12);--indigo-ring:rgba(99,102,241,0.2);
}
[data-theme="dark"] body{background:#1A1F2E;}
/* Structural panels — same hierarchy as Describe: sidebar & main = mid, right panel = darkest */
[data-theme="dark"] .arch-sidebar{background:#2A3250!important;border-right-color:#3A4260!important;}
[data-theme="dark"] .arch-main{background:#212840!important;}
[data-theme="dark"] [style*="background:#f5f3ff"]{background:#1A1F2E!important;}
/* White & near-white backgrounds (cards float above panels) */
[data-theme="dark"] [style*="background:var(--white)"]{background:#2A3250!important;}
[data-theme="dark"] [style*="background:#fafaff"]{background:#212840!important;}
[data-theme="dark"] [style*="background:#FAFAFA"]{background:#212840!important;}
[data-theme="dark"] [style*="background:#f0f4ff"]{background:#2A3250!important;}
[data-theme="dark"] [style*="background:#eef2ff"]{background:rgba(99,102,241,0.18)!important;}
[data-theme="dark"] [style*="background:#F3F4F6"]{background:#3A4260!important;}
/* Borders */
[data-theme="dark"] [style*="border-bottom:1px solid #c7d2fe"]{border-bottom-color:#3A4260!important;}
[data-theme="dark"] [style*="border:1px solid #e0e7ff"]{border-color:#3A4260!important;}
[data-theme="dark"] [style*="border:1px solid rgba(99,102,241"]{border-color:rgba(99,102,241,0.06)!important;}
/* Sidebar-specific */
[data-theme="dark"] .arch-sidebar [style*="border-top:1px solid #e5e7eb"]{border-top-color:#3A4260!important;}
[data-theme="dark"] .arch-sidebar [style*="background:#e5e7eb"]{background:#3A4260!important;}
[data-theme="dark"] .arch-sidebar [style*="color:#1a1a1a"]{color:#ECE9F5!important;}
[data-theme="dark"] .arch-sidebar [style*="color:#6b7280"]{color:#9AA3BC!important;}
[data-theme="dark"] .arch-sidebar [style*="color:#444441"]{color:#6A7490!important;}
[data-theme="dark"] .arch-sidebar [style*="color:#9ca3af"]{color:#6A7490!important;}
/* Phase & progress dots: filled indigo → light lavender (matching Describe's --accent-primary in dark) */
[data-theme="dark"] .arch-sidebar [style*="background:#6366F1"]{background:#A5B4FC!important;color:#1A1F2E!important;}
[data-theme="dark"] [style*="color:#4338ca"]{color:#A5B4FC!important;}
[data-theme="dark"] .sidebar-phase.active{background:rgba(165,180,252,0.12)!important;}
/* Blueprint rows */
[data-theme="dark"] .blueprint-row:hover{background:#323C5E!important;}
[data-theme="dark"] .blueprint-row.locked{background:#242B48!important;}
[data-theme="dark"] .blueprint-row.locked:hover{background:#2E3A5A!important;}
/* Option buttons */
[data-theme="dark"] .opt-btns{border-color:#3A4260!important;}
[data-theme="dark"] .opt-btn{color:#C8D0E8!important;border-right-color:#3A4260!important;}
[data-theme="dark"] .opt-btn:hover{background:#2E3A5A!important;color:#A5B4FC!important;}
[data-theme="dark"] .opt-btn.selected{background:rgba(99,102,241,0.15)!important;color:#A5B4FC!important;}
[data-theme="dark"] .opt-btn.why-btn{color:#A5B4FC!important;}
[data-theme="dark"] .why-btn{color:#9AA3BC!important;border-color:#3A4260!important;}
/* Right panel */
[data-theme="dark"] .deliverable-row{color:#9AA3BC!important;}
[data-theme="dark"] .deliverable-row:hover{background:#2E3A5A!important;}
/* Popups & modals */
[data-theme="dark"] #why-popup>div{background:#242B48!important;box-shadow:0 0 0 1px rgba(165,180,252,0.18),0 24px 64px rgba(0,0,0,0.55),0 0 48px rgba(99,102,241,0.14)!important;}
[data-theme="dark"] #save-exit-box{background:#242B48!important;box-shadow:0 0 0 1px rgba(165,180,252,0.18),0 24px 64px rgba(0,0,0,0.55),0 0 48px rgba(99,102,241,0.14)!important;}
[data-theme="dark"] .modal-card{background:#242B48!important;box-shadow:0 0 0 1px rgba(165,180,252,0.18),0 24px 64px rgba(0,0,0,0.55),0 0 48px rgba(99,102,241,0.14)!important;}
/* Buttons */
[data-theme="dark"] #sidebar-project-name{color:#6A7490!important;}
[data-theme="dark"] #dark-toggle{background:#2A3250!important;border-color:#3A4260!important;color:var(--mid)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]{background:#1E2640!important;border-color:#3A4260!important;}
[data-theme="dark"] button[onclick="saveAndExit()"] span{color:#A5B4FC!important;}
/* Next button — same gradient as Describe's next button */
[data-theme="dark"] button[onclick="openWhy()"]{color:#A5B4FC!important;}
[data-theme="dark"] .btn-primary{background:linear-gradient(135deg,#4338CA,#6366F1)!important;color:#FFFFFF!important;box-shadow:0 4px 14px rgba(99,102,241,0.25)!important;}
/* Scrollbar */
[data-theme="dark"] ::-webkit-scrollbar{width:6px;height:6px;}
[data-theme="dark"] ::-webkit-scrollbar-track{background:#1A1F2E;}
[data-theme="dark"] ::-webkit-scrollbar-thumb{background:#3A4260;border-radius:3px;}
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover{background:#5865A0;}
[data-theme="dark"] *{scrollbar-color:#3A4260 #1A1F2E;scrollbar-width:thin;}
[data-theme="dark"] .vibn-avatar{background:#6366F1!important;}
/* Sidebar */
.sidebar-phase{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:8px;}
.sidebar-phase.active{background:#fafaff;}
.phase-dot{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:10px;}
/* Blueprint row */
.blueprint-row{display:grid;grid-template-columns:36px 1fr 248px;align-items:center;gap:16px;padding:15px 22px;border-bottom:1px solid var(--border);transition:background 0.15s;}
.blueprint-row:last-child{border-bottom:none;border-radius:0 0 14px 14px;}
.blueprint-row:hover{background:#FAFAFF;}
.blueprint-row.locked{background:#FAFAFA;}
.blueprint-row.locked:hover{background:#F5F5F5;}
/* Option toggle buttons */
.opt-btns{display:flex;gap:0;flex-shrink:0;border:1.5px solid var(--border);border-radius:8px;overflow:visible;}
.opt-btn{flex:1;text-align:center;font-size:12px;font-weight:500;color:var(--mid);background:transparent;border:none;border-right:1.5px solid var(--border);border-radius:0;padding:6px 13px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all 0.15s;white-space:nowrap;position:relative;}
.opt-btn:first-child{border-radius:7px 0 0 7px;}
.opt-btn:last-child{border-right:none;border-radius:0 7px 7px 0;}
.opt-btn:hover{background:#F5F5FF;color:var(--indigo);}
.opt-btn.selected{background:var(--indigo-soft);color:var(--indigo-dark);font-weight:600;}
/* Why button (hosting) */
.why-btn{font-size:11.5px;font-weight:600;color:var(--mid);background:transparent;border:1px solid var(--border);border-radius:6px;padding:5px 11px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:border-color 0.15s,color 0.15s;white-space:nowrap;}
.why-btn:hover{border-color:var(--indigo);color:var(--indigo);}
/* Primary button */
.btn-primary{background:linear-gradient(135deg,var(--indigo-deep),var(--indigo-dark));color:#FFFFFF;border:none;border-radius:8px;padding:10px 22px;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s,transform 0.2s;}
.btn-primary:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px var(--indigo-ring);transform:translateY(-1px);}
/* What you're getting panel */
.deliverable-row{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:7px;font-size:12px;color:var(--mid);transition:background 0.12s;}
.deliverable-row:hover{background:var(--cream);}
/* Modal */
.modal-bg{display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:100;align-items:center;justify-content:center;}
.modal-bg.open{display:flex;}
.modal-card{background:var(--white);border-radius:16px;width:400px;overflow:hidden;box-shadow:0 24px 64px rgba(30,27,75,0.18);}
/* Option buttons in modal */
.option-btn{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:10px;border:1px solid var(--border);background:var(--white);cursor:pointer;text-align:left;margin-bottom:8px;transition:all 0.15s;}
.option-btn:hover{border-color:var(--indigo);background:var(--cream);}
.option-btn.selected{border-color:var(--indigo);background:var(--cream);box-shadow:0 0 0 3px var(--indigo-ring);}
/* Save popup */
#save-exit-popup{display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:700;align-items:center;justify-content:center;padding:24px;}
#save-exit-popup.visible{display:flex;}
#save-exit-box{background:#FFFFFF;border-radius:16px;box-shadow:0 24px 64px rgba(30,27,75,0.18);padding:32px;width:100%;max-width:380px;text-align:center;}
#save-exit-box .save-icon{width:48px;height:48px;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;margin:0 auto 16px;}
#save-exit-box h3{font-size:18px;font-weight:700;color:var(--ink);margin-bottom:8px;}
#save-exit-box p{font-size:13px;color:var(--muted);line-height:1.6;margin-bottom:20px;}
#save-exit-box .save-cancel{font-size:12px;color:var(--muted);cursor:pointer;text-decoration:underline;background:none;border:none;font-family:'Plus Jakarta Sans',sans-serif;}
#save-exit-box .save-cancel:hover{color:var(--ink);}
/* Why accordion */
/* ── Mobile tab bar (hidden on desktop) ── */
.mob-tabs{display:none;flex-shrink:0;background:#EEF0FF;border-top:1px solid #D4D8FA;padding-bottom:env(safe-area-inset-bottom);}
[data-theme="dark"] .mob-tabs{background:#212840!important;}
.mob-tab-btn{flex:1;padding:11px 8px;border:none;background:transparent;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:500;color:var(--muted);cursor:pointer;border-top:2px solid transparent;transition:color 0.15s,border-color 0.15s;}
.mob-tab-btn.active{color:#6366F1;border-top-color:#6366F1;font-weight:600;}
.mob-dash-btn{background:none;border:none;font-family:'Plus Jakarta Sans',sans-serif;font-size:11.5px;font-weight:500;color:var(--muted);cursor:pointer;padding:11px 12px;white-space:nowrap;flex:none;transition:color 0.15s;}
.mob-dash-btn:hover{color:var(--ink);}
[data-theme="dark"] .mob-tab-btn{color:#6A7490!important;}
[data-theme="dark"] .mob-tab-btn.active{color:#A5B4FC!important;border-top-color:#A5B4FC!important;}
/* ── Responsive ── */
/* Tablet (641px 1024px): top tab bar, full-height panels */
@media (min-width:641px) and (max-width:1024px){
body{height:100dvh;overflow:hidden;}
.arch-layout{flex-direction:column!important;height:100dvh!important;overflow:hidden!important;}
.arch-sidebar{display:none!important;}
.mob-tabs{display:flex!important;order:0;border-top:none!important;border-bottom:1px solid #D4D8FA!important;padding-bottom:0!important;}
.mob-tab-btn{border-top:none;border-bottom:2px solid transparent;}
.mob-tab-btn.active{border-top-color:transparent;border-bottom-color:#6366F1;}
[data-theme="dark"] .mob-tab-btn.active{border-bottom-color:#A5B4FC!important;border-top-color:transparent!important;}
.arch-main{display:none!important;order:1;overflow:hidden!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-main.tab-active{display:flex!important;}
.arch-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right{display:none!important;order:1;width:100%!important;border-left:none!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-right.tab-active{display:flex!important;}
.arch-right-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right-footer{padding:12px 16px 20px!important;}
.arch-right-footer a{width:80%;display:block;}
.blueprint-row{grid-template-columns:36px 1fr!important;row-gap:10px;padding:13px 18px!important;}
.blueprint-row .opt-btns{grid-column:1 / -1;width:100%;}
}
/* Mobile (≤ 640px): tabbed layout, tabs at bottom */
@media (max-width:640px){
body{height:100dvh;overflow:hidden;}
.arch-layout{flex-direction:column!important;height:100dvh!important;overflow:hidden!important;}
.arch-sidebar{display:none!important;}
.mob-tabs{display:flex!important;order:2;}
.arch-main{display:none!important;order:1;overflow:hidden!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-main.tab-active{display:flex!important;}
.arch-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right{display:none!important;order:1;width:100%!important;border-left:none!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-right.tab-active{display:flex!important;}
.arch-right-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.blueprint-row{grid-template-columns:36px 1fr!important;row-gap:10px;padding:13px 16px!important;}
.blueprint-row .opt-btns{grid-column:1 / -1;width:100%;}
.opt-btn{flex:1;padding:7px 8px!important;font-size:11.5px!important;}
.arch-topbar{padding:14px 16px 12px!important;}
.arch-right-footer{padding:12px 16px 20px!important;}
.arch-right-footer a{width:100%!important;display:block!important;}
.modal-card{width:calc(100vw - 32px)!important;}
#why-popup>div{max-width:calc(100vw - 32px)!important;}
}
/* Mobile with trackpad (laptop narrow): tabs at top */
@media (max-width:640px) and (hover:hover) and (pointer:fine){
.mob-tabs{order:0!important;border-top:none!important;border-bottom:1px solid #D4D8FA!important;padding-bottom:0!important;}
.mob-tab-btn{border-top:none;border-bottom:2px solid transparent;}
.mob-tab-btn.active{border-top-color:transparent;border-bottom-color:#6366F1;}
[data-theme="dark"] .mob-tab-btn.active{border-bottom-color:#A5B4FC!important;}
.arch-main{order:1!important;}
.arch-right{order:1!important;}
}
</style>
</head>
<body>
<div class="arch-layout" style="display:flex;height:100%;overflow:hidden;">
<!-- Mobile tab bar (hidden on desktop, shown on ≤ 640px) -->
<div class="mob-tabs" id="mob-tabs">
<button onclick="saveAndExit()" class="mob-dash-btn">Dashboard</button>
<div style="width:1px;background:var(--border);margin:8px 0;flex-shrink:0;"></div>
<button class="mob-tab-btn active" id="tab-blueprint" onclick="switchArchTab('blueprint')">Blueprint</button>
<button class="mob-tab-btn" id="tab-scope" onclick="switchArchTab('scope')">Scope</button>
</div>
<!-- ── SIDEBAR ── -->
<div class="arch-sidebar" style="width:200px;background:#ffffff;border-right:1px solid #e5e7eb;display:flex;flex-direction:column;padding:18px 12px;flex-shrink:0;">
<div style="padding:0 6px;margin-bottom:26px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;"><span class="f" style="font-size:13px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:16px;font-weight:700;color:#1a1a1a;letter-spacing:-0.02em;">vibn</span>
</div>
<div id="sidebar-project-name" style="font-size:11px;font-weight:500;color:#9ca3af;padding-left:34px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:none;"></div>
</div>
<div style="font-size:9.5px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:#9ca3af;padding:0 6px;margin-bottom:8px;">MVP Setup</div>
<div style="display:flex;flex-direction:column;gap:2px;flex:1;">
<div class="sidebar-phase">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Describe</div>
</div>
<div class="sidebar-phase active">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div><div style="font-size:12.5px;font-weight:600;color:#1a1a1a;">Architect</div><div style="font-size:10px;color:#9ca3af;">What gets built</div></div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Design</div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Market</div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Build MVP</div>
</div>
</div>
<div style="border-top:1px solid #e5e7eb;margin-top:14px;padding-top:12px;">
<button onclick="saveAndExit()" style="display:flex;align-items:center;justify-content:center;gap:7px;width:100%;background:#eef2ff;border:1px solid #e0e7ff;border-radius:8px;padding:9px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:background 0.15s;" onmouseover="this.style.background='#e0e7ff'" onmouseout="this.style.background='#eef2ff'">
<span style="font-size:12px;font-weight:600;color:#6366F1;">Save & go to dashboard</span>
</button>
<button id="dark-toggle" onclick="toggleTheme()" style="margin-top:8px;display:flex;align-items:center;justify-content:center;width:100%;background:transparent;border:1px solid var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:500;color:var(--mid);transition:background 0.15s,border-color 0.15s;" onmouseover="this.style.borderColor='#6366F1';this.style.color='#6366F1';" onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--mid)';">🌙 Dark mode</button>
</div>
</div>
<!-- ── MAIN ── -->
<div class="arch-main" style="flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;position:relative;z-index:1;">
<!-- Top bar -->
<div class="arch-topbar" style="padding:18px 28px 14px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;flex-shrink:0;">
<div>
<div class="f" style="font-size:17px;font-weight:700;color:var(--ink);margin-bottom:3px;">Your product blueprint</div>
<div style="font-size:12.5px;color:var(--muted);">We set everything up — review and confirm to continue.</div>
</div>
</div>
<!-- Scrollable body -->
<div class="arch-scroll" style="flex:1;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:12px;">
<!-- Intro message -->
<div style="display:flex;align-items:flex-start;gap:10px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px;"><span style="font-size:12px;font-weight:700;color:#FFFFFF;">V</span></div>
<div style="max-width:84%;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:4px 12px 12px 12px;padding:11px 14px;font-size:13px;color:var(--ink);line-height:1.65;">
Here's the technical stack we've set up for <strong id="intro-project-name" style="font-weight:600;">your product</strong>. These are the best defaults for an idea like yours — review each decision below and change anything that doesn't feel right.
</div>
</div>
<!-- Blueprint card -->
<div style="background:var(--white);border:1px solid var(--border);border-radius:14px;overflow:visible;box-shadow:0 4px 20px rgba(30,27,75,0.05);">
<!-- Card header -->
<div style="padding:14px 22px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div style="width:8px;height:8px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>
<span style="font-size:13px;font-weight:600;color:var(--ink);">How vibn will build it</span>
<button onclick="openWhy()" style="margin-left:auto;background:none;border:none;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;color:#6366F1;font-weight:600;padding:0;display:flex;align-items:center;gap:5px;">💡 Why these choices?</button>
</div>
<!-- Frontend -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Frontend</div>
<div style="font-size:11.5px;color:var(--muted);">Where will your users mostly be when they use your product — at a desk, or on the go? This shapes every screen we design.</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="frontend" data-tip="Runs in any browser, desktop & mobile" onclick="selectOpt('frontend',this)">Web app</button>
<button class="opt-btn" data-group="frontend" data-tip="Optimised for phones, still works on desktop" onclick="selectOpt('frontend',this)">Mobile-first</button>
</div>
</div>
<!-- Backend -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Backend & Database</div>
<div style="font-size:11.5px;color:var(--muted);">The invisible part that stores your users' data and makes everything work behind the scenes</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="backend" data-tip="Standard setup, works for almost everything" onclick="selectOpt('backend',this)">API + database</button>
<button class="opt-btn" data-group="backend" data-tip="Live updates between users — great for collaboration" onclick="selectOpt('backend',this)">Real-time</button>
</div>
</div>
<!-- Auth -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Sign up & Login</div>
<div style="font-size:11.5px;color:var(--muted);">How people create an account and get back in — fewer steps means more people actually sign up</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="auth" data-tip="Google & GitHub sign-in — less friction, more sign-ups" onclick="selectOpt('auth',this)">Email + social</button>
<button class="opt-btn" data-group="auth" data-tip="Simpler setup, no third-party login" onclick="selectOpt('auth',this)">Email only</button>
</div>
</div>
<!-- Payments -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Payments</div>
<div style="font-size:11.5px;color:var(--muted);">How you get paid — Stripe handles the card processing so you never touch sensitive data</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="payments" data-tip="Monthly or annual recurring payments" onclick="selectOpt('payments',this)">Subscription</button>
<button class="opt-btn" data-group="payments" data-tip="Pay once, own forever" onclick="selectOpt('payments',this)">One-time</button>
</div>
</div>
<!-- Email -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Email</div>
<div style="font-size:11.5px;color:var(--muted);">Automated messages sent to your users — from welcome emails on day one to newsletters later</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="email" data-tip="Welcome emails, resets & marketing newsletters" onclick="selectOpt('email',this)">Full suite</button>
<button class="opt-btn" data-group="email" data-tip="Just transactional emails — resets and confirmations" onclick="selectOpt('email',this)">Essentials only</button>
</div>
</div>
<!-- Hosting — locked -->
<div class="blueprint-row locked">
<div style="width:32px;height:32px;border-radius:9px;background:#F3F4F6;display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--muted);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Hosting</div>
<div style="font-size:11.5px;color:var(--muted);">Where your product lives — on your own servers, so no one else controls your data or your costs</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" style="cursor:default;">Your servers 🔒</button>
<button class="opt-btn why-btn" onclick="openHostingWhy()" style="border-radius:0 7px 7px 0;border-right:none;color:#6366F1;font-weight:600;">Why?</button>
</div>
</div>
</div>
<!-- Reassurance note -->
<div style="display:flex;align-items:center;gap:10px;padding:11px 16px;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:10px;">
<span style="font-size:16px;flex-shrink:0;">💬</span>
<p style="font-size:12px;color:var(--mid);line-height:1.55;margin:0;">Not sure about any of these? Don't worry — you can change them anytime before we start building.</p>
</div>
</div>
</div>
<!-- ── RIGHT PANEL ── -->
<div class="arch-right" style="width:384px;border-left:1px solid var(--border);background:#f5f3ff;display:flex;flex-direction:column;flex-shrink:0;">
<!-- Panel header — matches Describe PRD style -->
<div style="flex-shrink:0;padding:18px 0 0;">
<div style="margin:0 16px;padding-bottom:14px;border-bottom:1px solid #c7d2fe;">
<div style="font-size:15px;font-weight:800;letter-spacing:0.04em;text-transform:uppercase;color:#4338ca;margin-bottom:5px;">What your users will be able to do</div>
<div style="font-size:12px;color:var(--ink3);line-height:1.5;">10 screens covering the full user journey, ready to design.</div>
</div>
</div>
<!-- Scrollable content -->
<div class="arch-right-scroll" style="flex:1;overflow-y:auto;padding:16px;">
<!-- Pages -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Pages</div>
<div style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-bottom:16px;">
<div style="padding:5px 12px;background:#fafaff;border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Public</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Discover your product</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>See your pricing</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Learn about you</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Auth</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Create an account</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Sign back in</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Reset their password</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">App</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Use the dashboard</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Manage their settings</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Payments</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Subscribe and pay</div>
<div class="deliverable-row" style="border-bottom:none;"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Manage their plan</div>
</div>
<!-- Infrastructure -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Infrastructure</div>
<div style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;">
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border);">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🖥</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Your own servers</div><div style="font-size:11px;color:var(--muted);">No platform lock-in, ever</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border);">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🔁</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Auto-deploy via Coolify</div><div style="font-size:11px;color:var(--muted);">Every push goes live instantly</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🔒</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Code stored in Gitea</div><div style="font-size:11px;color:var(--muted);">Private repo, yours alone</div></div>
</div>
</div>
<!-- Timeline / cost signal -->
<div style="display:flex;align-items:center;justify-content:center;gap:16px;padding:10px 0 2px;">
<span style="font-size:11px;color:var(--muted);display:flex;align-items:center;gap:5px;"><span>~34 weeks to build</span></span>
<span style="font-size:11px;color:var(--muted);">·</span>
<span style="font-size:11px;color:var(--muted);display:flex;align-items:center;gap:5px;">💰 <span>No platform fees</span></span>
</div>
</div>
<!-- Footer -->
<div class="arch-right-footer" style="border-top:1px solid var(--border);padding:9px 0 13px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;">
<p style="font-size:11.5px;color:var(--muted);text-align:center;margin:0 0 10px;line-height:1.5;">All set — let's decide how it looks.</p>
<a href="07_design.html" style="text-decoration:none;display:block;width:80%;">
<button class="btn-primary" style="width:100%;padding:12px 14px;border-radius:8px;">Next: Design</button>
</a>
</div>
</div>
</div>
<!-- ── WHY POPUP ── -->
<div id="why-popup" style="display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:200;align-items:center;justify-content:center;padding:24px;" onclick="closeWhy()">
<div style="background:var(--white);border-radius:16px;width:100%;max-width:480px;box-shadow:0 24px 64px rgba(30,27,75,0.18);padding:32px;" onclick="event.stopPropagation()">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:20px;">
<span style="font-size:20px;">💡</span>
<h3 style="font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Why we chose this for your product</h3>
</div>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;">Based on your idea, vibn picked a <strong style="color:var(--ink);font-weight:600;">web app with subscription billing</strong> — the fastest path to recurring revenue for a SaaS product.</p>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink);font-weight:600;">Email + social login</strong> keeps sign-up friction low. Most people won't create a password for something they haven't tried yet — one click with Google removes that barrier.</p>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:24px;"><strong style="color:var(--ink);font-weight:600;">Your own hosting</strong> means you own the infrastructure outright. No platform lock-in, no surprise price hikes. Coolify + Gitea are already configured to your account.</p>
<button onclick="closeWhy()" class="btn-primary" style="width:100%;padding:12px;">Got it</button>
</div>
</div>
<!-- ── SAVE POPUP ── -->
<div id="save-exit-popup">
<div id="save-exit-box">
<div class="save-icon"></div>
<h3>Your progress is saved.</h3>
<p>You can come back to this project anytime from your dashboard — everything will be exactly where you left it.</p>
<button onclick="window.location.href='03_dashboard.html'" style="width:100%;background:linear-gradient(135deg,#2e2a5e,#4338ca);color:#fff;border:none;border-radius:10px;padding:12px;font-family:'Plus Jakarta Sans',sans-serif;font-size:14px;font-weight:600;cursor:pointer;margin-bottom:10px;">Got it, go to dashboard</button>
<button class="save-cancel" onclick="cancelSaveExit()">Stay on this page</button>
</div>
</div>
<!-- ── MODAL ── -->
<div id="modal" class="modal-bg" onclick="closeModal()">
<div class="modal-card" onclick="event.stopPropagation()">
<div style="padding:18px 22px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;">
<span id="modal-title" class="f" style="font-size:15px;font-weight:700;color:var(--ink);"></span>
<button onclick="closeModal()" style="background:transparent;border:none;color:var(--muted);cursor:pointer;font-size:18px;line-height:1;">×</button>
</div>
<div style="padding:16px 22px;" id="modal-options"></div>
<div style="padding:10px 22px 18px;">
<button onclick="closeModal()" class="btn-primary" style="width:100%;padding:12px;border-radius:9px;">Got it</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
try {
var name = localStorage.getItem('vibn_project_name') || 'My project';
var el = document.getElementById('sidebar-project-name');
el.textContent = name;
el.style.display = 'block';
var intro = document.getElementById('intro-project-name');
if(intro) intro.textContent = name;
} catch(e){}
// Init Blueprint tab on tablet + mobile
if(window.innerWidth <= 1024){
document.querySelector('.arch-main').classList.add('tab-active');
}
});
function switchArchTab(tab){
var main = document.querySelector('.arch-main');
var right = document.querySelector('.arch-right');
var btnBlueprint = document.getElementById('tab-blueprint');
var btnScope = document.getElementById('tab-scope');
if(tab === 'blueprint'){
main.classList.add('tab-active');
right.classList.remove('tab-active');
btnBlueprint.classList.add('active');
btnScope.classList.remove('active');
} else {
right.classList.add('tab-active');
main.classList.remove('tab-active');
btnScope.classList.add('active');
btnBlueprint.classList.remove('active');
}
}
function saveAndExit(){ document.getElementById('save-exit-popup').classList.add('visible'); }
function cancelSaveExit(){ document.getElementById('save-exit-popup').classList.remove('visible'); }
function openWhy(){ document.getElementById('why-popup').style.display='flex'; }
function closeWhy(){ document.getElementById('why-popup').style.display='none'; }
function selectOpt(group, el){
document.querySelectorAll('[data-group="'+group+'"]').forEach(function(b){ b.classList.remove('selected'); });
el.classList.add('selected');
}
function openHostingWhy(){
document.getElementById('modal-title').textContent = 'Why your own servers?';
document.getElementById('modal-options').innerHTML =
'<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink)">Most platforms rent you server space</strong> — which means they control your data, your uptime, and your bill. The day they raise prices or shut down, your product goes with it.</p>' +
'<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink)">With vibn, your product lives on your own servers.</strong> You own the infrastructure outright. Nobody can lock you out, hike your costs, or access your users\u2019 data without your permission.</p>' +
'<p style="font-size:13px;color:var(--mid);line-height:1.8;">We handle the hard part: <a href="https://coolify.io" target="_blank" style="color:var(--indigo);font-weight:600;text-decoration:none;">Coolify</a> auto-deploys your code every time you push an update, and <a href="https://gitea.com" target="_blank" style="color:var(--indigo);font-weight:600;text-decoration:none;">Gitea</a> stores your codebase securely. You get full control of your infrastructure \u2014 without needing to know how any of it works.</p>';
document.getElementById('modal').classList.add('open');
}
function openModal(title, opt1, desc1, opt2, desc2){
document.getElementById('modal-title').textContent = title;
document.getElementById('modal-options').innerHTML = '<p style="font-size:13px;color:var(--mid);line-height:1.6;">'+desc1+'</p>';
document.getElementById('modal').classList.add('open');
}
function closeModal(){ document.getElementById('modal').classList.remove('open'); }
function showTip(el){
hideTip();
var tip=document.createElement('div');
tip.id='vibn-tip';
tip.textContent=el.dataset.tip;
tip.style.cssText='position:fixed;background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#fff;font-size:11px;font-weight:500;line-height:1.5;padding:6px 10px;border-radius:6px;white-space:nowrap;z-index:9999;pointer-events:none;box-shadow:0 4px 16px rgba(67,56,202,0.35);font-family:Plus Jakarta Sans,sans-serif;transition:opacity 0.1s;';
document.body.appendChild(tip);
var r=el.getBoundingClientRect();
tip.style.left=(r.left+r.width/2-tip.offsetWidth/2)+'px';
tip.style.top=(r.top-tip.offsetHeight-9)+'px';
var arrow=document.createElement('div');
arrow.id='vibn-tip-arrow';
arrow.style.cssText='position:fixed;border:5px solid transparent;border-top-color:#4338CA;z-index:9999;pointer-events:none;';
document.body.appendChild(arrow);
arrow.style.left=(r.left+r.width/2-5)+'px';
arrow.style.top=(r.top-9)+'px';
}
function hideTip(){
var t=document.getElementById('vibn-tip');
var a=document.getElementById('vibn-tip-arrow');
if(t)t.remove();
if(a)a.remove();
}
document.addEventListener('mouseover',function(e){var b=e.target.closest('.opt-btn[data-tip]');if(b)showTip(b);});
document.addEventListener('mouseout',function(e){var b=e.target.closest('.opt-btn[data-tip]');if(b)hideTip();});
function toggleTheme(){const html=document.documentElement;const isDark=html.dataset.theme==='dark';html.dataset.theme=isDark?'':'dark';document.getElementById('dark-toggle').textContent=isDark?'🌙 Dark mode':'☀️ Light mode';localStorage.setItem('vibn-theme',isDark?'':'dark');}
(function(){const saved=localStorage.getItem('vibn-theme');if(saved==='dark'){document.documentElement.dataset.theme='dark';document.addEventListener('DOMContentLoaded',function(){const btn=document.getElementById('dark-toggle');if(btn)btn.textContent='☀️ Light mode';});}})();
</script>
</body></html>

View File

@@ -1,44 +0,0 @@
# vibn — UX Screen Pack
Design system: **Ink & parchment** — Lora serif + Inter sans, no colour accent.
All HTML files open directly in any browser — no build step required.
## Complete screen inventory
| File | Screen | Interactive? |
|------|--------|-------------|
| `01_homepage.html` | Marketing homepage | Scroll |
| `02_signup.html` | Sign up (3 steps) | ✓ Click through steps, mode selection |
| `03_dashboard.html` | Projects dashboard | ✓ Projects / Clients / Invoices / Costs nav |
| `04_welcome.html` | Welcome phase | Static |
| `05_discover.html` | Discover phase | ✓ Live chat, PRD fills in |
| `06_architect.html` | Architect phase | ✓ Change modal per block |
| `07_design.html` | Design phase | ✓ Live style preview switching |
| `08_market.html` | Market phase | ✓ Voice sliders, Topics, Website style |
| `09_build.html` | Build phase | ✓ Review + animated 12-step pipeline |
| `10_vibe_editor.html` | Vibe editor (post-launch) | ✓ Chat, preview updates, deploy status |
| `vibn-website.jsx` | Marketing site | React component |
| `vibn-dashboard.jsx` | Dashboard + billing | React component |
| `00_design-tokens.css` | Design tokens | Reference |
## Full user flow
01 Homepage → 02 Sign up → 03 Dashboard → 04 Welcome →
05 Discover → 06 Architect → 07 Design → 08 Market →
09 Build → 10 Vibe editor
## Design tokens
| Token | Value | Usage |
|-------|-------|-------|
| `--ink` | `#1a1510` | Primary text, buttons |
| `--ink3` | `#444441` | Secondary text |
| `--mid` | `#5f5e5a` | Body text |
| `--muted` | `#888780` | Labels, captions |
| `--stone` | `#b4b2a9` | Disabled, hints |
| `--cream` | `#f1efe8` | Surface tint, hover |
| `--paper` | `#f7f4ee` | Page background |
| `--white` | `#fdfcfa` | Card backgrounds |
| `--border` | `#e8e2d9` | All borders |
Heading font: **Lora** (serif)
Body font: **Inter** (sans-serif)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1,119 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>Sign in Google Accounts</title>
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;600&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:'Roboto',sans-serif;background:#FFFFFF;display:flex;flex-direction:column;align-items:center;min-height:100vh;padding:40px 24px;}
.card{width:100%;max-width:400px;border:1px solid #DADCE0;border-radius:8px;padding:40px 40px 28px;display:flex;flex-direction:column;align-items:center;}
.google-logo{margin-bottom:24px;}
h1{font-family:'Google Sans',sans-serif;font-size:24px;font-weight:400;color:#202124;margin-bottom:8px;text-align:center;}
.subtitle{font-size:16px;color:#202124;margin-bottom:24px;text-align:center;}
/* Account tile */
.account-tile{width:100%;border:1px solid #DADCE0;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:16px;cursor:pointer;transition:background 0.15s;margin-bottom:12px;}
.account-tile:hover{background:#F8F9FA;}
.avatar{width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,#4285F4,#34A853);display:flex;align-items:center;justify-content:center;font-family:'Google Sans',sans-serif;font-size:16px;font-weight:500;color:#FFFFFF;flex-shrink:0;}
.account-info{flex:1;text-align:left;}
.account-name{font-family:'Google Sans',sans-serif;font-size:14px;font-weight:500;color:#202124;margin-bottom:2px;}
.account-email{font-size:13px;color:#5F6368;}
.chevron{color:#5F6368;}
/* Add account */
.add-account{width:100%;border:1px solid #DADCE0;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:16px;cursor:pointer;transition:background 0.15s;margin-bottom:24px;}
.add-account:hover{background:#F8F9FA;}
.add-icon{width:40px;height:40px;border-radius:50%;background:#F1F3F4;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:20px;color:#5F6368;}
.add-label{font-size:14px;color:#202124;}
.divider{width:100%;height:1px;background:#E8EAED;margin-bottom:20px;}
/* Continue button */
.btn-continue{background:#1A73E8;color:#FFFFFF;border:none;border-radius:4px;padding:10px 24px;font-family:'Google Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer;transition:background 0.15s,box-shadow 0.15s;box-shadow:0 1px 2px rgba(0,0,0,0.2);}
.btn-continue:hover{background:#1765CC;box-shadow:0 2px 6px rgba(0,0,0,0.2);}
.footer{margin-top:auto;padding-top:24px;display:flex;gap:24px;justify-content:center;}
.footer a{font-size:12px;color:#5F6368;text-decoration:none;}
.footer a:hover{text-decoration:underline;}
/* Loading state */
.loading{display:none;flex-direction:column;align-items:center;gap:16px;margin-top:20px;}
.spinner{width:32px;height:32px;border:3px solid #E8EAED;border-top-color:#1A73E8;border-radius:50%;animation:spin 0.8s linear infinite;}
@keyframes spin{to{transform:rotate(360deg);}}
.loading-text{font-size:14px;color:#5F6368;}
</style>
</head>
<body>
<div class="card">
<!-- Google logo -->
<div class="google-logo">
<svg width="75" height="24" viewBox="0 0 75 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30.5 12.3c0-.7-.1-1.4-.2-2h-9.6v3.8h5.5c-.2 1.3-1 2.4-2.1 3.1v2.6h3.4c2-1.8 3-4.5 3-7.5z" fill="#4285F4"/>
<path d="M20.7 19.9c2.7 0 5-.9 6.7-2.4l-3.4-2.6c-.9.6-2 1-3.3 1-2.6 0-4.7-1.7-5.5-4.1H11.7v2.7c1.7 3.4 5.2 5.4 9 5.4z" fill="#34A853"/>
<path d="M15.2 11.8c-.2-.6-.3-1.2-.3-1.8s.1-1.2.3-1.8V7.5H11.7C11 8.8 10.7 10.3 10.7 12s.3 3.2 1 4.5l3.5-2.7z" fill="#FBBC05"/>
<path d="M20.7 5.9c1.4 0 2.7.5 3.7 1.5l2.8-2.8C25.7 3 23.4 2 20.7 2c-3.8 0-7.3 2-9 5.4l3.5 2.7c.8-2.4 2.9-4.2 5.5-4.2z" fill="#EA4335"/>
<text x="36" y="17" font-family="'Product Sans',Roboto,sans-serif" font-size="16" fill="#5F6368">Google</text>
</svg>
</div>
<h1>Sign in</h1>
<p class="subtitle">to continue to vibn</p>
<!-- Account selector (shown by default) -->
<div id="account-select" style="width:100%;">
<div class="account-tile" onclick="selectAccount()">
<div class="avatar">J</div>
<div class="account-info">
<div class="account-name">Jane Smith</div>
<div class="account-email">jane@gmail.com</div>
</div>
<svg class="chevron" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
</div>
<div class="add-account" onclick="selectAccount()">
<div class="add-icon"></div>
<div class="add-label">Use another account</div>
</div>
<div class="divider"></div>
<p style="font-size:12px;color:#5F6368;text-align:center;line-height:1.6;">To continue, Google will share your name, email address, and profile picture with vibn.</p>
</div>
<!-- Loading state (shown after selection) -->
<div class="loading" id="loading">
<div class="spinner"></div>
<div class="loading-text">Signing you in…</div>
</div>
</div>
<div class="footer">
<a href="#">Help</a>
<a href="#">Privacy</a>
<a href="#">Terms</a>
</div>
<script>
function selectAccount(){
// Show loading
document.getElementById('account-select').style.display='none';
document.getElementById('loading').style.display='flex';
// After brief delay, notify parent and close
setTimeout(function(){
if(window.opener){
window.opener.postMessage({type:'google-auth-success',name:'Jane Smith',email:'jane@gmail.com'},'*');
}
window.close();
}, 1000);
}
</script>
</body>
</html>

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vibn — UX screen pack (local)</title>
<link rel="icon" href="favicon_clean.ico">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
background: #f7f4ee;
color: #1a1510;
padding: 48px 24px;
max-width: 42rem;
margin: 0 auto;
line-height: 1.5;
}
h1 { font-size: 1.35rem; margin-bottom: 0.5rem; }
p { color: #5f5e5a; font-size: 0.95rem; margin-bottom: 1.5rem; }
ol { padding-left: 1.25rem; }
li { margin: 0.5rem 0; }
a { color: #1a1510; font-weight: 600; }
a:hover { text-decoration: underline; }
.note { font-size: 0.85rem; color: #888780; margin-top: 2rem; padding-top: 1rem; border-top: 1px solid #e8e2d9; }
</style>
</head>
<body>
<h1>vibn — UX screen pack</h1>
<p>Static HTML prototypes. Suggested flow:</p>
<ol>
<li><a href="01_homepage.html">01 — Homepage</a></li>
<li><a href="02_signup.html">02 — Sign up</a></li>
<li><a href="03_dashboard.html">03 — Dashboard</a></li>
<li><a href="05_describe.html">05 — Describe / discover</a></li>
<li><a href="06_architect.html">06 — Architect</a></li>
</ol>
<p style="margin-top:1.25rem;"><a href="google-auth-popup.html">Google auth popup</a> · <a href="00_design-tokens.css">Design tokens (CSS)</a></p>
<p class="note"><code>vibn-website.jsx</code> and <code>vibn-dashboard.jsx</code> are React source references — use the HTML screens here, or wire those into a React app separately.</p>
</body>
</html>

View File

@@ -1,8 +0,0 @@
{
"folders": [
{
"path": ".."
}
],
"settings": {}
}

1055
justine/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
{
"name": "justine-vibn-ux",
"private": true,
"scripts": {
"dev": "serve -l 3040",
"start": "serve -l 3040"
},
"devDependencies": {
"serve": "^14.2.4"
}
}

View File

@@ -1,26 +0,0 @@
/* vibn Design Tokens — Ink & Parchment */
/* Import this in any HTML file or reference these values */
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
:root {
--ink: #1a1510;
--ink2: #2c2c2a;
--ink3: #444441;
--mid: #5f5e5a;
--muted: #888780;
--stone: #b4b2a9;
--parch: #d3d1c7;
--cream: #f1efe8;
--paper: #f7f4ee;
--white: #fdfcfa;
--border: #e8e2d9;
--serif: 'Lora', Georgia, serif;
--sans: 'Inter', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: var(--sans); background: var(--paper); color: var(--ink); }
.f { font-family: var(--serif); }
.s { font-family: var(--sans); }

View File

@@ -1,335 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>vibn — Homepage</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#444441;--mid:#6B7280;--muted:#9CA3AF;--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#f7f4ee;--white:#FFFFFF;--border:#E5E7EB;--serif:'Plus Jakarta Sans',sans-serif;--sans:'Plus Jakarta Sans',sans-serif;}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFE,#F0EEFF);min-height:100vh;color:var(--ink);}
.f{font-family:var(--serif);}
nav{background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 52px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;}
.nav-links{display:flex;gap:32px;align-items:center;}
.btn-ink{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:8px;padding:9px 22px;font-family:var(--sans);font-size:13.5px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.btn-ink-lg{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:10px;padding:15px 36px;font-family:var(--sans);font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn-ink-lg:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.gradient-em{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;font-style:italic;}
.gradient-text{background:linear-gradient(to right,#6366F1,#8B5CF6);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.gradient-num{background:linear-gradient(135deg,#2E2A5E,#4338CA);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.empathy-card{background:var(--white);border:1px solid var(--border);border-left:3px solid rgba(99,102,241,0.8);border-radius:12px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;box-shadow:0 10px 30px rgba(30,27,75,0.05);transition:border-color 0.2s ease,background 0.2s ease;}
.empathy-card:hover{border-color:#6366F1;background:#FAFAFF;}
/* ── Layout grid classes (for responsive overrides) ── */
.hero-grid{display:grid;grid-template-columns:1fr 1fr;gap:96px;align-items:center;}
.empathy-grid{display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center;}
.phase-grid{display:grid;grid-template-columns:1fr 1fr;border:1px solid rgba(99,102,241,0.2);border-radius:14px;overflow:hidden;}
.wyg-grid{display:grid;grid-template-columns:1fr 1fr 1fr;}
.quote-grid{display:grid;grid-template-columns:1fr 1.6fr 1fr;gap:28px;align-items:center;margin-bottom:20px;}
.stats-grid{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;}
.footer-tagline{display:block;font-size:12px;color:var(--muted);margin-top:4px;font-family:var(--sans);}
/* ── Hamburger ── */
.hamburger{display:none;flex-direction:column;gap:5px;background:none;border:none;cursor:pointer;padding:6px;}
.hamburger span{display:block;width:22px;height:2px;background:var(--ink);border-radius:2px;transition:transform 0.25s ease,opacity 0.25s ease;}
.hamburger.open span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.hamburger.open span:nth-child(2){opacity:0;}
.hamburger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}
/* Mobile drawer */
.mobile-menu{display:none;position:fixed;top:62px;left:0;right:0;background:rgba(250,250,250,0.98);border-bottom:1px solid var(--border);padding:20px 24px 28px;z-index:49;flex-direction:column;gap:0;box-shadow:0 8px 24px rgba(30,27,75,0.08);}
.mobile-menu.open{display:flex;}
.mobile-menu a{font-size:15px;color:var(--ink);text-decoration:none;padding:13px 0;border-bottom:1px solid var(--border);font-weight:500;}
.mobile-menu a:last-of-type{border-bottom:none;}
.mobile-menu .mobile-menu-cta{margin-top:18px;}
/* ── Mobile ── */
@media (max-width:768px){
nav{padding:0 20px;}
.nav-links{display:none;}
.hamburger{display:flex;}
.nav-right-btns{display:none;}
.hero-grid{grid-template-columns:1fr;gap:44px;}
.hero-section{padding:52px 24px 48px !important;}
.empathy-section{padding:56px 24px !important;}
.empathy-grid{grid-template-columns:1fr;gap:36px;}
.how-section{padding:64px 24px !important;}
.phase-grid{grid-template-columns:1fr;}
.phase-grid > div{border-right:none !important;padding:28px 24px !important;}
.wyg-grid{grid-template-columns:1fr;}
.wyg-grid > div{border-right:none !important;border-bottom:1px solid var(--border);padding:32px 24px !important;}
.wyg-grid > div:last-child{border-bottom:none;}
.wyg-section{padding:0 24px !important;}
.quote-grid{grid-template-columns:1fr;}
.quote-side{display:none !important;}
.quote-section{padding:32px 24px 28px !important;}
.stats-grid{grid-template-columns:1fr 1fr;}
.stats-grid > div{padding:28px 16px !important;}
.stats-grid > div:nth-child(odd){padding-left:0 !important;}
.stats-grid > div:nth-child(3),.stats-grid > div:nth-child(4){border-top:1px solid var(--border);}
.stats-grid > div:nth-child(even){border-right:none !important;}
.stats-section{padding:0 24px !important;}
.cta-section{padding:56px 20px !important;}
.cta-card{padding:44px 28px !important;}
.hero-h1{font-size:40px !important;line-height:1.1 !important;}
.hero-sub{font-size:15px !important;}
footer{flex-direction:column;gap:20px;text-align:center;padding:32px 24px !important;}
.footer-links{flex-wrap:wrap;justify-content:center;}
}
</style>
</head>
<body>
<nav>
<div style="display:flex;align-items:center;gap:10px;">
<div class="logo-box" style="width:30px;height:30px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:7px;display:flex;align-items:center;justify-content:center;"><span class="f" style="font-size:15px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:19px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<div class="nav-links">
<a href="#how-it-works" style="font-size:14px;color:var(--muted);text-decoration:none;">How it works</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Stories</a>
<a href="#" style="font-size:14px;color:var(--muted);text-decoration:none;">Blog</a>
</div>
<div class="nav-right-btns" style="display:flex;align-items:center;gap:12px;">
<a href="03_dashboard.html" style="font-size:14px;color:#6366F1;font-weight:600;text-decoration:none;">Log in</a>
<a href="02_signup.html"><button class="btn-ink">Get started free</button></a>
</div>
<button class="hamburger" id="hamburger" aria-label="Open menu" onclick="toggleMenu()">
<span></span><span></span><span></span>
</button>
</nav>
<!-- Mobile drawer -->
<div class="mobile-menu" id="mobile-menu">
<a href="#how-it-works" onclick="closeMenu()">How it works</a>
<a href="#" onclick="closeMenu()">Pricing</a>
<a href="#" onclick="closeMenu()">Stories</a>
<a href="#" onclick="closeMenu()">Blog</a>
<a href="03_dashboard.html" style="color:#6366F1;font-weight:600;" onclick="closeMenu()">Log in</a>
<div class="mobile-menu-cta">
<a href="02_signup.html"><button class="btn-ink-lg" style="width:100%;">Get started free</button></a>
</div>
</div>
<!-- HERO -->
<section class="hero-section" style="max-width:980px;margin:0 auto;padding:88px 52px 72px;">
<div class="hero-grid">
<!-- Left: copy -->
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:22px;">For non-technical founders</div>
<h1 class="f hero-h1" style="font-size:58px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.06;margin-bottom:28px;">
You have the idea.<br>We handle<br><em class="gradient-em">everything else.</em>
</h1>
<p class="hero-sub" style="font-size:17px;color:var(--mid);line-height:1.75;">You describe it. Vibn builds it, launches it, and markets it. From idea to <strong style="color:var(--ink);">live</strong> product in <strong style="color:var(--ink);">72 hours</strong> — no code, no agencies, no waiting.</p>
</div>
<!-- Right: product moment card -->
<div style="flex-shrink:0;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:16px;overflow:hidden;box-shadow:0 20px 60px rgba(30,27,75,0.05);">
<!-- Input area -->
<div style="padding:24px 26px 20px;background:#FCFCFF;border-bottom:1px solid var(--border);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:12px;">Your idea</div>
<p class="f" style="font-size:15px;font-style:italic;color:var(--ink);line-height:1.65;margin-bottom:14px;">"I want to build a booking tool for independent personal trainers."</p>
<div style="display:flex;justify-content:flex-end;">
<span style="font-size:11px;color:var(--muted);background:var(--white);border:1px solid var(--border);border-radius:5px;padding:3px 9px;letter-spacing:0.04em;">↵ Enter</span>
</div>
</div>
<!-- Output area -->
<div style="padding:20px 26px 24px;background:var(--white);">
<div style="font-size:10px;font-weight:600;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">vibn generated</div>
<div style="display:flex;flex-direction:column;gap:0;">
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Pages</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Landing, Dashboard, Booking, Payments</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Stack</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Auth, database, payments — handled</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;border-bottom:1px solid var(--border);">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Revenue</span>
<span style="font-size:13px;color:var(--ink);font-weight:600;">Subscription · $29 / mo</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:10px 0;">
<span style="font-size:12px;color:var(--muted);font-weight:500;">Status</span>
<span style="font-size:13px;font-weight:600;color:#6366F1;">&nbsp; Ready to build</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CTA row -->
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;margin-top:52px;">
<a href="02_signup.html"><button class="btn-ink-lg">Start free — no code needed</button></a>
<div><span style="font-size:13.5px;color:#818CF8;">★★★★★</span><span style="font-size:13.5px;color:var(--stone);">&nbsp;&nbsp;280 founders launched</span></div>
<p style="font-size:12px;color:#9CA3AF;">No credit card required · Free forever plan</p>
<a href="#how-it-works" style="font-size:13.5px;color:#6366F1;text-decoration:none;font-weight:500;margin-top:4px;">See how it works →</a>
</div>
</section>
<!-- EMPATHY -->
<section class="empathy-section" style="border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:80px 52px;">
<div style="max-width:980px;margin:0 auto;">
<div class="empathy-grid">
<div>
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:18px;">Sound familiar?</div>
<h2 class="f" style="font-size:36px;font-weight:700;color:#1A1A1A;line-height:1.18;margin-bottom:24px;letter-spacing:-0.02em;">The idea is the hard part. <span class="gradient-text">Everything else shouldn't be.</span></h2>
<p style="font-size:15px;color:var(--mid);line-height:1.82;margin-bottom:20px;">You know exactly what you want to build and who it's for. But the moment you think about servers, databases, deployment pipelines, SEO — the whole thing stalls.</p>
<p style="font-size:15px;color:var(--mid);line-height:1.82;">vibn exists to remove all of that. Not abstract it — <em class="f" style="font-style:italic;">remove it entirely.</em></p>
</div>
<div style="display:flex;flex-direction:column;gap:14px;">
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I need to hire a developer first"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">vibn is your developer. Start building the moment you have an idea.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more staring at a blank marketing calendar</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">AI generates and publishes your content every single week.</div></div></div>
<div class="empathy-card"><div style="width:20px;height:20px;border-radius:50%;border:1.5px solid rgba(99,102,241,0.4);display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:2px;"><div style="width:7px;height:7px;border-radius:50%;background:#6366F1;"></div></div><div><div class="f" style="font-size:14px;font-weight:600;color:#1A1A1A;margin-bottom:4px;">No more "I'll launch when it's ready"</div><div style="font-size:13px;color:var(--mid);line-height:1.7;">Most founders ship their first version in under 72 hours.</div></div></div>
</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section id="how-it-works" class="how-section" style="max-width:980px;margin:0 auto;padding:84px 52px;">
<div style="font-size:11px;font-weight:600;letter-spacing:0.13em;text-transform:uppercase;color:var(--muted);margin-bottom:16px;">How it works</div>
<h2 class="f" style="font-size:42px;font-weight:700;color:#1A1A1A;letter-spacing:-0.02em;margin-bottom:54px;max-width:480px;line-height:1.15;">Four phases. One <span class="gradient-text">complete</span> product.</h2>
<div class="phase-grid">
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">01 — Discover</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Define your idea</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon.</p></div>
<div style="padding:40px 44px;background:var(--white);border-bottom:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">02 — Design</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Choose your style</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">Pick a visual style and see your exact site and emails live before a single line of code is written.</p></div>
<div style="padding:40px 44px;background:var(--white);border-right:1px solid rgba(99,102,241,0.2);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">03 — Build</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Your app, live</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English.</p></div>
<div style="padding:40px 44px;background:var(--white);"><div style="font-size:11px;font-weight:600;letter-spacing:0.1em;text-transform:uppercase;color:rgba(99,102,241,0.6);margin-bottom:14px;">04 — Grow</div><div class="f" style="font-size:22px;font-weight:700;color:#1A1A1A;margin-bottom:10px;">Market &amp; automate</div><p style="font-size:13.5px;color:var(--mid);line-height:1.72;">AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on users.</p></div>
</div>
</section>
<!-- WHAT YOU GET -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div class="wyg-grid wyg-section" style="max-width:980px;margin:0 auto;padding:0 52px;">
<div style="padding:44px 40px 44px 0;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A live, working product</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Not a prototype. Real auth, real payments, real database — on your own URL from day one.</p>
<p style="font-size:12px;color:var(--muted);line-height:1.6;text-align:center;margin-top:10px;">Runs on your own servers — your data, your infrastructure, no lock-in.</p>
</div>
<div style="padding:44px 40px;border-right:1px solid var(--border);">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A full marketing engine</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Blog posts, onboarding emails, and social content — written and published automatically every week.</p>
</div>
<div style="padding:44px 0 44px 40px;">
<div style="font-size:13px;font-weight:700;color:#6366F1;margin-bottom:12px;text-align:center;"></div>
<div class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;margin-bottom:8px;text-align:center;">A product that evolves</div>
<p style="font-size:13.5px;color:var(--mid);line-height:1.7;text-align:center;">Describe changes in plain English. Vibn handles the code so your product grows as fast as your ideas.</p>
</div>
</div>
</section>
<!-- QUOTE BAND -->
<section class="quote-section" style="background:#1A1A1A;padding:32px 52px 28px;">
<div style="max-width:980px;margin:0 auto;">
<div class="quote-grid">
<!-- Left: supporting quote -->
<div class="quote-side" style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Alex K., founder of Taskly</span>
</div>
</div>
<!-- Center: dominant quote -->
<div style="background:rgba(255,255,255,0.05);border-radius:12px;padding:22px 26px;">
<div style="width:3px;height:16px;background:#6366F1;border-radius:2px;margin-bottom:12px;opacity:0.7;"></div>
<p class="f" style="font-size:16px;color:#FFFFFF;line-height:1.7;font-style:italic;margin-bottom:12px;">"I have zero coding experience. Three weeks in, I have 300 paying users. That's entirely because of vibn."</p>
<span style="font-size:11px;color:var(--muted);font-weight:600;">— Marcus L., founder of Flowmatic</span>
</div>
<!-- Right: supporting quote -->
<div class="quote-side" style="display:flex;gap:14px;opacity:0.85;">
<div style="width:2px;background:#6366F1;border-radius:2px;flex-shrink:0;"></div>
<div>
<p class="f" style="font-size:12.5px;color:#FFFFFF;line-height:1.65;font-style:italic;margin-bottom:8px;">"The marketing autopilot saved me ten hours a week. My blog runs itself. I just focus on product."</p>
<span style="font-size:10.5px;color:var(--muted);font-weight:600;">— Sara R., founder of Nudge</span>
</div>
</div>
</div>
<!-- Pagination dots -->
<div style="display:flex;justify-content:center;gap:7px;">
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
<div style="width:16px;height:5px;border-radius:3px;background:#FFFFFF;"></div>
<div style="width:5px;height:5px;border-radius:50%;background:rgba(255,255,255,0.3);"></div>
</div>
</div>
</section>
<!-- STATS -->
<section style="background:var(--white);border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<div class="stats-grid stats-section" style="max-width:980px;margin:0 auto;padding:0 52px;">
<div style="padding:40px 0;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">280+</div><div style="font-size:13px;color:var(--muted);">founders launched</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">72h</div><div style="font-size:13px;color:var(--muted);">average time to first version</div></div>
<div style="padding:40px 0 40px 36px;border-right:1px solid var(--border);"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">4.9★</div><div style="font-size:13px;color:var(--muted);">average rating</div></div>
<div style="padding:40px 0 40px 36px;"><div class="f gradient-num" style="font-size:40px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">3×</div><div style="font-size:13px;color:var(--muted);">faster than hiring a developer</div></div>
</div>
</section>
<!-- CTA -->
<section class="cta-section" style="padding:80px 52px;text-align:center;">
<div class="cta-card" style="max-width:680px;margin:0 auto;background:#FFFFFF;border-radius:20px;padding:64px 52px;box-shadow:0 0 0 1px rgba(99,102,241,0.15),0 20px 60px rgba(30,27,75,0.08);">
<h2 class="f" style="font-size:48px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;line-height:1.1;margin-bottom:20px;">Your idea deserves to exist.</h2>
<p style="font-size:16px;color:var(--mid);line-height:1.75;margin-bottom:38px;">Thousands of ideas never make it past a spreadsheet. Yours doesn't have to be one of them.</p>
<a href="02_signup.html"><button class="btn-ink-lg" style="margin-bottom:16px;">Build my product — free</button></a>
<div style="font-size:12.5px;color:var(--muted);">Joins 280+ non-technical founders already live</div>
</div>
</section>
<!-- FOOTER -->
<footer style="background:rgba(250,250,250,0.95);border-top:1px solid var(--border);padding:32px 52px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;">
<div>
<span class="f" style="font-size:16px;font-weight:700;color:var(--ink);">vibn</span>
<span class="footer-tagline">The fastest way from idea to product.</span>
</div>
<div class="footer-links" style="display:flex;gap:28px;">
<a href="#how-it-works" style="font-size:13px;color:var(--muted);text-decoration:none;">How it works</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Pricing</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Privacy</a>
<a href="#" style="font-size:13px;color:var(--muted);text-decoration:none;">Terms</a>
</div>
<span style="font-size:12.5px;color:var(--muted);text-align:right;display:block;">© 2026 vibn</span>
</footer>
<script>
function toggleMenu(){
var btn=document.getElementById('hamburger');
var menu=document.getElementById('mobile-menu');
var open=menu.classList.toggle('open');
btn.classList.toggle('open',open);
document.body.style.overflow=open?'hidden':'';
}
function closeMenu(){
document.getElementById('hamburger').classList.remove('open');
document.getElementById('mobile-menu').classList.remove('open');
document.body.style.overflow='';
}
// Close on anchor click (for same-page links like #how-it-works)
document.querySelectorAll('.mobile-menu a[href^="#"]').forEach(function(a){
a.addEventListener('click',closeMenu);
});
</script>
</body>
</html>

View File

@@ -1,329 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>vibn — Sign up</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{
--ink:#1A1A1A;
--mid:#6B7280;
--muted:#9CA3AF;
--border:#E5E7EB;
--white:#FFFFFF;
--soft:#F5F3FF;
--hover:#FAFAFF;
--serif:'Plus Jakarta Sans',sans-serif;
--sans:'Plus Jakarta Sans',sans-serif;
}
body{font-family:var(--sans);background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);min-height:100vh;display:flex;flex-direction:column;color:var(--ink);}
.f{font-family:var(--serif);}
/* Inputs */
input::placeholder{color:var(--muted);}
input{width:100%;border:1px solid var(--border);border-radius:8px;padding:10px 13px;font-family:var(--sans);font-size:14px;color:var(--ink);background:#FAFAFA;outline:none;transition:border-color 0.15s,box-shadow 0.15s;}
input:focus{border-color:#6366F1;box-shadow:0 0 0 3px rgba(99,102,241,0.12);}
input.error{border-color:#F87171;}
/* Primary button */
.btn{width:100%;background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:10px;padding:13px;font-family:var(--sans);font-size:14px;font-weight:600;cursor:pointer;margin-top:4px;box-shadow:0 10px 25px rgba(30,27,75,0.15);transition:box-shadow 0.2s ease,transform 0.2s ease;}
.btn:hover{box-shadow:0 10px 25px rgba(30,27,75,0.15),0 0 0 6px rgba(99,102,241,0.15);transform:translateY(-1px);}
.btn:disabled{opacity:0.4;cursor:default;transform:none;box-shadow:0 10px 25px rgba(30,27,75,0.15);}
/* Mode option cards */
.mode-opt{border:1px solid var(--border);background:transparent;border-radius:10px;padding:16px;cursor:pointer;margin-bottom:10px;display:flex;align-items:center;gap:12px;transition:all 0.15s;}
.mode-opt:hover{border-color:#6366F1;background:var(--hover);}
.mode-opt.selected{border-color:#6366F1;background:var(--hover);box-shadow:0 0 0 3px rgba(99,102,241,0.1);}
/* Password strength */
.strength-bar{display:flex;gap:4px;margin-top:8px;}
.strength-seg{flex:1;height:3px;border-radius:2px;background:var(--border);transition:background 0.2s ease;}
.strength-label{font-size:11px;color:var(--muted);margin-top:5px;min-height:16px;}
/* Password toggle */
.pwd-wrap{position:relative;}
.pwd-wrap input{padding-right:40px;}
.pwd-toggle{position:absolute;right:11px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:var(--muted);padding:4px;display:flex;align-items:center;transition:color 0.15s;}
.pwd-toggle:hover{color:var(--ink);}
/* Google button */
.btn-google{width:100%;background:transparent;border:1px solid var(--border);color:var(--ink);border-radius:10px;padding:11px;font-family:var(--sans);font-size:13.5px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:9px;transition:border-color 0.15s,background 0.15s;}
.btn-google:hover{border-color:#6366F1;background:var(--hover);}
/* Billing notice — animated */
.billing-notice{overflow:hidden;max-height:0;opacity:0;transition:max-height 0.3s ease,opacity 0.25s ease,margin-bottom 0.3s ease;margin-bottom:0;}
.billing-notice.visible{max-height:140px;opacity:1;margin-bottom:20px;}
/* Experience hint */
.mode-hint{text-align:center;font-size:12px;color:var(--muted);margin-top:10px;min-height:18px;transition:opacity 0.2s ease;}
.exp-feedback{overflow:hidden;max-height:0;opacity:0;transition:max-height 0.3s ease,opacity 0.25s ease,margin-bottom 0.3s ease;margin-bottom:0;border-radius:10px;padding:0 16px;}
.exp-feedback.visible{max-height:80px;opacity:1;margin-bottom:4px;padding:13px 16px;}
</style>
</head>
<body>
<nav style="background:rgba(250,250,250,0.95);border-bottom:1px solid var(--border);padding:0 40px;height:62px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:50;">
<div style="display:flex;align-items:center;gap:9px;">
<div style="width:28px;height:28px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:7px;display:flex;align-items:center;justify-content:center;"><span class="f" style="font-size:14px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<span style="font-size:13.5px;color:var(--muted);">Already have an account? <a href="03_dashboard.html" style="color:#6366F1;font-weight:600;text-decoration:none;">Log in</a></span>
</nav>
<div style="flex:1;display:flex;align-items:center;justify-content:center;padding:40px 24px;">
<div style="width:100%;max-width:440px;">
<!-- Step indicator -->
<div id="steps" style="display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:32px;">
<div style="display:flex;align-items:center;gap:6px;" id="s1">
<div id="s1c" style="width:24px;height:24px;border-radius:50%;background:#6366F1;display:flex;align-items:center;justify-content:center;font-size:11px;color:#FFFFFF;font-weight:700;">1</div>
<span style="font-size:12.5px;font-weight:600;color:var(--ink);">Account</span>
</div>
<div style="width:28px;height:1px;background:var(--border);"></div>
<div style="display:flex;align-items:center;gap:6px;opacity:0.35;" id="s2">
<div id="s2c" style="width:24px;height:24px;border-radius:50%;background:var(--border);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted);font-weight:700;">2</div>
<span id="s2l" style="font-size:12.5px;color:var(--muted);">Your experience</span>
</div>
<div style="width:28px;height:1px;background:var(--border);"></div>
<div style="display:flex;align-items:center;gap:6px;opacity:0.35;" id="s3">
<div id="s3c" style="width:24px;height:24px;border-radius:50%;background:var(--border);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--muted);font-weight:700;">3</div>
<span id="s3l" style="font-size:12.5px;color:var(--muted);">Ready</span>
</div>
</div>
<!-- STEP 1 -->
<div id="step1" style="background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<h2 class="f" style="font-size:23px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:6px;">Let's build your first product.</h2>
<p style="font-size:14px;color:var(--muted);margin-bottom:22px;">Free to start · No credit card needed</p>
<!-- Google first -->
<button onclick="openGoogleAuth()" class="btn-google" style="margin-bottom:20px;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
Continue with Google
</button>
<div style="margin-bottom:20px;display:flex;align-items:center;gap:12px;">
<div style="flex:1;height:1px;background:var(--border);"></div>
<span style="font-size:12px;color:var(--muted);">or continue with email</span>
<div style="flex:1;height:1px;background:var(--border);"></div>
</div>
<!-- Email form -->
<div style="display:flex;flex-direction:column;gap:15px;">
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Full name</label>
<input type="text" id="inp-name" placeholder="Jane Smith" oninput="validateStep1()"/>
</div>
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Email</label>
<input type="email" id="inp-email" placeholder="jane@studio.com" oninput="validateStep1()"/>
</div>
<div>
<label style="display:block;font-size:11px;font-weight:600;color:var(--mid);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:6px;">Password</label>
<div class="pwd-wrap">
<input type="password" id="pwd" placeholder="8+ characters" oninput="checkStrength(this.value);validateStep1()"/>
<button type="button" class="pwd-toggle" onclick="togglePwd()" id="pwd-toggle-btn" aria-label="Show password">
<svg id="eye-open" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
<svg id="eye-closed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none;"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"/><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
</button>
</div>
<div class="strength-bar"><div class="strength-seg" id="seg1"></div><div class="strength-seg" id="seg2"></div><div class="strength-seg" id="seg3"></div></div>
<div class="strength-label" id="strength-label"></div>
</div>
<!-- Social proof above button -->
<p style="text-align:center;font-size:12px;color:var(--muted);margin-bottom:-4px;">Joining 280+ founders already building</p>
<button id="step1btn" class="btn" onclick="goStep(2)" disabled>Continue →</button>
<p style="text-align:center;font-size:11.5px;color:var(--muted);margin-top:2px;">By continuing you agree to our <a href="#" style="color:var(--muted);text-decoration:underline;">Terms</a> and <a href="#" style="color:var(--muted);text-decoration:underline;">Privacy Policy</a></p>
</div>
</div>
<!-- STEP 2 -->
<div id="step2" style="display:none;background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<h2 class="f" style="font-size:23px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:6px;">How experienced are you?</h2>
<p style="font-size:14px;color:var(--muted);margin-bottom:24px;">Just so we know who we're building with</p>
<div id="modes">
<div class="mode-opt" onclick="selectExperience('beginner',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">First time</div><div style="font-size:12.5px;color:var(--muted);">I've never shipped a product before</div></div>
</div>
<div class="mode-opt" onclick="selectExperience('some',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Some experience</div><div style="font-size:12.5px;color:var(--muted);">I've built things before</div></div>
</div>
<div class="mode-opt" onclick="selectExperience('experienced',this)">
<div style="width:36px;height:36px;border-radius:9px;background:var(--soft);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;color:#6366F1;"></div>
<div><div class="f" style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Experienced</div><div style="font-size:12.5px;color:var(--muted);">I ship products regularly</div></div>
</div>
</div>
<!-- Contextual feedback — animated -->
<div id="exp-feedback" class="exp-feedback" style="background:var(--soft);border:1px solid rgba(99,102,241,0.2);">
<div id="exp-feedback-text" style="font-size:13px;color:#4338CA;line-height:1.6;"></div>
</div>
<button id="step2btn" class="btn" style="margin-top:20px;" onclick="goStep(3)" disabled>Set up my workspace →</button>
<p class="mode-hint" id="mode-hint">Select an option above to continue</p>
<p style="text-align:center;margin-top:6px;"><a onclick="goStep(1)" style="font-size:13px;color:var(--muted);text-decoration:none;cursor:pointer;">← Back</a></p>
</div>
<!-- STEP 3 -->
<div id="step3" style="display:none;background:var(--white);border:1px solid var(--border);border-radius:16px;padding:32px;box-shadow:0 10px 30px rgba(30,27,75,0.05);">
<div style="display:flex;align-items:center;gap:12px;margin-bottom:6px;">
<div style="width:36px;height:36px;background:var(--soft);border:1px solid rgba(99,102,241,0.25);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;color:#6366F1;"></div>
<h2 class="f" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">You're in. Got an idea?</h2>
</div>
<p id="done-msg" style="font-size:14px;color:var(--muted);line-height:1.7;margin-bottom:20px;padding-left:48px;">Describe it in one sentence and we'll carry it straight into your workspace.</p>
<!-- Seed input -->
<textarea id="seed-idea" placeholder="e.g. A booking tool for independent personal trainers." style="width:100%;border:1px solid var(--border);border-radius:8px;padding:11px 13px;font-family:var(--sans);font-size:14px;color:var(--ink);background:#FAFAFA;outline:none;resize:none;height:88px;line-height:1.6;transition:border-color 0.15s,box-shadow 0.15s;margin-bottom:16px;" onfocus="this.style.borderColor='#6366F1';this.style.boxShadow='0 0 0 3px rgba(99,102,241,0.12)';" onblur="this.style.borderColor='#E5E7EB';this.style.boxShadow='none';"></textarea>
<button id="dash-btn" class="btn" style="margin-top:0;" onclick="openDashboard()">Start building →</button>
<p style="text-align:center;margin-top:14px;">
<a onclick="goToDashboard()" style="font-size:13px;color:var(--muted);text-decoration:none;cursor:pointer;">I'll do this later — take me to the dashboard</a>
</p>
<p style="text-align:center;margin-top:10px;"><a onclick="goStep(2)" style="font-size:12px;color:var(--muted);text-decoration:none;cursor:pointer;opacity:0.6;">← Back</a></p>
</div>
</div>
</div>
<script>
/* Google auth popup */
function openGoogleAuth(){
var w=500,h=600;
var left=(screen.width/2)-(w/2);
var top=(screen.height/2)-(h/2);
window.open('google-auth-popup.html','google-auth','width='+w+',height='+h+',left='+left+',top='+top+',toolbar=no,menubar=no,scrollbars=no');
window.addEventListener('message',function(e){
if(e.data&&e.data.type==='google-auth-success'){
goStep(2);
}
},{once:true});
}
var mode=null;
var EXP_FEEDBACK={
beginner:"We've got you — we'll explain every step clearly, no jargon, no assumptions. You'll have a product live before you know it.",
some:"Great! You know the ropes — let's move fast and make something great.",
experienced:"You know the process. We'll keep things efficient and get straight to the point."
};
var EXP_DONE={
beginner:"Everything is in place. We'll guide you every step of the way.",
some:"Everything is in place. Let's get straight to building.",
experienced:"Everything is in place. Let's move fast."
};
/* Step navigation */
function goStep(n){
[1,2,3].forEach(function(i){
document.getElementById('step'+i).style.display=i===n?'block':'none';
var s=document.getElementById('s'+i);
if(s) s.style.opacity=i<=n?'1':'0.35';
var c=document.getElementById('s'+i+'c');
if(c){
c.style.background=i<n?'#4338CA':i===n?'#6366F1':'#E5E7EB';
c.style.color=i<=n?'#FFFFFF':'#9CA3AF';
c.textContent=i<n?'✓':String(i);
}
});
}
/* Step 1 — form validation */
function validateStep1(){
var name=document.getElementById('inp-name').value.trim();
var email=document.getElementById('inp-email').value.trim();
var pwd=document.getElementById('pwd').value;
var emailOk=/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
var pwdOk=pwd.length>=8;
document.getElementById('step1btn').disabled=!(name.length>0 && emailOk && pwdOk);
}
/* Password show / hide */
function togglePwd(){
var input=document.getElementById('pwd');
var eyeOpen=document.getElementById('eye-open');
var eyeClosed=document.getElementById('eye-closed');
var isHidden=input.type==='password';
input.type=isHidden?'text':'password';
eyeOpen.style.display=isHidden?'none':'block';
eyeClosed.style.display=isHidden?'block':'none';
}
/* Password strength */
function checkStrength(v){
var segs=['seg1','seg2','seg3'];
var labelEl=document.getElementById('strength-label');
if(v.length===0){
segs.forEach(function(id){document.getElementById(id).style.background='#E5E7EB';});
labelEl.textContent='';
return;
}
if(v.length<8){
segs.forEach(function(id){document.getElementById(id).style.background='#E5E7EB';});
document.getElementById('seg1').style.background='#F87171';
labelEl.textContent='Not enough characters — 8 minimum';
labelEl.style.color='#F87171';
return;
}
var score=1;
if(/[A-Z]/.test(v)&&/[0-9]/.test(v)) score++;
if(/[^A-Za-z0-9]/.test(v)||v.length>=12) score++;
var colors=['#E5E7EB','#E5E7EB','#E5E7EB'];
var label='';
if(score===1){colors[0]='#F87171';label='Weak';}
else if(score===2){colors[0]='#FBBF24';colors[1]='#FBBF24';label='Fair';}
else{colors[0]='#4338CA';colors[1]='#6366F1';colors[2]='#818CF8';label='Strong';}
segs.forEach(function(id,i){document.getElementById(id).style.background=colors[i];});
labelEl.textContent=label;
labelEl.style.color=score===1?'#F87171':score===2?'#FBBF24':'#6366F1';
}
/* Step 2 — experience selection */
function selectExperience(level,el){
mode=level;
document.querySelectorAll('.mode-opt').forEach(function(d){d.classList.remove('selected');});
el.classList.add('selected');
// Show contextual feedback
var feedback=document.getElementById('exp-feedback');
var feedbackText=document.getElementById('exp-feedback-text');
feedbackText.textContent=EXP_FEEDBACK[level];
feedback.classList.add('visible');
// Enable button + hide hint
document.getElementById('step2btn').disabled=false;
document.getElementById('mode-hint').style.opacity='0';
document.getElementById('done-msg').textContent=EXP_DONE[level];
}
/* Step 3 — start building (carries seed idea to Describe) */
function openDashboard(){
var btn=document.getElementById('dash-btn');
btn.textContent='Setting up…';
btn.disabled=true;
var idea=(document.getElementById('seed-idea').value||'').trim();
setTimeout(function(){
try {
sessionStorage.setItem('vibn_new_project','1');
if(idea) sessionStorage.setItem('vibn_seed_idea', idea);
} catch(e){}
window.location.href='05_describe.html';
},800);
}
/* Step 3 — skip to dashboard */
function goToDashboard(){
window.location.href='03_dashboard.html';
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,638 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<script>if(localStorage.getItem('vibn-theme')==='dark')document.documentElement.dataset.theme='dark';</script>
<title>vibn — Architect</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{
--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#444441;--mid:#6B7280;--muted:#9CA3AF;
--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#F5F3FF;--white:#FFFFFF;--border:#E5E7EB;
--indigo:#6366F1;--indigo-dark:#4338CA;--indigo-deep:#2E2A5E;
--indigo-soft:rgba(99,102,241,0.08);--indigo-ring:rgba(99,102,241,0.12);
}
body{font-family:'Plus Jakarta Sans',sans-serif;background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);display:flex;flex-direction:column;height:100vh;overflow:hidden;}
.f{font-family:'Plus Jakarta Sans',sans-serif;}
/* ── Dark mode tokens — exact match with design.html ── */
[data-theme="dark"]{--ink:#EEEEFF;--ink2:#B8B8D0;--ink3:#8484A8;--mid:#9898B8;--muted:#c2c2ee;--border:rgba(255,255,255,0.08);
--cream:rgba(108,124,255,0.14);--paper:#0A1120;--white:rgba(255,255,255,0.05);--stone:rgba(255,255,255,0.08);
--parch:rgba(255,255,255,0.06);--section:rgba(108,124,255,0.55);--accent-primary:#6C7CFF;--indigo:#6C7CFF;--indigo-dark:#6C7CFF;
--indigo-deep:#4B42D8;--indigo-soft:rgba(108,124,255,0.14);--indigo-ring:rgba(108,124,255,0.22);--dm-surf-sidebar:rgba(12,18,34,0.72);
--dm-surf-topbar:rgba(12,18,34,0.58);--dm-surf-panel:rgba(12,18,34,0.58);--dm-surf-right:rgba(12,18,34,0.58);
--dm-surf-card:rgba(255,255,255,0.05);--dm-surf-refine:rgba(8,12,22,0.60);--dm-border:rgba(255,255,255,0.08);
--dm-border-strong:rgba(255,255,255,0.14);--dm-border-hero:rgba(255,255,255,0.18);--dm-accent:#6C7CFF;
--dm-accent-fill:rgba(108,124,255,0.14);--dm-accent-fill-mid:rgba(108,124,255,0.20);--dm-accent-border:rgba(108,124,255,0.55);
--dm-text-1:#EEEEFF;--dm-text-2:#B4B4CC;--dm-text-3:#d2d2ef;--dm-shadow-panel:0 4px 36px rgba(0,0,0,0.55);
--dm-shadow-hero:0 20px 70px rgba(0,0,0,0.65),0 6px 24px rgba(0,0,0,0.40),inset 0 1px 0 rgba(255,255,255,0.10);}
[data-theme="dark"] body{background:linear-gradient(to bottom,rgba(108,80,255,0.06) 0%,rgba(60,120,255,0.10) 38%,transparent 62%),linear-gradient(to bottom,rgba(108,124,255,0.10),transparent 180px),radial-gradient(900px 520px at 14% -8%,rgba(108,124,255,0.24),transparent 62%),radial-gradient(760px 420px at 88% 0%,rgba(72,145,255,0.16),transparent 60%),linear-gradient(180deg,#18213B 0%,#101726 48%,#0A1120 100%);}[data-theme="dark"] #mock {background: #fff !important;}
/* Sidebar */
[data-theme="dark"] .sidebar-col{background:var(--dm-surf-sidebar)!important;border-right:1px solid var(--dm-border)!important;box-shadow:2px 0 28px rgba(0,0,0,0.60)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .sidebar-col [style*="border-top:1px solid #e5e7eb"]{border-top-color:var(--dm-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#e5e7eb"]{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#1a1a1a"]{color:var(--dm-text-1)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#6b7280"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#444441"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#9ca3af"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#6366F1"]{background:var(--dm-accent)!important;color:#0F1424!important;}
[data-theme="dark"] .sidebar-phase.active{background:var(--dm-accent-fill)!important;}
[data-theme="dark"] .sidebar-phase:not(.active):hover{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] #sidebar-project-name{color:var(--dm-text-3)!important;}
/*Arch-scroll*/
[data-theme="dark"] .arch-scroll{background:var(--dm-surf-panel)!important;border-right:1px solid var(--dm-border)!important;box-shadow:4px 0 0px rgba(0,0,0,0.55)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
/* Main content */
[data-theme="dark"] .arch-main{background:transparent!important;}
[data-theme="dark"] [style*="background:#f5f3ff"]{background:rgba(108,124,255,0.04)!important;}
[data-theme="dark"] [style*="background:var(--white)"]{background:var(--dm-surf-card)!important;}
[data-theme="dark"] [style*="background:#fafaff"],[data-theme="dark"] [style*="background:#FAFAFA"]{background:rgba(255,255,255,0.03)!important;}
[data-theme="dark"] [style*="background:#f0f4ff"]{background:var(--dm-surf-card)!important;}
[data-theme="dark"] [style*="background:#eef2ff"]{background:var(--dm-accent-fill)!important;}
[data-theme="dark"] [style*="background:#F3F4F6"]{background:rgba(255,255,255,0.05)!important;}
/* Borders */
[data-theme="dark"] [style*="border-bottom:1px solid #c7d2fe"]{border-bottom-color:var(--dm-border)!important;}
[data-theme="dark"] [style*="border:1px solid #e0e7ff"]{border-color:var(--dm-border)!important;}
[data-theme="dark"] [style*="border:1px solid rgba(99,102,241"]{border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] [style*="color:#4338ca"]{color:var(--dm-accent)!important;}
/* Blueprint rows */
[data-theme="dark"] .blueprint-row:hover{background:rgba(108,124,255,0.07)!important;}
[data-theme="dark"] .blueprint-row.locked{background:rgba(255,255,255,0.02)!important;}
[data-theme="dark"] .blueprint-row.locked:hover{background:rgba(255,255,255,0.04)!important;}
/* Option buttons */
[data-theme="dark"] .opt-btns{border-color:var(--dm-border)!important;}
[data-theme="dark"] .opt-btn{color:var(--dm-text-2)!important;border-right-color:var(--dm-border)!important;}
[data-theme="dark"] .opt-btn:hover{background:rgba(108,124,255,0.09)!important;color:var(--dm-accent)!important;}
[data-theme="dark"] .opt-btn.selected{background:var(--dm-accent-fill)!important;color:var(--dm-accent)!important;font-weight:600!important;box-shadow:inset 0 0 0 1px rgba(108,124,255,0.32),0 2px 16px rgba(108,124,255,0.22)!important;}
[data-theme="dark"] .opt-btn.why-btn{color:var(--dm-accent)!important;}
[data-theme="dark"] .why-btn{color:var(--dm-text-3)!important;border-color:var(--dm-border)!important;}
[data-theme="dark"] .why-btn:hover{color:var(--dm-accent)!important;border-color:var(--dm-accent-border)!important;}
/* Right panel / deliverables */
[data-theme="dark"] .arch-right{background:var(--dm-surf-right)!important;border-left:1px solid var(--dm-border)!important;box-shadow:-4px 0 36px rgba(0,0,0,0.55)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .deliverable-row{color:var(--dm-text-3)!important;}
[data-theme="dark"] .deliverable-row:hover{background:rgba(255,255,255,0.04)!important;}
/* Popups & modals */
[data-theme="dark"] #why-popup>div{background:#111828!important;box-shadow:0 0 0 1px rgba(108,124,255,0.50),0 0 0 4px rgba(108,124,255,0.14),0 0 60px rgba(108,124,255,0.28),0 24px 64px rgba(0,0,0,0.72)!important;}
[data-theme="dark"] #save-exit-box{background:#111828!important;box-shadow:0 0 0 1px rgba(108,124,255,0.50),0 0 0 4px rgba(108,124,255,0.14),0 0 60px rgba(108,124,255,0.28),0 24px 64px rgba(0,0,0,0.72)!important;}
[data-theme="dark"] .modal-card{background:#111828!important;box-shadow:0 0 0 1px rgba(108,124,255,0.50),0 0 0 4px rgba(108,124,255,0.14),0 0 60px rgba(108,124,255,0.28),0 24px 64px rgba(0,0,0,0.72)!important;}
[data-theme="dark"] .arch-blueprint-card{box-shadow:0 0 0 1px rgba(108,124,255,0.22),0 2px 24px rgba(108,124,255,0.14),0 0 48px rgba(108,124,255,0.08)!important;}
/* Buttons */
[data-theme="dark"] #dark-toggle{background:rgba(255,255,255,0.05)!important;border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] #dark-toggle:hover{background:rgba(255,255,255,0.10)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover{background:var(--dm-accent-fill-mid)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover span{color:#fff!important;}
[data-theme="dark"] button[onclick="saveAndExit()"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] button[onclick="openWhy()"]{color:var(--dm-accent)!important;}
[data-theme="dark"] .btn-primary{background:linear-gradient(135deg,#4B42D8 0%,#6C7CFF 100%)!important;color:#fff!important;box-shadow:0 4px 22px rgba(108,124,255,0.38),inset 0 1px 0 rgba(255,255,255,0.14)!important;}
[data-theme="dark"] .btn-primary:hover{box-shadow:0 6px 32px rgba(108,124,255,0.50),inset 0 1px 0 rgba(255,255,255,0.18)!important;}
[data-theme="dark"] .vibn-avatar{background:var(--dm-accent)!important;}
[data-theme="dark"] .arch-intro-bubble{box-shadow:0 0 0 1px rgba(108,124,255,0.12),0 2px 18px rgba(108,124,255,0.10),0 0 36px rgba(108,124,255,0.06)!important;}
[data-theme="dark"] .arch-deliverable-card{box-shadow:0 0 0 1px rgba(108,124,255,0.10),0 2px 14px rgba(108,124,255,0.08)!important;}
/* Topbar */
[data-theme="dark"] .arch-topbar{
background: var(--dm-surf-topbar) !important;
border-bottom: 1px solid rgba(255,255,255,0.08) !important;
box-shadow: none !important;
-webkit-backdrop-filter: none !important;
backdrop-filter: none !important;
position: relative;
}
[data-theme="dark"] .arch-topbar::after{
content: none !important;
display: none !important;
}
[data-theme="dark"] .arch-topbar .f{
color: var(--dm-text-1) !important;
}
[data-theme="dark"] .arch-topbar [style*="color:#9ca3af"]{
color: var(--dm-text-3) !important;
}
/* Scrollbar */
[data-theme="dark"] ::-webkit-scrollbar{width:5px;height:5px;}
[data-theme="dark"] ::-webkit-scrollbar-track{background:transparent;}
[data-theme="dark"] ::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.12);border-radius:3px;}
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.22);}
[data-theme="dark"] *{scrollbar-color:rgba(255,255,255,0.12) transparent;scrollbar-width:thin;}
/* Sidebar */
.sidebar-phase{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:8px;}
.sidebar-phase.active{background:#fafaff;}
.phase-dot{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:10px;}
/* Blueprint row */
.blueprint-row{display:grid;grid-template-columns:36px 1fr 248px;align-items:center;gap:16px;padding:15px 22px;border-bottom:1px solid var(--border);transition:background 0.15s;}
.blueprint-row:last-child{border-bottom:none;border-radius:0 0 14px 14px;}
.blueprint-row:hover{background:#FAFAFF;}
.blueprint-row.locked{background:#FAFAFA;}
.blueprint-row.locked:hover{background:#F5F5F5;}
/* Option toggle buttons */
.opt-btns{display:flex;gap:0;flex-shrink:0;border:1.5px solid var(--border);border-radius:8px;overflow:visible;}
.opt-btn{flex:1;text-align:center;font-size:12px;font-weight:500;color:var(--mid);background:transparent;border:none;border-right:1.5px solid var(--border);border-radius:0;padding:6px 13px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all 0.15s;white-space:nowrap;position:relative;}
.opt-btn:first-child{border-radius:7px 0 0 7px;}
.opt-btn:last-child{border-right:none;border-radius:0 7px 7px 0;}
.opt-btn:hover{background:#F5F5FF;color:var(--indigo);}
.opt-btn.selected{background:var(--indigo-soft);color:var(--indigo-dark);font-weight:600;box-shadow:0 2px 10px rgba(99,102,241,0.12);}
/* Intro AI bubble */
.arch-intro-bubble{box-shadow:0 2px 12px rgba(99,102,241,0.08);}
/* Deliverable cards (Pages + Infrastructure) */
.arch-deliverable-card{box-shadow:0 2px 12px rgba(99,102,241,0.08);}
/* Why button (hosting) */
.why-btn{font-size:11.5px;font-weight:600;color:var(--mid);background:transparent;border:1px solid var(--border);border-radius:6px;padding:5px 11px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:border-color 0.15s,color 0.15s;white-space:nowrap;}
.why-btn:hover{border-color:var(--indigo);color:var(--indigo);}
/* Primary button */
.btn-primary{background:linear-gradient(135deg,var(--indigo-deep),var(--indigo-dark));color:#FFFFFF;border:none;border-radius:8px;padding:10px 22px;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 4px 18px rgba(99,102,241,0.22),0 1px 4px rgba(99,102,241,0.12);transition:box-shadow 0.2s,transform 0.2s;}
.btn-primary:hover{box-shadow:0 6px 24px rgba(99,102,241,0.30),0 1px 4px rgba(99,102,241,0.14),0 0 0 6px var(--indigo-ring);transform:translateY(-1px);}
/* What you're getting panel */
.deliverable-row{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:7px;font-size:12px;color:var(--mid);transition:background 0.12s;}
.deliverable-row:hover{background:var(--cream);}
/* Modal */
.modal-bg{display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:100;align-items:center;justify-content:center;}
.modal-bg.open{display:flex;}
.modal-card{background:var(--white);border-radius:16px;width:400px;overflow:hidden;box-shadow:0 24px 64px rgba(30,27,75,0.18);}
/* Option buttons in modal */
.option-btn{display:flex;align-items:center;gap:12px;padding:12px 16px;border-radius:10px;border:1px solid var(--border);background:var(--white);cursor:pointer;text-align:left;margin-bottom:8px;transition:all 0.15s;}
.option-btn:hover{border-color:var(--indigo);background:var(--cream);}
.option-btn.selected{border-color:var(--indigo);background:var(--cream);box-shadow:0 0 0 3px var(--indigo-ring);}
/* Save popup */
#save-exit-popup{display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:700;align-items:center;justify-content:center;padding:24px;}
#save-exit-popup.visible{display:flex;}
#save-exit-box{background:#FFFFFF;border-radius:16px;box-shadow:0 24px 64px rgba(30,27,75,0.18);padding:32px;width:100%;max-width:380px;text-align:center;}
#save-exit-box .save-icon{width:48px;height:48px;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;margin:0 auto 16px;}
#save-exit-box h3{font-size:18px;font-weight:700;color:var(--ink);margin-bottom:8px;}
#save-exit-box p{font-size:13px;color:var(--muted);line-height:1.6;margin-bottom:20px;}
#save-exit-box .save-cancel{font-size:12px;color:var(--muted);cursor:pointer;text-decoration:underline;background:none;border:none;font-family:'Plus Jakarta Sans',sans-serif;}
#save-exit-box .save-cancel:hover{color:var(--ink);}
/* Why accordion */
/* ── Mobile tab bar (hidden on desktop) ── */
.mob-tabs{display:none;flex-shrink:0;background:#EEF0FF;border-top:1px solid #D4D8FA;padding-bottom:env(safe-area-inset-bottom);}
[data-theme="dark"] .mob-tabs{background:rgba(8,12,24,0.90)!important;border-top-color:var(--dm-border)!important;}
.mob-tab-btn{flex:1;padding:11px 8px;border:none;background:transparent;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:500;color:var(--muted);cursor:pointer;border-top:2px solid transparent;transition:color 0.15s,border-color 0.15s;}
.mob-tab-btn.active{color:#6366F1;border-top-color:#6366F1;font-weight:600;}
.mob-dash-btn{background:none;border:none;font-family:'Plus Jakarta Sans',sans-serif;font-size:11.5px;font-weight:500;color:var(--muted);cursor:pointer;padding:11px 12px;white-space:nowrap;flex:none;transition:color 0.15s;}
.mob-dash-btn:hover{color:var(--ink);}
[data-theme="dark"] .mob-tab-btn{color:var(--dm-text-3)!important;}
[data-theme="dark"] .mob-tab-btn.active{color:var(--dm-accent)!important;border-top-color:var(--dm-accent)!important;}
/* ── Responsive ── */
/* Tablet (641px 1024px): top tab bar, full-height panels */
@media (min-width:641px) and (max-width:1024px){
body{height:100dvh;overflow:hidden;}
.arch-layout{flex-direction:column!important;height:100dvh!important;overflow:hidden!important;}
.sidebar-col{display:none!important;}
.mob-tabs{display:flex!important;order:0;border-top:none!important;border-bottom:1px solid #D4D8FA!important;padding-bottom:0!important;}
.mob-tab-btn{border-top:none;border-bottom:2px solid transparent;}
.mob-tab-btn.active{border-top-color:transparent;border-bottom-color:#6366F1;}
[data-theme="dark"] .mob-tab-btn.active{border-bottom-color:var(--dm-accent)!important;border-top-color:transparent!important;}
.arch-main{display:none!important;order:1;overflow:hidden!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-main.tab-active{display:flex!important;}
.arch-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right{display:none!important;order:1;width:100%!important;border-left:none!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-right.tab-active{display:flex!important;}
.arch-right-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right-footer{padding:12px 16px 20px!important;}
.arch-right-footer a{width:80%;display:block;}
.blueprint-row{grid-template-columns:36px 1fr!important;row-gap:10px;padding:13px 18px!important;}
.blueprint-row .opt-btns{grid-column:1 / -1;width:100%;}
}
/* Mobile (≤ 640px): tabbed layout, tabs at bottom */
@media (max-width:640px){
body{height:100dvh;overflow:hidden;}
.arch-layout{flex-direction:column!important;height:100dvh!important;overflow:hidden!important;}
.sidebar-col{display:none!important;}
.mob-tabs{display:flex!important;order:2;}
.arch-main{display:none!important;order:1;overflow:hidden!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-main.tab-active{display:flex!important;}
.arch-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.arch-right{display:none!important;order:1;width:100%!important;border-left:none!important;flex:1 1 0%!important;height:0!important;min-height:0!important;}
.arch-right.tab-active{display:flex!important;}
.arch-right-scroll{flex:1 1 0%!important;height:0!important;min-height:0!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;}
.blueprint-row{grid-template-columns:36px 1fr!important;row-gap:10px;padding:13px 16px!important;}
.blueprint-row .opt-btns{grid-column:1 / -1;width:100%;}
.opt-btn{flex:1;padding:7px 8px!important;font-size:11.5px!important;}
.arch-topbar{padding:14px 16px 12px!important;}
.arch-right-footer{padding:12px 16px 20px!important;}
.arch-right-footer a{width:100%!important;display:block!important;}
.modal-card{width:calc(100vw - 32px)!important;}
#why-popup>div{max-width:calc(100vw - 32px)!important;}
}
/* Mobile with trackpad (laptop narrow): tabs at top */
@media (max-width:640px) and (hover:hover) and (pointer:fine){
.mob-tabs{order:0!important;border-top:none!important;border-bottom:1px solid #D4D8FA!important;padding-bottom:0!important;}
.mob-tab-btn{border-top:none;border-bottom:2px solid transparent;}
.mob-tab-btn.active{border-top-color:transparent;border-bottom-color:#6366F1;}
[data-theme="dark"] .mob-tab-btn.active{border-bottom-color:var(--dm-accent)!important;}
.arch-main{order:1!important;}
.arch-right{order:1!important;}
}
</style>
</head>
<body>
<div class="arch-layout" style="display:flex;height:100%;overflow:hidden;">
<!-- Mobile tab bar (hidden on desktop, shown on ≤ 640px) -->
<div class="mob-tabs" id="mob-tabs">
<button onclick="saveAndExit()" class="mob-dash-btn">Dashboard</button>
<div style="width:1px;background:var(--border);margin:8px 0;flex-shrink:0;"></div>
<button class="mob-tab-btn active" id="tab-blueprint" onclick="switchArchTab('blueprint')">Blueprint</button>
<button class="mob-tab-btn" id="tab-scope" onclick="switchArchTab('scope')">Scope</button>
</div>
<!-- ── SIDEBAR ── -->
<div class="sidebar-col" style="width:200px;background:#ffffff;border-right:1px solid #e5e7eb;display:flex;flex-direction:column;padding:18px 12px;flex-shrink:0;">
<div style="padding:0 6px;margin-bottom:26px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;"><span class="f" style="font-size:13px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:16px;font-weight:700;color:#1a1a1a;letter-spacing:-0.02em;">vibn</span>
</div>
<div id="sidebar-project-name" style="font-size:11px;font-weight:500;color:#9ca3af;padding-left:34px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:none;"></div>
</div>
<div style="font-size:9.5px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:#9ca3af;padding:0 6px;margin-bottom:8px;">MVP Setup</div>
<div style="display:flex;flex-direction:column;gap:2px;flex:1;">
<div class="sidebar-phase" onclick="window.location.href='05_describe.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Describe</div>
</div>
<div class="sidebar-phase active">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);">Architect</div><div style="font-size:10px;color:#9ca3af;">What gets built</div></div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Design</div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Website</div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div style="font-size:12.5px;color:#9ca3af;">Build MVP</div>
</div>
</div>
<div style="border-top:1px solid #e5e7eb;margin-top:14px;padding-top:12px;">
<button onclick="saveAndExit()" style="display:flex;align-items:center;justify-content:center;gap:7px;width:100%;background:#eef2ff;border:1px solid #e0e7ff;border-radius:8px;padding:9px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:background 0.15s;" onmouseover="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#e0e7ff'" onmouseout="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#eef2ff'">
<span style="font-size:12px;font-weight:600;color:#6366F1;">Save & go to dashboard</span>
</button>
<button id="dark-toggle" onclick="toggleTheme()" style="margin-top:8px;display:flex;align-items:center;justify-content:center;width:100%;background:transparent;border:1px solid var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:500;color:var(--mid);transition:background 0.15s,border-color 0.15s;" onmouseover="this.style.borderColor='#6366F1';this.style.color='#6366F1';" onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--mid)';">🌙 Dark mode</button>
</div>
</div>
<!-- ── MAIN ── -->
<div class="arch-main" style="flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;position:relative;z-index:1;">
<!-- Top bar -->
<div class="arch-topbar" style="padding:18px 28px 14px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;flex-shrink:0;">
<div>
<div class="f" style="font-size:17px;font-weight:700;color:var(--ink);margin-bottom:3px;">Your product blueprint</div>
<div style="font-size:12.5px;color:var(--muted);">Weve translated your idea into a complete system — how its built, how it runs, and how users interact with it. Review and confirm to continue</div>
</div>
</div>
<!-- Scrollable body -->
<div class="arch-scroll" style="flex:1;overflow-y:auto;padding:24px 28px;display:flex;flex-direction:column;gap:12px;">
<!-- Intro message -->
<div style="display:flex;align-items:flex-start;gap:10px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px;"><span style="font-size:12px;font-weight:700;color:#FFFFFF;">V</span></div>
<div class="arch-intro-bubble" style="max-width:84%;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:4px 12px 12px 12px;padding:11px 14px;font-size:13px;color:var(--ink);line-height:1.65;">
Here's the technical stack we've set up for <strong id="intro-project-name" style="font-weight:600;">your product</strong>. These are the best defaults for an idea like yours — review each decision below and change anything that doesn't feel right.
</div>
</div>
<!-- Blueprint card -->
<div class="arch-blueprint-card" style="background:var(--white);border:1px solid var(--border);border-radius:14px;overflow:visible;box-shadow:0 4px 20px rgba(30,27,75,0.05);">
<!-- Card header -->
<div style="padding:14px 22px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div style="width:8px;height:8px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>
<span style="font-size:13px;font-weight:600;color:var(--ink);">How vibn will build it</span>
<button onclick="openWhy()" style="margin-left:auto;background:none;border:none;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;color:#6366F1;font-weight:600;padding:0;display:flex;align-items:center;gap:5px;">💡 Why these choices?</button>
</div>
<!-- Frontend -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Frontend</div>
<div style="font-size:11.5px;color:var(--muted);">Where will your users mostly be when they use your product — at a desk, or on the go? This shapes every screen we design.</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="frontend" data-tip="Runs in any browser, desktop & mobile" onclick="selectOpt('frontend',this)">Web app</button>
<button class="opt-btn" data-group="frontend" data-tip="Optimised for phones, still works on desktop" onclick="selectOpt('frontend',this)">Mobile-first</button>
</div>
</div>
<!-- Backend -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Backend & Database</div>
<div style="font-size:11.5px;color:var(--muted);">The invisible part that stores your users' data and makes everything work behind the scenes</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="backend" data-tip="Standard setup, works for almost everything" onclick="selectOpt('backend',this)">API + database</button>
<button class="opt-btn" data-group="backend" data-tip="Live updates between users — great for collaboration" onclick="selectOpt('backend',this)">Real-time</button>
</div>
</div>
<!-- Auth -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Sign up & Login</div>
<div style="font-size:11.5px;color:var(--muted);">How people create an account and get back in — fewer steps means more people actually sign up</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="auth" data-tip="Google & GitHub sign-in — less friction, more sign-ups" onclick="selectOpt('auth',this)">Email + social</button>
<button class="opt-btn" data-group="auth" data-tip="Simpler setup, no third-party login" onclick="selectOpt('auth',this)">Email only</button>
</div>
</div>
<!-- Payments -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);">$</div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Payments</div>
<div style="font-size:11.5px;color:var(--muted);">How you get paid — Stripe handles the card processing so you never touch sensitive data</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="payments" data-tip="Monthly or annual recurring payments" onclick="selectOpt('payments',this)">Subscription</button>
<button class="opt-btn" data-group="payments" data-tip="Pay once, own forever" onclick="selectOpt('payments',this)">One-time</button>
</div>
</div>
<!-- Email -->
<div class="blueprint-row">
<div style="width:32px;height:32px;border-radius:9px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--indigo);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Email</div>
<div style="font-size:11.5px;color:var(--muted);">Automated messages sent to your users — from welcome emails on day one to newsletters later</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="email" data-tip="Welcome emails, resets & marketing newsletters" onclick="selectOpt('email',this)">Full suite</button>
<button class="opt-btn" data-group="email" data-tip="Just transactional emails — resets and confirmations" onclick="selectOpt('email',this)">Essentials only</button>
</div>
</div>
<!-- Hosting — locked -->
<div class="blueprint-row locked">
<div style="width:32px;height:32px;border-radius:9px;background:#F3F4F6;display:flex;align-items:center;justify-content:center;font-size:15px;color:var(--muted);"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Hosting</div>
<div style="font-size:11.5px;color:var(--muted);">Where your product lives — on your own servers, so no one else controls your data or your costs</div>
</div>
<div class="opt-btns">
<button class="opt-btn selected" style="cursor:default;">Your servers 🔒</button>
<button class="opt-btn why-btn" onclick="openHostingWhy()" style="border-radius:0 7px 7px 0;border-right:none;color:#6366F1;font-weight:600;">Why?</button>
</div>
</div>
</div>
<!-- Reassurance note -->
<div style="display:flex;align-items:center;gap:10px;padding:11px 16px;background:#f0f4ff;border:1px solid #e0e7ff;border-radius:10px;">
<span style="font-size:16px;flex-shrink:0;">💬</span>
<p style="font-size:12px;color:var(--mid);line-height:1.55;margin:0;">Not sure about any of these? Don't worry — you can change them anytime before we start building.</p>
</div>
</div>
</div>
<!-- ── RIGHT PANEL ── -->
<div class="arch-right" style="width:384px;border-left:1px solid var(--border);background:#f5f3ff;display:flex;flex-direction:column;flex-shrink:0;">
<!-- Panel header — matches Describe PRD style -->
<div style="flex-shrink:0;padding:18px 0 0;">
<div style="margin:0 16px;padding-bottom:14px;border-bottom:1px solid #c7d2fe;">
<div style="font-size:15px;font-weight:800;letter-spacing:0.04em;text-transform:uppercase;color:#4338ca;margin-bottom:5px;">What your users will be able to do</div>
<div style="font-size:12px;color:#A0A0B8;line-height:1.5;">10 screens covering the full user journey, ready to design.</div>
</div>
</div>
<!-- Scrollable content -->
<div class="arch-right-scroll" style="flex:1;overflow-y:auto;padding:16px;">
<!-- Pages -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Pages</div>
<div class="arch-deliverable-card" style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-bottom:16px;">
<div style="padding:5px 12px;background:#fafaff;border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Public</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Discover your product</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>See your pricing</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Learn about you</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Auth</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Create an account</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Sign back in</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Reset their password</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">App</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Use the dashboard</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Manage their settings</div>
<div style="padding:5px 12px;background:#fafaff;border-top:1px solid var(--border);border-bottom:1px solid var(--border);">
<span style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);">Payments</span>
</div>
<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Subscribe and pay</div>
<div class="deliverable-row" style="border-bottom:none;"><div style="width:5px;height:5px;border-radius:50%;background:#10B981;flex-shrink:0;"></div>Manage their plan</div>
</div>
<!-- Infrastructure -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Infrastructure</div>
<div class="arch-deliverable-card" style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;">
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border);">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🖥</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Your own servers</div><div style="font-size:11px;color:var(--muted);">No platform lock-in, ever</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border);">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🔁</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Auto-deploy via Coolify</div><div style="font-size:11px;color:var(--muted);">Every push goes live instantly</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;">
<div style="width:28px;height:28px;border-radius:7px;background:var(--indigo-soft);display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;">🔒</div>
<div><div style="font-size:12px;font-weight:600;color:var(--ink);">Code stored in Gitea</div><div style="font-size:11px;color:var(--muted);">Private repo, yours alone</div></div>
</div>
</div>
<!-- Timeline / cost signal -->
<div style="display:flex;align-items:center;justify-content:center;gap:16px;padding:10px 0 2px;">
<span style="font-size:11px;color:var(--muted);display:flex;align-items:center;gap:5px;"><span>~34 weeks to build</span></span>
<span style="font-size:11px;color:var(--muted);">·</span>
<span style="font-size:11px;color:var(--muted);display:flex;align-items:center;gap:5px;">💰 <span>No platform fees</span></span>
</div>
</div>
<!-- Footer -->
<div class="arch-right-footer" style="border-top:1px solid var(--border);padding:9px 0 13px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;">
<p style="font-size:11.5px;color:var(--muted);text-align:center;margin:0 0 10px;line-height:1.5;">All set — let's decide how it looks.</p>
<a href="07_design.html" style="text-decoration:none;display:block;width:80%;">
<button class="btn-primary" style="width:100%;padding:12px 14px;border-radius:8px;">Next: Design</button>
</a>
</div>
</div>
</div>
<!-- ── WHY POPUP ── -->
<div id="why-popup" style="display:none;position:fixed;inset:0;background:rgba(15,14,26,0.45);backdrop-filter:blur(2px);z-index:200;align-items:center;justify-content:center;padding:24px;" onclick="closeWhy()">
<div style="background:var(--white);border-radius:16px;width:100%;max-width:480px;box-shadow:0 24px 64px rgba(30,27,75,0.18);padding:32px;" onclick="event.stopPropagation()">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:20px;">
<span style="font-size:20px;">💡</span>
<h3 style="font-size:17px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Why we chose this for your product</h3>
</div>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;">Based on your idea, vibn picked a <strong style="color:var(--ink);font-weight:600;">web app with subscription billing</strong> — the fastest path to recurring revenue for a SaaS product.</p>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink);font-weight:600;">Email + social login</strong> keeps sign-up friction low. Most people won't create a password for something they haven't tried yet — one click with Google removes that barrier.</p>
<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:24px;"><strong style="color:var(--ink);font-weight:600;">Your own hosting</strong> means you own the infrastructure outright. No platform lock-in, no surprise price hikes. Coolify + Gitea are already configured to your account.</p>
<button onclick="closeWhy()" class="btn-primary" style="width:100%;padding:12px;">Got it</button>
</div>
</div>
<!-- ── SAVE POPUP ── -->
<div id="save-exit-popup">
<div id="save-exit-box">
<div class="save-icon"></div>
<h3>Your progress is saved.</h3>
<p>You can come back to this project anytime from your dashboard — everything will be exactly where you left it.</p>
<button onclick="window.location.href='03_dashboard.html'" style="width:100%;background:linear-gradient(135deg,#2e2a5e,#4338ca);color:#fff;border:none;border-radius:10px;padding:12px;font-family:'Plus Jakarta Sans',sans-serif;font-size:14px;font-weight:600;cursor:pointer;margin-bottom:10px;">Got it, go to dashboard</button>
<button class="save-cancel" onclick="cancelSaveExit()">Stay on this page</button>
</div>
</div>
<!-- ── MODAL ── -->
<div id="modal" class="modal-bg" onclick="closeModal()">
<div class="modal-card" onclick="event.stopPropagation()">
<div style="padding:18px 22px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;">
<span id="modal-title" class="f" style="font-size:15px;font-weight:700;color:var(--ink);"></span>
<button onclick="closeModal()" style="background:transparent;border:none;color:var(--muted);cursor:pointer;font-size:18px;line-height:1;">×</button>
</div>
<div style="padding:16px 22px;" id="modal-options"></div>
<div style="padding:10px 22px 18px;">
<button onclick="closeModal()" class="btn-primary" style="width:100%;padding:12px;border-radius:9px;">Got it</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
try {
var name = localStorage.getItem('vibn_project_name') || 'My project';
var el = document.getElementById('sidebar-project-name');
el.textContent = name;
el.style.display = 'block';
var intro = document.getElementById('intro-project-name');
if(intro) intro.textContent = name;
} catch(e){}
// Init Blueprint tab on tablet + mobile
if(window.innerWidth <= 1024){
document.querySelector('.arch-main').classList.add('tab-active');
}
});
function switchArchTab(tab){
var main = document.querySelector('.arch-main');
var right = document.querySelector('.arch-right');
var btnBlueprint = document.getElementById('tab-blueprint');
var btnScope = document.getElementById('tab-scope');
if(tab === 'blueprint'){
main.classList.add('tab-active');
right.classList.remove('tab-active');
btnBlueprint.classList.add('active');
btnScope.classList.remove('active');
} else {
right.classList.add('tab-active');
main.classList.remove('tab-active');
btnScope.classList.add('active');
btnBlueprint.classList.remove('active');
}
}
function saveAndExit(){ document.getElementById('save-exit-popup').classList.add('visible'); }
function cancelSaveExit(){ document.getElementById('save-exit-popup').classList.remove('visible'); }
function openWhy(){ document.getElementById('why-popup').style.display='flex'; }
function closeWhy(){ document.getElementById('why-popup').style.display='none'; }
function selectOpt(group, el){
document.querySelectorAll('[data-group="'+group+'"]').forEach(function(b){ b.classList.remove('selected'); });
el.classList.add('selected');
if (group === 'frontend') {
localStorage.setItem('vibn_frontend', el.getAttribute('data-tip'));
}
}
function openHostingWhy(){
document.getElementById('modal-title').textContent = 'Why your own servers?';
document.getElementById('modal-options').innerHTML =
'<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink)">Most platforms rent you server space</strong> — which means they control your data, your uptime, and your bill. The day they raise prices or shut down, your product goes with it.</p>' +
'<p style="font-size:13px;color:var(--mid);line-height:1.8;margin-bottom:12px;"><strong style="color:var(--ink)">With vibn, your product lives on your own servers.</strong> You own the infrastructure outright. Nobody can lock you out, hike your costs, or access your users\u2019 data without your permission.</p>' +
'<p style="font-size:13px;color:var(--mid);line-height:1.8;">We handle the hard part: <a href="https://coolify.io" target="_blank" style="color:var(--indigo);font-weight:600;text-decoration:none;">Coolify</a> auto-deploys your code every time you push an update, and <a href="https://gitea.com" target="_blank" style="color:var(--indigo);font-weight:600;text-decoration:none;">Gitea</a> stores your codebase securely. You get full control of your infrastructure \u2014 without needing to know how any of it works.</p>';
document.getElementById('modal').classList.add('open');
}
function openModal(title, opt1, desc1, opt2, desc2){
document.getElementById('modal-title').textContent = title;
document.getElementById('modal-options').innerHTML = '<p style="font-size:13px;color:var(--mid);line-height:1.6;">'+desc1+'</p>';
document.getElementById('modal').classList.add('open');
}
function closeModal(){ document.getElementById('modal').classList.remove('open'); }
function showTip(el){
hideTip();
var tip=document.createElement('div');
tip.id='vibn-tip';
tip.textContent=el.dataset.tip;
tip.style.cssText='position:fixed;background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#fff;font-size:11px;font-weight:500;line-height:1.5;padding:6px 10px;border-radius:6px;white-space:nowrap;z-index:9999;pointer-events:none;box-shadow:0 4px 16px rgba(67,56,202,0.35);font-family:Plus Jakarta Sans,sans-serif;transition:opacity 0.1s;';
document.body.appendChild(tip);
var r=el.getBoundingClientRect();
tip.style.left=(r.left+r.width/2-tip.offsetWidth/2)+'px';
tip.style.top=(r.top-tip.offsetHeight-9)+'px';
var arrow=document.createElement('div');
arrow.id='vibn-tip-arrow';
arrow.style.cssText='position:fixed;border:5px solid transparent;border-top-color:#4338CA;z-index:9999;pointer-events:none;';
document.body.appendChild(arrow);
arrow.style.left=(r.left+r.width/2-5)+'px';
arrow.style.top=(r.top-9)+'px';
}
function hideTip(){
var t=document.getElementById('vibn-tip');
var a=document.getElementById('vibn-tip-arrow');
if(t)t.remove();
if(a)a.remove();
}
document.addEventListener('mouseover',function(e){var b=e.target.closest('.opt-btn[data-tip]');if(b)showTip(b);});
document.addEventListener('mouseout',function(e){var b=e.target.closest('.opt-btn[data-tip]');if(b)hideTip();});
function toggleTheme(){const html=document.documentElement;const isDark=html.dataset.theme==='dark';html.dataset.theme=isDark?'':'dark';document.getElementById('dark-toggle').textContent=isDark?'🌙 Dark mode':'☀️ Light mode';localStorage.setItem('vibn-theme',isDark?'':'dark');}
(function(){const saved=localStorage.getItem('vibn-theme');if(saved==='dark'){document.documentElement.dataset.theme='dark';document.addEventListener('DOMContentLoaded',function(){const btn=document.getElementById('dark-toggle');if(btn)btn.textContent='☀️ Light mode';});}})();
</script>
</body></html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,805 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<script>if(localStorage.getItem('vibn-theme')==='dark')document.documentElement.dataset.theme='dark';</script>
<title>vibn — Website</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{--ink:#1a1510;--ink2:#2c2c2a;--ink3:#444441;--mid:#5f5e5a;--muted:#888780;--stone:#b4b2a9;--parch:#d3d1c7;--cream:#f1efe8;--paper:#f7f4ee;--white:#fdfcfa;--border:#e8e2d9; --section: #b8a9e93f;}
/* ── Dark mode tokens — exact match with design.html ── */
[data-theme="dark"]{--ink:#EEEEFF;--ink2:#B8B8D0;--ink3:#8484A8;--mid:#9898B8;--muted:#c2c2ee;--border:rgba(255,255,255,0.08);--cream:rgba(108,124,255,0.14);--paper:#0A1120;--white:rgba(255,255,255,0.05);--stone:rgba(255,255,255,0.08);--parch:rgba(255,255,255,0.06);--section:rgba(108,124,255,0.55);--accent-primary:#6C7CFF;--dm-surf-sidebar:rgba(12,18,34,0.72);--dm-surf-topbar:rgba(12,18,34,0.58);--dm-surf-panel:rgba(12,18,34,0.58);--dm-surf-right:rgba(12,18,34,0.58);--dm-surf-card:rgba(255,255,255,0.05);--dm-surf-refine:rgba(8,12,22,0.60);--dm-border:rgba(255,255,255,0.08);--dm-border-strong:rgba(255,255,255,0.14);--dm-border-hero:rgba(255,255,255,0.18);--dm-accent:#6C7CFF;--dm-accent-fill:rgba(108,124,255,0.14);--dm-accent-fill-mid:rgba(108,124,255,0.20);--dm-accent-border:rgba(108,124,255,0.55);--dm-text-1:#EEEEFF;--dm-text-2:#B4B4CC;--dm-text-3:#d2d2ef;--dm-shadow-panel:0 4px 36px rgba(0,0,0,0.55);--dm-shadow-hero:0 20px 70px rgba(0,0,0,0.65),0 6px 24px rgba(0,0,0,0.40),inset 0 1px 0 rgba(255,255,255,0.10);}
html:not([data-theme="dark"]) .preview-box {background: linear-gradient(to bottom, #FAFAFA, #F5F3FF);}
[data-theme="dark"] body{background:linear-gradient(to bottom,rgba(108,80,255,0.06) 0%,rgba(60,120,255,0.10) 38%,transparent 62%),linear-gradient(to bottom,rgba(108,124,255,0.10),transparent 180px),radial-gradient(900px 520px at 14% -8%,rgba(108,124,255,0.24),transparent 62%),radial-gradient(760px 420px at 88% 0%,rgba(72,145,255,0.16),transparent 60%),linear-gradient(180deg,#18213B 0%,#101726 48%,#0A1120 100%);}
[data-theme="dark"] .sidebar-col{background:var(--dm-surf-sidebar)!important;border-right:1px solid var(--dm-border)!important;box-shadow:2px 0 28px rgba(0,0,0,0.60)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#1a1a1a"],[data-theme="dark"] .sidebar-col [style*="color: #1a1a1a"]{color:var(--dm-text-1)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#6b7280"],[data-theme="dark"] .sidebar-col [style*="color: #6b7280"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="color: #9ca3af"]{color:var(--dm-text-3)!important;}
.ph-name{color:#9ca3af;}
[data-theme="dark"] .ph-name{color:var(--dm-text-3);}
[data-theme="dark"] .sidebar-col [style*="color:#444441"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#6366F1"]{background:var(--dm-accent)!important;color:#0F1424!important;}
[data-theme="dark"] .sidebar-col [style*="background:#e5e7eb"]{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-phase.active{background:var(--dm-accent-fill)!important;}
[data-theme="dark"] .sidebar-phase:not(.active):hover{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#fafaff"]{background:rgba(108,124,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="border:1px solid rgba(99,102,241"]{border-color:var(--dm-border)!important;}
[data-theme="dark"] .sidebar-col [style*="border-top:1px solid #e5e7eb"]{border-top-color:var(--dm-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover{background:var(--dm-accent-fill-mid)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover span{color:#fff!important;}
[data-theme="dark"] button[onclick="saveAndExit()"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] #sidebar-project-name{color:var(--dm-text-3)!important;}
[data-theme="dark"] #dark-toggle{background:rgba(255,255,255,0.05)!important;border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] #dark-toggle:hover{background:rgba(255,255,255,0.10)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] .vibn-avatar{background:var(--dm-accent)!important;}
[data-theme="dark"] .arch-topbar{background:var(--dm-surf-topbar)!important;border-bottom:1px solid rgba(255,255,255,0.04)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .arch-topbar .f{color:var(--dm-text-1)!important;}
[data-theme="dark"] .arch-topbar [style*="color:#9ca3af"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .website-left{background:var(--dm-surf-panel)!important;border-right:1px solid var(--dm-border)!important;box-shadow:4px 0 36px rgba(0,0,0,0.55)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .website-left [style*="color:#9ca3af"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .website-left [style*="background:#f0f0f8"]{background:rgba(108,124,255,0.08)!important;}
[data-theme="dark"] .tab{color:var(--dm-text-3)!important;}
[data-theme="dark"] .tab.on{color:var(--dm-accent)!important;border-bottom-color:var(--dm-accent)!important;}
body{font-family:'Plus Jakarta Sans',sans-serif;background:var(--paper);display:flex;flex-direction:column;height:100vh;overflow:hidden;}
.f{font-family:'Plus Jakarta Sans',sans-serif;}
.sidebar-phase{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:8px;}
.sidebar-phase.active{background:#fafaff;}
.phase-dot{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:10px;}
.tab{padding:11px 22px;border:none;background:transparent;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:13.5px;color:var(--muted);border-bottom:2px solid transparent;}
.tab.on{color:#6366F1;border-bottom-color:#6366F1;font-weight:600;}
input[type=range]{-webkit-appearance:none;width:100%;height:4px;border-radius:2px;background:#c7d2fe;outline:none;cursor:pointer;}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;border-radius:50%;background:#6366F1;cursor:pointer;}
[data-theme="dark"] input[type=range]{background:rgba(255,255,255,0.12);}
[data-theme="dark"] input[type=range]::-webkit-slider-thumb{background:var(--dm-accent);}
.section{display:none;}
.section.active{display:block;}
#sec-style.active{display:flex;}
.ws-btn{border-radius:9px;border:1px solid var(--border);padding:11px 13px;cursor:pointer;text-align:left;margin-bottom:7px;width:100%;transition:all 0.15s;}
.ws-btn.selected{border:2px solid var(--ink);}
.deliverable-row{display:flex;align-items:center;gap:8px;padding:7px 10px;font-size:12px;color:var(--mid);border-bottom:1px solid var(--border);}
.deliverable-row:last-child{border-bottom:none;}
.vpill{border:1.5px solid #e0e7ff;border-radius:20px;padding:4px 11px;font-size:11px;font-weight:500;color:#6b7280;background:#fff;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all 0.15s;white-space:nowrap;}
.vpill:hover{border-color:#6366F1;color:#6366F1;}
.vpill.active{background:#6366F1;border-color:#6366F1;color:#fff;font-weight:600;box-shadow:0 2px 10px rgba(99,102,241,0.12);}
.tchip{border:1.5px solid #e0e7ff;border-radius:20px;padding:4px 12px;font-size:11.5px;font-weight:500;color:#6b7280;background:#fff;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all 0.15s;}
.tchip:hover{border-color:#6366F1;color:#6366F1;}
.tchip.active{background:#6366F1;border-color:#6366F1;color:#fff;font-weight:600;box-shadow:0 1px 6px rgba(99,102,241,0.10);}
.scard{border:2px solid #e0e7ff;border-radius:8px;cursor:pointer;text-align:left;background:#fff;overflow:hidden;transition:all 0.15s;padding:0;}
.scard:hover{border-color:#a5b4fc;}
.scard.selected{border-color:#6366F1;box-shadow:0 0 0 3px rgba(99,102,241,0.1),0 2px 10px rgba(99,102,241,0.12);}
.ws-rp-card{box-shadow:0 2px 12px rgba(99,102,241,0.08);}
.next-btn{width:100%;background:linear-gradient(135deg,#4338CA,#6366F1);color:#FFFFFF;border:none;border-radius:8px;padding:12px 14px;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 4px 18px rgba(99,102,241,0.22),0 1px 4px rgba(99,102,241,0.12);transition:box-shadow 0.2s;}
.scard-name{font-size:11px;font-weight:700;color:#1a1a1a;}
.scard-desc{font-size:9.5px;color:#6b7280;margin-top:1px;}
[data-theme="dark"] .vpill{background:var(--dm-surf-card)!important;border-color:var(--dm-border)!important;color:#fff)!important;}
[data-theme="dark"] .vpill:hover{border-color:rgba(108,124,255,0.45)!important;color:var(--dm-text-2)!important;}
[data-theme="dark"] .vpill.active{background:var(--dm-accent)!important;border-color:var(--dm-accent)!important;color:#fff!important;}
[data-theme="dark"] .tchip{background:var(--dm-surf-card)!important;border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] .tchip.active{background:var(--dm-accent)!important;border-color:var(--dm-accent)!important;color:#fff!important;}
[data-theme="dark"] .scard{background:var(--dm-surf-card)!important;border-color:var(--dm-border)!important;}
[data-theme="dark"] .scard:hover{border-color:var(--dm-border-strong)!important;}
[data-theme="dark"] .scard.selected{border-color:var(--dm-accent)!important;box-shadow:0 0 0 2px rgba(108,124,255,0.22)!important;}
[data-theme="dark"] .scard-name{color:var(--dm-text-1)!important;}
[data-theme="dark"] .scard-desc{color:var(--dm-text-3)!important;}
[data-theme="dark"] .main-content-area{background:transparent!important;}
[data-theme="dark"] .main-content-area [style*="background:#f0f0f8"],[data-theme="dark"] .main-content-area [style*="background:#f8f9ff"]{background:rgba(255,255,255,0.03)!important;}
@keyframes pulse-dot{0%,100%{opacity:1}50%{opacity:0.35}}
.opt-btns{display:flex;gap:0;flex-shrink:0;border:1.5px solid var(--border);border-radius:8px;overflow:visible;}
.opt-btn{flex:1;text-align:center;font-size:12px;font-weight:500;color:var(--mid);background:transparent;border:none;border-right:1.5px solid var(--border);border-radius:0;padding:6px 13px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:all 0.15s;white-space:nowrap;position:relative;}
.opt-btn:first-child{border-radius:7px 0 0 7px;}
.opt-btn:last-child{border-right:none;border-radius:0 7px 7px 0;}
.opt-btn:hover{background:#f5f5ff;color:#6366F1;}
.opt-btn.selected{background:rgba(99,102,241,0.08);color:#4338CA;font-weight:600;}
[data-theme="dark"] .opt-btns{border-color:var(--dm-border)!important;}
[data-theme="dark"] .opt-btn{color:var(--dm-text-2)!important;border-right-color:var(--dm-border)!important;}
[data-theme="dark"] .opt-btn:hover{background:rgba(108,124,255,0.09)!important;color:var(--dm-accent)!important;}
[data-theme="dark"] .opt-btn.selected{background:var(--dm-accent-fill)!important;color:var(--dm-accent)!important;font-weight:600!important;box-shadow:inset 0 0 0 1px rgba(108,124,255,0.32),0 2px 16px rgba(108,124,255,0.22)!important;}
[data-theme="dark"] .website-right{background:var(--dm-surf-right)!important;border-left:1px solid var(--dm-border)!important;box-shadow:-4px 0 36px rgba(0,0,0,0.55)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .website-right [style*="border-bottom:1px solid #c7d2fe"]{border-bottom-color:var(--dm-border)!important;}
[data-theme="dark"] .website-right [style*="color:#4338ca"]{color:var(--dm-accent)!important;}
[data-theme="dark"] .website-right [style*="background:#eef2ff"]{background:var(--dm-accent-fill)!important;color:var(--dm-accent)!important;}
.sec-div{height:1px;background: var(--section);}
[data-theme="dark"] .website-left .sec-div{background:rgba(108,124,255,0.20)!important;}
.surprise-btn{width:100%;padding:10px;border:1.5px solid #e0e7ff;border-radius:9px;background:#6366F1;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:600;color:#ffffff;cursor:pointer;transition:all 0.15s;text-align:center;display:block;box-shadow:0 2px 14px rgba(99,102,241,0.22);}
.surprise-btn:hover{background:#5045c8;border-color:#c7d2fe;}
[data-theme="dark"] .preview-box{background:rgba(6,10,20,0.32)!important;}
[data-theme="dark"] .preview-chrome-box{border:1.5px solid var(--dm-border-hero)!important;box-shadow:var(--dm-shadow-hero),0 0 0 1px rgba(108,124,255,0.08)!important;}
[data-theme="dark"] [style*="background:#eef2ff;border-radius:11px"]{background:var(--dm-surf-topbar)!important;border-color:var(--dm-border)!important;}
[data-theme="dark"] span[style*="color:#6366F1;background:#eef2ff"]{color:var(--dm-accent)!important;background:var(--dm-accent-fill)!important;}
[data-theme="dark"] [style*="color:#6366F1"][style*="text-transform:uppercase"]{color:var(--dm-accent)!important;}
[data-theme="dark"] .surprise-btn{background:linear-gradient(135deg,#5450CC,var(--dm-accent))!important;border-color:rgba(108,124,255,0.35)!important;color:#fff!important;box-shadow:0 4px 18px rgba(108,124,255,0.22)!important;}
[data-theme="dark"] .surprise-btn:hover{background:linear-gradient(135deg,#4840BE,#6070F8)!important;box-shadow:0 6px 26px rgba(108,124,255,0.30)!important;}
[data-theme="dark"] ::-webkit-scrollbar{width:5px;height:5px;}
[data-theme="dark"] ::-webkit-scrollbar-track{background:transparent;}
[data-theme="dark"] ::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.12);border-radius:3px;}
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.22);}
[data-theme="dark"] *{scrollbar-color:rgba(255,255,255,0.12) transparent;scrollbar-width:thin;}
</style>
</head>
<body>
<div style="display:flex;height:100%;overflow:hidden;">
<!-- SIDEBAR -->
<div class="sidebar-col" style="width:200px;background:#ffffff;border-right:1px solid #e5e7eb;display:flex;flex-direction:column;padding:18px 12px;flex-shrink:0;">
<div style="padding:0 6px;margin-bottom:26px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;"><span class="f" style="font-size:13px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:16px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">vibn</span>
</div>
<div id="sidebar-project-name" style="font-size:11px;font-weight:500;color:#9ca3af;padding-left:34px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:none;"></div>
</div>
<div class="ph-name" style="font-size:9.5px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;padding:0 6px;margin-bottom:8px;">MVP Setup</div>
<div style="display:flex;flex-direction:column;gap:2px;flex:1;">
<div class="sidebar-phase" onclick="window.location.href='05_describe.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div class="ph-name" style="font-size:12.5px;">Describe</div>
</div>
<div class="sidebar-phase" onclick="window.location.href='06_architect.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div class="ph-name" style="font-size:12.5px;">Architect</div>
</div>
<div class="sidebar-phase" onclick="window.location.href='07_design.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div class="ph-name" style="font-size:12.5px;">Design</div>
</div>
<div class="sidebar-phase active">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);">Website</div><div class="ph-name" style="font-size:10px;">How you'll grow</div></div>
</div>
<div class="sidebar-phase">
<div class="phase-dot" style="background:#e5e7eb;color:#9ca3af;"></div>
<div class="ph-name" style="font-size:12.5px;">Build MVP</div>
</div>
</div>
<div style="border-top:1px solid #e5e7eb;margin-top:14px;padding-top:12px;">
<button onclick="saveAndExit()" style="display:flex;align-items:center;justify-content:center;gap:7px;width:100%;background:#eef2ff;border:1px solid #e0e7ff;border-radius:8px;padding:9px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:background 0.15s;" onmouseover="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#e0e7ff'" onmouseout="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#eef2ff'">
<span style="font-size:12px;font-weight:600;color:#6366F1;">Save & go to dashboard</span>
</button>
<button id="dark-toggle" onclick="toggleTheme()" style="margin-top:8px;display:flex;align-items:center;justify-content:center;width:100%;background:transparent;border:1px solid var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:500;color:var(--mid);transition:background 0.15s,border-color 0.15s;" onmouseover="this.style.borderColor='#6366F1';this.style.color='#6366F1';" onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--mid)';">🌙 Dark mode</button>
</div>
</div>
<!-- MAIN -->
<!-- TOP BAR -->
<div style="flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;">
<div class="arch-topbar" style="padding:18px 28px 14px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;flex-shrink:0;">
<div>
<div class="f" style="font-size:17px;font-weight:700;color:var(--ink);margin-bottom:3px;">Website</div>
<div style="font-size:12.5px;color:#9ca3af;">This is what people see before signing up. Set your voice, topics, and website style</div>
</div>
</div>
<div class="main-content-area" style="flex:1;overflow:hidden;display:flex;background:#f8f9ff;">
<!-- LEFT: Controls — single panel, no individual cards -->
<div class="website-left" style="width:272px;border-right:1px solid #e0e7ff;overflow-y:auto;padding:0;display:flex;flex-direction:column;flex-shrink:0;background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);">
<!-- Voice section -->
<div style="padding:16px 16px 14px;">
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.09em;text-transform:uppercase;color:#6366F1;margin-bottom:12px;">Voice</div>
<div style="margin-bottom:10px;">
<div style="font-size:10.5px;color:#9ca3af;margin-bottom:5px;">Tone</div>
<div style="display:flex;gap:5px;" id="pills-tone">
<button class="vpill active" onclick="setPill(this,'tone',0)">Friendly</button>
<button class="vpill" onclick="setPill(this,'tone',50)">Balanced</button>
<button class="vpill" onclick="setPill(this,'tone',100)">Professional</button>
</div>
</div>
<div style="margin-bottom:10px;">
<div style="font-size:10.5px;color:#9ca3af;margin-bottom:5px;">Style</div>
<div style="display:flex;gap:5px;" id="pills-style">
<button class="vpill" onclick="setPill(this,'style',0)">Casual</button>
<button class="vpill active" onclick="setPill(this,'style',50)">Balanced</button>
<button class="vpill" onclick="setPill(this,'style',100)">Precise</button>
</div>
</div>
<div>
<div style="font-size:10.5px;color:#9ca3af;margin-bottom:5px;">Personality</div>
<div style="display:flex;gap:5px;" id="pills-pers">
<button class="vpill active" onclick="setPill(this,'pers',0)">Warm</button>
<button class="vpill" onclick="setPill(this,'pers',50)">Steady</button>
<button class="vpill" onclick="setPill(this,'pers',100)">Direct</button>
</div>
</div>
</div>
<div class="sec-div" style="height:1px;background: var(--section);margin:0 16px;"></div>
<!-- Topics section -->
<div style="padding:14px 16px;">
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.09em;text-transform:uppercase;color:#6366F1;margin-bottom:10px;">Topics</div>
<div style="display:flex;flex-wrap:wrap;gap:6px;">
<button class="tchip active" onclick="toggleTopic(this,'problem')">The problem</button>
<button class="tchip active" onclick="toggleTopic(this,'audience')">Who it's for</button>
<button class="tchip active" onclick="toggleTopic(this,'timing')">Why now</button>
<button class="tchip" onclick="toggleTopic(this,'benefits')">Key benefits</button>
<button class="tchip" onclick="toggleTopic(this,'comparison')">vs. alternatives</button>
</div>
</div>
<div class="sec-div" style="height:1px;background: var(--section);margin:0 16px;"></div>
<!-- Style section -->
<div style="padding:14px 16px;">
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.09em;text-transform:uppercase;color:#6366F1;margin-bottom:10px;">Website style</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:7px;">
<button class="scard selected" id="sc-editorial" onclick="setStyle('editorial','#ffffff','#ef4444','Editorial','Bold headlines, strong opinions')">
<div style="height:28px;background:#fff;border-radius:5px 5px 0 0;padding:5px 8px;display:flex;flex-direction:column;gap:3px;border:1px solid rgba(0,0,0,0.07);border-bottom:none;">
<div style="width:50%;height:3px;border-radius:2px;background:#111;"></div>
<div style="width:26%;height:6px;border-radius:3px;background:#ef4444;"></div>
</div>
<div style="padding:4px 8px 6px;"><div class="scard-name">Editorial</div><div class="scard-desc" style="color:#ef4444;">Bold & opinionated</div></div>
</button>
<button class="scard" id="sc-startup" onclick="setStyle('startup','#f8fafc','#0ea5e9','Startup energy','Clear, conversion-focused')">
<div style="height:28px;background:#f8fafc;border-radius:5px 5px 0 0;padding:5px 8px;display:flex;flex-direction:column;gap:3px;border:1px solid rgba(0,0,0,0.05);border-bottom:none;">
<div style="width:50%;height:3px;border-radius:2px;background:#0f172a;opacity:0.65;"></div>
<div style="width:26%;height:6px;border-radius:3px;background:#0ea5e9;"></div>
</div>
<div style="padding:4px 8px 6px;"><div class="scard-name">Startup</div><div class="scard-desc" style="color:#0ea5e9;">Clean & focused</div></div>
</button>
<button class="scard" id="sc-minimal" onclick="setStyle('minimal','#ffffff','#111111','Ultra minimal','Let the product speak')">
<div style="height:28px;background:#fff;border-radius:6px 6px 0 0;padding:5px 8px;display:flex;flex-direction:column;gap:3px;border:1px solid rgba(0,0,0,0.06);border-bottom:none;">
<div style="width:50%;height:3px;border-radius:2px;background:#111;opacity:0.75;"></div>
<div style="width:26%;height:6px;border-radius:3px;background:#111;"></div>
</div>
<div style="padding:4px 8px 6px;"><div class="scard-name">Minimal</div><div class="scard-desc" style="color:#6b6b6b;">Less is more</div></div>
</button>
<button class="scard" id="sc-soft" onclick="setStyle('soft','#FAFCFA','#7FA58A','Soft UI','Smooth, friendly, and polished')">
<div style="height:28px;background:#FAFCFA;border-radius:5px 5px 0 0;padding:5px 8px;display:flex;flex-direction:column;gap:3px;border:1px solid rgba(0,0,0,0.06);border-bottom:none;">
<div style="width:50%;height:3px;border-radius:2px;background:#1f2937;opacity:0.45;"></div>
<div style="width:26%;height:6px;border-radius:3px;background:#7FA58A;"></div>
</div>
<div style="padding:4px 8px 6px;">
<div class="scard-name">Soft UI</div>
<div class="scard-desc" style="color:#6B8A78;">Smooth & approachable</div>
</div>
</button>
</div>
</div>
<!-- AI decide — flush to bottom -->
<div style="margin-top:auto;padding:14px 16px 18px;">
<div class="sec-div" style="margin:0 0 14px;"></div>
<button class="surprise-btn" onclick="aiDecide()">✨ Surprise me</button>
</div>
</div>
<!-- RIGHT: Preview — fills all available space -->
<div class = "preview-box"style="flex:1;display:flex;flex-direction:column;overflow:hidden;padding:4px 6px 6px;min-width:0;">
<!-- Label + device toggle -->
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:5px;padding:0 2px;">
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:#9ca3af;display:flex;align-items:center;gap:7px;">
<span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;animation:pulse-dot 2s infinite;"></span>
Live preview
</div>
<div class="opt-btns">
<button class="opt-btn selected" data-group="device" data-tip="Runs in any browser, desktop & mobile" onclick="setDevice(this)">Web app</button>
<button class="opt-btn" data-group="device" data-tip="Optimised for phones, still works on desktop" onclick="setDevice(this)">Mobile-first</button>
</div>
</div>
<!-- Browser chrome -->
<div class="preview-chrome-box" style="flex:1;border-radius:12px;overflow:hidden;border:1.5px solid #e0e7ff;box-shadow:0 4px 24px rgba(99,102,241,0.08);display:flex;flex-direction:column;min-height:0;">
<div style="background:#f5f3ff;padding:7px 12px;display:flex;align-items:center;gap:8px;border-bottom:1px solid #e0e7ff;flex-shrink:0;">
<div style="display:flex;gap:4px;"><div style="width:7px;height:7px;border-radius:50%;background:#c7d2fe;"></div><div style="width:7px;height:7px;border-radius:50%;background:#c7d2fe;"></div><div style="width:7px;height:7px;border-radius:50%;background:#c7d2fe;"></div></div>
<div style="flex:1;background:#fff;border:1px solid #e0e7ff;border-radius:4px;padding:2px 9px;font-family:monospace;font-size:10px;color:#6366F1;">yourproduct.com</div>
</div>
<div id="preview-scroll" style="flex:1;overflow-y:auto;transition:background 0.3s;">
<div id="live-preview"></div>
</div>
</div>
</div>
<!-- Hidden: copy IDs kept for JS compatibility -->
<div style="display:none;">
<div id="copy-headline"></div>
<div id="copy-sub"></div>
<div id="copy-cta"></div>
<div id="copy-bullets"></div>
</div>
</div>
</div>
<!-- RIGHT PANEL -->
<div class="website-right" style="width:384px;border-left:1px solid var(--border);background:#f5f3ff;display:flex;flex-direction:column;flex-shrink:0;">
<div style="flex-shrink:0;padding:18px 0 0;">
<div style="margin:0 16px;padding-bottom:14px;border-bottom:1px solid #c7d2fe;">
<div style="font-size:15px;font-weight:800;letter-spacing:0.04em;text-transform:uppercase;color:#4338ca;margin-bottom:5px;">Your brand at a glance</div>
<div style="font-size:12px;color:#A0A0B8;line-height:1.5;">A summary of how your brand will look and sound to the world.</div>
</div>
</div>
<div style="flex:1;overflow-y:auto;padding:16px;">
<!-- 1. Your brand voice -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Your brand voice</div>
<div class="ws-rp-card" id="rp-voice-sentence" style="background:var(--white);border:1px solid var(--border);border-radius:10px;padding:11px 13px;margin-bottom:16px;font-size:12.5px;color:var(--ink);line-height:1.55;"></div>
<!-- 2. Website experience -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Website experience</div>
<div class="ws-rp-card" id="rp-experience" style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-bottom:16px;"></div>
<!-- 3. How users will perceive it -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">How users will perceive it</div>
<div class="ws-rp-card" id="rp-perception" style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-bottom:16px;"></div>
<!-- 4. Optimized for -->
<div style="font-size:9.5px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);margin-bottom:8px;">Optimized for</div>
<div class="ws-rp-card" id="rp-topics-list" style="background:var(--white);border:1px solid var(--border);border-radius:10px;overflow:hidden;margin-bottom:16px;"></div>
<!-- Hidden: kept for JS compat -->
<span id="rp-tone" style="display:none;">Friendly</span>
<span id="rp-style" style="display:none;">Balanced</span>
<span id="rp-pers" style="display:none;">Warm</span>
<span id="rp-ws-name" style="display:none;">Editorial</span>
<span id="rp-ws-desc" style="display:none;">Bold headlines, strong opinions</span>
</div>
<div style="border-top:1px solid var(--border);padding:9px 0 13px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;">
<p style="font-size:11.5px;color:var(--muted);text-align:center;margin:0 0 10px;line-height:1.5;">All set — let's build it.</p>
<a href="09_build.html" style="text-decoration:none;display:block;width:80%;"><button class="next-btn">Next : Build my product</button></a>
</div>
</div>
</div>
<script>
/* ── State ── */
var VOICE = {tone:'Friendly', style:'Balanced', pers:'Warm'};
var TOPICS = {problem:true, audience:true, timing:true, benefits:false, comparison:false};
var STYLE = {id:'editorial', bg:'#ffffff', accent:'#ef4444', label:'Editorial', desc:'Bold headlines, strong opinions'};
var DEVICE = 'desktop';
var PILL_LABELS = {
tone: {0:'Friendly', 50:'Balanced', 100:'Professional'},
style: {0:'Casual', 50:'Balanced', 100:'Precise'},
pers: {0:'Warm', 50:'Steady', 100:'Direct'}
};
var COPY_MATRIX = {
/* Friendly ─────────────────────────────────────────────────────────────── */
'Friendly-Casual-Warm': {h:'Build something people actually love', s:"We make it super easy to go from idea to product — no stress, just results. You'll wonder why you waited.", cta:"Let's build together"},
'Friendly-Casual-Steady': {h:'From idea to launch, one step at a time', s:"We walk with you every step — from your first spark to your first 1,000 users. No rush, just progress.", cta:'Start your journey'},
'Friendly-Casual-Direct': {h:'Stop waiting. Start building.', s:"Your idea is good. Let's make it real — it's way simpler than you think.", cta:'Get started now'},
'Friendly-Balanced-Warm': {h:'Your idea deserves to exist', s:'A thoughtful platform for founders who want to move fast without cutting corners.', cta:'Build something real'},
'Friendly-Balanced-Steady': {h:'Build, launch, and grow — all in one place', s:'Everything you need to turn a product idea into a growing business.', cta:'Start building'},
'Friendly-Balanced-Direct': {h:'From zero to product in days', s:'The fastest path from idea to market — no fluff, no wasted time.', cta:'Launch your product'},
'Friendly-Precise-Warm': {h:'From rough idea to live product in 5 clear steps', s:'A guided, step-by-step process that covers every decision — from architecture to your first customer — with care.', cta:'See how it works'},
'Friendly-Precise-Steady': {h:'A proven 5-step path to your first 1,000 users', s:'Our structured process covers architecture, design, copy, and launch — every stage defined, nothing left to chance.', cta:'Follow the process'},
'Friendly-Precise-Direct': {h:"Ship in days. Here's exactly how.", s:'5 defined steps. One platform. From idea to production-ready product — zero guesswork, zero wasted time.', cta:'Start now'},
/* Balanced ─────────────────────────────────────────────────────────────── */
'Balanced-Casual-Warm': {h:'Turn your idea into something real', s:"We're here to help you build the thing you've been thinking about — no overthinking required.", cta:'Build something real'},
'Balanced-Casual-Steady': {h:'Build it. Ship it. Grow it.', s:'We take the guesswork out of building a product. Just follow the process and watch it come together.', cta:'Start building'},
'Balanced-Casual-Direct': {h:'Idea to product. Fast.', s:'Stop planning, start shipping. We give you everything you need to move fast and get to market.', cta:'Get moving'},
'Balanced-Balanced-Warm': {h:'Your idea deserves to exist', s:'A thoughtful platform for founders who want to move fast without cutting corners.', cta:'Build something real'},
'Balanced-Balanced-Steady': {h:'Build, launch, and grow — all in one place', s:'Everything you need to turn a product idea into a growing business.', cta:'Start building'},
'Balanced-Balanced-Direct': {h:'From zero to product in days', s:'The fastest path from idea to market. No fluff, no wasted time.', cta:'Launch your product'},
'Balanced-Precise-Warm': {h:'From concept to customers in one structured flow', s:'Our platform guides you through every decision — from architecture to launch copy — with precision and care.', cta:'Explore the workflow'},
'Balanced-Precise-Steady': {h:'A structured path from idea to market', s:'Every step is defined, every deliverable is clear. Move confidently from concept to launch.', cta:'See the process'},
'Balanced-Precise-Direct': {h:'Zero to launched in 5 defined steps', s:'Architecture, design, copy, and deployment — all mapped upfront. No surprises, no wasted cycles.', cta:'Start now'},
/* Professional ─────────────────────────────────────────────────────────── */
'Professional-Casual-Warm': {h:'Sophisticated tools for ambitious builders', s:'We combine enterprise-grade infrastructure with a process that feels surprisingly human and approachable.', cta:'Explore the platform'},
'Professional-Casual-Steady': {h:'The reliable way to go from idea to product', s:'A proven approach that serious founders use to ship faster — without the complexity or the headaches.', cta:'Get started'},
'Professional-Casual-Direct': {h:'Build fast. Ship confident.', s:'Skip the setup headaches. We handle the complexity so you can focus on what actually matters — shipping.', cta:'Start now'},
'Professional-Balanced-Warm': {h:'Enterprise-grade tools, founder-friendly experience',s:'Sophisticated infrastructure wrapped in an experience designed for ambitious builders.', cta:'Explore the platform'},
'Professional-Balanced-Steady': {h:'The reliable path from idea to market', s:'A structured, proven approach to building and launching software products at speed.', cta:'Get started'},
'Professional-Balanced-Direct': {h:'Build fast. Ship confident.', s:'Production-ready infrastructure and AI-assisted development. Ship in days, not months.', cta:'Start now'},
'Professional-Precise-Warm': {h:'Production-grade infrastructure with a human touch',s:'From scalable architecture to conversion-optimised copy — every component built to specification, every decision explained.',cta:'Review the specs'},
'Professional-Precise-Steady': {h:'A methodical approach to product development at speed',s:'Defined workflows, documented architecture, and measurable milestones — from initial concept through to market launch.',cta:'See the methodology'},
'Professional-Precise-Direct': {h:'Ship production-ready in days.', s:'Automated architecture decisions, AI-generated copy, one-click deployment. Measurable output at every stage.', cta:'Get started'}
};
var TOPIC_TEXT = {
problem: 'Solves a real, painful problem',
audience: 'Built for a specific, well-defined audience',
timing: 'The market is ready right now',
benefits: 'Clear advantages over the status quo',
comparison: 'Better than existing alternatives'
};
var TOPIC_RP_LABELS = {
problem: 'Highlighting a clear pain point',
audience: 'Targeting a specific audience',
timing: 'Creating urgency',
benefits: 'Showing value quickly',
comparison: 'Differentiating from competitors'
};
/* ── Device ── */
function setDevice(btn) {
document.querySelectorAll('[data-group="device"]').forEach(function(b){ b.classList.remove('selected'); });
btn.classList.add('selected');
DEVICE = btn.getAttribute('data-tip') === 'Optimised for phones, still works on desktop' ? 'mobile' : 'desktop';
renderPreview();
}
/* ── Controls ── */
function saveWebsiteState(){
try {
var topicLabels = {problem:'The problem', audience:"Who it's for", timing:'Why now', benefits:'Key benefits', comparison:'vs. alternatives'};
var activeTopics = Object.keys(TOPICS).filter(function(k){ return TOPICS[k]; }).map(function(k){ return topicLabels[k]; });
localStorage.setItem('vibn_website', JSON.stringify({
voice: VOICE,
styleLabel: STYLE.label,
topics: activeTopics
}));
} catch(e){}
}
function setPill(el, key, val) {
document.getElementById('pills-' + key).querySelectorAll('.vpill').forEach(function(p){ p.classList.remove('active'); });
el.classList.add('active');
VOICE[key] = PILL_LABELS[key][val];
document.getElementById('rp-' + key).textContent = VOICE[key];
renderAll();
saveWebsiteState();
}
function toggleTopic(el, key) {
var on = !el.classList.contains('active');
el.classList.toggle('active', on);
TOPICS[key] = on;
renderAll();
saveWebsiteState();
}
function setStyle(id, bg, accent, label, desc) {
document.querySelectorAll('.scard').forEach(function(c){ c.classList.remove('selected'); });
document.getElementById('sc-' + id).classList.add('selected');
STYLE = {id:id, bg:bg, accent:accent, label:label, desc:desc};
document.getElementById('rp-ws-name').textContent = label;
document.getElementById('rp-ws-desc').textContent = desc;
renderAll();
saveWebsiteState();
}
/* ── Copy generation ── */
function getCopy() {
return COPY_MATRIX[VOICE.tone + '-' + VOICE.style + '-' + VOICE.pers] || COPY_MATRIX['Balanced-Balanced-Steady'];
}
function getBullets() {
return Object.keys(TOPICS).filter(function(k){ return TOPICS[k]; }).map(function(k){ return TOPIC_TEXT[k]; });
}
/* ── Render ── */
function renderPreview() {
var copy = getCopy();
var bullets = getBullets();
var bg = STYLE.bg;
var accent = STYLE.accent;
var isDark = ['#0f172a','#0c0a09','#1a1a1a'].indexOf(bg) !== -1;
var tc = isDark ? '#ffffff' : '#111111';
var sub = isDark ? 'rgba(255,255,255,0.55)' : '#6b7280';
var border = isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.06)';
/* ── Per-style theme variables ── */
function hexRgbaW(h,a){ var r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16); return 'rgba('+r+','+g+','+b+','+a+')'; }
var S = {
editorial: {
r: 4, cardR: 4, navR: 4,
shadow: 'none', cardShadow: 'none',
headingWeight: 800, headingTracking: '-0.03em',
border: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.12)',
navBorder: isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.12)',
cardBg: isDark ? 'rgba(255,255,255,0.05)' : '#fff',
sectionBg: isDark ? 'rgba(255,255,255,0.03)' : 'rgba(0,0,0,0.02)',
pillBg: isDark ? 'rgba(255,255,255,0.08)' : hexRgbaW(accent,0.10),
ctaR: '4px', secPad: '22px 24px', heroPad: '24px 24px 14px',
subColor: isDark ? 'rgba(255,255,255,0.50)' : '#374151'
},
startup: {
r: 8, cardR: 8, navR: 6,
shadow: '0 1px 4px rgba(0,0,0,0.07)', cardShadow: '0 1px 4px rgba(0,0,0,0.07)',
headingWeight: 700, headingTracking: '-0.02em',
border: isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)',
navBorder: isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.07)',
cardBg: isDark ? 'rgba(255,255,255,0.05)' : '#fff',
sectionBg: isDark ? 'rgba(255,255,255,0.03)' : 'rgba(99,102,241,0.03)',
pillBg: isDark ? 'rgba(255,255,255,0.08)' : hexRgbaW(accent,0.07),
ctaR: '8px', secPad: '28px 24px', heroPad: '26px 24px 16px',
subColor: sub
},
minimal: {
r: 4, cardR: 4, navR: 4,
shadow: 'none', cardShadow: 'none',
headingWeight: 600, headingTracking: '-0.01em',
border: isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
navBorder: isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
cardBg: isDark ? 'rgba(255,255,255,0.03)' : '#fafafa',
sectionBg: isDark ? 'rgba(255,255,255,0.02)' : 'rgba(0,0,0,0.01)',
pillBg: isDark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.04)',
ctaR: '4px', secPad: '36px 24px', heroPad: '36px 24px 20px',
subColor: isDark ? 'rgba(255,255,255,0.40)' : '#9ca3af'
},
warm: {
r: 14, cardR: 14, navR: 8,
shadow: '0 2px 12px rgba(0,0,0,0.08)', cardShadow: '0 2px 8px rgba(0,0,0,0.06)',
headingWeight: 700, headingTracking: '-0.01em',
border: isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.05)',
navBorder: isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.06)',
cardBg: isDark ? 'rgba(255,255,255,0.05)' : hexRgbaW(accent,0.04),
sectionBg: isDark ? 'rgba(255,255,255,0.03)' : hexRgbaW(accent,0.05),
pillBg: isDark ? 'rgba(255,255,255,0.08)' : hexRgbaW(accent,0.08),
ctaR: '14px', secPad: '28px 24px', heroPad: '30px 24px 18px',
subColor: sub
}
}[STYLE.id] || {
r:8, cardR:8, navR:6, shadow:'none', cardShadow:'none',
headingWeight:700, headingTracking:'-0.02em',
border: border, navBorder: border,
cardBg: isDark?'rgba(255,255,255,0.05)':'#fff',
sectionBg: isDark?'rgba(255,255,255,0.03)':'rgba(99,102,241,0.03)',
pillBg: isDark?'rgba(255,255,255,0.08)':hexRgbaW(accent,0.07),
ctaR:'8px', secPad:'28px 24px', heroPad:'26px 24px 16px',
subColor: sub
};
/* override shared vars with per-style ones */
border = S.border;
sub = S.subColor;
var pillsHtml = '';
if (bullets.length) {
pillsHtml = '<div style="padding:0 24px 18px;display:flex;flex-wrap:wrap;gap:6px;justify-content:center;">';
bullets.forEach(function(b) {
pillsHtml += '<div style="background:' + S.pillBg + ';border-radius:20px;padding:3px 11px;font-size:10px;color:' + (isDark ? 'rgba(255,255,255,0.65)' : accent) + ';">' + b + '</div>';
});
pillsHtml += '</div>';
}
// Problem section
var problemHtml = (TOPICS.problem || TOPICS.audience)
? '<div style="padding:'+S.secPad+';background:' + S.sectionBg + ';border-top:1px solid ' + S.border + ';text-align:center;">'
+ '<div style="font-size:8.5px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:' + accent + ';margin-bottom:10px;">The Problem</div>'
+ '<div style="font-size:15px;font-weight:'+S.headingWeight+';color:' + tc + ';letter-spacing:'+S.headingTracking+';line-height:1.3;margin-bottom:8px;">Most founders waste months on the wrong things</div>'
+ '<div style="font-size:11px;color:' + sub + ';line-height:1.65;max-width:340px;margin-left:auto;margin-right:auto;">Building a product is hard. Knowing what to build, how to position it, and who to build it for shouldn\'t be. That\'s what we fix.</div>'
+ '</div>'
: '';
// Benefits section
var benefitItems = [
{icon:'⚡', title:'10× faster setup', body:'Skip the research rabbit hole — vibn structures everything for you.'},
{icon:'🎯', title:'Laser-focused', body:'Every decision is tied to your specific audience and problem.'},
{icon:'🚀', title:'Launch-ready output', body:'Get copy, architecture, and a website in one session.'}
];
var benefitCols = DEVICE === 'mobile' ? '1fr' : '1fr 1fr 1fr';
var benefitsHtml = '<div style="padding:'+S.secPad+';border-top:1px solid ' + S.border + ';">'
+ '<div style="font-size:8.5px;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;color:' + accent + ';margin-bottom:14px;">Why it works</div>'
+ '<div style="display:grid;grid-template-columns:' + benefitCols + ';gap:10px;">';
benefitItems.forEach(function(b) {
benefitsHtml += '<div style="background:' + S.cardBg + ';border:1px solid ' + S.border + ';border-radius:' + S.cardR + 'px;padding:12px;box-shadow:' + S.cardShadow + ';">'
+ '<div style="font-size:16px;margin-bottom:6px;">' + b.icon + '</div>'
+ '<div style="font-size:10.5px;font-weight:'+S.headingWeight+';color:' + tc + ';margin-bottom:4px;">' + b.title + '</div>'
+ '<div style="font-size:9.5px;color:' + sub + ';line-height:1.5;">' + b.body + '</div>'
+ '</div>';
});
benefitsHtml += '</div></div>';
// Final CTA section
var ctaSectionHtml = '<div style="padding:36px 24px;text-align:center;background:' + accent + ';margin-top:0;">'
+ '<div style="font-size:17px;font-weight:'+S.headingWeight+';color:#fff;letter-spacing:'+S.headingTracking+';line-height:1.25;margin-bottom:8px;">Ready to stop planning<br>and start building?</div>'
+ '<div style="font-size:10.5px;color:rgba(255,255,255,0.75);margin-bottom:16px;">Join founders who shipped their MVP in days, not months.</div>'
+ '<div style="display:inline-block;background:#fff;color:' + accent + ';font-size:11px;font-weight:700;padding:9px 22px;border-radius:' + S.ctaR + ';">' + copy.cta + '</div>'
+ '</div>';
var isAppDark = document.documentElement.dataset.theme === 'dark';
var phoneGlow = isAppDark
? '0 8px 40px rgba(0,0,0,0.65),0 0 0 1px rgba(255,255,255,0.18),0 0 32px rgba(255,255,255,0.12),0 0 64px rgba(255,255,255,0.06)'
: '0 8px 32px rgba(0,0,0,0.15)';
var mobileWrapOpen = DEVICE === 'mobile'
? '<div style="background:' + (isDark ? '#111827' : '#f0f0f8') + ';padding:20px 0;min-height:100%;"><div style="background:' + bg + ';max-width:375px;margin:0 auto;border-radius:' + S.r*2 + 'px;overflow:hidden;box-shadow:' + phoneGlow + ';font-family:\'Plus Jakarta Sans\',sans-serif;">'
: '';
var mobileWrapClose = DEVICE === 'mobile' ? '</div></div>' : '';
var html = (DEVICE === 'mobile' ? mobileWrapOpen : '<div style="background:' + bg + ';font-family:\'Plus Jakarta Sans\',sans-serif;">')
+ '<div style="padding:9px 16px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid ' + S.navBorder + ';box-shadow:' + S.shadow + ';">'
+ '<span style="font-size:12px;font-weight:'+S.headingWeight+';color:' + tc + ';">YourApp</span>'
+ '<div style="display:flex;gap:12px;"><span style="font-size:9.5px;color:' + sub + ';">Product</span><span style="font-size:9.5px;color:' + sub + ';">Pricing</span></div>'
+ '<div style="background:' + accent + ';color:#fff;font-size:9.5px;font-weight:700;padding:4px 10px;border-radius:' + S.ctaR + ';">' + copy.cta + '</div>'
+ '</div>'
+ '<div style="padding:'+S.heroPad+';text-align:center;">'
+ '<div style="font-size:20px;font-weight:'+S.headingWeight+';color:' + tc + ';letter-spacing:'+S.headingTracking+';line-height:1.2;margin-bottom:9px;">' + copy.h + '</div>'
+ '<div style="font-size:11.5px;color:' + sub + ';line-height:1.65;margin-bottom:16px;max-width:300px;margin-left:auto;margin-right:auto;">' + copy.s + '</div>'
+ '<div style="display:inline-flex;gap:8px;justify-content:center;">'
+ '<div style="background:' + accent + ';color:#fff;font-size:11px;font-weight:700;padding:8px 18px;border-radius:' + S.ctaR + ';box-shadow:' + S.shadow + ';">' + copy.cta + '</div>'
+ '<div style="background:transparent;color:' + sub + ';font-size:11px;padding:8px 14px;border-radius:' + S.ctaR + ';border:1px solid ' + S.border + ';">See how it works</div>'
+ '</div></div>'
+ pillsHtml
+ problemHtml
+ benefitsHtml
+ ctaSectionHtml
+ (DEVICE === 'mobile' ? mobileWrapClose : '</div>');
var el = document.getElementById('live-preview');
el.style.transition = 'opacity 0.25s';
el.style.opacity = '0';
setTimeout(function() { el.innerHTML = html; el.style.opacity = '1'; }, 150);
}
function renderCopy() {
var copy = getCopy();
var bullets = getBullets();
function fade(id, fn) {
var el = document.getElementById(id);
el.style.transition = 'opacity 0.2s';
el.style.opacity = '0';
setTimeout(function() { fn(el); el.style.opacity = '1'; }, 130);
}
fade('copy-headline', function(el) { el.textContent = copy.h; });
fade('copy-sub', function(el) { el.textContent = copy.s; });
fade('copy-cta', function(el) { el.textContent = copy.cta; });
fade('copy-bullets', function(el) {
el.innerHTML = bullets.map(function(b) {
return '<div style="display:flex;align-items:flex-start;gap:6px;font-size:11.5px;color:#6b7280;"><span style="color:#6366F1;flex-shrink:0;font-size:11px;">✓</span><span>' + b + '</span></div>';
}).join('');
});
// Update right panel topics
var rpTopics = document.getElementById('rp-topics-list');
if (rpTopics) {
rpTopics.innerHTML = Object.keys(TOPICS).filter(function(k) { return TOPICS[k]; }).map(function(k) {
return '<div class="deliverable-row"><div style="width:5px;height:5px;border-radius:50%;background:#6366F1;flex-shrink:0;"></div>' + TOPIC_RP_LABELS[k] + '</div>';
}).join('');
}
}
/* ── Right-panel lookup tables ── */
var RP_TONE_ADJ = {Friendly:'Approachable', Balanced:'Measured', Professional:'Authoritative'};
var RP_STYLE_ADJ = {Casual:'conversational and informal', Balanced:'clear and well-crafted', Precise:'precise and data-led'};
var RP_PERS_ADJ = {Warm:'a warm, human feel', Steady:'a steady, reliable character', Direct:'a bold, direct edge'};
/* "Website experience" — bullet 1: visual style, bullet 2: writing style, bullet 3: tone */
var RP_EXP_VSTYLE = {
editorial: 'Strong visual hierarchy — bold headlines, designed to stop the scroll',
startup: 'Clean, conversion-first layout with benefit-led sections and clear CTAs',
minimal: 'Generous whitespace — nothing wasted, content takes centre stage',
warm: 'Approachable visuals and soft forms with trust signals woven in naturally'
};
var RP_EXP_WRITINGSTYLE = {
Casual: 'Copy that feels natural and conversational — no jargon, no fluff',
Balanced: 'Clear, well-crafted messaging that informs and builds confidence',
Precise: 'Data-led, specific language with measurable claims and no vagueness'
};
var RP_EXP_TONE = {
Friendly: 'Designed to welcome and reassure — visitors feel at ease immediately',
Balanced: 'Positioned to engage and convert — approachable and credible in equal measure',
Professional: 'Built to establish authority and attract qualified, high-intent leads'
};
/* "How users will perceive it" — bullet 1: visual style, bullet 2: tone, bullet 3: personality quote */
var RP_PERC_VSTYLE = {
editorial: 'Bold and self-assured',
startup: 'Modern and credible',
minimal: 'Calm and considered',
warm: 'Genuine and human'
};
var RP_PERC_TONE = {
Friendly: 'Inviting',
Balanced: 'Trustworthy',
Professional: 'Authoritative'
};
var RP_PERC_PERS = {
Warm: '\u201cThey actually get my problem\u201d',
Steady: '\u201cThese people know what they\u2019re doing\u201d',
Direct: '\u201cI want to try this right now\u201d'
};
function renderRightPanel() {
var dot = '<div style="width:5px;height:5px;border-radius:50%;background:#6366F1;flex-shrink:0;"></div>';
// 1. Brand voice sentence
var vEl = document.getElementById('rp-voice-sentence');
if (vEl) {
vEl.textContent =
(RP_TONE_ADJ[VOICE.tone] || VOICE.tone) + ', ' +
(RP_STYLE_ADJ[VOICE.style]|| VOICE.style) + ' \u2014 with ' +
(RP_PERS_ADJ[VOICE.pers] || VOICE.pers) + '.';
}
// 2. Website experience — reflects website style + writing style + tone
var expEl = document.getElementById('rp-experience');
if (expEl) {
expEl.innerHTML = [
RP_EXP_VSTYLE[STYLE.id] || '',
RP_EXP_WRITINGSTYLE[VOICE.style] || '',
RP_EXP_TONE[VOICE.tone] || ''
].map(function(b) {
return '<div class="deliverable-row">' + dot + b + '</div>';
}).join('');
}
// 3. How users will perceive it — reflects website style + tone + personality
var percEl = document.getElementById('rp-perception');
if (percEl) {
percEl.innerHTML = [
RP_PERC_VSTYLE[STYLE.id] || '',
RP_PERC_TONE[VOICE.tone] || '',
RP_PERC_PERS[VOICE.pers] || ''
].map(function(b) {
return '<div class="deliverable-row">' + dot + b + '</div>';
}).join('');
}
}
function renderAll() {
renderPreview();
renderCopy();
renderRightPanel();
}
/* ── AI Decide ── */
function aiDecide() {
// Balanced tone, Balanced style, Warm personality
document.getElementById('pills-tone').querySelectorAll('.vpill').forEach(function(p, i) { p.classList.toggle('active', i === 1); });
VOICE.tone = 'Balanced'; document.getElementById('rp-tone').textContent = 'Balanced';
document.getElementById('pills-style').querySelectorAll('.vpill').forEach(function(p, i) { p.classList.toggle('active', i === 1); });
VOICE.style = 'Balanced'; document.getElementById('rp-style').textContent = 'Balanced';
document.getElementById('pills-pers').querySelectorAll('.vpill').forEach(function(p, i) { p.classList.toggle('active', i === 0); });
VOICE.pers = 'Warm'; document.getElementById('rp-pers').textContent = 'Warm';
// Topics: problem + audience + benefits
var aiTopics = {problem:true, audience:true, timing:false, benefits:true, comparison:false};
document.querySelectorAll('.tchip').forEach(function(c) {
var m = c.getAttribute('onclick').match(/'(\w+)'\)/);
if (m) { var k = m[1]; c.classList.toggle('active', !!aiTopics[k]); TOPICS[k] = !!aiTopics[k]; }
});
// Startup style (also calls renderAll internally)
setStyle('startup', '#f8fafc', '#0ea5e9', 'Startup energy', 'Clear, conversion-focused');
}
/* ── Theme ── */
function saveAndExit() { window.location.href = '03_dashboard.html'; }
function toggleTheme() {
const html = document.documentElement;
const isDark = html.dataset.theme === 'dark';
html.dataset.theme = isDark ? '' : 'dark';
document.getElementById('dark-toggle').textContent = isDark ? '🌙 Dark mode' : '☀️ Light mode';
localStorage.setItem('vibn-theme', isDark ? '' : 'dark');
}
(function() {
const saved = localStorage.getItem('vibn-theme');
if (saved === 'dark') {
document.documentElement.dataset.theme = 'dark';
document.addEventListener('DOMContentLoaded', function() {
const btn = document.getElementById('dark-toggle');
if (btn) btn.textContent = '☀️ Light mode';
});
}
})();
document.addEventListener('DOMContentLoaded', function() {
try {
var name = localStorage.getItem('vibn_project_name') || 'My project';
var el = document.getElementById('sidebar-project-name');
el.textContent = name; el.style.display = 'block';
} catch(e) {}
// Sync device mode from Architect frontend selection
try {
var frontendTip = localStorage.getItem('vibn_frontend');
if (frontendTip === 'Optimised for phones, still works on desktop') {
DEVICE = 'mobile';
document.querySelectorAll('[data-group="device"]').forEach(function(b) {
b.classList.toggle('selected', b.getAttribute('data-tip') === frontendTip);
});
}
} catch(e) {}
renderAll();
});
</script>
</body></html>

View File

@@ -1,412 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<script>if(localStorage.getItem('vibn-theme')==='dark')document.documentElement.dataset.theme='dark';</script>
<title>vibn — Build</title>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
:root{
--ink:#1A1A1A;--ink2:#2c2c2a;--ink3:#6366F1;--mid:#6B7280;--muted:#888780;
--stone:#b4b2a9;--parch:#d3d1c7;--cream:#eef2ff;--paper:#F5F3FF;--white:#FFFFFF;--border:#e0e7ff;
--indigo:#6366F1;--indigo-dark:#4338CA;--indigo-deep:#2E2A5E;
--indigo-soft:rgba(99,102,241,0.08);--indigo-ring:rgba(99,102,241,0.12);--subtitle:#7171b7;
}
body{font-family:'Plus Jakarta Sans',sans-serif;background:linear-gradient(to bottom,#FAFAFA,#F5F3FF);display:flex;flex-direction:column;height:100vh;overflow:hidden;}
.f{font-family:'Plus Jakarta Sans',sans-serif;}
.sidebar-phase{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:8px;}
.sidebar-phase.active{background:#fafaff;}
.phase-dot{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:10px;}
@keyframes spin{to{transform:rotate(360deg);}}
.spinning{display:inline-block;animation:spin 1s linear infinite;}
/* ── Progress screen ── */
.grad-title{background:linear-gradient(135deg,#1A1A2E 0%,#2E2A5E 30%,#4338CA 65%,#6366F1 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
[data-theme="dark"] .grad-title{background:linear-gradient(135deg,#d0d0f0 0%,#9090cc 30%,#6C7CFF 65%,#A8B4FF 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
@keyframes grad-flow{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
.grad-anim{background:linear-gradient(270deg,#1A1A2E,#4338CA,#6366F1,#A5B4FC,#6366F1,#4338CA,#1A1A2E);background-size:400% 400%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;animation:grad-flow 4s ease infinite;}
[data-theme="dark"] .grad-anim{background:linear-gradient(270deg,#4B42D8,#6C7CFF,#C7D2FE,#A8B4FF,#6C7CFF,#4B42D8);background-size:400% 400%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;animation:grad-flow 4s ease infinite;}
@keyframes confetti-fall{0%{transform:translateY(-20px) rotate(0deg);opacity:1}80%{opacity:1}100%{transform:translateY(105vh) rotate(800deg);opacity:0}}
.step-num{width:24px;height:24px;border-radius:50%;background:linear-gradient(135deg,#4338CA,#818CF8);display:flex;align-items:center;justify-content:center;font-size:11px;color:#fff;font-weight:700;flex-shrink:0;}
.btn-gitea{background:transparent;color:var(--mid);border:1px solid var(--border);border-radius:11px;padding:14px;font-family:'Plus Jakarta Sans',sans-serif;font-size:13px;font-weight:500;cursor:pointer;transition:background 0.18s,border-color 0.18s,color 0.18s;}
.btn-gitea:hover{background:var(--cream);border-color:rgba(99,102,241,0.22);color:var(--indigo);}
[data-theme="dark"] .btn-gitea{border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] .btn-gitea:hover{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;color:var(--dm-accent)!important;}
/* ── Launch section ── */
.launch-divider{border:none;border-top:1px solid var(--border);margin:28px 0;}
.launch-card{background:var(--white);border:1px solid var(--border);border-radius:16px;padding:28px 28px 24px;box-shadow:0 2px 12px rgba(99,102,241,0.06),0 0 0 1px rgba(255,255,255,0.60);}
[data-theme="dark"] .launch-card{background:rgba(255,255,255,0.07)!important;border-color:rgba(255,255,255,0.10)!important;box-shadow:0 0 0 1px rgba(255,255,255,0.12),0 0 28px rgba(255,255,255,0.07),0 4px 24px rgba(0,0,0,0.35)!important;}
.build-step{display:flex;align-items:center;gap:11px;padding:9px 0;border-bottom:1px solid var(--border);}
.build-step:last-child{border-bottom:none;}
.build-step-icon{width:24px;height:24px;border-radius:6px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:11px;color:var(--ink3);flex-shrink:0;opacity:0.8;transform:scale(0.95);}
.build-step > div > span{font-size:14px!important;}
.build-step > span{font-size:12px!important;color:var(--muted)!important;}
.build-cta{width:100%;background:linear-gradient(135deg,#2E2A5E 0%,#4338CA 55%,#6366F1 100%);color:#fff;border:none;border-radius:12px;padding:16px 24px;font-family:'Plus Jakarta Sans',sans-serif;font-size:15px;font-weight:700;cursor:pointer;letter-spacing:-0.01em;transition:box-shadow 0.2s,transform 0.2s;box-shadow:0 8px 24px rgba(99,102,241,0.25),0 2px 6px rgba(99,102,241,0.12);}
.build-cta:hover{transform:translateY(-1px);box-shadow:0 12px 32px rgba(99,102,241,0.40),0 0 0 4px rgba(99,102,241,0.10);}
.build-cta:active{transform:translateY(0);box-shadow:0 2px 10px rgba(99,102,241,0.22);}
.build-cta:disabled{opacity:0.75;cursor:not-allowed;transform:none;}
.includes-chip{display:inline-flex;align-items:center;font-size:11px;font-weight:500;color:var(--mid);background:var(--cream);border-radius:20px;padding:3px 9px;}
[data-theme="dark"] .launch-divider{border-top-color:rgba(255,255,255,0.06)!important;}
[data-theme="dark"] .build-cta{background:linear-gradient(135deg,#4B42D8 0%,#6C7CFF 100%)!important;box-shadow:0 4px 22px rgba(108,124,255,0.38),inset 0 1px 0 rgba(255,255,255,0.12)!important;}
[data-theme="dark"] .build-cta:hover{box-shadow:0 8px 36px rgba(108,124,255,0.55),0 0 0 4px rgba(108,124,255,0.16),inset 0 1px 0 rgba(255,255,255,0.16)!important;}
[data-theme="dark"] .includes-chip{background:rgba(108,124,255,0.12)!important;color:var(--dm-text-3)!important;}
/* ── Dark mode tokens — exact match with architect / describe ── */
[data-theme="dark"]{--ink:#EEEEFF;--ink2:#B8B8D0;--ink3:#8484A8;--mid:#9898B8;--muted:#c2c2ee;--border:rgba(255,255,255,0.08);
--cream:rgba(108,124,255,0.14);--paper:#0A1120;--white:rgba(255,255,255,0.05);--stone:rgba(255,255,255,0.08);
--parch:rgba(255,255,255,0.06);--indigo:#6C7CFF;--indigo-dark:#6C7CFF;--indigo-deep:#4B42D8;--subtitle:#a8a8d7;--text:#d9d9ee;
--indigo-soft:rgba(108,124,255,0.14);--indigo-ring:rgba(108,124,255,0.22);
--dm-surf-sidebar:rgba(12,18,34,0.72);--dm-surf-topbar:rgba(12,18,34,0.58);--dm-surf-panel:rgba(12,18,34,0.58);
--dm-surf-card:rgba(255,255,255,0.07);--dm-border:rgba(255,255,255,0.08);
--dm-border-strong:rgba(255,255,255,0.14);--dm-accent:#6C7CFF;
--dm-accent-fill:rgba(108,124,255,0.14);--dm-accent-fill-mid:rgba(108,124,255,0.20);--dm-accent-border:rgba(108,124,255,0.55);
--dm-text-1:#EEEEFF;--dm-text-2:#B4B4CC;--dm-text-3:#d2d2ef;}
[data-theme="dark"] body{background:linear-gradient(to bottom,rgba(12, 18, 34, 0.58) 0%,rgba(60,120,255,0.10) 38%,transparent 62%),linear-gradient(to bottom,rgba(108,124,255,0.10),transparent 180px),radial-gradient(900px 520px at 14% -8%,rgba(108,124,255,0.24),transparent 62%),radial-gradient(760px 420px at 88% 0%,rgba(72,145,255,0.16),transparent 60%),linear-gradient(180deg,#18213B 0%,#101726 48%,#0A1120 100%);}[data-theme="dark"] #mock {background: #fff !important;}
/* ── Sidebar ── */
[data-theme="dark"] .sidebar-col{background:var(--dm-surf-sidebar)!important;border-right:1px solid var(--dm-border)!important;box-shadow:2px 0 28px rgba(0,0,0,0.60)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] .sidebar-col [style*="border-top:1px solid #e5e7eb"]{border-top-color:var(--dm-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#e5e7eb"]{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#1a1a1a"]{color:var(--dm-text-1)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#6b7280"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#444441"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="color:#9ca3af"]{color:var(--dm-text-3)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#6366F1"]{background:var(--dm-accent)!important;color:#0F1424!important;}
[data-theme="dark"] .sidebar-phase.active{background:var(--dm-accent-fill)!important;}
[data-theme="dark"] .sidebar-phase:not(.active):hover{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] .sidebar-col [style*="background:#eef2ff"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] #sidebar-project-name{color:var(--dm-text-3)!important;}
/* ── Main content ── */
[data-theme="dark"] #screen-review{color:var(--dm-text-1);}
/* Cards */
[data-theme="dark"] [style*="background:var(--white)"]{background:var(--dm-surf-card)!important;}
[data-theme="dark"] [style*="border:1px solid var(--border)"]{border-color:var(--dm-border)!important;}
[data-theme="dark"] [style*="border-bottom:1px solid var(--border)"]{border-bottom-color:var(--dm-border)!important;}
[data-theme="dark"] [style*="border-right:1px solid var(--border)"]{border-right-color:var(--dm-border)!important;}
/* Infra note & icon boxes using --cream */
[data-theme="dark"] [style*="background:var(--cream)"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-border)!important;}
/* Progress active row in renderSteps */
[data-theme="dark"] #steps-list [style*="background:var(--cream)"]{background:var(--dm-accent-fill)!important;}
/* Step done-dot: background:var(--ink) → accent; checkmark span inside: color:var(--white) → white */
[data-theme="dark"] #steps-list [style*="background:var(--ink)"]{background:var(--dm-accent)!important;}
[data-theme="dark"] #steps-list [style*="color:var(--white)"]{color:#fff!important;}
/* Done-section numbered circles and their text */
[data-theme="dark"] #done-section [style*="background:var(--ink)"]{background:var(--dm-accent)!important;color:#fff!important;}
/* Done-section "Open my app" button */
[data-theme="dark"] #done-section a button{background:linear-gradient(135deg,#4B42D8 0%,#6C7CFF 100%)!important;color:#fff!important;box-shadow:0 4px 22px rgba(108,124,255,0.38)!important;}
/* Secondary "View in Gitea" button */
[data-theme="dark"] #done-section [style*="background:var(--white)"][style*="color:var(--mid)"]{background:rgba(255,255,255,0.07)!important;border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
/* ── CTA build button ── */
[data-theme="dark"] button[onclick="startBuild()"]{background:linear-gradient(135deg,#4B42D8 0%,#6C7CFF 100%)!important;color:#fff!important;box-shadow:0 4px 22px rgba(108,124,255,0.38),inset 0 1px 0 rgba(255,255,255,0.14)!important;}
[data-theme="dark"] button[onclick="startBuild()"]:hover{box-shadow:0 6px 32px rgba(108,124,255,0.50),inset 0 1px 0 rgba(255,255,255,0.18)!important;}
/* ── Save & dark-toggle buttons ── */
[data-theme="dark"] button[onclick="saveAndExit()"]{background:var(--dm-accent-fill)!important;border-color:var(--dm-accent-border)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover{background:var(--dm-accent-fill-mid)!important;}
[data-theme="dark"] button[onclick="saveAndExit()"]:hover span{color:#fff!important;}
[data-theme="dark"] button[onclick="saveAndExit()"] span{color:var(--dm-accent)!important;}
[data-theme="dark"] #dark-toggle{background:rgba(255,255,255,0.05)!important;border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] #dark-toggle:hover{background:rgba(255,255,255,0.10)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] .vibn-avatar{background:var(--dm-accent)!important;}
/* ── Scrollbar ── */
[data-theme="dark"] ::-webkit-scrollbar{width:6px;height:6px;}
[data-theme="dark"] ::-webkit-scrollbar-track{background:#0A1120;}
[data-theme="dark"] ::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.12);border-radius:3px;}
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover{background:rgba(108,124,255,0.45);}
[data-theme="dark"] *{scrollbar-color:rgba(255,255,255,0.12) #0A1120;scrollbar-width:thin;}
</style>
</head>
<body>
<div style="display:flex;height:100%;overflow:hidden;">
<!-- SIDEBAR -->
<div class="sidebar-col" style="width:200px;background:#ffffff;border-right:1px solid #e5e7eb;display:flex;flex-direction:column;padding:18px 12px;flex-shrink:0;">
<div style="padding:0 6px;margin-bottom:26px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
<div class="vibn-avatar" style="width:26px;height:26px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;"><span class="f" style="font-size:13px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:16px;font-weight:700;color:#1a1a1a;letter-spacing:-0.02em;">vibn</span>
</div>
<div id="sidebar-project-name" style="font-size:11px;font-weight:500;color:#9ca3af;padding-left:34px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:none;"></div>
</div>
<div style="font-size:9.5px;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:#9ca3af;padding:0 6px;margin-bottom:8px;">MVP Setup</div>
<div style="display:flex;flex-direction:column;gap:2px;flex:1;">
<div class="sidebar-phase" onclick="window.location.href='05_describe.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Describe</div>
</div>
<div class="sidebar-phase" onclick="window.location.href='06_architect.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Architect</div>
</div>
<div class="sidebar-phase" onclick="window.location.href='07_design.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Design</div>
</div>
<div class="sidebar-phase" onclick="window.location.href='08_website.html'" style="cursor:pointer;" onmouseover="this.style.background='#f5f3ff'" onmouseout="this.style.background='transparent'">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div style="font-size:12.5px;color:#6b7280;">Website</div>
</div>
<div class="sidebar-phase active">
<div class="phase-dot" style="background:#6366F1;color:#ffffff;"></div>
<div><div style="font-size:12.5px;font-weight:600;color:#1a1a1a;">Build MVP</div><div style="font-size:10px;color:#9ca3af;">Review &amp; launch</div></div>
</div>
</div>
<div style="border-top:1px solid #e5e7eb;margin-top:14px;padding-top:12px;">
<button onclick="saveAndExit()" style="display:flex;align-items:center;justify-content:center;gap:7px;width:100%;background:#eef2ff;border:1px solid #e0e7ff;border-radius:8px;padding:9px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;transition:background 0.15s;" onmouseover="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#e0e7ff'" onmouseout="this.style.background=document.documentElement.dataset.theme==='dark'?'':'#eef2ff'">
<span style="font-size:12px;font-weight:600;color:#6366F1;">Save & go to dashboard</span>
</button>
<button id="dark-toggle" onclick="toggleTheme()" style="margin-top:8px;display:flex;align-items:center;justify-content:center;width:100%;background:transparent;border:1px solid var(--border);border-radius:8px;padding:8px 10px;cursor:pointer;font-family:'Plus Jakarta Sans',sans-serif;font-size:12px;font-weight:500;color:var(--mid);transition:background 0.15s,border-color 0.15s;" onmouseover="this.style.borderColor='#6366F1';this.style.color='#6366F1';" onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--mid)';">🌙 Dark mode</button>
</div>
</div>
<!-- MAIN -->
<div style="flex:1;overflow-y:auto;">
<!-- REVIEW SCREEN -->
<div id="screen-review" style="padding:28px 32px;max-width:680px;margin:0 auto;">
<div class="f" style="font-size:22px;font-weight:700;color:var(--ink);margin-bottom:6px;">Ready to build</div>
<p style="font-size:13.5px;color:var(--muted);margin-bottom:22px;">Review everything below. Once you hit Build, AI codes your full product and deploys it.</p>
<div style="background:var(--white);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:14px;">
<div style="padding:12px 18px;border-bottom:1px solid var(--border);"><span style="font-size:10.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;">What's being built</span></div>
<div style="display:grid;grid-template-columns:1fr 1fr;">
<div style="padding:13px 18px;border-right:1px solid var(--border);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Sign up &amp; login</div><div style="font-size:13px;font-weight:600;color:var(--ink);">Email + social login</div></div></div>
<div style="padding:13px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;">$</div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Payments</div><div style="font-size:13px;font-weight:600;color:var(--ink);">Subscription billing</div></div></div>
<div style="padding:13px 18px;border-right:1px solid var(--border);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Email</div><div style="font-size:13px;font-weight:600;color:var(--ink);">Transactional + marketing</div></div></div>
<div style="padding:13px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Product style</div><div style="font-size:13px;font-weight:600;color:var(--ink);">Clean &amp; focused</div></div></div>
<div style="padding:13px 18px;border-right:1px solid var(--border);display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Website style</div><div style="font-size:13px;font-weight:600;color:var(--ink);">Startup energy</div></div></div>
<div style="padding:13px 18px;display:flex;align-items:center;gap:10px;"><div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div><div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Campaign topics</div><div style="font-size:13px;font-weight:600;color:var(--ink);">3 topics ready</div></div></div>
</div>
</div>
<div style="background:var(--white);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:14px;">
<div style="padding:12px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;"><span style="font-size:10.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;">Pages</span><span style="font-size:12px;color:var(--muted);">14 pages total</span></div>
<div style="padding:16px 18px;display:grid;grid-template-columns:repeat(4,1fr);gap:0;">
<div style="padding:0 14px 0 0;border-right:1px solid var(--border);margin-right:14px;"><div style="font-size:9.5px;font-weight:700;color:var(--subtitle);text-transform:uppercase;letter-spacing:0.07em;margin-bottom:8px;">Public</div><div style="font-size:12.5px;color:var(--ink2);line-height:2.0;">Landing page<br>Pricing<br>About<br>Blog</div></div>
<div style="padding:0 14px 0 0;border-right:1px solid var(--border);margin-right:14px;"><div style="font-size:9.5px;font-weight:700;color:var(--subtitle);text-transform:uppercase;letter-spacing:0.07em;margin-bottom:8px;">Auth</div><div style="font-size:12.5px;color:var(--ink2);line-height:2.0;">Sign up<br>Log in<br>Forgot password</div></div>
<div style="padding:0 14px 0 0;border-right:1px solid var(--border);margin-right:14px;"><div style="font-size:9.5px;font-weight:700;color:var(--subtitle);text-transform:uppercase;letter-spacing:0.07em;margin-bottom:8px;">App</div><div style="font-size:12.5px;color:var(--ink2);line-height:2.0;">Dashboard<br>Onboarding<br>Settings</div></div>
<div><div style="font-size:9.5px;font-weight:700;color:var(--subtitle);text-transform:uppercase;letter-spacing:0.07em;margin-bottom:8px;">Payments</div><div style="font-size:12.5px;color:var(--ink2);line-height:2.0;">Checkout<br>Success<br>Manage subscription</div></div>
</div>
</div>
<div style="background:var(--white);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:14px;">
<div style="padding:12px 18px;border-bottom:1px solid var(--border);"><span style="font-size:10.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;">Your design</span></div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;">
<div style="padding:13px 18px;border-right:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Feel</div><div id="build-feel" style="font-size:13px;font-weight:600;color:var(--ink);">Friendly</div></div>
</div>
<div style="padding:13px 18px;border-right:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div id="build-color-swatch" style="width:26px;height:26px;border-radius:50%;background:#6366F1;flex-shrink:0;box-shadow:0 0 0 3px var(--white),0 0 0 4px #e0e7ff;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Accent</div><div id="build-color" style="font-size:13px;font-weight:600;color:var(--ink);">Indigo</div></div>
</div>
<div style="padding:13px 18px;display:flex;align-items:center;gap:10px;">
<div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Layout</div><div id="build-structure" style="font-size:13px;font-weight:600;color:var(--ink);">Clean</div></div>
</div>
</div>
</div>
<div style="background:var(--white);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:14px;">
<div style="padding:12px 18px;border-bottom:1px solid var(--border);"><span style="font-size:10.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;">Your website</span></div>
<div style="display:grid;grid-template-columns:1fr 1fr;">
<div style="padding:13px 18px;border-right:1px solid var(--border);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Voice</div><div id="build-voice" style="font-size:13px;font-weight:600;color:var(--ink);">Friendly · Balanced · Warm</div></div>
</div>
<div style="padding:13px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;">
<div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Website style</div><div id="build-ws-style" style="font-size:13px;font-weight:600;color:var(--ink);">Editorial</div></div>
</div>
<div style="padding:13px 18px;grid-column:1/-1;display:flex;align-items:center;gap:10px;">
<div style="width:26px;height:26px;border-radius:7px;background:var(--cream);display:flex;align-items:center;justify-content:center;font-size:12px;color:var(--ink3);flex-shrink:0;"></div>
<div><div style="font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:0.05em;margin-bottom:2px;">Topics</div><div id="build-topics" style="font-size:13px;font-weight:600;color:var(--ink);">The problem · Who it's for · Why now</div></div>
</div>
</div>
</div>
<!-- ── Launch section ── -->
<hr class="launch-divider">
<div class="launch-card">
<div style="margin-bottom:24px;">
<div style="font-size:24px;font-weight:700;color:var(--ink);letter-spacing:-0.01em;margin-bottom:8px;">You're ready to build your product</div>
<p style="font-size:14px;color:var(--muted);line-height:1.5;max-width:520px;">Your app will be generated, your backend configured, and everything deployed to your infrastructure — fully automated, no code needed.</p>
</div>
<div style="margin-top:26px;margin-bottom:6px;">
<div style="font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:14px;opacity:0.7;">What happens next</div>
<div class="build-step">
<div class="build-step-icon"></div>
<div style="flex:1;"><span style="font-size:13px;font-weight:500;color:var(--ink);">Generate UI &amp; all pages</span></div>
<span style="font-size:11px;color:var(--stone);">~30s</span>
</div>
<div class="build-step">
<div class="build-step-icon"></div>
<div style="flex:1;"><span style="font-size:13px;font-weight:500;color:var(--ink);">Set up database &amp; backend</span></div>
<span style="font-size:11px;color:var(--stone);">~45s</span>
</div>
<div class="build-step">
<div class="build-step-icon"></div>
<div style="flex:1;"><span style="font-size:13px;font-weight:500;color:var(--ink);">Connect auth, payments &amp; email</span></div>
<span style="font-size:11px;color:var(--stone);">~30s</span>
</div>
<div class="build-step">
<div class="build-step-icon"></div>
<div style="flex:1;"><span style="font-size:13px;font-weight:500;color:var(--ink);">Deploy your app live</span></div>
<span style="font-size:11px;color:var(--stone);">~20s</span>
</div>
</div>
<p style="font-size:11.5px;color:var(--muted);margin-bottom:28px;">Takes ~24 minutes · All steps run in parallel</p>
<button id="build-cta-btn" class="build-cta" onclick="startBuild()">Build my product</button>
<p style="font-size:12.5px;color:var(--muted);text-align:center;margin-top:10px;margin-bottom:4px;opacity:0.85;">No code needed &nbsp;·&nbsp; You can edit everything after</p>
</div>
<div style="text-align:center;padding-bottom:8px;">
<button onclick="window.history.back()" style="background:none;border:none;font-family:'Plus Jakarta Sans',sans-serif;font-size:12.5px;color:var(--muted);cursor:pointer;padding:6px 0;transition:color 0.15s;" onmouseover="this.style.color='var(--ink)'" onmouseout="this.style.color='var(--muted)'">← Go back and tweak choices</button>
</div>
</div>
<!-- PROGRESS SCREEN -->
<div id="screen-progress" style="display:none;padding:32px;max-width:580px;margin:0 auto;width:100%;">
<div id="prog-header" style="text-align:center;margin-bottom:26px;">
<div class="f grad-anim" style="font-size:24px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">Building your product…</div>
<div id="step-counter" style="font-size:13.5px;color:var(--muted);">Step 0 of 12</div>
</div>
<div id="steps-list" style="background:var(--white);border:1px solid var(--border);border-radius:13px;overflow:hidden;margin-bottom:18px;"></div>
<div id="done-section" style="display:none;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:12px;padding:18px 20px;margin-bottom:14px;">
<div class="grad-title" style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.06em;margin-bottom:12px;">Your next 3 actions</div>
<div style="display:flex;gap:12px;padding:10px 0;border-bottom:1px solid var(--border);"><div class="step-num">1</div><div><div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Open your live app</div><div style="font-size:12px;color:var(--muted);line-height:1.5;">Share the URL with 5 real people today.</div></div></div>
<div style="display:flex;gap:12px;padding:10px 0;border-bottom:1px solid var(--border);"><div class="step-num">2</div><div><div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Sign up as a user</div><div style="font-size:12px;color:var(--muted);line-height:1.5;">Go through your own onboarding. Fix anything confusing.</div></div></div>
<div style="display:flex;gap:12px;padding:10px 0;"><div class="step-num">3</div><div><div style="font-size:13px;font-weight:600;color:var(--ink);margin-bottom:2px;">Post your first topic</div><div style="font-size:12px;color:var(--muted);line-height:1.5;">AI has drafted your first content batch. Publish one today.</div></div></div>
</div>
<div style="display:flex;gap:10px;">
<a href="10_vibe_editor.html" style="flex:2;display:block;text-decoration:none;"><button class="build-cta" style="border-radius:11px;font-size:14px;">Open my app ↗</button></a>
<button class="btn-gitea" style="flex:1;">View in Gitea ↗</button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
try {
var name = localStorage.getItem('vibn_project_name') || 'My project';
var el = document.getElementById('sidebar-project-name');
el.textContent = name;
el.style.display = 'block';
} catch(e){}
/* ── Populate design summary ── */
try {
var ds = JSON.parse(localStorage.getItem('vibn_design') || 'null');
if(ds){
var feelLabels = {premium:'Premium SaaS', friendly:'Friendly & Approachable', minimal:'Minimal & Clean'};
var structLabels = {clean:'Clean', data:'Data-rich', bold:'Bold'};
document.getElementById('build-feel').textContent = feelLabels[ds.feel] || ds.feel;
document.getElementById('build-structure').textContent = structLabels[ds.structure] || ds.structure;
document.getElementById('build-color').textContent = ds.colorName || ds.color;
var swatch = document.getElementById('build-color-swatch');
swatch.style.background = ds.colorHex || '#6366F1';
swatch.style.boxShadow = '0 0 0 3px var(--white),0 0 0 4px '+(ds.colorHex ? ds.colorHex+'44' : '#e0e7ff');
}
} catch(e){}
/* ── Populate website summary ── */
try {
var ws = JSON.parse(localStorage.getItem('vibn_website') || 'null');
if(ws){
if(ws.voice){
document.getElementById('build-voice').textContent = ws.voice.tone + ' · ' + ws.voice.style + ' · ' + ws.voice.pers;
}
if(ws.styleLabel){
document.getElementById('build-ws-style').textContent = ws.styleLabel;
}
if(ws.topics && ws.topics.length){
document.getElementById('build-topics').textContent = ws.topics.join(' · ');
}
}
} catch(e){}
});
var STEPS=[
{l:'Creating Gitea repository',d:'Setting up version control for your project'},
{l:'Scaffolding the app',d:'Next.js · TypeScript · Tailwind CSS'},
{l:'Setting up your database',d:'PostgreSQL + schema based on your product plan'},
{l:'Building sign up & login',d:'Email + Google + GitHub OAuth'},
{l:'Wiring payments',d:'Stripe checkout, webhooks, billing portal'},
{l:'Generating app pages',d:'Dashboard, settings, onboarding, invite flow'},
{l:'Applying your design',d:'Clean & focused theme applied across all pages'},
{l:'Building marketing website',d:'Startup energy style · SEO-ready'},
{l:'Setting up email',d:'Welcome, password reset, and marketing templates'},
{l:'Pushing to Gitea',d:'Full codebase committed and pushed'},
{l:'Deploying via Coolify',d:'Building Docker image, deploying to your servers'},
{l:'Running health checks',d:'Verifying all pages, auth, and payments are live'},
];
var cur=0, iv=null;
function startBuild(){
var btn = document.getElementById('build-cta-btn');
if(btn){ btn.disabled=true; btn.innerHTML='<span class="spinning" style="display:inline-block;margin-right:7px;font-size:12px;">◎</span>Building your product…'; }
setTimeout(function(){
document.getElementById('screen-review').style.display='none';
document.getElementById('screen-progress').style.display='block';
renderSteps();
iv=setInterval(function(){
cur++;
if(cur>=STEPS.length){
clearInterval(iv);
document.getElementById('prog-header').innerHTML='<div style="font-size:36px;margin-bottom:12px;">🚀</div><div class="f grad-title" style="font-size:24px;font-weight:700;letter-spacing:-0.03em;margin-bottom:6px;">Your MVP is live</div><div style="font-size:13.5px;color:var(--muted);">Deployed to Coolify · Pushed to Gitea · Ready to share</div>';
document.getElementById('done-section').style.display='block';
triggerConfetti();
} else {
document.getElementById('step-counter').textContent='Step '+cur+' of 12';
}
renderSteps();
},700);
},400);
}
function renderSteps(){
var list=document.getElementById('steps-list'); list.innerHTML='';
STEPS.forEach(function(s,i){
var done=i<cur, active=i===cur;
var div=document.createElement('div');
div.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 15px;border-bottom:'+(i<STEPS.length-1?'1px solid var(--border)':'none')+';background:'+(active?'var(--cream)':'transparent')+';transition:background 0.3s;';
var dotBg=done?'linear-gradient(135deg,#2E2A5E,#6366F1)':active?'linear-gradient(135deg,#4338CA,#6C7CFF)':'var(--parch)';
var dotContent=done?'<span style="color:#fff;font-size:9px;font-weight:900;">✓</span>'
:active?'<span class="spinning" style="color:#fff;font-size:8px;">◎</span>':'';
div.innerHTML='<div style="width:20px;height:20px;border-radius:50%;background:'+dotBg+';display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all 0.3s;">'+dotContent+'</div>'
+'<div style="flex:1;"><div style="font-size:12.5px;font-weight:'+(active?'600':'400')+';color:'+(done?'var(--muted)':active?'var(--ink)':'var(--stone)')+';">'+s.l+'</div>'
+((done||active)?'<div style="font-size:11px;color:var(--mid);margin-top:1px;">'+s.d+'</div>':'')+'</div>';
list.appendChild(div);
});
}
function triggerConfetti(){
var wrap=document.createElement('div');
wrap.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9999;overflow:hidden;';
document.body.appendChild(wrap);
var colors=['#6366F1','#818CF8','#4338CA','#A5B4FC','#C7D2FE','#FCD34D','#F472B6','#34D399','#60A5FA','#FBBF24'];
var shapes=['50%','3px','0'];
for(var i=0;i<110;i++){
var el=document.createElement('div');
var color=colors[Math.floor(Math.random()*colors.length)];
var size=Math.random()*9+4;
var left=Math.random()*100;
var delay=Math.random()*1.2;
var dur=Math.random()*2.5+2;
var br=shapes[Math.floor(Math.random()*shapes.length)];
var xDrift=(Math.random()-0.5)*200;
el.style.cssText='position:absolute;top:-12px;left:'+left+'%;width:'+size+'px;height:'+(size*(Math.random()*0.6+0.4))+'px;background:'+color+';border-radius:'+br+';animation:confetti-fall '+dur+'s '+delay+'s ease-in forwards;transform:translateX('+xDrift+'px) rotate('+(Math.random()*360)+'deg);';
wrap.appendChild(el);
}
setTimeout(function(){if(wrap.parentNode)wrap.parentNode.removeChild(wrap);},5000);
}
function saveAndExit(){window.location.href='03_dashboard.html';}
function toggleTheme(){const html=document.documentElement;const isDark=html.dataset.theme==='dark';html.dataset.theme=isDark?'':'dark';document.getElementById('dark-toggle').textContent=isDark?'🌙 Dark mode':'☀️ Light mode';localStorage.setItem('vibn-theme',isDark?'':'dark');}
(function(){const saved=localStorage.getItem('vibn-theme');if(saved==='dark'){document.documentElement.dataset.theme='dark';document.addEventListener('DOMContentLoaded',function(){const btn=document.getElementById('dark-toggle');if(btn)btn.textContent='☀️ Light mode';});}})();
</script>
</body></html>

View File

@@ -1,44 +0,0 @@
# vibn — UX Screen Pack
Design system: **Ink & parchment** — Lora serif + Inter sans, no colour accent.
All HTML files open directly in any browser — no build step required.
## Complete screen inventory
| File | Screen | Interactive? |
|------|--------|-------------|
| `01_homepage.html` | Marketing homepage | Scroll |
| `02_signup.html` | Sign up (3 steps) | ✓ Click through steps, mode selection |
| `03_dashboard.html` | Projects dashboard | ✓ Projects / Clients / Invoices / Costs nav |
| `04_welcome.html` | Welcome phase | Static |
| `05_discover.html` | Discover phase | ✓ Live chat, PRD fills in |
| `06_architect.html` | Architect phase | ✓ Change modal per block |
| `07_design.html` | Design phase | ✓ Live style preview switching |
| `08_market.html` | Market phase | ✓ Voice sliders, Topics, Website style |
| `09_build.html` | Build phase | ✓ Review + animated 12-step pipeline |
| `10_vibe_editor.html` | Vibe editor (post-launch) | ✓ Chat, preview updates, deploy status |
| `vibn-website.jsx` | Marketing site | React component |
| `vibn-dashboard.jsx` | Dashboard + billing | React component |
| `00_design-tokens.css` | Design tokens | Reference |
## Full user flow
01 Homepage → 02 Sign up → 03 Dashboard → 04 Welcome →
05 Discover → 06 Architect → 07 Design → 08 Market →
09 Build → 10 Vibe editor
## Design tokens
| Token | Value | Usage |
|-------|-------|-------|
| `--ink` | `#1a1510` | Primary text, buttons |
| `--ink3` | `#444441` | Secondary text |
| `--mid` | `#5f5e5a` | Body text |
| `--muted` | `#888780` | Labels, captions |
| `--stone` | `#b4b2a9` | Disabled, hints |
| `--cream` | `#f1efe8` | Surface tint, hover |
| `--paper` | `#f7f4ee` | Page background |
| `--white` | `#fdfcfa` | Card backgrounds |
| `--border` | `#e8e2d9` | All borders |
Heading font: **Lora** (serif)
Body font: **Inter** (sans-serif)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1,119 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="icon" href="favicon_clean.ico">
<title>Sign in Google Accounts</title>
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;600&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:'Roboto',sans-serif;background:#FFFFFF;display:flex;flex-direction:column;align-items:center;min-height:100vh;padding:40px 24px;}
.card{width:100%;max-width:400px;border:1px solid #DADCE0;border-radius:8px;padding:40px 40px 28px;display:flex;flex-direction:column;align-items:center;}
.google-logo{margin-bottom:24px;}
h1{font-family:'Google Sans',sans-serif;font-size:24px;font-weight:400;color:#202124;margin-bottom:8px;text-align:center;}
.subtitle{font-size:16px;color:#202124;margin-bottom:24px;text-align:center;}
/* Account tile */
.account-tile{width:100%;border:1px solid #DADCE0;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:16px;cursor:pointer;transition:background 0.15s;margin-bottom:12px;}
.account-tile:hover{background:#F8F9FA;}
.avatar{width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,#4285F4,#34A853);display:flex;align-items:center;justify-content:center;font-family:'Google Sans',sans-serif;font-size:16px;font-weight:500;color:#FFFFFF;flex-shrink:0;}
.account-info{flex:1;text-align:left;}
.account-name{font-family:'Google Sans',sans-serif;font-size:14px;font-weight:500;color:#202124;margin-bottom:2px;}
.account-email{font-size:13px;color:#5F6368;}
.chevron{color:#5F6368;}
/* Add account */
.add-account{width:100%;border:1px solid #DADCE0;border-radius:8px;padding:12px 16px;display:flex;align-items:center;gap:16px;cursor:pointer;transition:background 0.15s;margin-bottom:24px;}
.add-account:hover{background:#F8F9FA;}
.add-icon{width:40px;height:40px;border-radius:50%;background:#F1F3F4;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:20px;color:#5F6368;}
.add-label{font-size:14px;color:#202124;}
.divider{width:100%;height:1px;background:#E8EAED;margin-bottom:20px;}
/* Continue button */
.btn-continue{background:#1A73E8;color:#FFFFFF;border:none;border-radius:4px;padding:10px 24px;font-family:'Google Sans',sans-serif;font-size:14px;font-weight:500;cursor:pointer;transition:background 0.15s,box-shadow 0.15s;box-shadow:0 1px 2px rgba(0,0,0,0.2);}
.btn-continue:hover{background:#1765CC;box-shadow:0 2px 6px rgba(0,0,0,0.2);}
.footer{margin-top:auto;padding-top:24px;display:flex;gap:24px;justify-content:center;}
.footer a{font-size:12px;color:#5F6368;text-decoration:none;}
.footer a:hover{text-decoration:underline;}
/* Loading state */
.loading{display:none;flex-direction:column;align-items:center;gap:16px;margin-top:20px;}
.spinner{width:32px;height:32px;border:3px solid #E8EAED;border-top-color:#1A73E8;border-radius:50%;animation:spin 0.8s linear infinite;}
@keyframes spin{to{transform:rotate(360deg);}}
.loading-text{font-size:14px;color:#5F6368;}
</style>
</head>
<body>
<div class="card">
<!-- Google logo -->
<div class="google-logo">
<svg width="75" height="24" viewBox="0 0 75 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30.5 12.3c0-.7-.1-1.4-.2-2h-9.6v3.8h5.5c-.2 1.3-1 2.4-2.1 3.1v2.6h3.4c2-1.8 3-4.5 3-7.5z" fill="#4285F4"/>
<path d="M20.7 19.9c2.7 0 5-.9 6.7-2.4l-3.4-2.6c-.9.6-2 1-3.3 1-2.6 0-4.7-1.7-5.5-4.1H11.7v2.7c1.7 3.4 5.2 5.4 9 5.4z" fill="#34A853"/>
<path d="M15.2 11.8c-.2-.6-.3-1.2-.3-1.8s.1-1.2.3-1.8V7.5H11.7C11 8.8 10.7 10.3 10.7 12s.3 3.2 1 4.5l3.5-2.7z" fill="#FBBC05"/>
<path d="M20.7 5.9c1.4 0 2.7.5 3.7 1.5l2.8-2.8C25.7 3 23.4 2 20.7 2c-3.8 0-7.3 2-9 5.4l3.5 2.7c.8-2.4 2.9-4.2 5.5-4.2z" fill="#EA4335"/>
<text x="36" y="17" font-family="'Product Sans',Roboto,sans-serif" font-size="16" fill="#5F6368">Google</text>
</svg>
</div>
<h1>Sign in</h1>
<p class="subtitle">to continue to vibn</p>
<!-- Account selector (shown by default) -->
<div id="account-select" style="width:100%;">
<div class="account-tile" onclick="selectAccount()">
<div class="avatar">J</div>
<div class="account-info">
<div class="account-name">Jane Smith</div>
<div class="account-email">jane@gmail.com</div>
</div>
<svg class="chevron" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>
</div>
<div class="add-account" onclick="selectAccount()">
<div class="add-icon"></div>
<div class="add-label">Use another account</div>
</div>
<div class="divider"></div>
<p style="font-size:12px;color:#5F6368;text-align:center;line-height:1.6;">To continue, Google will share your name, email address, and profile picture with vibn.</p>
</div>
<!-- Loading state (shown after selection) -->
<div class="loading" id="loading">
<div class="spinner"></div>
<div class="loading-text">Signing you in…</div>
</div>
</div>
<div class="footer">
<a href="#">Help</a>
<a href="#">Privacy</a>
<a href="#">Terms</a>
</div>
<script>
function selectAccount(){
// Show loading
document.getElementById('account-select').style.display='none';
document.getElementById('loading').style.display='flex';
// After brief delay, notify parent and close
setTimeout(function(){
if(window.opener){
window.opener.postMessage({type:'google-auth-success',name:'Jane Smith',email:'jane@gmail.com'},'*');
}
window.close();
}, 1000);
}
</script>
</body>
</html>

View File

@@ -1,484 +0,0 @@
// vibn — Projects Dashboard
// Restyled from original (DM Sans + purple/colour accents) → Ink & parchment
// Design: Lora serif + Inter sans, #1a1510 ink, #f7f4ee paper, no colour accent
// Usage: default export, no required props
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
border2:"#d3d1c7",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Shared primitives ─────────────────────────────────────────────────────────
function StatusPill({ label, variant = "default" }) {
const styles = {
live: { bg: T.cream, text: T.ink3, border: T.border },
building: { bg: T.cream, text: T.ink3, border: T.border },
default: { bg: T.paper, text: T.muted, border: T.border },
invoiced: { bg: T.ink, text: T.paper, border: T.ink },
unbilled: { bg: T.cream, text: T.ink3, border: T.border },
scheduled: { bg: T.parch, text: T.ink2, border: T.border2 },
};
const s = styles[variant] || styles.default;
return (
<span style={{
fontFamily: F.sans, fontSize: 10.5, fontWeight: 600,
color: s.text, background: s.bg,
border: `1px solid ${s.border}`,
borderRadius: 5, padding: "2px 8px", whiteSpace: "nowrap",
}}>{label}</span>
);
}
function InkBtn({ children, onClick, small, outline }) {
return (
<button onClick={onClick} style={{
fontFamily: F.sans, fontWeight: 600,
fontSize: small ? 12 : 13.5,
padding: small ? "6px 14px" : "10px 22px",
background: outline ? "transparent" : T.ink,
color: outline ? T.ink3 : T.paper,
border: outline ? `1px solid ${T.border2}` : "none",
borderRadius: 8, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ screen, setScreen }) {
return (
<nav style={{
background: T.white, borderBottom: `1px solid ${T.border}`,
padding: "0 32px", height: 60, display: "flex",
alignItems: "center", justifyContent: "space-between",
}}>
<div onClick={() => setScreen("projects")} style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer" }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 18, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 22 }}>
{screen === "billing" && (
<span onClick={() => setScreen("projects")} style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}> All projects</span>
)}
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}>Settings</span>
<div style={{ width: 30, height: 30, borderRadius: "50%", background: T.ink3, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.sans, fontSize: 11, color: T.paper, fontWeight: 700 }}>JD</div>
</div>
</nav>
);
}
// ─── Data ──────────────────────────────────────────────────────────────────────
const PROJECTS = [
{
id: "launchpad", label: "Launchpad", initial: "L",
type: "own", status: "live", url: "launchpad.vibn.app",
stats: { visitors: "2.4k", signups: 183, mrr: "$840" },
},
{
id: "flowmatic", label: "Flowmatic", initial: "F",
type: "client", status: "live", url: "flowmatic.app",
client: "Acme Corp",
stats: { visitors: "890", signups: 54, mrr: "$210" },
costs: { total: 48.20, llm: 29.20, compute: 11.60, other: 7.40, billed: false },
},
{
id: "taskly", label: "Taskly", initial: "T",
type: "client", status: "building", url: null,
client: "Beta Labs", buildProgress: 60,
costs: { total: 12.40, llm: 9.20, compute: 3.20, other: 0, billed: false },
},
];
const ACTIVITY = [
{ text: "Launchpad — Blog post published:", detail: '"How to launch faster with AI"', time: "2h ago" },
{ text: "Flowmatic — New signup:", detail: "marcus@email.com", time: "4h ago" },
{ text: "Taskly — Checkout page built and deployed", detail: "", time: "6h ago" },
{ text: "Launchpad — Newsletter #12", detail: "scheduled", time: "Yesterday" },
];
const BILLING_ROWS = [
{ label: "Flowmatic", initial: "F", client: "Acme Corp", llm: 29.20, compute: 11.60, other: 7.40, total: 48.20, billed: false },
{ label: "Taskly", initial: "T", client: "Beta Labs", llm: 9.20, compute: 3.20, other: 0, total: 12.40, billed: false },
{ label: "Flowmatic", initial: "F", client: "Acme · Feb", llm: 22.10, compute: 8.40, other: 4.20, total: 34.70, billed: true },
];
const COST_LOG = [
{ time: "2h ago", desc: "LLM: Homepage copy generation", project: "Flowmatic", cost: 0.82 },
{ time: "3h ago", desc: "LLM: Checkout page code", project: "Taskly", cost: 1.24 },
{ time: "5h ago", desc: "LLM: Weekly newsletter draft", project: "Flowmatic", cost: 0.43 },
{ time: "6h ago", desc: "Compute: Build pipeline run", project: "Taskly", cost: 0.18 },
{ time: "8h ago", desc: "LLM: Discover phase Q&A", project: "Flowmatic", cost: 0.31 },
{ time: "Yesterday", desc: "Email delivery · 240 recipients", project: "Flowmatic", cost: 0.96 },
];
// ─── Project card ──────────────────────────────────────────────────────────────
function ProjectCard({ project }) {
const isClient = project.type === "client";
const isBuilding = project.status === "building";
return (
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{/* Header preview */}
{isBuilding ? (
<div style={{ height: 100, background: T.cream, borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 500, marginBottom: 10 }}>
Build phase · {project.buildProgress}% complete
</div>
<div style={{ width: 160, height: 4, background: T.parch, borderRadius: 3, overflow: "hidden" }}>
<div style={{ width: `${project.buildProgress}%`, height: "100%", background: T.ink3, borderRadius: 3 }} />
</div>
</div>
{isClient && (
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.mid, background: T.white, border: `1px solid ${T.border}`, borderRadius: 5, padding: "2px 8px" }}>
Client
</div>
)}
</div>
) : (
<div style={{ height: 100, background: T.ink, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ background: "rgba(247,244,238,0.1)", borderRadius: 8, width: "55%", padding: "10px 14px" }}>
<div style={{ height: 8, background: "rgba(247,244,238,0.6)", borderRadius: 3, width: "65%", marginBottom: 6 }} />
<div style={{ height: 5, background: "rgba(247,244,238,0.25)", borderRadius: 3, width: "85%" }} />
</div>
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: "rgba(247,244,238,0.6)", background: "rgba(247,244,238,0.1)", borderRadius: 5, padding: "2px 8px" }}>
{isClient ? "Client" : "My product"}
</div>
</div>
)}
<div style={{ padding: "18px 20px" }}>
{/* Identity row */}
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 12, color: T.paper, fontWeight: 700 }}>
{project.initial}
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>{project.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>
{isClient ? `${project.client} · ` : ""}
{project.url || "Setting up pages…"}
</div>
</div>
</div>
<StatusPill label={isBuilding ? "Building" : "Live"} variant={isBuilding ? "building" : "live"} />
</div>
{/* Cost strip — client + building */}
{isClient && project.costs && isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs so far</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<StatusPill label="Unbilled" variant="unbilled" />
</div>
)}
{/* Cost strip — client + live */}
{isClient && project.costs && !isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ flex: 1 }}>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs this month</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.mid, lineHeight: 1.7 }}>
LLM ${project.costs.llm.toFixed(2)}<br />
Compute ${project.costs.compute.toFixed(2)}
</div>
{!project.costs.billed && (
<button style={{ background: T.ink, border: "none", color: T.paper, borderRadius: 7, padding: "7px 13px", fontFamily: F.sans, fontSize: 11.5, fontWeight: 600, cursor: "pointer" }}>
Bill
</button>
)}
</div>
)}
{/* Stats */}
{!isBuilding && project.stats && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 14 }}>
{[["visitors", project.stats.visitors], ["signups", project.stats.signups], ["MRR", project.stats.mrr]].map(([k, v]) => (
<div key={k} style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>{v}</div>
<div style={{ fontFamily: F.sans, fontSize: 10, color: T.muted }}>{k}</div>
</div>
))}
</div>
)}
{/* Actions */}
{isBuilding ? (
<button style={{ width: "100%", background: T.ink, border: "none", color: T.paper, borderRadius: 8, padding: 10, fontFamily: F.sans, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
Continue building
</button>
) : (
<div style={{ display: "flex", gap: 6 }}>
{[["⬡", "Build"], ["◈", "Grow"]].map(([icon, label]) => (
<div key={label} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "7px 10px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, cursor: "pointer" }}>
<span style={{ fontSize: 11 }}>{icon}</span>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.ink3 }}>{label}</span>
</div>
))}
<div style={{ padding: "7px 12px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, fontFamily: F.sans, fontSize: 11.5, color: T.ink3, cursor: "pointer" }}>
</div>
</div>
)}
</div>
</div>
);
}
// ─── Projects screen ───────────────────────────────────────────────────────────
function ProjectsScreen({ setScreen }) {
const totalUnbilled = PROJECTS
.filter(p => p.type === "client" && p.costs?.billed === false)
.reduce((s, p) => s + p.costs.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "36px 32px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 32 }}>
<div>
<h1 style={{ fontFamily: F.serif, fontSize: 26, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", marginBottom: 4 }}>Your projects</h1>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted }}>3 active · 1 building</p>
</div>
<div style={{ display: "flex", gap: 10, alignItems: "center" }}>
{totalUnbilled > 0 && (
<button onClick={() => setScreen("billing")} style={{ fontFamily: F.sans, fontSize: 13, color: T.ink3, background: T.cream, border: `1px solid ${T.border}`, borderRadius: 8, padding: "9px 16px", cursor: "pointer" }}>
${totalUnbilled.toFixed(2)} unbilled
</button>
)}
<InkBtn>+ New project</InkBtn>
</div>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 28 }}>
{PROJECTS.map(p => <ProjectCard key={p.id} project={p} />)}
{/* New project CTA card */}
<div
style={{ background: "transparent", border: `1px dashed ${T.parch}`, borderRadius: 14, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, padding: 40, cursor: "pointer", minHeight: 220 }}
onMouseEnter={e => e.currentTarget.style.background = T.cream}
onMouseLeave={e => e.currentTarget.style.background = "transparent"}
>
<div style={{ width: 42, height: 42, borderRadius: 10, border: `1px solid ${T.parch}`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 22, color: T.stone }}>+</div>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>New project</div>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.muted }}>For yourself or a client</div>
</div>
</div>
</div>
{/* Activity feed */}
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, padding: "20px 24px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Recent activity</div>
{ACTIVITY.map((a, i) => (
<div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 0", borderBottom: i < ACTIVITY.length - 1 ? `1px solid ${T.border}` : "none" }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink3, flexShrink: 0 }} />
<div style={{ flex: 1, fontFamily: F.sans, fontSize: 13.5, color: T.ink }}>
{a.text}{" "}{a.detail && <span style={{ color: T.muted }}>{a.detail}</span>}
</div>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.stone, whiteSpace: "nowrap" }}>{a.time}</span>
</div>
))}
</div>
</div>
);
}
// ─── Billing screen ────────────────────────────────────────────────────────────
function BillingScreen() {
const [tab, setTab] = useState("billing");
const unbilled = BILLING_ROWS.filter(r => !r.billed).reduce((s, r) => s + r.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "28px 32px" }}>
{/* Sub-tabs */}
<div style={{ display: "flex", borderBottom: `1px solid ${T.border}`, marginBottom: 28 }}>
{[["billing", "Client billing"], ["costs", "Cost tracker"]].map(([id, label]) => (
<button key={id} onClick={() => setTab(id)} style={{
padding: "10px 18px", border: "none", background: "transparent",
borderBottom: tab === id ? `2px solid ${T.ink}` : "2px solid transparent",
fontFamily: F.sans, fontSize: 13.5, cursor: "pointer",
color: tab === id ? T.ink : T.muted, fontWeight: tab === id ? 600 : 400,
}}>{label}</button>
))}
</div>
{tab === "billing" && <>
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 22 }}>
<div>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Client billing</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>All costs tracked and ready to invoice</p>
</div>
<InkBtn>Generate invoice</InkBtn>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 10, marginBottom: 24 }}>
{[
{ label: "Total unbilled", value: `$${unbilled.toFixed(2)}` },
{ label: "LLM costs", value: "$38.40" },
{ label: "Compute", value: "$14.80" },
{ label: "Other", value: "$7.40" },
].map(c => (
<div key={c.label} style={{ background: T.cream, borderRadius: 10, padding: "14px 16px" }}>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted, marginBottom: 5 }}>{c.label}</div>
<div style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink }}>{c.value}</div>
</div>
))}
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Breakdown by client</span>
<select style={{ border: `1px solid ${T.border}`, borderRadius: 6, padding: "4px 10px", fontFamily: F.sans, fontSize: 12, color: T.muted, background: T.paper, outline: "none" }}>
<option>March 2026</option>
</select>
</div>
<div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Project / Client", "LLM", "Compute", "Other", "Total", "Status"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{BILLING_ROWS.map((r, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "13px 20px", borderBottom: i < BILLING_ROWS.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center", opacity: r.billed ? 0.5 : 1 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 24, height: 24, background: T.ink, borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 10, color: T.paper, fontWeight: 700 }}>{r.initial}</div>
<div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>{r.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>{r.client}</div>
</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.llm.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.compute.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.other.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.total.toFixed(2)}</div>
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
<StatusPill label={r.billed ? "Invoiced" : "Unbilled"} variant={r.billed ? "invoiced" : "unbilled"} />
{!r.billed && (
<button style={{ background: "transparent", border: `1px solid ${T.border2}`, borderRadius: 5, padding: "3px 9px", fontFamily: F.sans, fontSize: 11, color: T.muted, cursor: "pointer" }}>Invoice</button>
)}
</div>
</div>
))}
</div>
</>}
{tab === "costs" && <>
<div style={{ marginBottom: 22 }}>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Cost tracker</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>Every dollar spent, broken down by type and project</p>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 20 }}>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>LLM usage</div>
{[
{ label: "Code generation", amount: 21.40, pct: 56 },
{ label: "Content & marketing", amount: 10.20, pct: 27 },
{ label: "Chat assist", amount: 6.80, pct: 18 },
].map(r => (
<div key={r.label} style={{ marginBottom: 14 }}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 12.5, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
<div style={{ height: 4, background: T.cream, borderRadius: 2, overflow: "hidden" }}>
<div style={{ width: `${r.pct}%`, height: "100%", background: T.ink, borderRadius: 2 }} />
</div>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total LLM</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$38.40</span>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Infrastructure</div>
{[
{ label: "Hosting & compute", amount: 11.60 },
{ label: "Database", amount: 3.20 },
{ label: "Email delivery", amount: 4.20 },
{ label: "Domain & SSL", amount: 3.20 },
].map(r => (
<div key={r.label} style={{ display: "flex", justifyContent: "space-between", padding: "8px 11px", background: T.cream, borderRadius: 7, marginBottom: 7 }}>
<span style={{ fontFamily: F.sans, fontSize: 13, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total infra</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$22.20</span>
</div>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}` }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Recent charges</span>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Time", "Description", "Project", "Cost"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{COST_LOG.map((row, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "11px 20px", borderBottom: i < COST_LOG.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>{row.time}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>{row.desc}</div>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.mid }}>{row.project}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${row.cost.toFixed(2)}</div>
</div>
))}
</div>
</>}
</div>
);
}
// ─── Root ──────────────────────────────────────────────────────────────────────
export default function Dashboard() {
const [screen, setScreen] = useState("projects");
return (
<div style={{ background: T.paper, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
button { font-family: inherit; cursor: pointer; }
input, select { font-family: inherit; }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-thumb { background: ${T.parch}; border-radius: 4px; }
`}</style>
<Nav screen={screen} setScreen={setScreen} />
{screen === "projects" && <ProjectsScreen setScreen={setScreen} />}
{screen === "billing" && <BillingScreen />}
</div>
);
}

View File

@@ -1,288 +0,0 @@
// vibn — Marketing Website
// Design: Ink & parchment — Lora serif + Inter sans, no colour accent
// Usage: <Website onGetStarted={fn} onLogin={fn} />
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Primitives ────────────────────────────────────────────────────────────────
function Eyebrow({ children }) {
return (
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 16 }}>
{children}
</div>
);
}
function PrimaryBtn({ children, onClick, large }) {
return (
<button onClick={onClick} style={{
background: T.ink, color: T.paper, border: "none",
fontFamily: F.sans, fontWeight: 600,
fontSize: large ? 15 : 14,
padding: large ? "14px 34px" : "10px 24px",
borderRadius: 10, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ onGetStarted, onLogin }) {
return (
<nav style={{
background: T.paper, borderBottom: `1px solid ${T.border}`,
padding: "0 48px", height: 60,
display: "flex", alignItems: "center", justifyContent: "space-between",
position: "sticky", top: 0, zIndex: 50,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 30, height: 30, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 19, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", gap: 32 }}>
{["Product", "Pricing", "Stories", "Blog"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>{l}</span>
))}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<span onClick={onLogin} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>Log in</span>
<PrimaryBtn onClick={onGetStarted}>Get started free</PrimaryBtn>
</div>
</nav>
);
}
// ─── Hero ──────────────────────────────────────────────────────────────────────
function Hero({ onCta }) {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "88px 48px 72px" }}>
<Eyebrow>For non-technical founders</Eyebrow>
<h1 style={{
fontFamily: F.serif, fontSize: 64, fontWeight: 700, color: T.ink,
letterSpacing: "-0.03em", lineHeight: 1.07, marginBottom: 28, maxWidth: 680,
}}>
You have the idea.<br />
We handle<br />
<em style={{ fontStyle: "italic", color: T.ink3 }}>everything else.</em>
</h1>
<p style={{ fontFamily: F.sans, fontSize: 17.5, color: T.mid, lineHeight: 1.75, maxWidth: 480, marginBottom: 40 }}>
No backend. No DevOps. No marketing agency. Describe your idea and vibn
builds, deploys, and promotes it automatically.
</p>
<div style={{ display: "flex", alignItems: "center", gap: 18, marginBottom: 14 }}>
<PrimaryBtn onClick={onCta} large>Start free no code needed</PrimaryBtn>
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.stone }}>&nbsp;&nbsp;280 founders launched</span>
</div>
<p style={{ fontFamily: F.sans, fontSize: 12, color: T.stone }}>No credit card required · Free forever plan</p>
</section>
);
}
// ─── Quote band ────────────────────────────────────────────────────────────────
const QUOTES = [
{ q: "I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing.", by: "Alex K.", role: "Founder, Taskly" },
{ q: "I have zero coding experience. Three weeks in I have 300 paying users. That's entirely because of vibn.", by: "Marcus L.", role: "Founder, Flowmatic" },
{ q: "The marketing autopilot alone saved me ten hours a week. My blog runs itself. I just focus on my product.", by: "Sara R.", role: "Founder, Nudge" },
];
function QuoteBand() {
return (
<section style={{ background: T.ink, padding: "52px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 40 }}>
{QUOTES.map((q, i) => (
<div key={i} style={{ display: "flex", gap: 20 }}>
<div style={{ width: 3, background: T.mid, borderRadius: 2, flexShrink: 0 }} />
<div>
<p style={{ fontFamily: F.serif, fontSize: 15, color: T.parch, lineHeight: 1.72, fontStyle: "italic", marginBottom: 12 }}>"{q.q}"</p>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 600 }}> {q.by}, {q.role}</span>
</div>
</div>
))}
</div>
</section>
);
}
// ─── How it works ──────────────────────────────────────────────────────────────
const PHASES = [
{ n: "01", id: "Discover", title: "Define your idea", body: "Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon." },
{ n: "02", id: "Design", title: "Choose your style", body: "Pick a visual style and see your exact site and emails live before a single line of code is written." },
{ n: "03", id: "Build", title: "Your app, live", body: "AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English." },
{ n: "04", id: "Grow", title: "Market & automate", body: "AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on your users." },
];
function HowItWorks() {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "80px 48px" }}>
<Eyebrow>How it works</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 40, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", lineHeight: 1.15, marginBottom: 52, maxWidth: 460 }}>
Four phases.<br />One complete product.
</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{PHASES.map((p, i) => (
<div key={i} style={{
padding: "38px 42px", background: T.white,
borderRight: (i % 2 === 0) ? `1px solid ${T.border}` : "none",
borderBottom: (i < 2) ? `1px solid ${T.border}` : "none",
}}>
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: T.muted, marginBottom: 14 }}>
{p.n} {p.id}
</div>
<div style={{ fontFamily: F.serif, fontSize: 21, fontWeight: 700, color: T.ink, marginBottom: 10 }}>{p.title}</div>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.mid, lineHeight: 1.7 }}>{p.body}</p>
</div>
))}
</div>
</section>
);
}
// ─── Stats bar ─────────────────────────────────────────────────────────────────
const STATS = [
{ n: "280+", label: "founders launched" },
{ n: "72h", label: "average time to first version" },
{ n: "4.9★", label: "average rating" },
{ n: "3×", label: "faster than hiring a developer" },
];
function StatsBar() {
return (
<section style={{ background: T.white, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}` }}>
<div style={{ maxWidth: 960, margin: "0 auto", padding: "0 48px", display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
{STATS.map((s, i) => (
<div key={i} style={{ padding: "38px 0", paddingLeft: i > 0 ? 36 : 0, borderRight: i < 3 ? `1px solid ${T.border}` : "none" }}>
<div style={{ fontFamily: F.serif, fontSize: 38, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", marginBottom: 6 }}>{s.n}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>{s.label}</div>
</div>
))}
</div>
</section>
);
}
// ─── Empathy section ───────────────────────────────────────────────────────────
const PAINS = [
{ title: "No more \"I need to hire a developer first\"", body: "vibn is your developer. Start building the moment you have an idea." },
{ title: "No more staring at a blank marketing calendar", body: "AI generates and publishes your content every single week." },
{ title: "No more \"I'll launch when it's ready\"", body: "Most founders ship their first version in under 72 hours." },
];
function EmpathySection() {
return (
<section style={{ background: T.cream, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}`, padding: "76px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 68, alignItems: "center" }}>
<div>
<Eyebrow>Sound familiar?</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 36, fontWeight: 700, color: T.ink, lineHeight: 1.18, marginBottom: 24, letterSpacing: "-0.02em" }}>
The idea is the hard part. Everything else shouldn't be.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8, marginBottom: 20 }}>
You know exactly what you want to build and who it's for. But the moment you think
about servers, databases, deployment pipelines, SEO strategies the whole thing stalls.
</p>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8 }}>
vibn exists to remove all of that. Not abstract it {" "}
<em style={{ fontFamily: F.serif, fontStyle: "italic" }}>remove it entirely.</em>
</p>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
{PAINS.map((p, i) => (
<div key={i} style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px", display: "flex", gap: 14, alignItems: "flex-start" }}>
<div style={{ width: 20, height: 20, borderRadius: "50%", border: `1.5px solid ${T.stone}`, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, marginTop: 2 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink }} />
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>{p.title}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted, lineHeight: 1.6 }}>{p.body}</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}
// ─── Final CTA ─────────────────────────────────────────────────────────────────
function FinalCta({ onCta }) {
return (
<section style={{ maxWidth: 660, margin: "0 auto", padding: "92px 48px", textAlign: "center" }}>
<h2 style={{ fontFamily: F.serif, fontSize: 46, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", lineHeight: 1.1, marginBottom: 20 }}>
Your idea deserves to exist.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 16, color: T.mid, lineHeight: 1.75, marginBottom: 36 }}>
Don't let the backend be the reason it doesn't. Start today free, no code, no credit card.
</p>
<PrimaryBtn onClick={onCta} large>Build my product free</PrimaryBtn>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone, marginTop: 16 }}>
Joins 280+ non-technical founders already live
</div>
</section>
);
}
// ─── Footer ────────────────────────────────────────────────────────────────────
function Footer() {
return (
<footer style={{ borderTop: `1px solid ${T.border}`, padding: "32px 48px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>vibn</span>
<div style={{ display: "flex", gap: 28 }}>
{["Product", "Pricing", "Stories", "Blog", "Privacy", "Terms"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 13, color: T.stone, cursor: "pointer" }}>{l}</span>
))}
</div>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone }}>© 2026 vibn</span>
</footer>
);
}
// ─── Root export ───────────────────────────────────────────────────────────────
export default function Website({ onGetStarted = () => {}, onLogin = () => {} }) {
return (
<div style={{ background: T.paper, color: T.ink, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Inter', sans-serif; }
button { font-family: inherit; }
`}</style>
<Nav onGetStarted={onGetStarted} onLogin={onLogin} />
<Hero onCta={onGetStarted} />
<QuoteBand />
<HowItWorks />
<StatsBar />
<EmpathySection />
<FinalCta onCta={onGetStarted} />
<Footer />
</div>
);
}

View File

@@ -1,484 +0,0 @@
// vibn — Projects Dashboard
// Restyled from original (DM Sans + purple/colour accents) → Ink & parchment
// Design: Lora serif + Inter sans, #1a1510 ink, #f7f4ee paper, no colour accent
// Usage: default export, no required props
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
border2:"#d3d1c7",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Shared primitives ─────────────────────────────────────────────────────────
function StatusPill({ label, variant = "default" }) {
const styles = {
live: { bg: T.cream, text: T.ink3, border: T.border },
building: { bg: T.cream, text: T.ink3, border: T.border },
default: { bg: T.paper, text: T.muted, border: T.border },
invoiced: { bg: T.ink, text: T.paper, border: T.ink },
unbilled: { bg: T.cream, text: T.ink3, border: T.border },
scheduled: { bg: T.parch, text: T.ink2, border: T.border2 },
};
const s = styles[variant] || styles.default;
return (
<span style={{
fontFamily: F.sans, fontSize: 10.5, fontWeight: 600,
color: s.text, background: s.bg,
border: `1px solid ${s.border}`,
borderRadius: 5, padding: "2px 8px", whiteSpace: "nowrap",
}}>{label}</span>
);
}
function InkBtn({ children, onClick, small, outline }) {
return (
<button onClick={onClick} style={{
fontFamily: F.sans, fontWeight: 600,
fontSize: small ? 12 : 13.5,
padding: small ? "6px 14px" : "10px 22px",
background: outline ? "transparent" : T.ink,
color: outline ? T.ink3 : T.paper,
border: outline ? `1px solid ${T.border2}` : "none",
borderRadius: 8, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ screen, setScreen }) {
return (
<nav style={{
background: T.white, borderBottom: `1px solid ${T.border}`,
padding: "0 32px", height: 60, display: "flex",
alignItems: "center", justifyContent: "space-between",
}}>
<div onClick={() => setScreen("projects")} style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer" }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 18, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 22 }}>
{screen === "billing" && (
<span onClick={() => setScreen("projects")} style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}> All projects</span>
)}
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}>Settings</span>
<div style={{ width: 30, height: 30, borderRadius: "50%", background: T.ink3, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.sans, fontSize: 11, color: T.paper, fontWeight: 700 }}>JD</div>
</div>
</nav>
);
}
// ─── Data ──────────────────────────────────────────────────────────────────────
const PROJECTS = [
{
id: "launchpad", label: "Launchpad", initial: "L",
type: "own", status: "live", url: "launchpad.vibn.app",
stats: { visitors: "2.4k", signups: 183, mrr: "$840" },
},
{
id: "flowmatic", label: "Flowmatic", initial: "F",
type: "client", status: "live", url: "flowmatic.app",
client: "Acme Corp",
stats: { visitors: "890", signups: 54, mrr: "$210" },
costs: { total: 48.20, llm: 29.20, compute: 11.60, other: 7.40, billed: false },
},
{
id: "taskly", label: "Taskly", initial: "T",
type: "client", status: "building", url: null,
client: "Beta Labs", buildProgress: 60,
costs: { total: 12.40, llm: 9.20, compute: 3.20, other: 0, billed: false },
},
];
const ACTIVITY = [
{ text: "Launchpad — Blog post published:", detail: '"How to launch faster with AI"', time: "2h ago" },
{ text: "Flowmatic — New signup:", detail: "marcus@email.com", time: "4h ago" },
{ text: "Taskly — Checkout page built and deployed", detail: "", time: "6h ago" },
{ text: "Launchpad — Newsletter #12", detail: "scheduled", time: "Yesterday" },
];
const BILLING_ROWS = [
{ label: "Flowmatic", initial: "F", client: "Acme Corp", llm: 29.20, compute: 11.60, other: 7.40, total: 48.20, billed: false },
{ label: "Taskly", initial: "T", client: "Beta Labs", llm: 9.20, compute: 3.20, other: 0, total: 12.40, billed: false },
{ label: "Flowmatic", initial: "F", client: "Acme · Feb", llm: 22.10, compute: 8.40, other: 4.20, total: 34.70, billed: true },
];
const COST_LOG = [
{ time: "2h ago", desc: "LLM: Homepage copy generation", project: "Flowmatic", cost: 0.82 },
{ time: "3h ago", desc: "LLM: Checkout page code", project: "Taskly", cost: 1.24 },
{ time: "5h ago", desc: "LLM: Weekly newsletter draft", project: "Flowmatic", cost: 0.43 },
{ time: "6h ago", desc: "Compute: Build pipeline run", project: "Taskly", cost: 0.18 },
{ time: "8h ago", desc: "LLM: Discover phase Q&A", project: "Flowmatic", cost: 0.31 },
{ time: "Yesterday", desc: "Email delivery · 240 recipients", project: "Flowmatic", cost: 0.96 },
];
// ─── Project card ──────────────────────────────────────────────────────────────
function ProjectCard({ project }) {
const isClient = project.type === "client";
const isBuilding = project.status === "building";
return (
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{/* Header preview */}
{isBuilding ? (
<div style={{ height: 100, background: T.cream, borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 500, marginBottom: 10 }}>
Build phase · {project.buildProgress}% complete
</div>
<div style={{ width: 160, height: 4, background: T.parch, borderRadius: 3, overflow: "hidden" }}>
<div style={{ width: `${project.buildProgress}%`, height: "100%", background: T.ink3, borderRadius: 3 }} />
</div>
</div>
{isClient && (
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.mid, background: T.white, border: `1px solid ${T.border}`, borderRadius: 5, padding: "2px 8px" }}>
Client
</div>
)}
</div>
) : (
<div style={{ height: 100, background: T.ink, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ background: "rgba(247,244,238,0.1)", borderRadius: 8, width: "55%", padding: "10px 14px" }}>
<div style={{ height: 8, background: "rgba(247,244,238,0.6)", borderRadius: 3, width: "65%", marginBottom: 6 }} />
<div style={{ height: 5, background: "rgba(247,244,238,0.25)", borderRadius: 3, width: "85%" }} />
</div>
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: "rgba(247,244,238,0.6)", background: "rgba(247,244,238,0.1)", borderRadius: 5, padding: "2px 8px" }}>
{isClient ? "Client" : "My product"}
</div>
</div>
)}
<div style={{ padding: "18px 20px" }}>
{/* Identity row */}
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 12, color: T.paper, fontWeight: 700 }}>
{project.initial}
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>{project.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>
{isClient ? `${project.client} · ` : ""}
{project.url || "Setting up pages…"}
</div>
</div>
</div>
<StatusPill label={isBuilding ? "Building" : "Live"} variant={isBuilding ? "building" : "live"} />
</div>
{/* Cost strip — client + building */}
{isClient && project.costs && isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs so far</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<StatusPill label="Unbilled" variant="unbilled" />
</div>
)}
{/* Cost strip — client + live */}
{isClient && project.costs && !isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ flex: 1 }}>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs this month</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.mid, lineHeight: 1.7 }}>
LLM ${project.costs.llm.toFixed(2)}<br />
Compute ${project.costs.compute.toFixed(2)}
</div>
{!project.costs.billed && (
<button style={{ background: T.ink, border: "none", color: T.paper, borderRadius: 7, padding: "7px 13px", fontFamily: F.sans, fontSize: 11.5, fontWeight: 600, cursor: "pointer" }}>
Bill
</button>
)}
</div>
)}
{/* Stats */}
{!isBuilding && project.stats && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 14 }}>
{[["visitors", project.stats.visitors], ["signups", project.stats.signups], ["MRR", project.stats.mrr]].map(([k, v]) => (
<div key={k} style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>{v}</div>
<div style={{ fontFamily: F.sans, fontSize: 10, color: T.muted }}>{k}</div>
</div>
))}
</div>
)}
{/* Actions */}
{isBuilding ? (
<button style={{ width: "100%", background: T.ink, border: "none", color: T.paper, borderRadius: 8, padding: 10, fontFamily: F.sans, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
Continue building
</button>
) : (
<div style={{ display: "flex", gap: 6 }}>
{[["⬡", "Build"], ["◈", "Grow"]].map(([icon, label]) => (
<div key={label} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "7px 10px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, cursor: "pointer" }}>
<span style={{ fontSize: 11 }}>{icon}</span>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.ink3 }}>{label}</span>
</div>
))}
<div style={{ padding: "7px 12px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, fontFamily: F.sans, fontSize: 11.5, color: T.ink3, cursor: "pointer" }}>
</div>
</div>
)}
</div>
</div>
);
}
// ─── Projects screen ───────────────────────────────────────────────────────────
function ProjectsScreen({ setScreen }) {
const totalUnbilled = PROJECTS
.filter(p => p.type === "client" && p.costs?.billed === false)
.reduce((s, p) => s + p.costs.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "36px 32px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 32 }}>
<div>
<h1 style={{ fontFamily: F.serif, fontSize: 26, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", marginBottom: 4 }}>Your projects</h1>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted }}>3 active · 1 building</p>
</div>
<div style={{ display: "flex", gap: 10, alignItems: "center" }}>
{totalUnbilled > 0 && (
<button onClick={() => setScreen("billing")} style={{ fontFamily: F.sans, fontSize: 13, color: T.ink3, background: T.cream, border: `1px solid ${T.border}`, borderRadius: 8, padding: "9px 16px", cursor: "pointer" }}>
${totalUnbilled.toFixed(2)} unbilled
</button>
)}
<InkBtn>+ New project</InkBtn>
</div>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 28 }}>
{PROJECTS.map(p => <ProjectCard key={p.id} project={p} />)}
{/* New project CTA card */}
<div
style={{ background: "transparent", border: `1px dashed ${T.parch}`, borderRadius: 14, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, padding: 40, cursor: "pointer", minHeight: 220 }}
onMouseEnter={e => e.currentTarget.style.background = T.cream}
onMouseLeave={e => e.currentTarget.style.background = "transparent"}
>
<div style={{ width: 42, height: 42, borderRadius: 10, border: `1px solid ${T.parch}`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 22, color: T.stone }}>+</div>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>New project</div>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.muted }}>For yourself or a client</div>
</div>
</div>
</div>
{/* Activity feed */}
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, padding: "20px 24px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Recent activity</div>
{ACTIVITY.map((a, i) => (
<div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 0", borderBottom: i < ACTIVITY.length - 1 ? `1px solid ${T.border}` : "none" }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink3, flexShrink: 0 }} />
<div style={{ flex: 1, fontFamily: F.sans, fontSize: 13.5, color: T.ink }}>
{a.text}{" "}{a.detail && <span style={{ color: T.muted }}>{a.detail}</span>}
</div>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.stone, whiteSpace: "nowrap" }}>{a.time}</span>
</div>
))}
</div>
</div>
);
}
// ─── Billing screen ────────────────────────────────────────────────────────────
function BillingScreen() {
const [tab, setTab] = useState("billing");
const unbilled = BILLING_ROWS.filter(r => !r.billed).reduce((s, r) => s + r.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "28px 32px" }}>
{/* Sub-tabs */}
<div style={{ display: "flex", borderBottom: `1px solid ${T.border}`, marginBottom: 28 }}>
{[["billing", "Client billing"], ["costs", "Cost tracker"]].map(([id, label]) => (
<button key={id} onClick={() => setTab(id)} style={{
padding: "10px 18px", border: "none", background: "transparent",
borderBottom: tab === id ? `2px solid ${T.ink}` : "2px solid transparent",
fontFamily: F.sans, fontSize: 13.5, cursor: "pointer",
color: tab === id ? T.ink : T.muted, fontWeight: tab === id ? 600 : 400,
}}>{label}</button>
))}
</div>
{tab === "billing" && <>
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 22 }}>
<div>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Client billing</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>All costs tracked and ready to invoice</p>
</div>
<InkBtn>Generate invoice</InkBtn>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 10, marginBottom: 24 }}>
{[
{ label: "Total unbilled", value: `$${unbilled.toFixed(2)}` },
{ label: "LLM costs", value: "$38.40" },
{ label: "Compute", value: "$14.80" },
{ label: "Other", value: "$7.40" },
].map(c => (
<div key={c.label} style={{ background: T.cream, borderRadius: 10, padding: "14px 16px" }}>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted, marginBottom: 5 }}>{c.label}</div>
<div style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink }}>{c.value}</div>
</div>
))}
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Breakdown by client</span>
<select style={{ border: `1px solid ${T.border}`, borderRadius: 6, padding: "4px 10px", fontFamily: F.sans, fontSize: 12, color: T.muted, background: T.paper, outline: "none" }}>
<option>March 2026</option>
</select>
</div>
<div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Project / Client", "LLM", "Compute", "Other", "Total", "Status"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{BILLING_ROWS.map((r, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "13px 20px", borderBottom: i < BILLING_ROWS.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center", opacity: r.billed ? 0.5 : 1 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 24, height: 24, background: T.ink, borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 10, color: T.paper, fontWeight: 700 }}>{r.initial}</div>
<div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>{r.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>{r.client}</div>
</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.llm.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.compute.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.other.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.total.toFixed(2)}</div>
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
<StatusPill label={r.billed ? "Invoiced" : "Unbilled"} variant={r.billed ? "invoiced" : "unbilled"} />
{!r.billed && (
<button style={{ background: "transparent", border: `1px solid ${T.border2}`, borderRadius: 5, padding: "3px 9px", fontFamily: F.sans, fontSize: 11, color: T.muted, cursor: "pointer" }}>Invoice</button>
)}
</div>
</div>
))}
</div>
</>}
{tab === "costs" && <>
<div style={{ marginBottom: 22 }}>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Cost tracker</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>Every dollar spent, broken down by type and project</p>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 20 }}>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>LLM usage</div>
{[
{ label: "Code generation", amount: 21.40, pct: 56 },
{ label: "Content & marketing", amount: 10.20, pct: 27 },
{ label: "Chat assist", amount: 6.80, pct: 18 },
].map(r => (
<div key={r.label} style={{ marginBottom: 14 }}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 12.5, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
<div style={{ height: 4, background: T.cream, borderRadius: 2, overflow: "hidden" }}>
<div style={{ width: `${r.pct}%`, height: "100%", background: T.ink, borderRadius: 2 }} />
</div>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total LLM</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$38.40</span>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Infrastructure</div>
{[
{ label: "Hosting & compute", amount: 11.60 },
{ label: "Database", amount: 3.20 },
{ label: "Email delivery", amount: 4.20 },
{ label: "Domain & SSL", amount: 3.20 },
].map(r => (
<div key={r.label} style={{ display: "flex", justifyContent: "space-between", padding: "8px 11px", background: T.cream, borderRadius: 7, marginBottom: 7 }}>
<span style={{ fontFamily: F.sans, fontSize: 13, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total infra</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$22.20</span>
</div>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}` }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Recent charges</span>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Time", "Description", "Project", "Cost"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{COST_LOG.map((row, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "11px 20px", borderBottom: i < COST_LOG.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>{row.time}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>{row.desc}</div>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.mid }}>{row.project}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${row.cost.toFixed(2)}</div>
</div>
))}
</div>
</>}
</div>
);
}
// ─── Root ──────────────────────────────────────────────────────────────────────
export default function Dashboard() {
const [screen, setScreen] = useState("projects");
return (
<div style={{ background: T.paper, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
button { font-family: inherit; cursor: pointer; }
input, select { font-family: inherit; }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-thumb { background: ${T.parch}; border-radius: 4px; }
`}</style>
<Nav screen={screen} setScreen={setScreen} />
{screen === "projects" && <ProjectsScreen setScreen={setScreen} />}
{screen === "billing" && <BillingScreen />}
</div>
);
}

View File

@@ -1,288 +0,0 @@
// vibn — Marketing Website
// Design: Ink & parchment — Lora serif + Inter sans, no colour accent
// Usage: <Website onGetStarted={fn} onLogin={fn} />
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Primitives ────────────────────────────────────────────────────────────────
function Eyebrow({ children }) {
return (
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 16 }}>
{children}
</div>
);
}
function PrimaryBtn({ children, onClick, large }) {
return (
<button onClick={onClick} style={{
background: T.ink, color: T.paper, border: "none",
fontFamily: F.sans, fontWeight: 600,
fontSize: large ? 15 : 14,
padding: large ? "14px 34px" : "10px 24px",
borderRadius: 10, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ onGetStarted, onLogin }) {
return (
<nav style={{
background: T.paper, borderBottom: `1px solid ${T.border}`,
padding: "0 48px", height: 60,
display: "flex", alignItems: "center", justifyContent: "space-between",
position: "sticky", top: 0, zIndex: 50,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 30, height: 30, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 19, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", gap: 32 }}>
{["Product", "Pricing", "Stories", "Blog"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>{l}</span>
))}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<span onClick={onLogin} style={{ fontFamily: F.sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>Log in</span>
<PrimaryBtn onClick={onGetStarted}>Get started free</PrimaryBtn>
</div>
</nav>
);
}
// ─── Hero ──────────────────────────────────────────────────────────────────────
function Hero({ onCta }) {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "88px 48px 72px" }}>
<Eyebrow>For non-technical founders</Eyebrow>
<h1 style={{
fontFamily: F.serif, fontSize: 64, fontWeight: 700, color: T.ink,
letterSpacing: "-0.03em", lineHeight: 1.07, marginBottom: 28, maxWidth: 680,
}}>
You have the idea.<br />
We handle<br />
<em style={{ fontStyle: "italic", color: T.ink3 }}>everything else.</em>
</h1>
<p style={{ fontFamily: F.sans, fontSize: 17.5, color: T.mid, lineHeight: 1.75, maxWidth: 480, marginBottom: 40 }}>
No backend. No DevOps. No marketing agency. Describe your idea and vibn
builds, deploys, and promotes it automatically.
</p>
<div style={{ display: "flex", alignItems: "center", gap: 18, marginBottom: 14 }}>
<PrimaryBtn onClick={onCta} large>Start free no code needed</PrimaryBtn>
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.stone }}>&nbsp;&nbsp;280 founders launched</span>
</div>
<p style={{ fontFamily: F.sans, fontSize: 12, color: T.stone }}>No credit card required · Free forever plan</p>
</section>
);
}
// ─── Quote band ────────────────────────────────────────────────────────────────
const QUOTES = [
{ q: "I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing.", by: "Alex K.", role: "Founder, Taskly" },
{ q: "I have zero coding experience. Three weeks in I have 300 paying users. That's entirely because of vibn.", by: "Marcus L.", role: "Founder, Flowmatic" },
{ q: "The marketing autopilot alone saved me ten hours a week. My blog runs itself. I just focus on my product.", by: "Sara R.", role: "Founder, Nudge" },
];
function QuoteBand() {
return (
<section style={{ background: T.ink, padding: "52px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 40 }}>
{QUOTES.map((q, i) => (
<div key={i} style={{ display: "flex", gap: 20 }}>
<div style={{ width: 3, background: T.mid, borderRadius: 2, flexShrink: 0 }} />
<div>
<p style={{ fontFamily: F.serif, fontSize: 15, color: T.parch, lineHeight: 1.72, fontStyle: "italic", marginBottom: 12 }}>"{q.q}"</p>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 600 }}> {q.by}, {q.role}</span>
</div>
</div>
))}
</div>
</section>
);
}
// ─── How it works ──────────────────────────────────────────────────────────────
const PHASES = [
{ n: "01", id: "Discover", title: "Define your idea", body: "Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon." },
{ n: "02", id: "Design", title: "Choose your style", body: "Pick a visual style and see your exact site and emails live before a single line of code is written." },
{ n: "03", id: "Build", title: "Your app, live", body: "AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English." },
{ n: "04", id: "Grow", title: "Market & automate", body: "AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus on your users." },
];
function HowItWorks() {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "80px 48px" }}>
<Eyebrow>How it works</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 40, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", lineHeight: 1.15, marginBottom: 52, maxWidth: 460 }}>
Four phases.<br />One complete product.
</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{PHASES.map((p, i) => (
<div key={i} style={{
padding: "38px 42px", background: T.white,
borderRight: (i % 2 === 0) ? `1px solid ${T.border}` : "none",
borderBottom: (i < 2) ? `1px solid ${T.border}` : "none",
}}>
<div style={{ fontFamily: F.sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: T.muted, marginBottom: 14 }}>
{p.n} {p.id}
</div>
<div style={{ fontFamily: F.serif, fontSize: 21, fontWeight: 700, color: T.ink, marginBottom: 10 }}>{p.title}</div>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.mid, lineHeight: 1.7 }}>{p.body}</p>
</div>
))}
</div>
</section>
);
}
// ─── Stats bar ─────────────────────────────────────────────────────────────────
const STATS = [
{ n: "280+", label: "founders launched" },
{ n: "72h", label: "average time to first version" },
{ n: "4.9★", label: "average rating" },
{ n: "3×", label: "faster than hiring a developer" },
];
function StatsBar() {
return (
<section style={{ background: T.white, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}` }}>
<div style={{ maxWidth: 960, margin: "0 auto", padding: "0 48px", display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
{STATS.map((s, i) => (
<div key={i} style={{ padding: "38px 0", paddingLeft: i > 0 ? 36 : 0, borderRight: i < 3 ? `1px solid ${T.border}` : "none" }}>
<div style={{ fontFamily: F.serif, fontSize: 38, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", marginBottom: 6 }}>{s.n}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>{s.label}</div>
</div>
))}
</div>
</section>
);
}
// ─── Empathy section ───────────────────────────────────────────────────────────
const PAINS = [
{ title: "No more \"I need to hire a developer first\"", body: "vibn is your developer. Start building the moment you have an idea." },
{ title: "No more staring at a blank marketing calendar", body: "AI generates and publishes your content every single week." },
{ title: "No more \"I'll launch when it's ready\"", body: "Most founders ship their first version in under 72 hours." },
];
function EmpathySection() {
return (
<section style={{ background: T.cream, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}`, padding: "76px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 68, alignItems: "center" }}>
<div>
<Eyebrow>Sound familiar?</Eyebrow>
<h2 style={{ fontFamily: F.serif, fontSize: 36, fontWeight: 700, color: T.ink, lineHeight: 1.18, marginBottom: 24, letterSpacing: "-0.02em" }}>
The idea is the hard part. Everything else shouldn't be.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8, marginBottom: 20 }}>
You know exactly what you want to build and who it's for. But the moment you think
about servers, databases, deployment pipelines, SEO strategies the whole thing stalls.
</p>
<p style={{ fontFamily: F.sans, fontSize: 15, color: T.mid, lineHeight: 1.8 }}>
vibn exists to remove all of that. Not abstract it {" "}
<em style={{ fontFamily: F.serif, fontStyle: "italic" }}>remove it entirely.</em>
</p>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
{PAINS.map((p, i) => (
<div key={i} style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px", display: "flex", gap: 14, alignItems: "flex-start" }}>
<div style={{ width: 20, height: 20, borderRadius: "50%", border: `1.5px solid ${T.stone}`, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, marginTop: 2 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink }} />
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>{p.title}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.muted, lineHeight: 1.6 }}>{p.body}</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}
// ─── Final CTA ─────────────────────────────────────────────────────────────────
function FinalCta({ onCta }) {
return (
<section style={{ maxWidth: 660, margin: "0 auto", padding: "92px 48px", textAlign: "center" }}>
<h2 style={{ fontFamily: F.serif, fontSize: 46, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", lineHeight: 1.1, marginBottom: 20 }}>
Your idea deserves to exist.
</h2>
<p style={{ fontFamily: F.sans, fontSize: 16, color: T.mid, lineHeight: 1.75, marginBottom: 36 }}>
Don't let the backend be the reason it doesn't. Start today free, no code, no credit card.
</p>
<PrimaryBtn onClick={onCta} large>Build my product free</PrimaryBtn>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone, marginTop: 16 }}>
Joins 280+ non-technical founders already live
</div>
</section>
);
}
// ─── Footer ────────────────────────────────────────────────────────────────────
function Footer() {
return (
<footer style={{ borderTop: `1px solid ${T.border}`, padding: "32px 48px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>vibn</span>
<div style={{ display: "flex", gap: 28 }}>
{["Product", "Pricing", "Stories", "Blog", "Privacy", "Terms"].map(l => (
<span key={l} style={{ fontFamily: F.sans, fontSize: 13, color: T.stone, cursor: "pointer" }}>{l}</span>
))}
</div>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.stone }}>© 2026 vibn</span>
</footer>
);
}
// ─── Root export ───────────────────────────────────────────────────────────────
export default function Website({ onGetStarted = () => {}, onLogin = () => {} }) {
return (
<div style={{ background: T.paper, color: T.ink, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Inter', sans-serif; }
button { font-family: inherit; }
`}</style>
<Nav onGetStarted={onGetStarted} onLogin={onLogin} />
<Hero onCta={onGetStarted} />
<QuoteBand />
<HowItWorks />
<StatsBar />
<EmpathySection />
<FinalCta onCta={onGetStarted} />
<Footer />
</div>
);
}

View File

@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VIBN Assist Preview</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
{
"name": "preview-assist-ui",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.0",
"vite": "^5.0.0"
}
}

View File

@@ -1,933 +0,0 @@
import { useState, useRef, useEffect } from "react";
import Website from "./Website.jsx";
import Dashboard from "./Dashboard.jsx";
// ─── DESIGN TOKENS ────────────────────────────────────────────────────────────
const C = {
ink: "#0f172a", ink2: "#1e293b", ink3: "#475569", muted: "#94a3b8",
border: "#f1f5f9", border2: "#e2e8f0", surface: "#f8fafc", white: "#fff",
green: "#22c55e", greenBg: "#f0fdf4",
purple: "#6366f1", purpleBg: "#eef2ff",
amber: "#f59e0b", amberBg: "#fffbeb", amberBorder: "#fde68a", amberText: "#92400e",
blue: "#0ea5e9", blueBg: "#f0f9ff",
rose: "#f43f5e", roseBg: "#fff1f2",
teal: "#14b8a6", tealBg: "#f0fdfa",
violet: "#8b5cf6", violetBg: "#f5f3ff",
};
const PHASES = [
{ id: "welcome", label: "Welcome", icon: "◎", desc: "How this works" },
{ id: "discover", label: "Discover", icon: "◇", desc: "Your idea" },
{ id: "architect", label: "Architect", icon: "⬡", desc: "What gets built" },
{ id: "design", label: "Design", icon: "◈", desc: "How it looks" },
{ id: "market", label: "Market", icon: "✦", desc: "How you'll grow" },
{ id: "build", label: "Build MVP", icon: "▲", desc: "Review & launch" },
];
// ─── DISCOVER DATA ────────────────────────────────────────────────────────────
const QUESTIONS = [
{ key: "idea", q: "Tell me about your idea. What does it do and who is it for?" },
{ key: "problem", q: "What's the painful thing your users are doing today instead?" },
{ key: "users", q: "Describe your ideal first customer in one sentence." },
{ key: "value", q: "What's the one thing they'll love most about your product?" },
{ key: "revenue", q: "How will you charge for it? Subscription, one-time, or free to start?" },
{ key: "features", q: "Name the 3 things users must be able to do in version one." },
];
// ─── ARCHITECT DATA ───────────────────────────────────────────────────────────
const ARCH_BLOCKS = [
{ id: "frontend", icon: "◇", label: "Frontend", color: C.purple, bg: C.purpleBg, chosen: "Web app", what: "The screens your users see — dashboard, sign up, settings, and everything in between. Works on desktop and mobile.", alts: [{ id: "webapp", label: "Web app", desc: "Runs in any browser, desktop & mobile" }, { id: "mobile", label: "Mobile-first", desc: "Optimised for phones, still works on desktop" }] },
{ id: "backend", icon: "⬡", label: "Backend & Database", color: C.blue, bg: C.blueBg, chosen: "API + database", what: "The engine behind the scenes. Stores all your data securely and runs your product's logic.", alts: [{ id: "api_pg", label: "API + database", desc: "Standard setup, works for almost everything" }, { id: "realtime", label: "Real-time", desc: "If your product needs live updates between users" }] },
{ id: "auth", icon: "◎", label: "Sign up & Login", color: C.rose, bg: C.roseBg, chosen: "Email + social login", what: "How your users create accounts and log in. Getting this right reduces drop-off at the first step.", alts: [{ id: "email_social", label: "Email + social login", desc: "Email/password plus Google & GitHub — recommended" }, { id: "email_only", label: "Email & password only", desc: "Simpler, no third-party login" }, { id: "magic_link", label: "Magic link", desc: "No password — users get a login link by email" }, { id: "sso", label: "SSO for teams", desc: "If you're selling to companies, not individuals" }] },
{ id: "payments", icon: "◈", label: "Payments", color: C.amber, bg: C.amberBg, chosen: "Subscription billing", what: "How you collect money from customers. Set up now so you're ready to charge from day one.", alts: [{ id: "subscription", label: "Subscription billing", desc: "Monthly or annual plans — recommended for SaaS" }, { id: "one_time", label: "One-time purchase", desc: "Pay once, own forever" }, { id: "usage", label: "Usage-based", desc: "Charge based on what users consume" }, { id: "free", label: "Free for now", desc: "No payments yet — add billing later" }] },
{ id: "email", icon: "✦", label: "Email", color: C.teal, bg: C.tealBg, chosen: "Transactional + marketing", what: "Emails sent to your users — welcome messages, password resets, and newsletters when you're ready.", alts: [{ id: "both", label: "Transactional + marketing", desc: "Welcome emails, resets, plus campaign capability" }, { id: "trans", label: "Transactional only", desc: "Just the essential emails, nothing more" }, { id: "none", label: "None for now", desc: "Skip email entirely — add it later" }] },
{ id: "hosting", icon: "▲", label: "Hosting", color: C.violet, bg: C.violetBg, chosen: "Your own servers", what: "Where your product lives. Deployed to your own infrastructure — you own everything, no lock-in.", alts: [{ id: "own", label: "Your own servers", desc: "Coolify + Gitea — already configured" }], locked: true },
];
const PAGES_GENERATED = [
{ group: "Public", color: C.purple, pages: ["Landing page", "Pricing", "About", "Blog"] },
{ group: "Auth", color: C.rose, pages: ["Sign up", "Log in", "Forgot password"] },
{ group: "App", color: C.blue, pages: ["Dashboard", "Onboarding", "Settings", "Invite team"] },
{ group: "Payments", color: C.amber, pages: ["Checkout", "Success", "Manage subscription"] },
];
// ─── DESIGN DATA ──────────────────────────────────────────────────────────────
// Production presets live in vibn-frontend/lib/design-kits/registry.ts (STARTER_KITS).
const DESIGN_FEELS = [
{ id: "clean", label: "Clean & focused", ref: "Like Notion or Linear", bg: "#fff", surface: "#f8fafc", text: "#0f172a", accent: "#6366f1", radius: 8 },
{ id: "bold", label: "Bold & confident", ref: "Like Stripe or Vercel", bg: "#0f172a", surface: "#1e293b", text: "#f8fafc", accent: "#f43f5e", radius: 8 },
{ id: "warm", label: "Warm & friendly", ref: "Like Mailchimp or Basecamp", bg: "#fffbeb", surface: "#fef3c7", text: "#78350f", accent: "#f59e0b", radius: 14 },
{ id: "fresh", label: "Fresh & modern", ref: "Like Loom or Superhuman", bg: "#f0fdf4", surface: "#dcfce7", text: "#14532d", accent: "#22c55e", radius: 10 },
{ id: "electric", label: "Electric & vivid", ref: "Like Figma or Framer", bg: "#faf5ff", surface: "#ede9fe", text: "#4c1d95", accent: "#8b5cf6", radius: 8 },
{ id: "luxury", label: "Premium & refined", ref: "Like Linear or Craft", bg: "#0c0a09", surface: "#1c1917", text: "#f5f5f4", accent: "#d4a853", radius: 6 },
];
// ─── MARKET DATA ─────────────────────────────────────────────────────────────
const VOICE_OPTIONS = [
{ key: "tone", label: "Tone", a: "Friendly & approachable", b: "Professional & authoritative" },
{ key: "style", label: "Style", a: "Conversational & casual", b: "Precise & concise" },
{ key: "personality", label: "Personality", a: "Warm & encouraging", b: "Direct & confident" },
];
const SUGGESTED_TOPICS = () => [
{ id: "t1", title: "The problem we're solving", angle: "Show users you deeply understand their pain before pitching your solution.", channels: ["Blog", "Tweet thread", "LinkedIn", "Email"] },
{ id: "t2", title: "Who this is built for", angle: "Paint a picture of your ideal user — they should read it and think 'that's me'.", channels: ["Blog", "LinkedIn", "Website section"] },
{ id: "t3", title: "Why now is the right time", angle: "What's changed in the market that makes this product possible or necessary?", channels: ["Blog", "Tweet thread", "Email"] },
];
const WEBSITE_FEELS = [
{ id: "editorial", label: "Editorial", ref: "Bold headlines, strong opinions", bg: "#fff", accent: "#ef4444" },
{ id: "startup", label: "Startup energy", ref: "Clear, conversion-focused", bg: "#f8fafc", accent: "#0ea5e9" },
{ id: "minimal", label: "Ultra minimal", ref: "Let the product speak", bg: "#fff", accent: "#111" },
{ id: "warm_w", label: "Warm & human", ref: "Feels personal and trustworthy", bg: "#fff7ed", accent: "#ea580c" },
];
// ─── SHARED UI ────────────────────────────────────────────────────────────────
function PhaseHeader({ title, desc, action }) {
return (
<div style={{ padding: "22px 32px 18px", background: C.white, borderBottom: `1px solid ${C.border}`, display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0 }}>
<div>
<div style={{ fontSize: 18, fontWeight: 800, color: C.ink, letterSpacing: "-0.03em" }}>{title}</div>
{desc && <div style={{ fontSize: 13, color: C.muted, marginTop: 2 }}>{desc}</div>}
</div>
{action}
</div>
);
}
function ContinueBtn({ label, onClick, disabled }) {
return (
<button onClick={onClick} disabled={disabled}
style={{ background: disabled ? C.border2 : C.ink, color: disabled ? C.muted : C.white, border: "none", borderRadius: 10, padding: "11px 22px", fontSize: 13.5, fontWeight: 700, cursor: disabled ? "default" : "pointer", letterSpacing: "-0.01em", transition: "all 0.2s" }}>
{label}
</button>
);
}
// ─── LIVE APP MOCKUP ──────────────────────────────────────────────────────────
function AppMockup({ feel }) {
const t = DESIGN_FEELS.find((f) => f.id === feel) || DESIGN_FEELS[0];
const isDark = t.bg === "#0f172a" || t.bg === "#0c0a09";
const border = isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)";
return (
<div style={{ width: "100%", height: "100%", background: t.bg, borderRadius: 10, overflow: "hidden", display: "flex", flexDirection: "column", transition: "all 0.4s", fontFamily: "DM Sans, sans-serif" }}>
<div style={{ padding: "10px 16px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: `1px solid ${border}`, flexShrink: 0 }}>
<div style={{ fontSize: 13, fontWeight: 800, color: t.text, letterSpacing: "-0.03em" }}>YourApp</div>
<div style={{ display: "flex", gap: 12 }}>{["Dashboard", "Settings", "Billing"].map((l) => <span key={l} style={{ fontSize: 10, color: t.text, opacity: 0.45 }}>{l}</span>)}</div>
<div style={{ background: t.accent, color: "#fff", fontSize: 10, fontWeight: 700, padding: "4px 10px", borderRadius: t.radius / 1.5 }}>Upgrade</div>
</div>
<div style={{ flex: 1, padding: "14px", overflow: "hidden", display: "flex", flexDirection: "column", gap: 10 }}>
<div style={{ fontSize: 12, fontWeight: 700, color: t.text, opacity: 0.8 }}>Dashboard</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 7 }}>
{[["Users", "182"], ["Revenue", "$2.4k"], ["Active", "94%"]].map(([l, v], i) => (
<div key={l} style={{ background: t.surface, borderRadius: t.radius / 1.5, padding: "9px 11px", border: `1px solid ${border}` }}>
<div style={{ fontSize: 9, color: t.text, opacity: 0.45, marginBottom: 4 }}>{l}</div>
<div style={{ fontSize: 15, fontWeight: 800, color: i === 1 ? t.accent : t.text }}>{v}</div>
</div>
))}
</div>
<div style={{ background: t.surface, borderRadius: t.radius / 1.5, padding: "10px 12px", border: `1px solid ${border}`, flex: 1 }}>
<div style={{ fontSize: 9, color: t.text, opacity: 0.4, marginBottom: 8 }}>Recent activity</div>
{["Alex signed up · 2m ago", "Priya upgraded to Pro · 1h ago", "Dan invited 3 teammates · 3h ago"].map((item, i) => (
<div key={i} style={{ display: "flex", alignItems: "center", gap: 7, padding: "5px 0", borderBottom: i < 2 ? `1px solid ${border}` : "none" }}>
<div style={{ width: 5, height: 5, borderRadius: "50%", background: t.accent, flexShrink: 0 }} />
<span style={{ fontSize: 10, color: t.text, opacity: 0.65 }}>{item}</span>
</div>
))}
</div>
</div>
</div>
);
}
// ─── PHASE: WELCOME ───────────────────────────────────────────────────────────
function WelcomePhase({ onStart }) {
const steps = [
{ icon: "◇", label: "You describe your idea", desc: "A short conversation — no technical knowledge needed." },
{ icon: "⬡", label: "We plan what gets built", desc: "AI maps out your full product architecture in plain language." },
{ icon: "◈", label: "You choose how it looks", desc: "Pick a visual style for your product and marketing." },
{ icon: "✦", label: "You set your market angle", desc: "Define your voice and the topics that'll drive your content." },
{ icon: "▲", label: "We build it", desc: "AI codes everything and deploys to your live URL." },
];
return (
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", padding: "40px" }}>
<div style={{ maxWidth: 540, width: "100%" }}>
<div style={{ marginBottom: 36 }}>
<div style={{ display: "inline-flex", alignItems: "center", gap: 8, background: C.purpleBg, border: "1px solid #c7d2fe", borderRadius: 20, padding: "5px 14px", marginBottom: 20 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: C.green, animation: "vpulse 2s infinite" }} />
<span style={{ fontSize: 12, fontWeight: 600, color: C.purple }}>vibn · MVP Builder</span>
</div>
<div style={{ fontSize: 32, fontWeight: 800, color: C.ink, letterSpacing: "-0.04em", lineHeight: 1.15, marginBottom: 14 }}>
From idea to live product.<br />No code needed.
</div>
<div style={{ fontSize: 15, color: C.ink3, lineHeight: 1.7, maxWidth: 440 }}>
Answer a few questions about your idea. AI plans, designs, and builds your full SaaS product then deploys it to your own servers. Takes about 10 minutes to set up.
</div>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 32 }}>
{steps.map((s, i) => (
<div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 14, padding: "14px 16px", background: C.white, borderRadius: 12, border: `1px solid ${C.border2}` }}>
<div style={{ width: 32, height: 32, borderRadius: 9, background: C.surface, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 14, color: C.ink3, flexShrink: 0, border: `1px solid ${C.border2}` }}>{s.icon}</div>
<div>
<div style={{ fontSize: 13.5, fontWeight: 700, color: C.ink, marginBottom: 2 }}>{s.label}</div>
<div style={{ fontSize: 12.5, color: C.muted, lineHeight: 1.5 }}>{s.desc}</div>
</div>
</div>
))}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 14 }}>
<button onClick={onStart} style={{ background: C.ink, color: C.white, border: "none", borderRadius: 12, padding: "14px 32px", fontSize: 15, fontWeight: 800, cursor: "pointer", letterSpacing: "-0.02em" }}>
Let's build it →
</button>
<span style={{ fontSize: 12.5, color: C.muted }}>~10 minutes · You own everything at the end</span>
</div>
</div>
</div>
);
}
// ─── PHASE: DISCOVER ─────────────────────────────────────────────────────────
function DiscoverPhase({ onComplete }) {
const [step, setStep] = useState(0);
const [answers, setAnswers] = useState({});
const [input, setInput] = useState("");
const [msgs, setMsgs] = useState([{ role: "assistant", text: "Let's start with the big picture.\n\n" + QUESTIONS[0].q }]);
const [done, setDone] = useState(false);
const bottomRef = useRef(null);
useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }, [msgs]);
const acks = { idea: "Good I can work with that.", problem: "That's a real pain worth solving.", users: "Clear. That focus will shape everything.", value: "Strong differentiator.", revenue: "Makes sense for this type of product." };
const send = () => {
if (!input.trim()) return;
const val = input.trim(); setInput("");
const q = QUESTIONS[step];
const newA = { ...answers, [q.key]: val };
setAnswers(newA);
setMsgs((m) => [...m, { role: "user", text: val }]);
setTimeout(() => {
const next = step + 1;
if (next < QUESTIONS.length) {
setStep(next);
setMsgs((m) => [...m, { role: "assistant", text: `${acks[q.key] || "Got it."}\n\n${QUESTIONS[next].q}` }]);
} else {
setMsgs((m) => [...m, { role: "assistant", text: "That's all I need.\n\nI've drafted your product plan on the right. Have a read — if it looks right, let's move on to planning what gets built." }]);
setDone(true);
}
}, 400);
};
return (
<div style={{ display: "flex", height: "100%", overflow: "hidden" }}>
<div style={{ flex: 1, display: "flex", flexDirection: "column", borderRight: `1px solid ${C.border}` }}>
<PhaseHeader title="Discover" desc="Tell me about your idea I'll turn it into a product plan" />
<div style={{ padding: "0 32px 12px", background: C.white, borderBottom: `1px solid ${C.border}` }}>
<div style={{ display: "flex", gap: 4 }}>
{QUESTIONS.map((_, i) => <div key={i} style={{ flex: 1, height: 3, borderRadius: 3, background: i < step ? C.ink : i === step ? C.purple : C.border2, transition: "background 0.3s" }} />)}
</div>
</div>
<div style={{ flex: 1, overflowY: "auto", padding: "24px 32px", display: "flex", flexDirection: "column", gap: 14 }}>
{msgs.map((msg, i) => (
<div key={i} style={{ display: "flex", flexDirection: "column", alignItems: msg.role === "user" ? "flex-end" : "flex-start" }}>
<div style={{ maxWidth: "80%", background: msg.role === "user" ? C.ink : C.surface, color: msg.role === "user" ? C.white : C.ink2, borderRadius: msg.role === "user" ? "14px 14px 4px 14px" : "14px 14px 14px 4px", padding: "12px 16px", fontSize: 13.5, lineHeight: 1.65, border: msg.role === "assistant" ? `1px solid ${C.border2}` : "none", whiteSpace: "pre-line" }}>{msg.text}</div>
</div>
))}
<div ref={bottomRef} />
</div>
<div style={{ padding: "14px 32px 24px", borderTop: `1px solid ${C.border}`, background: C.white }}>
{!done
? <div style={{ display: "flex", gap: 8, background: C.surface, border: `1px solid ${C.border2}`, borderRadius: 12, padding: "10px 14px" }}>
<input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} placeholder="Type your answer…" style={{ flex: 1, border: "none", background: "transparent", fontSize: 14, color: C.ink, outline: "none" }} autoFocus />
<button onClick={send} style={{ background: C.ink, color: C.white, border: "none", borderRadius: 8, padding: "8px 16px", fontSize: 13, fontWeight: 700, cursor: "pointer" }}>→</button>
</div>
: <button onClick={() => onComplete(answers)} style={{ width: "100%", background: C.ink, color: C.white, border: "none", borderRadius: 10, padding: "13px", fontSize: 14, fontWeight: 700, cursor: "pointer" }}>Plan looks good — next: Architect →</button>
}
</div>
</div>
<div style={{ width: 280, overflowY: "auto", background: C.surface, padding: "22px 18px", display: "flex", flexDirection: "column", gap: 8 }}>
<div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", color: C.muted, marginBottom: 4 }}>Your product plan</div>
{QUESTIONS.map((q, i) => (
<div key={i} style={{ padding: "11px 13px", background: C.white, borderRadius: 10, border: `1px solid ${i < step ? C.border2 : C.border}`, opacity: i > step ? 0.35 : 1, transition: "all 0.3s" }}>
<div style={{ fontSize: 10, fontWeight: 700, color: i <= step ? C.purple : C.muted, letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: 3 }}>{q.key}</div>
<div style={{ fontSize: 12.5, color: i < step ? C.ink2 : C.muted, lineHeight: 1.5 }}>{answers[q.key] || "Waiting…"}</div>
</div>
))}
</div>
</div>
);
}
// ─── PHASE: ARCHITECT ─────────────────────────────────────────────────────────
function ArchCard({ block, label, onEdit }) {
return (
<div style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, overflow: "hidden", display: "flex", flexDirection: "column" }}
onMouseEnter={(e) => (e.currentTarget.style.boxShadow = "0 4px 20px rgba(0,0,0,0.07)")}
onMouseLeave={(e) => (e.currentTarget.style.boxShadow = "none")}>
<div style={{ height: 3, background: block.color, opacity: 0.6 }} />
<div style={{ padding: "16px 18px", flex: 1 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 10 }}>
<div style={{ width: 34, height: 34, borderRadius: 9, background: block.bg, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16, color: block.color, flexShrink: 0 }}>{block.icon}</div>
<div style={{ fontSize: 13.5, fontWeight: 700, color: C.ink }}>{block.label}</div>
</div>
<div style={{ fontSize: 12.5, color: C.ink3, lineHeight: 1.65, marginBottom: 14 }}>{block.what}</div>
<div style={{ display: "inline-flex", alignItems: "center", gap: 6, background: block.bg, borderRadius: 20, padding: "5px 11px" }}>
<div style={{ width: 6, height: 6, borderRadius: "50%", background: block.color }} />
<span style={{ fontSize: 12, fontWeight: 600, color: block.color }}>{label}</span>
</div>
</div>
<div style={{ padding: "10px 18px", borderTop: `1px solid ${C.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontSize: 11.5, color: C.muted }}>{block.locked ? "Required for your setup" : "AI recommended this"}</span>
<button onClick={onEdit} style={{ fontSize: 12, fontWeight: 600, color: block.locked ? C.muted : C.ink3, background: "transparent", border: `1px solid ${C.border2}`, borderRadius: 7, padding: "5px 11px", cursor: "pointer" }}>{block.locked ? "Why? →" : "Change →"}</button>
</div>
</div>
);
}
function ArchitectPhase({ onComplete }) {
const [choices, setChoices] = useState(() => Object.fromEntries(ARCH_BLOCKS.map((b) => [b.id, b.alts[0].id])));
const [editing, setEditing] = useState(null);
const editBlock = ARCH_BLOCKS.find((b) => b.id === editing);
const save = (id, val) => { setChoices((c) => ({ ...c, [id]: val })); setEditing(null); };
const choiceLabel = (block) => block.alts.find((a) => a.id === choices[block.id])?.label || block.alts[0].label;
return (
<div style={{ display: "flex", height: "100%", overflow: "hidden" }}>
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
<PhaseHeader title="Architect" desc="Here's what we're going to build. AI has made smart choices — change anything that doesn't feel right."
action={<ContinueBtn label="Confirm next: Design " onClick={() => onComplete(choices)} />} />
<div style={{ flex: 1, overflowY: "auto", padding: "24px 32px" }}>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 14, marginBottom: 14 }}>
{ARCH_BLOCKS.slice(0, 3).map((b) => <ArchCard key={b.id} block={b} label={choiceLabel(b)} onEdit={() => setEditing(b.id)} />)}
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 14 }}>
{ARCH_BLOCKS.slice(3).map((b) => <ArchCard key={b.id} block={b} label={choiceLabel(b)} onEdit={() => setEditing(b.id)} />)}
</div>
</div>
</div>
<div style={{ width: 250, borderLeft: `1px solid ${C.border}`, background: C.white, overflowY: "auto", padding: "22px 18px", flexShrink: 0 }}>
<div style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", color: C.muted, marginBottom: 16 }}>Pages to build</div>
{PAGES_GENERATED.map((g) => (
<div key={g.group}>
<div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 7 }}>
<div style={{ width: 6, height: 6, borderRadius: "50%", background: g.color }} />
<div style={{ fontSize: 10, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: C.muted }}>{g.group}</div>
</div>
{g.pages.map((p) => (
<div key={p} style={{ display: "flex", alignItems: "center", gap: 8, padding: "7px 10px", background: C.surface, borderRadius: 7, border: `1px solid ${C.border}`, marginBottom: 4, fontSize: 12.5, color: C.ink3 }}>
<div style={{ width: 5, height: 5, borderRadius: "50%", background: g.color, opacity: 0.5, flexShrink: 0 }} />{p}
</div>
))}
</div>
))}
<div style={{ marginTop: 18, padding: "13px", background: C.violetBg, border: "1px solid #ddd6fe", borderRadius: 11 }}>
<div style={{ fontSize: 12, fontWeight: 700, color: C.violet, marginBottom: 4 }}>◉ Your infrastructure</div>
<div style={{ fontSize: 12, color: "#5b21b6", lineHeight: 1.6 }}>Code pushed to Gitea. Coolify auto-deploys. You own everything.</div>
</div>
</div>
{editing && editBlock && (
<div style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,0.5)", zIndex: 600, display: "flex", alignItems: "center", justifyContent: "center", backdropFilter: "blur(4px)", animation: "fadeIn 0.15s" }}>
<div style={{ background: C.white, borderRadius: 18, width: 420, boxShadow: "0 24px 60px rgba(0,0,0,0.2)", overflow: "hidden", animation: "slideup 0.2s" }}>
<div style={{ padding: "20px 24px", borderBottom: `1px solid ${C.border}`, display: "flex", alignItems: "center", gap: 12 }}>
<div style={{ width: 36, height: 36, borderRadius: 10, background: editBlock.bg, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16, color: editBlock.color, flexShrink: 0 }}>{editBlock.icon}</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 15, fontWeight: 700, color: C.ink }}>{editBlock.label}</div>
<div style={{ fontSize: 12, color: C.muted, lineHeight: 1.5 }}>{editBlock.what}</div>
</div>
<button onClick={() => setEditing(null)} style={{ background: "transparent", border: "none", color: C.muted, cursor: "pointer", fontSize: 20 }}>×</button>
</div>
<div style={{ padding: "16px 24px", display: "flex", flexDirection: "column", gap: 8 }}>
{editBlock.alts.map((alt) => {
const isSel = choices[editBlock.id] === alt.id;
return (
<button key={alt.id} onClick={() => !editBlock.locked && setChoices((c) => ({ ...c, [editBlock.id]: alt.id }))}
style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 16px", borderRadius: 11, border: isSel ? `2px solid ${editBlock.color}` : `1px solid ${C.border2}`, background: isSel ? editBlock.bg : C.white, cursor: editBlock.locked ? "default" : "pointer", textAlign: "left", transition: "all 0.15s" }}>
<div style={{ width: 18, height: 18, borderRadius: "50%", border: `2px solid ${isSel ? editBlock.color : C.border2}`, background: isSel ? editBlock.color : "transparent", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
{isSel && <div style={{ width: 6, height: 6, borderRadius: "50%", background: C.white }} />}
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13.5, fontWeight: isSel ? 700 : 500, color: C.ink }}>{alt.label}</div>
<div style={{ fontSize: 12, color: C.muted }}>{alt.desc}</div>
</div>
</button>
);
})}
</div>
<div style={{ padding: "10px 24px 20px", display: "flex", gap: 8 }}>
<button onClick={() => setEditing(null)} style={{ flex: 1, background: C.surface, color: C.ink3, border: `1px solid ${C.border2}`, borderRadius: 10, padding: "11px", fontSize: 13, cursor: "pointer" }}>Cancel</button>
<button onClick={() => save(editing, choices[editing])} style={{ flex: 2, background: C.ink, color: C.white, border: "none", borderRadius: 10, padding: "11px", fontSize: 13, fontWeight: 700, cursor: "pointer" }}>Save</button>
</div>
</div>
</div>
)}
</div>
);
}
// ─── PHASE: DESIGN ────────────────────────────────────────────────────────────
function DesignPhase({ onComplete }) {
const [feel, setFeel] = useState("clean");
return (
<div style={{ display: "flex", height: "100%", overflow: "hidden" }}>
<div style={{ width: 280, borderRight: `1px solid ${C.border}`, display: "flex", flexDirection: "column", overflow: "hidden", background: C.white }}>
<PhaseHeader title="Design" desc="How should your product feel?" />
<div style={{ flex: 1, overflowY: "auto", padding: "20px 20px", display: "flex", flexDirection: "column", gap: 8 }}>
<div style={{ fontSize: 11.5, color: C.muted, lineHeight: 1.6, marginBottom: 8, padding: "0 2px" }}>
Pick the feeling you want users to get. You can refine every detail after launch — this sets the foundation.
</div>
{DESIGN_FEELS.map((f) => {
const isDark = f.bg === "#0f172a" || f.bg === "#0c0a09";
const isSel = feel === f.id;
return (
<button key={f.id} onClick={() => setFeel(f.id)}
style={{ borderRadius: 12, border: isSel ? `2px solid ${C.ink}` : `1px solid ${C.border2}`, overflow: "hidden", cursor: "pointer", textAlign: "left", transition: "all 0.15s", background: f.bg, padding: 0, boxShadow: isSel ? "0 2px 16px rgba(0,0,0,0.1)" : "none" }}>
<div style={{ padding: "12px 14px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
<div style={{ fontSize: 13.5, fontWeight: 700, color: f.text }}>{f.label}</div>
{isSel && <span style={{ color: C.green, fontSize: 13, fontWeight: 900 }}>✓</span>}
</div>
<div style={{ fontSize: 11.5, color: f.text, opacity: 0.55 }}>{f.ref}</div>
<div style={{ display: "flex", gap: 5, marginTop: 10 }}>
{[f.bg, f.accent, f.surface].map((col, i) => <div key={i} style={{ width: 14, height: 14, borderRadius: "50%", background: col, border: `1.5px solid ${isDark ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.1)"}` }} />)}
</div>
</div>
{isSel && <div style={{ height: 3, background: f.accent }} />}
</button>
);
})}
</div>
<div style={{ padding: "14px 20px 20px", borderTop: `1px solid ${C.border}` }}>
<button onClick={() => onComplete({ feel })} style={{ width: "100%", background: C.ink, color: C.white, border: "none", borderRadius: 10, padding: "12px", fontSize: 13.5, fontWeight: 700, cursor: "pointer" }}>
Looks good — next: Market →
</button>
</div>
</div>
<div style={{ flex: 1, background: "#dde3ea", display: "flex", flexDirection: "column" }}>
<div style={{ padding: "11px 18px", background: C.white, borderBottom: `1px solid ${C.border}`, display: "flex", alignItems: "center", gap: 8 }}>
<div style={{ display: "flex", gap: 5 }}>{["#f43f5e", "#f59e0b", "#22c55e"].map((c) => <div key={c} style={{ width: 10, height: 10, borderRadius: "50%", background: c }} />)}</div>
<span style={{ fontFamily: "monospace", fontSize: 11.5, color: C.muted }}>app.yourproduct.com</span>
<span style={{ marginLeft: "auto", fontSize: 11.5, fontWeight: 600, color: C.ink3 }}>{DESIGN_FEELS.find((f) => f.id === feel)?.label}</span>
</div>
<div style={{ flex: 1, padding: 28, overflow: "hidden" }}>
<AppMockup feel={feel} />
</div>
</div>
</div>
);
}
// ─── PHASE: MARKET ────────────────────────────────────────────────────────────
function WebsitePreview({ feel }) {
const t = WEBSITE_FEELS.find((f) => f.id === feel) || WEBSITE_FEELS[0];
const isDark = t.bg === "#0c0a09" || t.bg === "#0f172a";
const border = isDark ? "rgba(255,255,255,0.07)" : "rgba(0,0,0,0.06)";
const textCol = isDark ? "#fff" : (t.text || C.ink);
return (
<div style={{ width: "100%", height: "100%", background: t.bg, borderRadius: 10, overflow: "hidden", fontFamily: "DM Sans, sans-serif", display: "flex", flexDirection: "column", transition: "all 0.4s" }}>
<div style={{ padding: "11px 18px", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: `1px solid ${border}` }}>
<div style={{ fontSize: 13, fontWeight: 800, color: textCol }}>YourApp</div>
<div style={{ display: "flex", gap: 14 }}>{["Product", "Blog", "Pricing"].map((l) => <span key={l} style={{ fontSize: 10, color: isDark ? "rgba(255,255,255,0.4)" : C.muted }}>{l}</span>)}</div>
<div style={{ background: t.accent, color: isDark && t.accent === "#d4a853" ? "#0c0a09" : "#fff", fontSize: 10, fontWeight: 700, padding: "5px 11px", borderRadius: 6 }}>Get started</div>
</div>
<div style={{ flex: 1, padding: "22px 20px", display: "flex", flexDirection: "column", alignItems: "center", gap: 14 }}>
<div style={{ textAlign: "center", maxWidth: 320 }}>
<div style={{ fontSize: 22, fontWeight: 800, color: textCol, letterSpacing: "-0.04em", lineHeight: 1.2, marginBottom: 8 }}>Launch your SaaS in days, not months</div>
<div style={{ fontSize: 12, color: isDark ? "rgba(255,255,255,0.45)" : C.muted, lineHeight: 1.65, marginBottom: 16 }}>Describe your idea. AI builds, deploys, and markets your product automatically.</div>
<div style={{ display: "flex", gap: 8, justifyContent: "center" }}>
<div style={{ background: t.accent, color: "#fff", fontSize: 12, fontWeight: 700, padding: "9px 18px", borderRadius: 7 }}>Start free</div>
<div style={{ background: "transparent", color: isDark ? "rgba(255,255,255,0.6)" : C.ink3, fontSize: 12, padding: "9px 14px", borderRadius: 7, border: `1px solid ${border}` }}>See demo</div>
</div>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, width: "100%" }}>
{[["", "Build", "AI writes every line"], ["", "Grow", "Content on autopilot"], ["", "Launch", "Live in minutes"]].map(([ic, lb, desc]) => (
<div key={lb} style={{ background: isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.03)", borderRadius: 8, padding: "12px 10px", border: `1px solid ${border}`, textAlign: "center" }}>
<div style={{ fontSize: 16, marginBottom: 5 }}>{ic}</div>
<div style={{ fontSize: 11, fontWeight: 700, color: textCol, marginBottom: 3 }}>{lb}</div>
<div style={{ fontSize: 10, color: isDark ? "rgba(255,255,255,0.35)" : C.muted }}>{desc}</div>
</div>
))}
</div>
</div>
</div>
);
}
function MarketPhase({ prd, onComplete }) {
const [tab, setTab] = useState("voice");
const [voice, setVoice] = useState({ tone: 0.3, style: 0.4, personality: 0.3 });
const [topics, setTopics] = useState(SUGGESTED_TOPICS());
const [editingTopic, setEditingTopic] = useState(null);
const [websiteFeel, setWebsiteFeel] = useState("startup");
const tabs = ["voice", "topics", "style"];
const tabLabels = { voice: "Voice", topics: "Topics", style: "Website style" };
const voiceDesc = (key, val) => { const opt = VOICE_OPTIONS.find((v) => v.key === key); return val < 0.4 ? opt.a : val > 0.6 ? opt.b : "Balanced"; };
const addTopic = () => { const id = `t${Date.now()}`; setTopics((t) => [...t, { id, title: "", angle: "", channels: ["Blog", "Email"], editing: true }]); setEditingTopic(id); };
const updateTopic = (id, field, val) => setTopics((t) => t.map((tp) => (tp.id === id ? { ...tp, [field]: val } : tp)));
const removeTopic = (id) => setTopics((t) => t.filter((tp) => tp.id !== id));
return (
<div style={{ display: "flex", height: "100%", overflow: "hidden", flexDirection: "column" }}>
<PhaseHeader title="Market" desc="Set your brand voice, campaign topics, and website style AI uses these to generate all your content."
action={<ContinueBtn label="Done review & build " onClick={() => onComplete({ voice, topics, websiteFeel })} />} />
<div style={{ display: "flex", borderBottom: `1px solid ${C.border}`, background: C.white, flexShrink: 0 }}>
{tabs.map((t) => (
<button key={t} onClick={() => setTab(t)} style={{ padding: "12px 24px", border: "none", background: "transparent", borderBottom: tab === t ? `2px solid ${C.ink}` : "2px solid transparent", cursor: "pointer", fontSize: 13.5, fontWeight: tab === t ? 700 : 400, color: tab === t ? C.ink : C.muted, transition: "all 0.15s", display: "flex", alignItems: "center", gap: 7 }}>
{tabLabels[t]}
{t === "topics" && <span style={{ fontSize: 11, background: C.surface, border: `1px solid ${C.border2}`, borderRadius: 10, padding: "1px 7px", color: C.ink3 }}>{topics.length}</span>}
</button>
))}
</div>
<div style={{ flex: 1, overflow: "hidden", display: "flex" }}>
{tab === "voice" && (
<div style={{ flex: 1, overflowY: "auto", padding: "32px", display: "flex", justifyContent: "center" }}>
<div style={{ width: "100%", maxWidth: 520 }}>
<div style={{ fontSize: 14, color: C.ink3, lineHeight: 1.7, marginBottom: 28 }}>This defines how your brand sounds — in emails, on your website, in social posts. AI uses this to write content that sounds like you.</div>
<div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
{VOICE_OPTIONS.map((opt) => (
<div key={opt.key} style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, padding: "20px 24px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 16 }}>
<div style={{ fontSize: 13, fontWeight: 700, color: C.ink }}>{opt.label}</div>
<div style={{ fontSize: 12.5, fontWeight: 600, color: C.purple, background: C.purpleBg, borderRadius: 20, padding: "3px 11px" }}>{voiceDesc(opt.key, voice[opt.key])}</div>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 10 }}>
<span style={{ fontSize: 12, color: C.ink3, width: 140, textAlign: "right", lineHeight: 1.4 }}>{opt.a}</span>
<input type="range" min="0" max="1" step="0.05" value={voice[opt.key]} onChange={(e) => setVoice((v) => ({ ...v, [opt.key]: parseFloat(e.target.value) }))} style={{ flex: 1, accentColor: C.ink, cursor: "pointer" }} />
<span style={{ fontSize: 12, color: C.ink3, width: 140, lineHeight: 1.4 }}>{opt.b}</span>
</div>
</div>
))}
</div>
<div style={{ marginTop: 24, padding: "16px 20px", background: C.surface, borderRadius: 12, border: `1px solid ${C.border2}` }}>
<div style={{ fontSize: 11, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.07em", marginBottom: 6 }}>How your brand will sound</div>
<div style={{ fontSize: 13.5, color: C.ink2, lineHeight: 1.7 }}>
{voice.tone < 0.4 ? "Warm and approachable" : voice.tone > 0.6 ? "Professional and authoritative" : "Balanced"}
{" · "}{voice.style < 0.4 ? "conversational" : voice.style > 0.6 ? "precise" : "clear"}
{" · "}{voice.personality < 0.4 ? "encouraging" : voice.personality > 0.6 ? "direct" : "steady"}
</div>
</div>
</div>
</div>
)}
{tab === "topics" && (
<div style={{ flex: 1, overflowY: "auto", padding: "28px 32px" }}>
<div style={{ maxWidth: 640 }}>
<div style={{ fontSize: 14, color: C.ink3, lineHeight: 1.7, marginBottom: 20 }}>Topics are the campaign angles your content will be built around. Each topic generates a blog post, tweet thread, LinkedIn post, and email. AI suggested these from your PRD — edit or add your own.</div>
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
{topics.map((topic) => (
<div key={topic.id} style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, overflow: "hidden" }}>
{editingTopic === topic.id ? (
<div style={{ padding: "18px 20px", display: "flex", flexDirection: "column", gap: 10 }}>
<input value={topic.title} onChange={(e) => updateTopic(topic.id, "title", e.target.value)} placeholder="Topic title" style={{ fontSize: 14, fontWeight: 600, color: C.ink, border: `1px solid ${C.border2}`, borderRadius: 8, padding: "9px 12px", outline: "none", background: C.surface }} autoFocus />
<textarea value={topic.angle} onChange={(e) => updateTopic(topic.id, "angle", e.target.value)} placeholder="What angle does this take?" style={{ fontSize: 13, color: C.ink2, border: `1px solid ${C.border2}`, borderRadius: 8, padding: "9px 12px", outline: "none", resize: "none", height: 72, background: C.surface, lineHeight: 1.6 }} />
<div style={{ display: "flex", gap: 8 }}>
<button onClick={() => setEditingTopic(null)} style={{ flex: 1, background: C.surface, color: C.ink3, border: `1px solid ${C.border2}`, borderRadius: 8, padding: "9px", fontSize: 13, cursor: "pointer" }}>Done</button>
<button onClick={() => { removeTopic(topic.id); setEditingTopic(null); }} style={{ background: "transparent", color: C.rose, border: "1px solid #fecdd3", borderRadius: 8, padding: "9px 14px", fontSize: 12, cursor: "pointer" }}>Remove</button>
</div>
</div>
) : (
<div style={{ padding: "16px 20px" }}>
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, marginBottom: 8 }}>
<div style={{ fontSize: 14, fontWeight: 700, color: C.ink, lineHeight: 1.4 }}>{topic.title || "Untitled topic"}</div>
<button onClick={() => setEditingTopic(topic.id)} style={{ fontSize: 12, color: C.ink3, background: "transparent", border: `1px solid ${C.border2}`, borderRadius: 7, padding: "4px 10px", cursor: "pointer", flexShrink: 0 }}>Edit</button>
</div>
<div style={{ fontSize: 13, color: C.ink3, lineHeight: 1.6, marginBottom: 12 }}>{topic.angle}</div>
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
<span style={{ fontSize: 10.5, fontWeight: 600, color: C.muted }}>Generates:</span>
{topic.channels.map((ch) => <span key={ch} style={{ fontSize: 11, fontWeight: 600, color: C.ink3, background: C.surface, border: `1px solid ${C.border2}`, borderRadius: 5, padding: "2px 8px" }}>{ch}</span>)}
</div>
</div>
)}
</div>
))}
{topics.length < 5 && (
<button onClick={addTopic} style={{ padding: "14px", background: "transparent", border: `1.5px dashed ${C.border2}`, borderRadius: 14, fontSize: 13.5, color: C.muted, cursor: "pointer", fontWeight: 500 }}>+ Add a topic</button>
)}
</div>
<div style={{ marginTop: 16, padding: "13px 16px", background: C.amberBg, border: `1px solid ${C.amberBorder}`, borderRadius: 11 }}>
<div style={{ fontSize: 12.5, color: C.amberText, lineHeight: 1.6 }}>💡 Start with 3 topics — you can always add more after launch. AI will generate all the content once your product is live.</div>
</div>
</div>
</div>
)}
{tab === "style" && (
<div style={{ flex: 1, overflow: "hidden", display: "flex" }}>
<div style={{ width: 260, borderRight: `1px solid ${C.border}`, overflowY: "auto", background: C.white, padding: "20px 18px", display: "flex", flexDirection: "column", gap: 8 }}>
<div style={{ fontSize: 12, color: C.muted, lineHeight: 1.6, marginBottom: 6 }}>How should your marketing website feel to visitors?</div>
{WEBSITE_FEELS.map((f) => {
const isSel = websiteFeel === f.id;
const isDark = f.bg === "#0c0a09" || f.bg === "#0f172a";
return (
<button key={f.id} onClick={() => setWebsiteFeel(f.id)}
style={{ borderRadius: 12, border: isSel ? `2px solid ${C.ink}` : `1px solid ${C.border2}`, background: f.bg, cursor: "pointer", textAlign: "left", padding: "12px 14px", transition: "all 0.15s", boxShadow: isSel ? "0 2px 12px rgba(0,0,0,0.08)" : "none" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
<div style={{ fontSize: 13.5, fontWeight: 700, color: isDark ? "#fff" : C.ink }}>{f.label}</div>
{isSel && <span style={{ color: C.green, fontSize: 12, fontWeight: 900 }}>✓</span>}
</div>
<div style={{ fontSize: 11.5, color: isDark ? "rgba(255,255,255,0.5)" : C.muted }}>{f.ref}</div>
<div style={{ display: "flex", gap: 5, marginTop: 9 }}>
{[f.bg, f.accent, "#f1f5f9"].map((col, i) => <div key={i} style={{ width: 12, height: 12, borderRadius: "50%", background: col, border: `1.5px solid ${isDark ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.1)"}` }} />)}
</div>
</button>
);
})}
</div>
<div style={{ flex: 1, background: "#dde3ea", display: "flex", flexDirection: "column" }}>
<div style={{ padding: "11px 18px", background: C.white, borderBottom: `1px solid ${C.border}`, display: "flex", alignItems: "center", gap: 8 }}>
<div style={{ display: "flex", gap: 5 }}>{["#f43f5e", "#f59e0b", "#22c55e"].map((c) => <div key={c} style={{ width: 10, height: 10, borderRadius: "50%", background: c }} />)}</div>
<span style={{ fontFamily: "monospace", fontSize: 11.5, color: C.muted }}>yourproduct.com</span>
<span style={{ marginLeft: "auto", fontSize: 11.5, fontWeight: 600, color: C.ink3 }}>{WEBSITE_FEELS.find((f) => f.id === websiteFeel)?.label}</span>
</div>
<div style={{ flex: 1, padding: 24, overflow: "hidden" }}>
<WebsitePreview feel={websiteFeel} />
</div>
</div>
</div>
)}
</div>
</div>
);
}
// ─── PHASE: BUILD ─────────────────────────────────────────────────────────────
function BuildPhase({ prd, arch, design, market }) {
const [building, setBuilding] = useState(false);
const [step, setStep] = useState(0);
const [done, setDone] = useState(false);
const BUILD_STEPS = [
{ label: "Creating Gitea repository", detail: "Setting up version control for your project" },
{ label: "Scaffolding the app", detail: "Next.js project structure, TypeScript, Tailwind" },
{ label: "Setting up your database", detail: "PostgreSQL + schema based on your product plan" },
{ label: "Building sign up & login", detail: arch?.auth === "email_social" ? "Email + Google + GitHub" : "Email & password" },
{ label: "Wiring payments", detail: arch?.payments === "free" ? "Skipped no payments yet" : "Stripe checkout, webhooks, billing portal" },
{ label: "Generating all app pages", detail: "Dashboard, settings, onboarding, invite flow" },
{ label: "Applying your design", detail: `${DESIGN_FEELS.find((f) => f.id === design?.feel)?.label || "Clean & focused"} theme` },
{ label: "Building your marketing website", detail: `${WEBSITE_FEELS.find((f) => f.id === market?.websiteFeel)?.label || "Startup energy"} style` },
{ label: "Setting up email", detail: "Welcome, password reset, and marketing templates" },
{ label: "Pushing to Gitea", detail: "Full codebase committed and pushed" },
{ label: "Deploying via Coolify", detail: "Building Docker image, deploying to your servers" },
{ label: "Running health checks", detail: "Verifying all pages, auth, and payments are live" },
];
const start = () => {
setBuilding(true);
let s = 0;
const iv = setInterval(() => {
s++;
setStep(s);
if (s >= BUILD_STEPS.length) { clearInterval(iv); setTimeout(() => setDone(true), 600); }
}, 800);
};
const feel = DESIGN_FEELS.find((f) => f.id === design?.feel) || DESIGN_FEELS[0];
if (building) {
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", padding: 40, background: C.surface }}>
<div style={{ width: "100%", maxWidth: 520 }}>
<div style={{ textAlign: "center", marginBottom: 28 }}>
{done ? (
<>
<div style={{ fontSize: 36, marginBottom: 12 }}>🚀</div>
<div style={{ fontSize: 26, fontWeight: 800, color: C.ink, letterSpacing: "-0.04em", marginBottom: 8 }}>Your MVP is live</div>
<div style={{ fontSize: 14, color: C.muted }}>Deployed to Coolify · Pushed to Gitea · Ready to share</div>
</>
) : (
<>
<div style={{ fontSize: 22, fontWeight: 800, color: C.ink, letterSpacing: "-0.04em", marginBottom: 6 }}>Building your product…</div>
<div style={{ fontSize: 13.5, color: C.muted }}>Step {Math.min(step, BUILD_STEPS.length)} of {BUILD_STEPS.length}</div>
</>
)}
</div>
<div style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, overflow: "hidden", marginBottom: 20 }}>
{BUILD_STEPS.map((s, i) => {
const isActive = i === step - 1 && !done;
const isDoneStep = i < step;
return (
<div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 16px", borderBottom: i < BUILD_STEPS.length - 1 ? `1px solid ${C.border}` : "none", background: isActive ? C.purpleBg : "transparent", transition: "background 0.3s" }}>
<div style={{ width: 22, height: 22, borderRadius: "50%", background: isDoneStep ? C.green : isActive ? C.purple : C.border2, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
{isDoneStep ? <span style={{ color: C.white, fontSize: 9, fontWeight: 900 }}>✓</span> : isActive ? <span style={{ color: C.white, fontSize: 9, display: "inline-block", animation: "vspin 1s linear infinite" }}>◎</span> : null}
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13, fontWeight: isActive ? 600 : 400, color: isDoneStep ? C.ink3 : isActive ? C.purple : C.muted }}>{s.label}</div>
{(isActive || isDoneStep) && <div style={{ fontSize: 11.5, color: C.muted, marginTop: 1 }}>{s.detail}</div>}
</div>
</div>
);
})}
</div>
{done && (
<>
<div style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, padding: "18px 20px", marginBottom: 16 }}>
<div style={{ fontSize: 12, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.07em", marginBottom: 12 }}>Your next 3 actions</div>
{[{ n: "1", label: "Open your live app", desc: "Share the URL with 5 real people today." }, { n: "2", label: "Sign up as a user", desc: "Go through your own onboarding." }, { n: "3", label: "Post your first topic", desc: "AI has drafted your first content batch." }].map((a) => (
<div key={a.n} style={{ display: "flex", gap: 12, padding: "10px 0", borderBottom: a.n !== "3" ? `1px solid ${C.border}` : "none" }}>
<div style={{ width: 24, height: 24, borderRadius: "50%", background: C.ink, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, color: C.white, flexShrink: 0 }}>{a.n}</div>
<div>
<div style={{ fontSize: 13.5, fontWeight: 600, color: C.ink, marginBottom: 2 }}>{a.label}</div>
<div style={{ fontSize: 12.5, color: C.muted, lineHeight: 1.5 }}>{a.desc}</div>
</div>
</div>
))}
</div>
<div style={{ display: "flex", gap: 10 }}>
<button style={{ flex: 2, background: C.ink, color: C.white, border: "none", borderRadius: 11, padding: "14px", fontSize: 14, fontWeight: 700, cursor: "pointer" }}>Open my app ↗</button>
<button style={{ flex: 1, background: C.white, color: C.ink3, border: `1px solid ${C.border2}`, borderRadius: 11, padding: "14px", fontSize: 13, cursor: "pointer" }}>View in Gitea ↗</button>
</div>
</>
)}
</div>
</div>
);
}
const summaryItems = [
{ label: "Sign up & login", value: ARCH_BLOCKS.find((b) => b.id === "auth")?.alts.find((a) => a.id === arch?.auth)?.label || "Email + social login", color: C.rose, icon: "" },
{ label: "Payments", value: ARCH_BLOCKS.find((b) => b.id === "payments")?.alts.find((a) => a.id === arch?.payments)?.label || "Subscription billing", color: C.amber, icon: "" },
{ label: "Email", value: ARCH_BLOCKS.find((b) => b.id === "email")?.alts.find((a) => a.id === arch?.email)?.label || "Transactional + marketing", color: C.teal, icon: "" },
{ label: "Product style", value: feel.label, color: C.purple, icon: "" },
{ label: "Website style", value: WEBSITE_FEELS.find((f) => f.id === market?.websiteFeel)?.label || "Startup energy", color: C.blue, icon: "" },
{ label: "Campaign topics", value: `${market?.topics?.length || 3} topics ready`, color: C.violet, icon: "" },
];
return (
<div style={{ height: "100%", overflowY: "auto", padding: "32px", display: "flex", justifyContent: "center", background: C.surface }}>
<div style={{ width: "100%", maxWidth: 620 }}>
<div style={{ marginBottom: 24 }}>
<div style={{ fontSize: 24, fontWeight: 800, color: C.ink, letterSpacing: "-0.04em", marginBottom: 6 }}>Ready to build</div>
<div style={{ fontSize: 14, color: C.muted, lineHeight: 1.6 }}>Review everything below. Once you hit Build, AI will code your full product and deploy it to your live URL.</div>
</div>
<div style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, overflow: "hidden", marginBottom: 16 }}>
<div style={{ padding: "14px 20px", borderBottom: `1px solid ${C.border}` }}>
<span style={{ fontSize: 11, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.07em" }}>What's being built</span>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 0 }}>
{summaryItems.map((item, i) => (
<div key={i} style={{ padding: "14px 20px", borderRight: i % 2 === 0 ? `1px solid ${C.border}` : "none", borderBottom: i < summaryItems.length - 2 ? `1px solid ${C.border}` : "none", display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 28, height: 28, borderRadius: 8, background: `${item.color}15`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12, color: item.color, flexShrink: 0 }}>{item.icon}</div>
<div>
<div style={{ fontSize: 11, color: C.muted, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 2 }}>{item.label}</div>
<div style={{ fontSize: 13.5, fontWeight: 600, color: C.ink2 }}>{item.value}</div>
</div>
</div>
))}
</div>
</div>
<div style={{ background: C.white, borderRadius: 14, border: `1px solid ${C.border2}`, overflow: "hidden", marginBottom: 16 }}>
<div style={{ padding: "14px 20px", borderBottom: `1px solid ${C.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontSize: 11, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.07em" }}>Pages</span>
<span style={{ fontSize: 12, color: C.muted }}>{PAGES_GENERATED.reduce((a, g) => a + g.pages.length, 0)} pages total</span>
</div>
<div style={{ padding: "16px 20px", display: "flex", gap: 20, flexWrap: "wrap" }}>
{PAGES_GENERATED.map((g) => (
<div key={g.group}>
<div style={{ fontSize: 10, fontWeight: 700, color: g.color, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 6, opacity: 0.8 }}>{g.group}</div>
{g.pages.map((p) => <div key={p} style={{ fontSize: 13, color: C.ink3, marginBottom: 4, display: "flex", gap: 6, alignItems: "center" }}><span style={{ fontSize: 8, color: g.color }}>●</span>{p}</div>)}
</div>
))}
</div>
</div>
<div style={{ background: C.violetBg, border: "1px solid #ddd6fe", borderRadius: 12, padding: "14px 18px", marginBottom: 24, display: "flex", gap: 12 }}>
<span style={{ fontSize: 16, color: C.violet }}>◉</span>
<div>
<div style={{ fontSize: 13, fontWeight: 700, color: C.violet, marginBottom: 3 }}>Deploying to your infrastructure</div>
<div style={{ fontSize: 12.5, color: "#5b21b6", lineHeight: 1.6 }}>Code is pushed to your Gitea repo. Coolify auto-deploys on push. Your domain, SSL, and database are all pre-configured.</div>
</div>
</div>
<button onClick={start} style={{ width: "100%", background: C.ink, color: C.white, border: "none", borderRadius: 13, padding: "18px", fontSize: 17, fontWeight: 800, cursor: "pointer", letterSpacing: "-0.02em", marginBottom: 10 }}>
▲ Build my MVP
</button>
<div style={{ fontSize: 12.5, color: C.muted, textAlign: "center" }}>~15 minutes · All pages built in parallel · You can refine everything after it's live</div>
</div>
</div>
);
}
// ─── FLOATING CHAT ────────────────────────────────────────────────────────────
const STARTERS = {
welcome: ["What exactly gets built?", "How long does the whole thing take?", "What do I need to prepare?"],
discover: ["Help me think through my idea", "What makes a good SaaS product?", "Who should I target first?"],
architect: ["Why did you choose these components?", "What's the difference between these options?", "Can I change things after it's built?"],
design: ["Which style works best for B2B?", "Can I change it after launch?", "What do the reference products look like?"],
market: ["How should I describe my voice?", "What makes a good campaign topic?", "How much content will be generated?"],
build: ["What gets built first?", "What do I do when it's live?", "Can I make changes during the build?"],
};
function FloatingChat({ msgs, onSend, phase, onClose }) {
const [input, setInput] = useState("");
const bottomRef = useRef(null);
useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: "smooth" }); }, [msgs]);
const send = (val) => {
const text = val || input; if (!text.trim()) return; setInput("");
onSend({ role: "user", text });
setTimeout(() => onSend({ role: "assistant", text: "Good question. Based on everything you've told me so far, I'd say: focus on getting to a live URL first. Every decision you're making now can be refined after launch." }), 600);
};
return (
<div style={{ position: "fixed", bottom: 80, right: 24, width: 304, background: C.white, borderRadius: 18, boxShadow: "0 8px 40px rgba(0,0,0,0.18)", border: `1px solid ${C.border2}`, zIndex: 500, display: "flex", flexDirection: "column", overflow: "hidden", animation: "slideup 0.2s ease" }}>
<div style={{ padding: "12px 14px", background: C.ink, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: C.green, animation: "vpulse 2s infinite" }} />
<span style={{ fontSize: 13, fontWeight: 700, color: C.white }}>Assist</span>
<span style={{ fontSize: 11, color: "rgba(255,255,255,0.35)", textTransform: "capitalize" }}>· {phase}</span>
</div>
<button onClick={onClose} style={{ background: "transparent", border: "none", color: "rgba(255,255,255,0.45)", cursor: "pointer", fontSize: 20 }}>×</button>
</div>
<div style={{ maxHeight: 220, overflowY: "auto", padding: "12px 14px", display: "flex", flexDirection: "column", gap: 8 }}>
{msgs.map((msg, i) => (
<div key={i} style={{ display: "flex", flexDirection: "column", alignItems: msg.role === "user" ? "flex-end" : "flex-start" }}>
<div style={{ maxWidth: "90%", background: msg.role === "user" ? C.ink : C.surface, color: msg.role === "user" ? C.white : C.ink2, borderRadius: msg.role === "user" ? "12px 12px 3px 12px" : "12px 12px 12px 3px", padding: "8px 11px", fontSize: 12.5, lineHeight: 1.55, border: msg.role === "assistant" ? `1px solid ${C.border}` : "none" }}>{msg.text}</div>
</div>
))}
<div ref={bottomRef} />
</div>
{msgs.length < 2 && (
<div style={{ padding: "0 10px 8px", display: "flex", flexDirection: "column", gap: 4 }}>
{(STARTERS[phase] || []).map((s, i) => (
<button key={i} onClick={() => send(s)} style={{ fontSize: 12, color: C.ink3, background: C.surface, border: `1px solid ${C.border2}`, borderRadius: 7, padding: "6px 10px", cursor: "pointer", textAlign: "left" }}>{s}</button>
))}
</div>
)}
<div style={{ padding: "8px 10px 12px", borderTop: `1px solid ${C.border}`, display: "flex", gap: 6 }}>
<input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} placeholder="Ask anything" style={{ flex: 1, border: `1px solid ${C.border2}`, borderRadius: 8, padding: "7px 10px", fontSize: 12.5, color: C.ink, outline: "none", background: C.surface }} />
<button onClick={() => send()} style={{ background: C.ink, color: C.white, border: "none", borderRadius: 8, padding: "7px 12px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>→</button>
</div>
</div>
);
}
// ─── ROOT ─────────────────────────────────────────────────────────────────────
const SIDEBAR_PHASES = PHASES.filter((p) => p.id !== "welcome");
const CHECKLIST = [
{ key: "prd", label: "Product plan", done: (p) => p !== "welcome" },
{ key: "arch", label: "Architecture", done: (p) => ["architect", "design", "market", "build"].includes(p) },
{ key: "design", label: "Product design", done: (p) => ["design", "market", "build"].includes(p) },
{ key: "market", label: "Marketing", done: (p) => ["market", "build"].includes(p) },
];
export default function App() {
const [phase, setPhase] = useState("website");
const [prd, setPrd] = useState({});
const [arch, setArch] = useState({});
const [design, setDesign] = useState({});
const [market, setMarket] = useState({ topics: SUGGESTED_TOPICS() });
const [chatOpen, setChatOpen] = useState(false);
const [chatMsgs, setChatMsgs] = useState([{ role: "assistant", text: "I'm here throughout the whole setup. Ask me anything." }]);
const goTo = (id) => setPhase(id);
return (
<div style={{ minHeight: "100vh", background: C.surface, display: "flex", flexDirection: "row" }}>
{["discover","architect","design","market","build"].includes(phase) && (
<aside style={{ width: 220, minWidth: 220, background: C.white, borderRight: `1px solid ${C.border2}`, flexShrink: 0, minHeight: "100vh", display: "flex", flexDirection: "column" }}>
{/* Logo */}
<div style={{ padding: "18px 18px 16px", display: "flex", alignItems: "center", gap: 9, borderBottom: `1px solid ${C.border}` }}>
<div style={{ width: 28, height: 28, borderRadius: 7, background: C.ink, display: "flex", alignItems: "center", justifyContent: "center", color: C.white, fontSize: 13, fontWeight: 700, letterSpacing: "-0.04em", flexShrink: 0 }}>v</div>
<span style={{ fontSize: 15, fontWeight: 700, color: C.ink, letterSpacing: "-0.04em" }}>vibn</span>
</div>
{/* Progress */}
<div style={{ padding: "16px 16px 12px", borderBottom: `1px solid ${C.border}` }}>
<div style={{ fontSize: 10, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 10 }}>Progress</div>
{CHECKLIST.map((c) => (
<div key={c.key} style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 7, fontSize: 12.5, color: c.done(phase) ? C.ink3 : C.muted }}>
<span style={{ color: c.done(phase) ? C.green : C.border2, fontSize: 10, flexShrink: 0 }}>{c.done(phase) ? "" : ""}</span>
{c.label}
</div>
))}
</div>
{/* Phase nav */}
<div style={{ padding: "12px 10px", flex: 1 }}>
<div style={{ fontSize: 10, fontWeight: 700, color: C.muted, textTransform: "uppercase", letterSpacing: "0.08em", padding: "0 8px", marginBottom: 6 }}>Phases</div>
{SIDEBAR_PHASES.map((p) => (
<button
key={p.id}
onClick={() => goTo(p.id)}
style={{
width: "100%",
display: "flex",
alignItems: "center",
gap: 9,
padding: "8px 10px",
marginBottom: 2,
borderRadius: 6,
border: "none",
background: phase === p.id ? C.purpleBg : "transparent",
color: phase === p.id ? C.purple : C.ink3,
cursor: "pointer",
textAlign: "left",
fontSize: 13,
fontWeight: phase === p.id ? 600 : 500,
transition: "background 0.12s",
}}
onMouseEnter={(e) => { if (phase !== p.id) e.currentTarget.style.background = C.surface; }}
onMouseLeave={(e) => { if (phase !== p.id) e.currentTarget.style.background = "transparent"; }}
>
<span style={{ opacity: 0.6, fontSize: 12, width: 16, textAlign: "center", flexShrink: 0 }}>{p.icon}</span>
{p.label}
</button>
))}
</div>
{/* User */}
<div style={{ padding: "14px 18px", borderTop: `1px solid ${C.border}`, display: "flex", alignItems: "center", gap: 9 }}>
<div style={{ width: 28, height: 28, borderRadius: "50%", background: C.surface, border: `1px solid ${C.border2}`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, color: C.ink3, flexShrink: 0 }}>M</div>
<div style={{ overflow: "hidden" }}>
<div style={{ fontSize: 12.5, fontWeight: 600, color: C.ink, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>Mark</div>
<div style={{ fontSize: 11, color: C.muted }}>Pro plan</div>
</div>
</div>
</aside>
)}
<main style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
{phase === "welcome" && <WelcomePhase onStart={() => setPhase("discover")} />}
{phase === "website" && <Website onGetStarted={() => setPhase("welcome")} onLogin={() => setPhase("dashboard")} />}
{phase === "dashboard" && (
<Dashboard
onNewProject={() => setPhase("welcome")}
onContinueBuilding={() => setPhase("build")}
/>
)}
{phase === "discover" && <DiscoverPhase onComplete={(data) => { setPrd(data); setPhase("architect"); }} />}
{phase === "architect" && <ArchitectPhase onComplete={(data) => { setArch(data); setPhase("design"); }} />}
{phase === "design" && <DesignPhase onComplete={(data) => { setDesign(data); setPhase("market"); }} />}
{phase === "market" && <MarketPhase prd={prd} onComplete={(data) => { setMarket(data); setPhase("build"); }} />}
{phase === "build" && <BuildPhase prd={prd} arch={arch} design={design} market={market} />}
</main>
{["discover","architect","design","market","build"].includes(phase) && !chatOpen && (
<button
onClick={() => setChatOpen(true)}
style={{
position: "fixed",
bottom: 24,
right: 24,
width: 56,
height: 56,
borderRadius: "50%",
background: C.ink,
color: C.white,
border: "none",
boxShadow: "0 4px 20px rgba(0,0,0,0.2)",
cursor: "pointer",
fontSize: 20,
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 400,
}}
>
💬
</button>
)}
{["discover","architect","design","market","build"].includes(phase) && chatOpen && (
<FloatingChat
msgs={chatMsgs}
onSend={(msg) => setChatMsgs((m) => [...m, msg])}
phase={phase}
onClose={() => setChatOpen(false)}
/>
)}
</div>
);
}

View File

@@ -1,497 +0,0 @@
// vibn — Projects Dashboard
// Restyled from original (DM Sans + purple/colour accents) → Ink & parchment
// Design: Lora serif + Inter sans, #1a1510 ink, #f7f4ee paper, no colour accent
// Usage: default export, no required props
import { useState } from "react";
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
border2:"#d3d1c7",
};
const F = { serif: "'Lora', Georgia, serif", sans: "'Inter', sans-serif" };
// ─── Shared primitives ─────────────────────────────────────────────────────────
function StatusPill({ label, variant = "default" }) {
const styles = {
live: { bg: T.cream, text: T.ink3, border: T.border },
building: { bg: T.cream, text: T.ink3, border: T.border },
default: { bg: T.paper, text: T.muted, border: T.border },
invoiced: { bg: T.ink, text: T.paper, border: T.ink },
unbilled: { bg: T.cream, text: T.ink3, border: T.border },
scheduled: { bg: T.parch, text: T.ink2, border: T.border2 },
};
const s = styles[variant] || styles.default;
return (
<span style={{
fontFamily: F.sans, fontSize: 10.5, fontWeight: 600,
color: s.text, background: s.bg,
border: `1px solid ${s.border}`,
borderRadius: 5, padding: "2px 8px", whiteSpace: "nowrap",
}}>{label}</span>
);
}
function InkBtn({ children, onClick, small, outline }) {
return (
<button onClick={onClick} style={{
fontFamily: F.sans, fontWeight: 600,
fontSize: small ? 12 : 13.5,
padding: small ? "6px 14px" : "10px 22px",
background: outline ? "transparent" : T.ink,
color: outline ? T.ink3 : T.paper,
border: outline ? `1px solid ${T.border2}` : "none",
borderRadius: 8, cursor: "pointer",
}}>{children}</button>
);
}
// ─── Nav ───────────────────────────────────────────────────────────────────────
function Nav({ screen, setScreen, onNewProject }) {
return (
<nav style={{
background: T.white, borderBottom: `1px solid ${T.border}`,
padding: "0 32px", height: 60, display: "flex",
alignItems: "center", justifyContent: "space-between",
}}>
<div onClick={() => setScreen("projects")} style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer" }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 7, display: "flex", alignItems: "center", justifyContent: "center" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 700, color: T.paper }}>V</span>
</div>
<span style={{ fontFamily: F.serif, fontSize: 18, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 22 }}>
{screen === "billing" && (
<span onClick={() => setScreen("projects")} style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}> All projects</span>
)}
<span style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted, cursor: "pointer" }}>Settings</span>
<div style={{ width: 30, height: 30, borderRadius: "50%", background: T.ink3, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.sans, fontSize: 11, color: T.paper, fontWeight: 700 }}>MH</div>
</div>
</nav>
);
}
// ─── Data ──────────────────────────────────────────────────────────────────────
const PROJECTS = [
{
id: "launchpad", label: "Launchpad", initial: "L",
type: "own", status: "live", url: "launchpad.vibn.app",
stats: { visitors: "2.4k", signups: 183, mrr: "$840" },
},
{
id: "flowmatic", label: "Flowmatic", initial: "F",
type: "client", status: "live", url: "flowmatic.app",
client: "Acme Corp",
stats: { visitors: "890", signups: 54, mrr: "$210" },
costs: { total: 48.20, llm: 29.20, compute: 11.60, other: 7.40, billed: false },
},
{
id: "taskly", label: "Taskly", initial: "T",
type: "client", status: "building", url: null,
client: "Beta Labs", buildProgress: 60,
costs: { total: 12.40, llm: 9.20, compute: 3.20, other: 0, billed: false },
},
];
const ACTIVITY = [
{ text: "Launchpad — Blog post published:", detail: '"How to launch faster with AI"', time: "2h ago" },
{ text: "Flowmatic — New signup:", detail: "marcus@email.com", time: "4h ago" },
{ text: "Taskly — Checkout page built and deployed", detail: "", time: "6h ago" },
{ text: "Launchpad — Newsletter #12", detail: "scheduled", time: "Yesterday" },
];
const BILLING_ROWS = [
{ label: "Flowmatic", initial: "F", client: "Acme Corp", llm: 29.20, compute: 11.60, other: 7.40, total: 48.20, billed: false },
{ label: "Taskly", initial: "T", client: "Beta Labs", llm: 9.20, compute: 3.20, other: 0, total: 12.40, billed: false },
{ label: "Flowmatic", initial: "F", client: "Acme · Feb", llm: 22.10, compute: 8.40, other: 4.20, total: 34.70, billed: true },
];
const COST_LOG = [
{ time: "2h ago", desc: "LLM: Homepage copy generation", project: "Flowmatic", cost: 0.82 },
{ time: "3h ago", desc: "LLM: Checkout page code", project: "Taskly", cost: 1.24 },
{ time: "5h ago", desc: "LLM: Weekly newsletter draft", project: "Flowmatic", cost: 0.43 },
{ time: "6h ago", desc: "Compute: Build pipeline run", project: "Taskly", cost: 0.18 },
{ time: "8h ago", desc: "LLM: Discover phase Q&A", project: "Flowmatic", cost: 0.31 },
{ time: "Yesterday", desc: "Email delivery · 240 recipients", project: "Flowmatic", cost: 0.96 },
];
// ─── Project card ──────────────────────────────────────────────────────────────
function ProjectCard({ project, onContinue }) {
const isClient = project.type === "client";
const isBuilding = project.status === "building";
return (
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{/* Header preview */}
{isBuilding ? (
<div style={{ height: 100, background: T.cream, borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 11.5, color: T.muted, fontWeight: 500, marginBottom: 10 }}>
Build phase · {project.buildProgress}% complete
</div>
<div style={{ width: 160, height: 4, background: T.parch, borderRadius: 3, overflow: "hidden" }}>
<div style={{ width: `${project.buildProgress}%`, height: "100%", background: T.ink3, borderRadius: 3 }} />
</div>
</div>
{isClient && (
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.mid, background: T.white, border: `1px solid ${T.border}`, borderRadius: 5, padding: "2px 8px" }}>
Client
</div>
)}
</div>
) : (
<div style={{ height: 100, background: T.ink, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
<div style={{ background: "rgba(247,244,238,0.1)", borderRadius: 8, width: "55%", padding: "10px 14px" }}>
<div style={{ height: 8, background: "rgba(247,244,238,0.6)", borderRadius: 3, width: "65%", marginBottom: 6 }} />
<div style={{ height: 5, background: "rgba(247,244,238,0.25)", borderRadius: 3, width: "85%" }} />
</div>
<div style={{ position: "absolute", top: 10, right: 12, fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: "rgba(247,244,238,0.6)", background: "rgba(247,244,238,0.1)", borderRadius: 5, padding: "2px 8px" }}>
{isClient ? "Client" : "My product"}
</div>
</div>
)}
<div style={{ padding: "18px 20px" }}>
{/* Identity row */}
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 28, height: 28, background: T.ink, borderRadius: 8, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 12, color: T.paper, fontWeight: 700 }}>
{project.initial}
</div>
<div>
<div style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>{project.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>
{isClient ? `${project.client} · ` : ""}
{project.url || "Setting up pages…"}
</div>
</div>
</div>
<StatusPill label={isBuilding ? "Building" : "Live"} variant={isBuilding ? "building" : "live"} />
</div>
{/* Cost strip — client + building */}
{isClient && project.costs && isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs so far</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<StatusPill label="Unbilled" variant="unbilled" />
</div>
)}
{/* Cost strip — client + live */}
{isClient && project.costs && !isBuilding && (
<div style={{ background: T.cream, border: `1px solid ${T.border}`, borderRadius: 9, padding: "10px 14px", marginBottom: 12, display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ flex: 1 }}>
<div style={{ fontFamily: F.sans, fontSize: 10, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: 3 }}>Costs this month</div>
<div style={{ fontFamily: F.serif, fontSize: 17, fontWeight: 700, color: T.ink }}>${project.costs.total.toFixed(2)}</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.mid, lineHeight: 1.7 }}>
LLM ${project.costs.llm.toFixed(2)}<br />
Compute ${project.costs.compute.toFixed(2)}
</div>
{!project.costs.billed && (
<button style={{ background: T.ink, border: "none", color: T.paper, borderRadius: 7, padding: "7px 13px", fontFamily: F.sans, fontSize: 11.5, fontWeight: 600, cursor: "pointer" }}>
Bill
</button>
)}
</div>
)}
{/* Stats */}
{!isBuilding && project.stats && (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 14 }}>
{[["visitors", project.stats.visitors], ["signups", project.stats.signups], ["MRR", project.stats.mrr]].map(([k, v]) => (
<div key={k} style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 16, fontWeight: 700, color: T.ink }}>{v}</div>
<div style={{ fontFamily: F.sans, fontSize: 10, color: T.muted }}>{k}</div>
</div>
))}
</div>
)}
{/* Actions */}
{isBuilding ? (
<button onClick={onContinue} style={{ width: "100%", background: T.ink, border: "none", color: T.paper, borderRadius: 8, padding: 10, fontFamily: F.sans, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
Continue building
</button>
) : (
<div style={{ display: "flex", gap: 6 }}>
{[["⬡", "Build"], ["◈", "Grow"]].map(([icon, label]) => (
<div key={label} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "7px 10px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, cursor: "pointer" }}>
<span style={{ fontSize: 11 }}>{icon}</span>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.ink3 }}>{label}</span>
</div>
))}
<div style={{ padding: "7px 12px", background: T.cream, border: `1px solid ${T.border}`, borderRadius: 7, fontFamily: F.sans, fontSize: 11.5, color: T.ink3, cursor: "pointer" }}>
</div>
</div>
)}
</div>
</div>
);
}
// ─── Projects screen ───────────────────────────────────────────────────────────
function ProjectsScreen({ setScreen, onNewProject, onContinueBuilding }) {
const totalUnbilled = PROJECTS
.filter(p => p.type === "client" && p.costs?.billed === false)
.reduce((s, p) => s + p.costs.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "36px 32px" }}>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 32 }}>
<div>
<h1 style={{ fontFamily: F.serif, fontSize: 26, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", marginBottom: 4 }}>Your projects</h1>
<p style={{ fontFamily: F.sans, fontSize: 13.5, color: T.muted }}>3 active · 1 building</p>
</div>
<div style={{ display: "flex", gap: 10, alignItems: "center" }}>
{totalUnbilled > 0 && (
<button onClick={() => setScreen("billing")} style={{ fontFamily: F.sans, fontSize: 13, color: T.ink3, background: T.cream, border: `1px solid ${T.border}`, borderRadius: 8, padding: "9px 16px", cursor: "pointer" }}>
${totalUnbilled.toFixed(2)} unbilled
</button>
)}
<InkBtn onClick={onNewProject}>+ New project</InkBtn>
</div>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 28 }}>
{PROJECTS.map(p => (
<ProjectCard
key={p.id}
project={p}
onContinue={p.status === "building" ? onContinueBuilding : undefined}
/>
))}
{/* New project CTA card */}
<div
onClick={onNewProject}
style={{ background: "transparent", border: `1px dashed ${T.parch}`, borderRadius: 14, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, padding: 40, cursor: "pointer", minHeight: 220 }}
onMouseEnter={e => e.currentTarget.style.background = T.cream}
onMouseLeave={e => e.currentTarget.style.background = "transparent"}
>
<div style={{ width: 42, height: 42, borderRadius: 10, border: `1px solid ${T.parch}`, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 22, color: T.stone }}>+</div>
<div style={{ textAlign: "center" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>New project</div>
<div style={{ fontFamily: F.sans, fontSize: 12.5, color: T.muted }}>For yourself or a client</div>
</div>
</div>
</div>
{/* Activity feed */}
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 14, padding: "20px 24px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Recent activity</div>
{ACTIVITY.map((a, i) => (
<div key={i} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 0", borderBottom: i < ACTIVITY.length - 1 ? `1px solid ${T.border}` : "none" }}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink3, flexShrink: 0 }} />
<div style={{ flex: 1, fontFamily: F.sans, fontSize: 13.5, color: T.ink }}>
{a.text}{" "}{a.detail && <span style={{ color: T.muted }}>{a.detail}</span>}
</div>
<span style={{ fontFamily: F.sans, fontSize: 11.5, color: T.stone, whiteSpace: "nowrap" }}>{a.time}</span>
</div>
))}
</div>
</div>
);
}
// ─── Billing screen ────────────────────────────────────────────────────────────
function BillingScreen() {
const [tab, setTab] = useState("billing");
const unbilled = BILLING_ROWS.filter(r => !r.billed).reduce((s, r) => s + r.total, 0);
return (
<div style={{ maxWidth: 1000, margin: "0 auto", padding: "28px 32px" }}>
{/* Sub-tabs */}
<div style={{ display: "flex", borderBottom: `1px solid ${T.border}`, marginBottom: 28 }}>
{[["billing", "Client billing"], ["costs", "Cost tracker"]].map(([id, label]) => (
<button key={id} onClick={() => setTab(id)} style={{
padding: "10px 18px", border: "none", background: "transparent",
borderBottom: tab === id ? `2px solid ${T.ink}` : "2px solid transparent",
fontFamily: F.sans, fontSize: 13.5, cursor: "pointer",
color: tab === id ? T.ink : T.muted, fontWeight: tab === id ? 600 : 400,
}}>{label}</button>
))}
</div>
{tab === "billing" && <>
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 22 }}>
<div>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Client billing</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>All costs tracked and ready to invoice</p>
</div>
<InkBtn>Generate invoice</InkBtn>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 10, marginBottom: 24 }}>
{[
{ label: "Total unbilled", value: `$${unbilled.toFixed(2)}` },
{ label: "LLM costs", value: "$38.40" },
{ label: "Compute", value: "$14.80" },
{ label: "Other", value: "$7.40" },
].map(c => (
<div key={c.label} style={{ background: T.cream, borderRadius: 10, padding: "14px 16px" }}>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted, marginBottom: 5 }}>{c.label}</div>
<div style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink }}>{c.value}</div>
</div>
))}
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}`, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Breakdown by client</span>
<select style={{ border: `1px solid ${T.border}`, borderRadius: 6, padding: "4px 10px", fontFamily: F.sans, fontSize: 12, color: T.muted, background: T.paper, outline: "none" }}>
<option>March 2026</option>
</select>
</div>
<div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Project / Client", "LLM", "Compute", "Other", "Total", "Status"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{BILLING_ROWS.map((r, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr 1fr 120px", padding: "13px 20px", borderBottom: i < BILLING_ROWS.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center", opacity: r.billed ? 0.5 : 1 }}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{ width: 24, height: 24, background: T.ink, borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: F.serif, fontSize: 10, color: T.paper, fontWeight: 700 }}>{r.initial}</div>
<div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>{r.label}</div>
<div style={{ fontFamily: F.sans, fontSize: 11, color: T.muted }}>{r.client}</div>
</div>
</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.llm.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.compute.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>${r.other.toFixed(2)}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.total.toFixed(2)}</div>
<div style={{ display: "flex", alignItems: "center", gap: 6 }}>
<StatusPill label={r.billed ? "Invoiced" : "Unbilled"} variant={r.billed ? "invoiced" : "unbilled"} />
{!r.billed && (
<button style={{ background: "transparent", border: `1px solid ${T.border2}`, borderRadius: 5, padding: "3px 9px", fontFamily: F.sans, fontSize: 11, color: T.muted, cursor: "pointer" }}>Invoice</button>
)}
</div>
</div>
))}
</div>
</>}
{tab === "costs" && <>
<div style={{ marginBottom: 22 }}>
<h2 style={{ fontFamily: F.serif, fontSize: 22, fontWeight: 700, color: T.ink, marginBottom: 4 }}>Cost tracker</h2>
<p style={{ fontFamily: F.sans, fontSize: 13, color: T.muted }}>Every dollar spent, broken down by type and project</p>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginBottom: 20 }}>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>LLM usage</div>
{[
{ label: "Code generation", amount: 21.40, pct: 56 },
{ label: "Content & marketing", amount: 10.20, pct: 27 },
{ label: "Chat assist", amount: 6.80, pct: 18 },
].map(r => (
<div key={r.label} style={{ marginBottom: 14 }}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
<span style={{ fontFamily: F.sans, fontSize: 12.5, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 12.5, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
<div style={{ height: 4, background: T.cream, borderRadius: 2, overflow: "hidden" }}>
<div style={{ width: `${r.pct}%`, height: "100%", background: T.ink, borderRadius: 2 }} />
</div>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total LLM</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$38.40</span>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, padding: "18px 20px" }}>
<div style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 16 }}>Infrastructure</div>
{[
{ label: "Hosting & compute", amount: 11.60 },
{ label: "Database", amount: 3.20 },
{ label: "Email delivery", amount: 4.20 },
{ label: "Domain & SSL", amount: 3.20 },
].map(r => (
<div key={r.label} style={{ display: "flex", justifyContent: "space-between", padding: "8px 11px", background: T.cream, borderRadius: 7, marginBottom: 7 }}>
<span style={{ fontFamily: F.sans, fontSize: 13, color: T.mid }}>{r.label}</span>
<span style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${r.amount.toFixed(2)}</span>
</div>
))}
<div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.border}`, display: "flex", justifyContent: "space-between" }}>
<span style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>Total infra</span>
<span style={{ fontFamily: F.serif, fontSize: 15, fontWeight: 700, color: T.ink }}>$22.20</span>
</div>
</div>
</div>
<div style={{ background: T.white, border: `1px solid ${T.border}`, borderRadius: 12, overflow: "hidden" }}>
<div style={{ padding: "13px 20px", borderBottom: `1px solid ${T.border}` }}>
<span style={{ fontFamily: F.serif, fontSize: 14, fontWeight: 600, color: T.ink }}>Recent charges</span>
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "9px 20px", background: T.cream, borderBottom: `1px solid ${T.border}` }}>
{["Time", "Description", "Project", "Cost"].map(h => (
<div key={h} style={{ fontFamily: F.sans, fontSize: 10.5, fontWeight: 600, color: T.muted, textTransform: "uppercase", letterSpacing: "0.05em" }}>{h}</div>
))}
</div>
{COST_LOG.map((row, i) => (
<div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 2fr 1fr 80px", padding: "11px 20px", borderBottom: i < COST_LOG.length - 1 ? `1px solid ${T.border}` : "none", alignItems: "center" }}>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.muted }}>{row.time}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, color: T.ink }}>{row.desc}</div>
<div style={{ fontFamily: F.sans, fontSize: 12, color: T.mid }}>{row.project}</div>
<div style={{ fontFamily: F.sans, fontSize: 13, fontWeight: 600, color: T.ink }}>${row.cost.toFixed(2)}</div>
</div>
))}
</div>
</>}
</div>
);
}
// ─── Root export ───────────────────────────────────────────────────────────────
export default function Dashboard({ onNewProject, onContinueBuilding }) {
const [screen, setScreen] = useState("projects");
return (
<div style={{ background: T.paper, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
button { font-family: inherit; cursor: pointer; }
input, select { font-family: inherit; }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-thumb { background: ${T.parch}; border-radius: 4px; }
`}</style>
<Nav screen={screen} setScreen={setScreen} />
{screen === "projects" && (
<ProjectsScreen
setScreen={setScreen}
onNewProject={onNewProject}
onContinueBuilding={onContinueBuilding}
/>
)}
{screen === "billing" && <BillingScreen />}
</div>
);
}

View File

@@ -1,318 +0,0 @@
import { useState } from "react";
// ── DESIGN TOKENS ─────────────────────────────────────────────────────────────
const T = {
ink: "#1a1510",
ink2: "#2c2c2a",
ink3: "#444441",
mid: "#5f5e5a",
muted: "#888780",
stone: "#b4b2a9",
parch: "#d3d1c7",
cream: "#f1efe8",
paper: "#f7f4ee",
white: "#fdfcfa",
border: "#e8e2d9",
border2: "#d3d1c7",
};
const serif = "'Lora', Georgia, serif";
const sans = "'Inter', sans-serif";
// ── SHARED COMPONENTS ─────────────────────────────────────────────────────────
function Nav({ onGetStarted, onLogin }) {
return (
<nav style={{
background: T.paper, borderBottom: `1px solid ${T.border}`,
padding: "0 48px", display: "flex", alignItems: "center",
justifyContent: "space-between", height: 60,
position: "sticky", top: 0, zIndex: 50,
}}>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<div style={{
width: 30, height: 30, background: T.ink, borderRadius: 7,
display: "flex", alignItems: "center", justifyContent: "center",
}}>
<span style={{ fontFamily: serif, fontSize: 15, fontWeight: 700, color: T.paper, lineHeight: 1 }}>V</span>
</div>
<span style={{ fontFamily: serif, fontSize: 19, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em" }}>vibn</span>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 30 }}>
{["Product", "Pricing", "Stories", "Blog"].map(l => (
<span key={l} style={{ fontFamily: sans, fontSize: 14, color: T.muted, cursor: "pointer" }}>{l}</span>
))}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
<button onClick={onLogin} style={{ fontFamily: sans, fontSize: 14, color: T.muted, cursor: "pointer", background: "none", border: "none", padding: 0 }}>Log in</button>
<button onClick={onGetStarted} style={{
background: T.ink, color: T.paper, fontFamily: sans,
fontSize: 13.5, fontWeight: 600, padding: "9px 22px",
border: "none", borderRadius: 8, cursor: "pointer",
}}>Get started free</button>
</div>
</nav>
);
}
// ── HERO ──────────────────────────────────────────────────────────────────────
function Hero({ onCta }) {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "84px 48px 68px" }}>
<div style={{ fontFamily: sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 22 }}>
For non-technical founders
</div>
<h1 style={{
fontFamily: serif, fontSize: 62, fontWeight: 700, color: T.ink,
letterSpacing: "-0.03em", lineHeight: 1.07, marginBottom: 26, maxWidth: 700,
}}>
You have the idea.<br />
We handle<br />
<em style={{ fontStyle: "italic", color: T.ink3 }}>everything else.</em>
</h1>
<p style={{ fontFamily: sans, fontSize: 17.5, color: T.mid, lineHeight: 1.75, maxWidth: 500, marginBottom: 38 }}>
No backend. No DevOps. No marketing agency. Describe your idea and vibn builds,
deploys, and promotes it automatically.
</p>
<div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap", marginBottom: 16 }}>
<button onClick={onCta} style={{
background: T.ink, color: T.paper, fontFamily: sans,
fontSize: 15, fontWeight: 600, padding: "14px 32px",
border: "none", borderRadius: 10, cursor: "pointer",
}}>
Start free no code needed
</button>
<span style={{ fontFamily: sans, fontSize: 13.5, color: T.stone }}>
&nbsp; 280 founders launched
</span>
</div>
<p style={{ fontFamily: sans, fontSize: 12, color: T.stone }}>
No credit card required · Free forever plan
</p>
</section>
);
}
// ── PULL QUOTE BAND ───────────────────────────────────────────────────────────
const QUOTES = [
{ text: "I had the idea for 2 years. The backend terrified me. vibn shipped it in 4 days and handles all my marketing.", name: "Alex K.", company: "founder of Taskly" },
{ text: "I have zero coding experience. Three weeks in, I have 300 paying users. That's entirely because of vibn.", name: "Marcus L.", company: "founder of Flowmatic" },
{ text: "The marketing autopilot alone saved me ten hours a week. My blog runs itself. I just focus on product.", name: "Sara R.", company: "founder of Nudge" },
];
function QuoteBand() {
return (
<section style={{ background: T.ink, padding: "52px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 40 }}>
{QUOTES.map((q, i) => (
<div key={i} style={{ display: "flex", gap: 18 }}>
<div style={{ width: 3, background: T.mid, borderRadius: 2, flexShrink: 0 }} />
<div>
<p style={{ fontFamily: serif, fontSize: 15, color: T.parch, lineHeight: 1.7, fontStyle: "italic", marginBottom: 10 }}>
"{q.text}"
</p>
<span style={{ fontFamily: sans, fontSize: 11.5, color: T.muted, fontWeight: 600 }}>
{q.name}, {q.company}
</span>
</div>
</div>
))}
</div>
</section>
);
}
// ── HOW IT WORKS ──────────────────────────────────────────────────────────────
const HOW_PHASES = [
{ n: "01", phase: "Discover", title: "Define your idea", body: "Six guided questions turn a rough idea into a full product plan — pages, architecture, revenue model. No jargon, no assumptions." },
{ n: "02", phase: "Design", title: "Choose your style", body: "Pick a visual style and see your exact site and emails live before a single line of code is written." },
{ n: "03", phase: "Build", title: "Your app, live", body: "AI writes every line. Auth, database, payments, all pages — deployed and live. Describe changes in plain English." },
{ n: "04", phase: "Grow", title: "Market & automate", body: "AI generates your blog, emails, and social schedule — publishing on autopilot so you can focus entirely on your users." },
];
function HowItWorks() {
return (
<section style={{ maxWidth: 960, margin: "0 auto", padding: "80px 48px" }}>
<div style={{ fontFamily: sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 16 }}>
How it works
</div>
<h2 style={{ fontFamily: serif, fontSize: 38, fontWeight: 700, color: T.ink, letterSpacing: "-0.02em", marginBottom: 52, maxWidth: 480, lineHeight: 1.15 }}>
Four phases. One complete product.
</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 0, border: `1px solid ${T.border}`, borderRadius: 14, overflow: "hidden" }}>
{HOW_PHASES.map((p, i) => (
<div key={i} style={{
padding: "36px 40px",
background: T.white,
borderRight: i % 2 === 0 ? `1px solid ${T.border}` : "none",
borderBottom: i < 2 ? `1px solid ${T.border}` : "none",
}}>
<div style={{ fontFamily: sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.1em", textTransform: "uppercase", color: T.muted, marginBottom: 16 }}>
{p.n} {p.phase}
</div>
<div style={{ fontFamily: serif, fontSize: 21, fontWeight: 700, color: T.ink, marginBottom: 10 }}>{p.title}</div>
<p style={{ fontFamily: sans, fontSize: 13.5, color: T.mid, lineHeight: 1.7 }}>{p.body}</p>
</div>
))}
</div>
</section>
);
}
// ── EMPATHY SECTION ───────────────────────────────────────────────────────────
const PAINS = [
{ title: "No more \"I need to hire a developer first\"", body: "vibn is your developer. Start building the moment you have an idea." },
{ title: "No more staring at a blank marketing calendar", body: "AI generates and publishes your content every single week." },
{ title: "No more \"I'll launch when it's ready\"", body: "Most founders ship their first version in under 72 hours." },
];
function EmpathySection() {
return (
<section style={{ background: T.cream, borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}`, padding: "72px 48px" }}>
<div style={{ maxWidth: 960, margin: "0 auto", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 64, alignItems: "center" }}>
<div>
<div style={{ fontFamily: sans, fontSize: 11, fontWeight: 600, letterSpacing: "0.13em", textTransform: "uppercase", color: T.muted, marginBottom: 18 }}>
Sound familiar?
</div>
<h2 style={{ fontFamily: serif, fontSize: 34, fontWeight: 700, color: T.ink, lineHeight: 1.2, marginBottom: 24, letterSpacing: "-0.02em" }}>
The idea is the hard part. Everything else shouldn't be.
</h2>
<p style={{ fontFamily: sans, fontSize: 15, color: T.mid, lineHeight: 1.8, marginBottom: 20 }}>
You know exactly what you want to build and who it's for. But the moment you think about
servers, databases, deployment pipelines, SEO the whole thing stalls.
</p>
<p style={{ fontFamily: sans, fontSize: 15, color: T.mid, lineHeight: 1.8 }}>
vibn exists to remove all of that. Not abstract it {" "}
<em style={{ fontFamily: serif, fontStyle: "italic" }}>remove it entirely.</em>
</p>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
{PAINS.map((p, i) => (
<div key={i} style={{
background: T.white, border: `1px solid ${T.border}`,
borderRadius: 10, padding: "18px 20px",
display: "flex", alignItems: "flex-start", gap: 14,
}}>
<div style={{
width: 20, height: 20, borderRadius: "50%",
border: `1.5px solid ${T.stone}`,
display: "flex", alignItems: "center", justifyContent: "center",
flexShrink: 0, marginTop: 2,
}}>
<div style={{ width: 7, height: 7, borderRadius: "50%", background: T.ink }} />
</div>
<div>
<div style={{ fontFamily: serif, fontSize: 14, fontWeight: 600, color: T.ink, marginBottom: 4 }}>{p.title}</div>
<div style={{ fontFamily: sans, fontSize: 13, color: T.muted, lineHeight: 1.6 }}>{p.body}</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}
// ── STATS BAR ─────────────────────────────────────────────────────────────────
function StatsBar() {
const stats = [
{ n: "280+", label: "founders launched" },
{ n: "72h", label: "average time to first version" },
{ n: "4.9", label: "average rating" },
{ n: "3×", label: "faster than hiring a developer" },
];
return (
<section style={{ borderTop: `1px solid ${T.border}`, borderBottom: `1px solid ${T.border}`, background: T.white }}>
<div style={{ maxWidth: 960, margin: "0 auto", padding: "0 48px", display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
{stats.map((s, i) => (
<div key={i} style={{
padding: "36px 0",
borderRight: i < 3 ? `1px solid ${T.border}` : "none",
paddingLeft: i > 0 ? 36 : 0,
}}>
<div style={{ fontFamily: serif, fontSize: 36, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", marginBottom: 6 }}>{s.n}</div>
<div style={{ fontFamily: sans, fontSize: 13, color: T.muted, lineHeight: 1.5 }}>{s.label}</div>
</div>
))}
</div>
</section>
);
}
// ── FINAL CTA ─────────────────────────────────────────────────────────────────
function FinalCta({ onCta }) {
return (
<section style={{ maxWidth: 680, margin: "0 auto", padding: "88px 48px", textAlign: "center" }}>
<h2 style={{ fontFamily: serif, fontSize: 44, fontWeight: 700, color: T.ink, letterSpacing: "-0.03em", lineHeight: 1.1, marginBottom: 20 }}>
Your idea deserves to exist.
</h2>
<p style={{ fontFamily: sans, fontSize: 16, color: T.mid, lineHeight: 1.75, marginBottom: 36 }}>
Don't let the backend be the reason it doesn't. Start today free, no code, no credit card.
</p>
<button onClick={onCta} style={{
display: "inline-block", background: T.ink, color: T.paper,
fontFamily: sans, fontSize: 15, fontWeight: 600,
padding: "15px 40px", border: "none", borderRadius: 10,
cursor: "pointer", marginBottom: 16,
}}>
Build my product free
</button>
<div style={{ fontFamily: sans, fontSize: 12.5, color: T.stone }}>
Joins 280+ non-technical founders already live
</div>
</section>
);
}
// ── FOOTER ────────────────────────────────────────────────────────────────────
function Footer() {
const links = ["Product", "Pricing", "Stories", "Blog", "Privacy", "Terms"];
return (
<footer style={{ borderTop: `1px solid ${T.border}`, padding: "32px 48px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<span style={{ fontFamily: serif, fontSize: 16, fontWeight: 700, color: T.ink }}>vibn</span>
<div style={{ display: "flex", gap: 28 }}>
{links.map(l => (
<span key={l} style={{ fontFamily: sans, fontSize: 13, color: T.stone, cursor: "pointer" }}>{l}</span>
))}
</div>
<span style={{ fontFamily: sans, fontSize: 12.5, color: T.stone }}>© 2026 vibn</span>
</footer>
);
}
// ── ROOT EXPORT ───────────────────────────────────────────────────────────────
export default function Website({ onGetStarted, onLogin }) {
return (
<div style={{ fontFamily: sans, background: T.paper, color: T.ink, minHeight: "100vh" }}>
<style>{`
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400;1,600&family=Inter:wght@400;500;600&display=swap');
* { box-sizing: border-box; margin: 0; padding: 0; }
button { font-family: inherit; }
`}</style>
<Nav onGetStarted={onGetStarted} onLogin={onLogin} />
<Hero onCta={onGetStarted} />
<QuoteBand />
<HowItWorks />
<StatsBar />
<EmpathySection />
<FinalCta onCta={onGetStarted} />
<Footer />
</div>
);
}

View File

@@ -1,14 +0,0 @@
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, -apple-system, sans-serif; }
@keyframes vpulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
@keyframes vspin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes slideup {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}

View File

@@ -1,10 +0,0 @@
import React from 'react'
import './index.css'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)

View File

@@ -1,6 +0,0 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})

0
prompt
View File

View File

@@ -1,5 +0,0 @@
1|clqAOiQPygpuwyA5HVDyWoKfNRtDH8l4Huge2PCmef521cc1
gitea
8f6b2cbc2c9722aedbd6e88b83078371fc1bf67f

Submodule vibn-frontend updated: fa9cfda712...2e03a96b20