This repository has been archived on 2026-06-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
master-ai/justine/vibn front end/03_dashboard.html
mawkone 99deb546c8 Rip out Theia, bump submodules, retire platform/ scaffold, snapshot docs + design assets
Theia rip-out (parent):
- Remove theia submodule entry (the local fork, Gitea repo, Coolify app,
  Cloud Run services, and Artifact Registry image are all gone)
- Drop README.md + INFRASTRUCTURE.md (obsolete "Project OS" snapshots
  that also leaked API tokens) and setup.sh (Theia clone bootstrap)
- Delete UI-DESIGN-GUIDE.md, BACKEND_AGENTS_PLAN.md, VIBN_BUILD_PLAN.md,
  VISUAL_EDITOR_PLAN.md, core-packages.md, ai-packages.md, tools-list.md
  (all 100% Theia-specific or superseded)
- Surgical scrubs of remaining Theia mentions in
  AGENT_EXECUTION_ARCHITECTURE.md and TURBOREPO_MIGRATION_PLAN.md

Submodule bumps:
- vibn-agent-runner: Theia rip-out + MCP refactor (api/wrapper/server
  pattern across shell/file/git/memory/prd/search/agent/gitea/coolify)
- vibn-frontend: Theia rip-out + P5.1 attach E2E + Justine UI WIP

Retire platform/ scaffold:
- Remove platform/backend/ (control-plane, executors, mcp-adapter),
  platform/client-ide/ (gcp-productos extension), platform/contracts/,
  platform/infra/terraform/, platform/scripts/templates/turborepo/
  (replaced by vibn-agent-runner + vibn-frontend + Coolify direct)
- Drop architecture.md, technical_spec.md, vision-ext.md,
  "1.Generate Control Plane API scaffold.md" (same era)

Docs / planning snapshots (new):
- AI_CAPABILITIES.md, AI_CAPABILITIES_ROADMAP.md
- AGENT_TELEMETRY_STREAMING_PROJECT.md
- VIBN_PRD.md, product-idea-a.md

Design assets (new):
- branding/{coolify,gitea,ux-testing}/ static brand collateral
- justine/ HTML mockups for the new onboarding/build flows
- preview-assist-ui/ Vite scratch app
- master-ai.code-workspace

Infra helpers (new):
- setup-coolify-montreal.sh provisioner
- gitea-docker-compose.yml
- vibn-coolify-schema.sql for the Coolify Postgres extensions
- prd-agent-prompt.pdf, prompt, root.txt, remixed-9edec9e9.tsx scratch
- flatten.sh helper

.gitignore: ignore **/node_modules, **/.next, **/.turbo, **/coverage

Made-with: Cursor
2026-04-22 18:06:37 -07:00

2013 lines
141 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 — Dashboard</title>
<link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=Inter:wght@400;500;600&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-dim:rgba(99,102,241,0.08); --indigo-border:rgba(99,102,241,0.18);
--green:#059669; --green-dim:#D1FAE5;
--amber:#F59E0B; --amber-dim:#FFFBEB; --amber-border:#FDE68A;
--serif:'Plus Jakarta Sans',sans-serif; --sans:'Plus Jakarta Sans',sans-serif;
}
body{font-family:var(--sans);background:linear-gradient(160deg,#F4F3F0 0%,#EDE9FA 100%);min-height:100vh;display:flex;flex-direction:column;height:100vh;overflow:hidden;color:var(--ink);}
.f{font-family:var(--serif);}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:0.35;}}
/* ── App shell ── */
.app-shell{display:flex;flex:1;overflow:hidden;}
/* ── Left panel ── */
.proj-nav{width:256px;flex-shrink:0;background:#FFFFFF;border:1px solid rgba(0,0,0,0.07);border-radius:12px;display:flex;flex-direction:column;overflow:hidden;margin:8px 0 8px 8px;box-shadow:0 2px 8px rgba(0,0,0,0.05);}
/* ── Nav item buttons (Dashboard, Clients, Invoices…) ── */
.nav-item-btn{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:10px;border:1px solid transparent;background:transparent;cursor:pointer;width:100%;text-align:left;transition:background 0.18s ease,border-color 0.18s ease;margin-bottom:2px;font-family:var(--sans);}
.nav-item-btn:hover{background:rgba(0,0,0,0.05);}
.nav-item-btn.active{background:rgba(99,102,241,0.12);border-color:var(--indigo-border);}
.nav-icon{width:28px;height:28px;border-radius:7px;background:rgba(99,102,241,0.12);color:#3730A3;display:flex;align-items:center;justify-content:center;font-size:13px;flex-shrink:0;transition:background 0.18s ease;}
.nav-item-btn.active .nav-icon{background:var(--indigo-dim);}
.nav-label{font-size:13px;font-weight:500;color:var(--ink);line-height:1.3;}
.nav-item-btn.active .nav-label{color:var(--indigo);font-weight:600;}
.nav-sub{font-size:10.5px;color:var(--muted);}
.nav-group-label{font-size:10px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--muted);padding:0 8px;margin-bottom:4px;}
/* ── Project rows ── */
.proj-list{max-height:168px;overflow-y:auto;padding:4px 8px 8px;flex-shrink:0;}
.proj-row{display:flex;align-items:flex-start;gap:10px;padding:9px 10px;border-radius:10px;cursor:pointer;border:1px solid transparent;transition:background 0.18s ease,border-color 0.18s ease;margin-bottom:2px;}
.proj-edit-btn{opacity:0;transition:opacity 0.18s ease;background:none;border:none;cursor:pointer;padding:3px;border-radius:5px;display:flex;align-items:center;color:var(--muted);flex-shrink:0;margin-left:2px;}
.proj-row:hover .proj-edit-btn{opacity:1;}
.proj-edit-btn:hover{color:var(--indigo);background:var(--indigo-dim);}
/* ── Project edit popover ── */
#proj-edit-popover{position:fixed;display:none;background:var(--white);border:1px solid var(--border);border-radius:12px;padding:14px;z-index:300;box-shadow:0 8px 28px rgba(0,0,0,0.14);width:206px;}
#proj-edit-name{width:100%;box-sizing:border-box;border:1px solid var(--border);border-radius:6px;padding:6px 9px;font-family:var(--sans);font-size:13px;color:var(--ink);background:var(--white);outline:none;transition:border-color 0.15s;}
#proj-edit-name:focus{border-color:var(--indigo);}
.color-swatch{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2.5px solid transparent;transition:transform 0.12s ease,border-color 0.12s ease;}
.color-swatch:hover{transform:scale(1.18);}
.color-swatch.active{border-color:var(--ink);}
.proj-row:hover{background:rgba(0,0,0,0.05);}
.proj-row.active{background:rgba(99,102,241,0.12);border-color:var(--indigo-border);}
.proj-row.active .proj-row-name{color:var(--indigo);}
.proj-icon{width:30px;height:30px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:12px;font-weight:700;color:var(--white);flex-shrink:0;}
.proj-row-name{font-size:12.5px;font-weight:600;color:var(--ink);display:flex;align-items:center;gap:5px;flex-wrap:wrap;margin-bottom:2px;}
.proj-row-metric{font-size:11.5px;color:var(--mid);margin-bottom:1px;font-weight:500;}
.proj-row-time{font-size:10px;color:var(--muted);}
.alert-dot{width:6px;height:6px;border-radius:50%;background:var(--amber);flex-shrink:0;margin-top:5px;}
/* ── Status pills ── */
.pill{display:inline-flex;align-items:center;gap:3px;font-size:10px;font-weight:600;padding:2px 7px;border-radius:4px;white-space:nowrap;}
.pill-live{background:var(--green-dim);color:var(--green);}
.pill-building{background:#EDE9FE;color:#4338CA;}
.pill-draft{background:#F3F4F6;color:var(--mid);}
.dot-live{width:5px;height:5px;border-radius:50%;background:var(--green);display:inline-block;flex-shrink:0;}
.dot-building{width:5px;height:5px;border-radius:50%;background:#6366F1;display:inline-block;flex-shrink:0;animation:pulse 1.8s ease infinite;}
/* ── Search ── */
.nav-search-wrap{position:relative;}
.nav-search{width:100%;border:1px solid rgba(0,0,0,0.1);border-radius:8px;padding:7px 10px 7px 30px;font-family:var(--sans);font-size:12px;color:var(--ink);background:rgba(0,0,0,0.05);outline:none;transition:border-color 0.18s ease,background 0.18s ease;}
.nav-search:focus{border-color:var(--indigo);background:rgba(255,255,255,0.7);}
.nav-search::placeholder{color:var(--muted);}
/* ── Buttons ── */
.btn-primary{background:linear-gradient(135deg,#2E2A5E,#4338CA);color:var(--white);border:none;border-radius:8px;padding:10px 20px;font-family:var(--sans);font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 4px 14px rgba(30,27,75,0.14);transition:box-shadow 0.2s,transform 0.15s;white-space:nowrap;}
.btn-primary:hover{box-shadow:0 6px 20px rgba(30,27,75,0.22);transform:translateY(-1px);}
.btn-secondary{background:var(--white);color:var(--ink);border:1px solid var(--border);border-radius:8px;padding:9px 18px;font-family:var(--sans);font-size:13px;font-weight:500;cursor:pointer;transition:border-color 0.15s,background 0.15s,color 0.15s;white-space:nowrap;}
.btn-secondary:hover{border-color:var(--indigo);background:var(--cream);color:var(--indigo);}
.btn-ghost{background:none;color:var(--mid);border:none;font-family:var(--sans);font-size:12px;cursor:pointer;padding:6px 10px;border-radius:6px;transition:background 0.12s,color 0.12s;white-space:nowrap;}
.btn-ghost:hover{background:var(--cream);color:var(--ink);}
.btn-amber{background:var(--amber-dim);color:#92400E;border:1px solid var(--amber-border);border-radius:8px;padding:9px 16px;font-family:var(--sans);font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background 0.15s;}
.btn-amber:hover{background:#FEF3C7}
/* ── Nav footer ── */
.nav-footer{padding:12px 14px;border-top:1px solid var(--border);flex-shrink:0;}
/* ── Workspace ── */
.workspace{flex:1;overflow-y:auto;background:transparent;}
.ws-inner{max-width:1140px;padding:32px 36px;margin:0 auto;}
.ws-section{display:none;}
.ws-section.active{display:block;}
/* ── Workspace header ── */
.ws-header{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:28px;padding-bottom:24px;border-bottom:1px solid var(--border);}
.ws-header-left{flex:1;min-width:0;}
.ws-header-identity{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:7px;}
.proj-name-heading{border-radius:6px;padding:2px 5px;margin:-2px -5px;}
.proj-name-input{font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;font-family:var(--serif);border:none;border-bottom:2px solid var(--indigo);background:transparent;outline:none;padding:2px 0;width:auto;min-width:60px;max-width:280px;}
.client-card-header{position:relative;}
.client-edit-btn{position:absolute;top:12px;right:12px;opacity:0;transition:opacity 0.18s ease;background:none;border:none;cursor:pointer;padding:4px;border-radius:5px;display:flex;align-items:center;color:var(--muted);}
.client-card-header:hover .client-edit-btn{opacity:1;}
.client-edit-btn:hover{color:var(--indigo);background:var(--indigo-dim);}
#client-edit-popover{display:none;}
.client-edit-field{width:100%;box-sizing:border-box;border:1px solid var(--border);border-radius:8px;padding:8px 11px;font-family:var(--sans);font-size:13px;color:var(--ink);background:var(--white);outline:none;transition:border-color 0.15s;margin-bottom:10px;}
.client-edit-field:last-of-type{margin-bottom:0;}
.client-edit-field:focus{border-color:var(--indigo);}
.client-edit-label{font-size:11px;font-weight:600;color:var(--mid);display:block;margin-bottom:5px;text-transform:uppercase;letter-spacing:0.06em;}
.ws-header-desc{font-size:13px;color:var(--mid);padding-left:48px;line-height:1.5;}
.ws-header-actions{display:flex;gap:8px;align-items:center;flex-shrink:0;padding-top:4px;}
/* ── Priority card ── */
.priority-card{background:var(--white);border:1px solid #E0E7FF;border-left:4px solid var(--indigo);border-radius:12px;padding:22px 24px;display:flex;align-items:flex-start;gap:18px;margin-bottom:24px;box-shadow:0 2px 16px rgba(99,102,241,0.07);}
.priority-icon{width:42px;height:42px;border-radius:10px;background:var(--indigo-dim);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0;margin-top:2px;}
.priority-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--indigo);margin-bottom:5px;}
.priority-title{font-size:17px;font-weight:700;color:var(--ink);margin-bottom:7px;letter-spacing:-0.01em;}
.priority-desc{font-size:13px;color:var(--mid);line-height:1.65;margin-bottom:16px;}
/* ── Metric card states ── */
.metric-card-up{border-color:#6EE7B7!important;background:#ECFDF5!important;}
.metric-card-up .metric-label{color:#065F46!important;}
.metric-card-up .metric-value{color:#065F46!important;}
.metric-card-down{border-color:var(--amber-border)!important;background:var(--amber-dim)!important;}
.metric-card-down .metric-label{color:#92400E!important;}
.metric-card-down .metric-value{color:#92400E!important;}
.metric-card-flat{border-color:#BFDBFE!important;background:#EFF6FF!important;}
.metric-card-flat .metric-label{color:#1E40AF!important;}
.metric-card-flat .metric-value{color:#1E40AF!important;}
/* Dark mode overrides */
[data-theme="dark"] .metric-card-up{border-color:rgba(5,150,105,0.35)!important;background:rgba(5,150,105,0.12)!important;}
[data-theme="dark"] .metric-card-up .metric-label,[data-theme="dark"] .metric-card-up .metric-value{color:#6EE7B7!important;}
[data-theme="dark"] .metric-card-down{border-color:rgba(245,158,11,0.30)!important;background:rgba(245,158,11,0.12)!important;}
[data-theme="dark"] .metric-card-down .metric-label,[data-theme="dark"] .metric-card-down .metric-value{color:#FDE68A!important;}
[data-theme="dark"] .metric-card-flat{border-color:rgba(59,130,246,0.30)!important;background:rgba(59,130,246,0.10)!important;}
[data-theme="dark"] .metric-card-flat .metric-label,[data-theme="dark"] .metric-card-flat .metric-value{color:#93C5FD!important;}
/* ── Metrics ── */
.metrics-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:24px;}
.metric-card{background:var(--white);border:1px solid #E0DDD8;border-radius:10px;padding:16px 18px;box-shadow:0 1px 4px rgba(0,0,0,0.05);}
.metric-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:6px;}
.metric-value{font-family:var(--serif);font-size:24px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:4px;}
.metric-sub{font-size:11.5px;color:var(--mid);}
.trend-up{font-size:11.5px;color:var(--green);font-weight:600;}
.trend-down{font-size:11.5px;color:var(--amber);font-weight:500;}
.trend-neutral{font-size:11.5px;color:#3B82F6;font-weight:500;}
[data-theme="dark"] .trend-neutral{color:#93C5FD;}
/* ── Progress ── */
.progress-bar{height:5px;background:#E5E7EB;border-radius:3px;overflow:hidden;margin-top:10px;}
.progress-fill{height:100%;border-radius:3px;background:linear-gradient(90deg,#6366F1,#8B5CF6);}
.progress-fill-gray{height:100%;border-radius:3px;background:linear-gradient(90deg,#9CA3AF,#6B7280);}
/* ── Content cards ── */
.cards-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
.content-card{background:var(--white);border:1px solid #E0DDD8;border-radius:12px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.05);}
.card-head{padding:14px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;}
.card-title{font-size:13px;font-weight:600;color:var(--ink);}
.card-body{padding:16px 20px;}
/* ── Rows inside cards ── */
.health-row{display:flex;align-items:flex-start;gap:12px;padding:10px 0;border-bottom:1px solid var(--border);}
.health-row:last-child{border-bottom:none;padding-bottom:0;}
.health-icon{font-size:15px;width:22px;text-align:center;flex-shrink:0;margin-top:1px;}
.health-title{font-size:13px;font-weight:500;color:var(--ink);margin-bottom:2px;}
.health-sub{font-size:11.5px;color:var(--muted);}
.activity-row{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-bottom:1px solid var(--border);}
.activity-row:last-child{border-bottom:none;padding-bottom:0;}
.activity-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;margin-top:5px;}
.fin-row{display:flex;align-items:center;justify-content:space-between;padding:9px 0;border-bottom:1px solid var(--border);}
.fin-row:last-child{border-bottom:none;}
.milestone-row{display:flex;align-items:flex-start;gap:12px;padding:11px 0;border-bottom:1px solid var(--border);}
.milestone-row:last-child{border-bottom:none;padding-bottom:0;}
.milestone-row.is-current{background:rgba(99,102,241,0.04);border-radius:8px;padding:11px 10px;margin:2px -10px;border-left:3px solid var(--indigo);border-bottom:none;padding-left:7px;}
.m-check{width:20px;height:20px;border-radius:50%;border:2px solid var(--border);flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;margin-top:1px;}
.m-check.done{background:var(--green);border-color:var(--green);color:var(--white);}
.m-check.current{background:var(--indigo);border-color:var(--indigo);color:var(--white);animation:pulse 2s ease infinite;}
.m-check.pending{opacity:0.35;}
.setup-row{display:flex;align-items:flex-start;gap:10px;padding:10px 0;border-bottom:1px solid var(--border);}
.setup-row:last-child{border-bottom:none;padding-bottom:0;}
.s-check{width:18px;height:18px;border-radius:5px;border:2px solid var(--border);flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;margin-top:1px;}
.s-check.done{background:var(--indigo);border-color:var(--indigo);color:var(--white);}
.rec-block{padding-bottom:14px;margin-bottom:14px;border-bottom:1px solid var(--border);}
.rec-block:last-child{padding-bottom:0;margin-bottom:0;border-bottom:none;}
/* ════════════════════════════════════
DASHBOARD LANDING PAGE styles
════════════════════════════════════ */
.dash-section-title{font-family:var(--serif);font-size:14px;font-weight:600;color:var(--ink);margin-bottom:13px;letter-spacing:-0.01em;}
/* Attention cards */
.attn-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:36px;}
.attn-card{border-radius:12px;padding:22px;border:1px solid transparent;display:flex;flex-direction:column;}
.attn-card-amber{background:#FFFBEB;border-color:#FDE68A;}
.attn-card-indigo{background:#EDE9FE;border-color:#DDD6FE;}
.attn-card-slate{background:#F8FAFC;border-color:#E2E8F0;}
.attn-value{font-family:var(--serif);font-size:30px;font-weight:700;letter-spacing:-0.03em;margin-bottom:5px;}
.attn-value-amber{color:#92400E;}
.attn-value-indigo{color:#3730A3;}
.attn-value-slate{color:#334155;}
.attn-desc{font-size:13px;line-height:1.5;flex:1;}
.attn-desc-amber{color:#78350F;}
.attn-desc-indigo{color:#3730A3;}
.attn-desc-slate{color:#475569;}
.attn-cta{margin-top:18px;font-size:12.5px;font-weight:600;cursor:pointer;background:none;border:none;padding:0;display:inline-flex;align-items:center;gap:5px;transition:gap 0.15s;font-family:var(--sans);}
.attn-cta:hover{gap:9px;}
.attn-cta-amber{color:#92400E;}
.attn-cta-indigo{color:#4338CA;}
.attn-cta-slate{color:#475569;}
/* Snapshot cards */
.snap-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:36px;}
.snap-card{background:var(--white);border:1px solid #E0DDD8;border-radius:10px;padding:16px 18px;box-shadow:0 1px 4px rgba(0,0,0,0.05);}
.snap-value{font-family:var(--serif);font-size:24px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;margin-bottom:4px;}
.snap-label{font-size:11.5px;color:var(--muted);}
/* Performance cards */
.perf-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:36px;}
.perf-card{background:var(--white);border:1px solid #E0DDD8;border-radius:12px;padding:22px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.05);}
.perf-value{font-family:var(--serif);font-size:32px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;margin-bottom:4px;}
.perf-change{font-size:12px;font-weight:600;margin-bottom:3px;}
.perf-sublabel{font-size:11.5px;color:var(--muted);}
.perf-chart-wrap{margin-top:18px;}
/* Article cards */
.article-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;}
.article-card{background:var(--white);border:1px solid #E0DDD8;border-radius:12px;padding:22px;display:flex;flex-direction:column;box-shadow:0 1px 4px rgba(0,0,0,0.05);}
.article-emoji{font-size:22px;margin-bottom:12px;}
.article-title{font-family:var(--serif);font-size:15px;font-weight:600;color:var(--ink);margin-bottom:7px;}
.article-desc{font-size:12.5px;color:var(--mid);line-height:1.6;flex:1;}
.article-cta{margin-top:14px;font-size:12px;font-weight:600;color:var(--indigo);cursor:pointer;background:none;border:none;padding:0;font-family:var(--sans);display:inline-flex;align-items:center;gap:4px;transition:gap 0.15s;}
.article-cta:hover{gap:7px;}
/* ── Section table (Clients, Invoices, Costs) ── */
.sec-table{width:100%;border-collapse:collapse;}
.sec-table th{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.06em;color:var(--muted);padding:10px 16px;border-bottom:2px solid var(--border);text-align:left;background:#FAFAFA;}
.sec-table td{font-size:13px;padding:13px 16px;border-bottom:1px solid var(--border);color:var(--ink);vertical-align:middle;}
.sec-table tr:last-child td{border-bottom:none;}
.sec-table tbody tr:hover td{background:var(--cream);}
/* ── Modal ── */
.modal-overlay{position:fixed;inset:0;background:rgba(15,14,26,0.45);display:none;align-items:center;justify-content:center;z-index:100;backdrop-filter:blur(2px);}
.modal-overlay.open{display:flex;}
.modal-card{background:var(--white);border-radius:16px;padding:28px;width:100%;max-width:420px;box-shadow:0 24px 64px rgba(30,27,75,0.18);}
.modal-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;}
.modal-input:focus{border-color:var(--indigo);}
.modal-input::placeholder{color:var(--muted);}
.for-card{flex:1;border:1px solid var(--border);border-radius:9px;padding:14px;cursor:pointer;text-align:center;background:#FAFAFA;transition:all 0.15s;}
.for-card:hover,.for-card.sel{border-color:var(--indigo);background:var(--cream);}
/* ── Responsive ── */
@media(max-width:860px){
.attn-grid,.perf-grid,.article-grid{grid-template-columns:1fr 1fr;}
.snap-grid{grid-template-columns:1fr 1fr;}
.cards-grid{grid-template-columns:1fr;}
.ws-header{flex-direction:column;gap:12px;}
.ws-header-actions{flex-wrap:wrap;}
.ws-inner{padding:24px 20px;}
}
@media(max-width:600px){
.proj-nav{display:none!important;}
.workspace{padding-bottom:64px;}
.attn-grid,.perf-grid,.article-grid,.snap-grid{grid-template-columns:1fr;}
.ws-inner{padding:20px 16px;}
.ws-header-actions{gap:6px;width:100%;}
.ws-header-actions .btn-secondary,.ws-header-actions .btn-primary{font-size:12px;padding:10px 8px;flex:1;text-align:center;justify-content:center;}
.dash-header-actions{flex-direction:column;gap:6px!important;padding-top:0!important;}
.dash-header-actions .btn-secondary,.dash-header-actions .btn-primary{font-size:11.5px;padding:7px 12px;width:100%;}
.clients-grid{grid-template-columns:1fr!important;}
.content-card{overflow-x:auto;overflow-y:visible;-webkit-overflow-scrolling:touch;}
.sec-table{min-width:460px;}
.mob-col-hide{display:none!important;}
.mob-hide{display:none!important;}
}
/* ── Mobile bottom tab bar ── */
.mob-tab-bar{display:none;position:fixed;bottom:0;left:0;right:0;height:60px;background:var(--white);border-top:1px solid var(--border);align-items:stretch;z-index:200;padding-bottom:env(safe-area-inset-bottom);}
.mob-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;border:none;background:transparent;cursor:pointer;font-family:var(--sans);font-size:10px;font-weight:500;color:var(--muted);padding:8px 4px;transition:color 0.15s;}
.mob-tab.active{color:var(--indigo);}
.mob-tab svg{flex-shrink:0;transition:transform 0.15s;}
.mob-tab.active svg{transform:scale(1.1);}
@media(max-width:600px){.mob-tab-bar{display:flex;}}
/* ── Mobile project cards ── */
.mob-proj-card{background:var(--white);border:1px solid var(--border);border-radius:14px;padding:16px;display:flex;align-items:center;gap:14px;cursor:pointer;transition:border-color 0.15s,box-shadow 0.15s;}
.mob-proj-card:hover{border-color:var(--indigo);box-shadow:0 2px 12px rgba(99,102,241,0.1);}
/* ── Dark mode: mobile tab bar ── */
[data-theme="dark"] .mob-tab-bar{background:rgba(12,18,34,0.90);border-top-color:rgba(255,255,255,0.08);}
[data-theme="dark"] .mob-tab{color:rgba(255,255,255,0.40);}
[data-theme="dark"] .mob-tab.active{color:#6C7CFF;}
[data-theme="dark"] .mob-proj-card{background:rgba(255,255,255,0.05);border-color:rgba(255,255,255,0.08);}
/* ── Dark mode tokens — exact match with architect.html ── */
[data-theme="dark"]{
--ink:#EEEEFF; --mid:#9898B8; --muted:#8484A8; --indigo:#6C7CFF;
--border:rgba(255,255,255,0.08); --cream:rgba(108,124,255,0.14); --paper:#0A1120; --white:rgba(255,255,255,0.05);
--indigo-dim:rgba(108,124,255,0.14); --indigo-border:rgba(108,124,255,0.55);
--green-dim:rgba(5,150,105,0.18);
--amber-dim:rgba(245,158,11,0.14); --amber-border:rgba(245,158,11,0.30);
--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.05);--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"] nav{background:var(--dm-surf-topbar)!important;border-bottom:1px solid var(--dm-border)!important;-webkit-backdrop-filter:blur(20px)!important;backdrop-filter:blur(20px)!important;}
[data-theme="dark"] nav .f,[data-theme="dark"] nav span{color:var(--dm-text-1)!important;}
[data-theme="dark"] .proj-nav{background:var(--dm-surf-sidebar);border-color:rgba(255,255,255,0.12);box-shadow:0 4px 24px rgba(0,0,0,0.40),0 0 0 1px rgba(255,255,255,0.08),0 0 28px rgba(255,255,255,0.06);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);}
[data-theme="dark"] .proj-row:hover{background:rgba(255,255,255,0.05);}
[data-theme="dark"] .proj-row.active{background:var(--dm-accent-fill);border-color:var(--dm-accent-border);}
[data-theme="dark"] .proj-row:hover .proj-edit-btn{color:var(--dm-accent);}
[data-theme="dark"] .proj-edit-btn:hover{color:var(--dm-accent)!important;background:var(--dm-accent-fill)!important;}
[data-theme="dark"] #proj-edit-popover{background:#111828;border-color:var(--dm-border);box-shadow:0 0 0 1px rgba(108,124,255,0.16),0 24px 64px rgba(0,0,0,0.68);}
[data-theme="dark"] #proj-edit-name{background:rgba(255,255,255,0.04);border-color:var(--dm-border);color:var(--dm-text-1);}
[data-theme="dark"] #proj-edit-name:focus{border-color:var(--dm-accent);}
[data-theme="dark"] .color-swatch.active{border-color:var(--dm-text-1);}
[data-theme="dark"] .client-edit-btn{color:var(--muted);}
[data-theme="dark"] .client-card-header:hover .client-edit-btn{color:var(--dm-accent);}
[data-theme="dark"] .client-edit-btn:hover{color:var(--dm-accent)!important;background:var(--dm-accent-fill)!important;}
[data-theme="dark"] #client-edit-modal .modal-card,[data-theme="dark"] #add-client-modal .modal-card{background:#111828!important;box-shadow:0 0 0 1px rgba(255,255,255,0.10),0 0 0 1px rgba(108,124,255,0.16),0 24px 64px rgba(0,0,0,0.68),0 0 48px rgba(108,124,255,0.09)!important;}
[data-theme="dark"] .client-edit-field{background:rgba(255,255,255,0.05)!important;border-color:var(--dm-border)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] .client-edit-field:focus{border-color:var(--dm-accent)!important;}
[data-theme="dark"] .client-edit-label{color:var(--dm-text-3)!important;}
[data-theme="dark"] .nav-item-btn:hover{background:rgba(255,255,255,0.06);}
[data-theme="dark"] .nav-item-btn.active{background:var(--dm-accent-fill);}
[data-theme="dark"] .nav-icon{background:var(--dm-accent);color:#fcfcff;}
[data-theme="dark"] #nav-dashboard{background:rgba(255,255,255,0.06)!important;}
[data-theme="dark"] #nav-dashboard:hover{background:rgba(255,255,255,0.10)!important;}
[data-theme="dark"] .nav-search{background:rgba(255,255,255,0.05);border-color:var(--dm-border);color:var(--dm-text-1);}
[data-theme="dark"] .nav-search:focus{background:rgba(255,255,255,0.08);}
[data-theme="dark"] .workspace{background:transparent;}
[data-theme="dark"] .ws-header{border-bottom-color:var(--dm-border);}
[data-theme="dark"] .snap-card,[data-theme="dark"] .perf-card,[data-theme="dark"] .article-card,
[data-theme="dark"] .metric-card,[data-theme="dark"] .content-card{background:var(--dm-surf-card);border-color:var(--dm-border);box-shadow:0 0 0 1px rgba(255,255,255,0.06),0 2px 8px rgba(0,0,0,0.25);}
[data-theme="dark"] .card-head{border-bottom-color:var(--dm-border);}
[data-theme="dark"] .health-row,[data-theme="dark"] .activity-row,[data-theme="dark"] .fin-row,
[data-theme="dark"] .milestone-row,[data-theme="dark"] .setup-row,[data-theme="dark"] .rec-block{border-bottom-color:var(--dm-border);}
[data-theme="dark"] .attn-card-amber{background:rgba(245,158,11,0.12);border-color:rgba(245,158,11,0.30);}
[data-theme="dark"] .attn-card-indigo{background:rgba(108,124,255,0.15);border-color:rgba(108,124,255,0.35);}
[data-theme="dark"] .attn-card-slate{background:var(--dm-surf-card);border-color:var(--dm-border);}
[data-theme="dark"] .attn-value-slate{color:var(--dm-text-2);}
[data-theme="dark"] .attn-desc-slate{color:var(--dm-text-3);}
[data-theme="dark"] .attn-cta-slate{color:var(--dm-text-3);}
[data-theme="dark"] .pill-building{background:var(--dm-accent-fill);color:var(--dm-accent);}
[data-theme="dark"] .pill-draft{background:rgba(255,255,255,0.08);color:var(--mid);}
[data-theme="dark"] .progress-bar{background:rgba(255,255,255,0.08);}
[data-theme="dark"] .btn-primary{background:linear-gradient(135deg,#4B42D8 0%,#6C7CFF 100%)!important;color:#FFFFFF;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"] .proj-icon{color:#FFFFFF;}
[data-theme="dark"] .btn-amber{color:#FDE68A;}
[data-theme="dark"] .btn-amber:hover{background:rgba(255,255,255,0.10)!important;border-color:var(--dm-accent)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] [style*="color:#92400E"]{color:#FDE68A!important;}
[data-theme="dark"] [style*="color:#4338CA"]{color:var(--dm-accent)!important;}
[data-theme="dark"] [style*="color:#6366F1"]{color:var(--dm-accent)!important;}
[data-theme="dark"] .btn-secondary{background:rgba(255,255,255,0.05);border-color:var(--dm-border);color:var(--dm-text-1);}
[data-theme="dark"] .btn-secondary:hover{background:rgba(255,255,255,0.10);border-color:var(--dm-accent);}
[data-theme="dark"] .btn-ghost:hover{background:rgba(108,124,255,0.09);color:var(--dm-text-1);}
[data-theme="dark"] .settings-input{background:rgba(255,255,255,0.05)!important;border-color:var(--dm-border)!important;color:var(--dm-text-1)!important;}
[data-theme="dark"] .settings-input:focus{border-color:var(--dm-accent)!important;}
[data-theme="dark"] #settings-save-bar{background:var(--dm-accent-fill)!important;border-color:var(--dm-border)!important;}
.plan-option:hover{border-color:var(--indigo)!important;background:rgba(99,102,241,0.04)!important;}
.plan-option-selected{border-color:var(--indigo)!important;background:rgba(99,102,241,0.06)!important;}
[data-theme="dark"] .plan-option{border-color:var(--dm-border)!important;}
[data-theme="dark"] .plan-option:hover{border-color:var(--dm-accent)!important;background:var(--dm-accent-fill)!important;}
[data-theme="dark"] .plan-option-current,[data-theme="dark"] .plan-option-selected{border-color:var(--dm-accent)!important;background:var(--dm-accent-fill)!important;}
[data-theme="dark"] .sec-table th{background:rgba(255,255,255,0.03);border-bottom-color:var(--dm-border);}
[data-theme="dark"] .sec-table td{border-bottom-color:var(--dm-border);}
[data-theme="dark"] .sec-table tbody tr:hover td{background:rgba(108,124,255,0.06);}
[data-theme="dark"] .modal-overlay{background:rgba(10,12,24,0.65);}
[data-theme="dark"] .modal-card{background:#111828!important;box-shadow:0 0 0 1px rgba(255,255,255,0.10),0 0 0 1px rgba(108,124,255,0.16),0 24px 64px rgba(0,0,0,0.68),0 0 48px rgba(108,124,255,0.09)!important;}
[data-theme="dark"] .modal-input{background:rgba(255,255,255,0.05);border-color:var(--dm-border);}
[data-theme="dark"] .for-card{background:rgba(255,255,255,0.04);border-color:var(--dm-border);}
[data-theme="dark"] .for-card:hover,[data-theme="dark"] .for-card.sel{background:var(--dm-accent-fill);border-color:var(--dm-accent);}
[data-theme="dark"] #new-client-form{background:var(--dm-accent-fill)!important;border-color:var(--dm-border)!important;}
[data-theme="dark"] #new-client-toggle{border-color:var(--dm-border)!important;color:var(--dm-text-3)!important;}
[data-theme="dark"] #new-client-toggle:hover{border-color:var(--dm-accent)!important;color:var(--dm-accent)!important;}
.client-picker-option{display:flex;align-items:center;gap:10px;padding:9px 12px;border:1px solid var(--border);border-radius:8px;cursor:pointer;background:var(--white);transition:all 0.15s;}
.client-picker-option:hover,.client-picker-option.sel{border-color:var(--indigo);background:var(--cream);}
[data-theme="dark"] .client-picker-option{background:rgba(255,255,255,0.04);border-color:var(--dm-border);}
[data-theme="dark"] .client-picker-option:hover,[data-theme="dark"] .client-picker-option.sel{background:var(--dm-accent-fill);border-color:var(--dm-accent);}
/* Inline-style hardcode overrides */
[data-theme="dark"] [style*="background:#EDE9FE"]{background:rgba(108,124,255,0.20)!important;}
[data-theme="dark"] [style*="background:#FAFAFA"]{background:rgba(255,255,255,0.03)!important;}
[data-theme="dark"] [style*="background:#F3F4F6"]{background:rgba(255,255,255,0.05)!important;}
[data-theme="dark"] [style*="background:#E5E7EB"]{background:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] [style*="border-color:#E5E7EB"]{border-color:rgba(255,255,255,0.08)!important;}
[data-theme="dark"] [style*="background:#F8FAFC"]{background:rgba(255,255,255,0.03)!important;}
/* Scrollbars */
[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>
<!-- ── TOP NAV ── -->
<nav style="background:rgba(250,250,250,0.97);border-bottom:1px solid #E5E7EB;height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 24px;flex-shrink:0;backdrop-filter:blur(8px);">
<div style="display:flex;align-items:center;gap:9px;">
<div style="width:27px;height:27px;background:linear-gradient(135deg,#2E2A5E,#4338CA);border-radius:6px;display:flex;align-items:center;justify-content:center;"><span class="f" style="font-size:13px;font-weight:700;color:#FFFFFF;">V</span></div>
<span class="f" style="font-size:17px;font-weight:700;color:#1A1A1A;letter-spacing:-0.02em;">vibn</span>
</div>
<div style="display:flex;align-items:center;gap:16px;">
<button id="theme-toggle" class="btn-secondary mob-hide" onclick="toggleTheme()" style="font-size:12.5px;padding:7px 14px;">🌙 Dark mode</button>
<button onclick="selectView('settings')" style="display:flex;align-items:center;gap:8px;cursor:pointer;padding:5px 8px;border-radius:8px;transition:background 0.12s;border:none;background:transparent;font-family:var(--sans);" onmouseover="this.style.background='rgba(0,0,0,0.05)'" onmouseout="this.style.background='transparent'">
<div style="width:29px;height:29px;border-radius:50%;background:#6366F1;display:flex;align-items:center;justify-content:center;font-size:11px;color:#FFFFFF;font-weight:600;flex-shrink:0;">JD</div>
<div class="mob-hide" style="text-align:left;">
<div style="font-size:13px;font-weight:600;color:var(--ink);line-height:1.2;">Jane D.</div>
<div style="font-size:10.5px;color:var(--muted);">Pro plan · 448 credits</div>
</div>
</button>
</div>
</nav>
<!-- ── APP SHELL ── -->
<div class="app-shell">
<!-- ═══════════════════════════════
LEFT PANEL
════════════════════════════════ -->
<aside class="proj-nav">
<!-- Non-scrollable top: Dashboard + Projects header -->
<div style="flex-shrink:0;">
<div style="padding:10px 8px 8px;">
<button id="nav-dashboard" onclick="selectView('dashboard')" style="display:flex;align-items:center;gap:11px;padding:11px 12px;border-radius:10px;border:none;background:rgba(255,255,255,0.55);cursor:pointer;width:100%;text-align:left;font-family:var(--sans);transition:background 0.18s ease;backdrop-filter:blur(4px);" onmouseover="this.style.background='rgba(255,255,255,0.75)'" onmouseout="this.style.background='rgba(255,255,255,0.55)'">
<div style="width:32px;height:32px;border-radius:8px;background:linear-gradient(135deg,#4338CA,#6366F1);display:flex;align-items:center;justify-content:center;font-size:15px;flex-shrink:0;color:#FFFFFF;"></div>
<div>
<div style="font-size:14px;font-weight:700;color:var(--ink);">Dashboard</div>
<div style="font-size:10.5px;color:var(--muted);">Overview</div>
</div>
</button>
</div>
<!-- Projects section header -->
<div style="padding:10px 8px 8px;margin-top:2px;">
<div style="display:flex;align-items:center;justify-content:space-between;padding:0 4px;margin-bottom:8px;">
<div class="nav-group-label" style="margin:0;">Projects</div>
<button onclick="openModal()" style="background:none;border:none;cursor:pointer;font-size:18px;color:var(--indigo);padding:0 4px;line-height:1;font-weight:300;" title="New project">+</button>
</div>
<div class="nav-search-wrap" id="proj-search-wrap">
<svg style="position:absolute;left:9px;top:50%;transform:translateY(-50%);pointer-events:none;" width="12" height="12" viewBox="0 0 20 20" fill="none"><path d="M8.5 3a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 8.5a6.5 6.5 0 1111.436 4.23l3.857 3.857a.75.75 0 01-1.06 1.06l-3.857-3.857A6.5 6.5 0 012 8.5z" fill="#9CA3AF"/></svg>
<input class="nav-search" type="search" placeholder="Search projects…" oninput="filterProjects(this.value)">
</div>
</div>
</div>
<!-- Scrollable project list -->
<div class="proj-list" id="proj-list">
<!-- EMPTY STATE — shown when user has no projects -->
<div id="proj-empty-state" style="display:none;padding:20px 8px 12px;text-align:center;">
<div style="width:36px;height:36px;border-radius:10px;background:var(--indigo-dim);display:flex;align-items:center;justify-content:center;margin:0 auto 10px;font-size:18px;"></div>
<div style="font-size:12px;font-weight:600;color:var(--ink);margin-bottom:4px;">No projects yet</div>
<div style="font-size:11px;color:var(--muted);margin-bottom:12px;line-height:1.5;">Start building your first product with vibn.</div>
<button onclick="openModal()" style="background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:7px;padding:7px 14px;font-family:var(--sans);font-size:11.5px;font-weight:600;cursor:pointer;width:100%;">+ Create first project</button>
</div>
<!-- Launchpad — Live, personal -->
<div class="proj-row" id="row-launchpad" onclick="selectProject('launchpad')" data-name="launchpad">
<div class="proj-icon" data-project-color="launchpad" style="background:#6366F1;">L</div>
<div style="flex:1;min-width:0;">
<div class="proj-row-name">Launchpad <span class="pill pill-live"><span class="dot-live"></span>Live</span></div>
<div class="proj-row-metric" style="font-weight:400;color:var(--muted);">Personal</div>
</div>
<button class="proj-edit-btn" onclick="openEditPopover(event,'launchpad')" title="Edit project"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
<!-- Flowmatic — Live, client: Acme Corp -->
<div class="proj-row" id="row-flowmatic" onclick="selectProject('flowmatic')" data-name="flowmatic">
<div class="proj-icon" data-project-color="flowmatic" style="background:#8B5CF6;">F</div>
<div style="flex:1;min-width:0;">
<div class="proj-row-name">Flowmatic <span class="pill pill-live"><span class="dot-live"></span>Live</span></div>
<div class="proj-row-metric" data-client-id="acme" style="font-weight:400;color:var(--muted);">Acme Corp</div>
</div>
<div class="alert-dot" title="$48.20 unbilled"></div>
<button class="proj-edit-btn" onclick="openEditPopover(event,'flowmatic')" title="Edit project"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
<!-- Taskly — Building, client: Beta Labs -->
<div class="proj-row" id="row-taskly" onclick="selectProject('taskly')" data-name="taskly">
<div class="proj-icon" data-project-color="taskly" style="background:#06B6D4;">T</div>
<div style="flex:1;min-width:0;">
<div class="proj-row-name">Taskly <span class="pill pill-building"><span class="dot-building"></span>Building</span></div>
<div class="proj-row-metric" data-client-id="betalabs" style="font-weight:400;color:var(--muted);">Beta Labs</div>
</div>
<button class="proj-edit-btn" onclick="openEditPopover(event,'taskly')" title="Edit project"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
<!-- Notion Clone — Draft -->
<div class="proj-row" id="row-notion" onclick="selectProject('notion')" data-name="notion clone">
<div class="proj-icon" data-project-color="notion" style="background:#9CA3AF;">N</div>
<div style="flex:1;min-width:0;">
<div class="proj-row-name">Notion Clone <span class="pill pill-draft">Draft</span></div>
<div class="proj-row-metric" style="font-weight:400;color:var(--muted);">Personal</div>
</div>
<button class="proj-edit-btn" onclick="openEditPopover(event,'notion')" title="Edit project"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
</div>
<!-- Non-scrollable bottom: Workspace + Account nav -->
<div style="flex:1;padding:12px 8px 16px;display:flex;flex-direction:column;">
<div class="nav-group-label" style="margin-bottom:4px;">Workspace</div>
<button class="nav-item-btn" id="nav-clients" onclick="selectView('clients')">
<div class="nav-icon"></div>
<div><div class="nav-label">Clients</div><div class="nav-sub">2 active clients</div></div>
<div style="margin-left:auto;background:#F3F4F6;border:1px solid var(--border);border-radius:8px;padding:1px 7px;font-size:10px;font-weight:600;color:var(--mid);">2</div>
</button>
<button class="nav-item-btn" id="nav-invoices" onclick="selectView('invoices')">
<div class="nav-icon"></div>
<div><div class="nav-label">Invoices</div><div class="nav-sub">$48.20 unbilled</div></div>
</button>
<div style="height:1px;background:var(--border);margin:8px 4px;"></div>
<div class="nav-group-label" style="margin-bottom:4px;">Account</div>
<button class="nav-item-btn" id="nav-costs" onclick="selectView('costs')">
<div class="nav-icon">$</div>
<div><div class="nav-label">Cost tracker</div><div class="nav-sub">$57.40 this month</div></div>
</button>
<button class="nav-item-btn" id="nav-settings" onclick="selectView('settings')">
<div class="nav-icon"></div>
<div class="nav-label">Settings</div>
</button>
<button class="nav-item-btn">
<div class="nav-icon">?</div>
<div class="nav-label">Help</div>
</button>
</div>
</aside>
<!-- ═══════════════════════════════
WORKSPACE (right panel)
════════════════════════════════ -->
<main class="workspace" id="workspace">
<!-- ════════════════════════════════════════
DASHBOARD — Landing page (home)
════════════════════════════════════════ -->
<div id="ws-dashboard" class="ws-section active">
<div class="ws-inner">
<!-- 1. Header -->
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:36px;">
<div>
<h1 class="f" id="greeting-text" style="font-size:28px;font-weight:700;color:var(--ink);letter-spacing:-0.03em;margin-bottom:7px;">Good morning, Jane.</h1>
<p style="font-size:14px;color:var(--muted);line-height:1.5;">Here's what's happening across your products today.</p>
</div>
<div class="dash-header-actions" style="display:flex;gap:9px;align-items:center;flex-shrink:0;padding-top:4px;">
<button class="btn-secondary" onclick="selectView('invoices')">Create invoice</button>
<button class="btn-primary" onclick="openModal()">+ New project</button>
</div>
</div>
<!-- EMPTY STATE — shown when user has no projects yet (toggle display to test) -->
<div id="ws-empty-state" style="display:none;margin-bottom:36px;">
<div style="background:var(--white);border:1px solid var(--border);border-radius:16px;padding:48px 36px;text-align:center;max-width:480px;margin:0 auto;">
<div style="width:56px;height:56px;border-radius:14px;background:linear-gradient(135deg,rgba(99,102,241,0.12),rgba(139,92,246,0.12));display:flex;align-items:center;justify-content:center;margin:0 auto 20px;font-size:26px;"></div>
<h2 class="f" style="font-size:20px;font-weight:700;color:var(--ink);margin-bottom:8px;letter-spacing:-0.02em;">Build your first product</h2>
<p style="font-size:14px;color:var(--muted);line-height:1.6;margin-bottom:24px;">Describe your idea, and vibn will architect, design, and help you ship it — no code required.</p>
<button onclick="openModal()" style="background:linear-gradient(135deg,#2E2A5E,#4338CA);color:#FFFFFF;border:none;border-radius:9px;padding:11px 28px;font-family:var(--sans);font-size:14px;font-weight:600;cursor:pointer;box-shadow:0 6px 18px rgba(30,27,75,0.18);">+ Start a new project</button>
</div>
</div>
<!-- 2. Portfolio Snapshot -->
<div class="dash-section-title">Portfolio snapshot</div>
<div class="snap-grid">
<div class="snap-card">
<div class="snap-value">4</div>
<div class="snap-label">Active projects</div>
</div>
<div class="snap-card">
<div class="snap-value" style="color:var(--green);">2</div>
<div class="snap-label">Live products</div>
</div>
<div class="snap-card">
<div class="snap-value" style="color:#4338CA;">1</div>
<div class="snap-label">Building now</div>
</div>
<div class="snap-card" style="border-color:var(--amber-border);background:var(--amber-dim);">
<div class="snap-value" style="color:#92400E;">$48.20</div>
<div class="snap-label" style="color:#B45309;">Unbilled revenue</div>
</div>
</div>
<!-- 3. Overall Performance -->
<div style="display:flex;align-items:baseline;justify-content:space-between;margin-bottom:13px;">
<div class="dash-section-title" style="margin-bottom:0;">Overall performance</div>
<span style="font-size:11.5px;color:var(--muted);">Aggregated across all projects</span>
</div>
<div class="perf-grid">
<div class="perf-card">
<div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:8px;">Monthly Revenue</div>
<div class="perf-value">$1,050</div>
<div class="perf-change" style="color:var(--green);">↑ +$60 from last month</div>
<div class="perf-sublabel">Launchpad $840 · Flowmatic $210</div>
<div class="perf-chart-wrap">
<!-- Revenue: ~$600→dip→$650→$760→$840 (Flowmatic joins)→$870→dip→$950→$1000→$1050 -->
<svg viewBox="0 0 120 44" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:44px;">
<defs><linearGradient id="mrr-g" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#6366F1" stop-opacity="0.14"/><stop offset="100%" stop-color="#6366F1" stop-opacity="0"/></linearGradient></defs>
<path d="M0,19 C4,19 9,20 13,20 C17,20 22,18 27,17 C32,16 36,15 40,15 C44,13 48,12 53,11 C58,10 62,9.5 67,9 C71,9 75,9.5 80,10 C84,8 88,7 93,6 C97,5 101,4.5 107,4 C112,3.5 116,2.5 120,2 L120,44 L0,44 Z" fill="url(#mrr-g)"/>
<path d="M0,19 C4,19 9,20 13,20 C17,20 22,18 27,17 C32,16 36,15 40,15 C44,13 48,12 53,11 C58,10 62,9.5 67,9 C71,9 75,9.5 80,10 C84,8 88,7 93,6 C97,5 101,4.5 107,4 C112,3.5 116,2.5 120,2" stroke="#6366F1" stroke-width="1.5" fill="none" stroke-linecap="round"/>
</svg>
</div>
</div>
<div class="perf-card">
<div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:8px;">Active Users</div>
<div class="perf-value">180</div>
<div class="perf-change" style="color:var(--green);">↑ +12 this week</div>
<div class="perf-sublabel">Across 2 live products</div>
<div class="perf-chart-wrap">
<!-- Users: 80→82→88→95→105→118→plateau~116→130→155→168→180 -->
<svg viewBox="0 0 120 44" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:44px;">
<defs><linearGradient id="usr-g" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#059669" stop-opacity="0.13"/><stop offset="100%" stop-color="#059669" stop-opacity="0"/></linearGradient></defs>
<path d="M0,24 C4,24 8,24 12,24 C16,23 20,22.5 24,22 C28,21.5 32,21 36,21 C40,20.3 44,19.7 48,19 C52,18 56,17 60,16 C64,16 68,16 72,16 C76,14.7 80,13.8 84,13 C88,10.7 92,9.3 96,8 C100,6.3 104,5.3 108,5 C112,4 116,3 120,2 L120,44 L0,44 Z" fill="url(#usr-g)"/>
<path d="M0,24 C4,24 8,24 12,24 C16,23 20,22.5 24,22 C28,21.5 32,21 36,21 C40,20.3 44,19.7 48,19 C52,18 56,17 60,16 C64,16 68,16 72,16 C76,14.7 80,13.8 84,13 C88,10.7 92,9.3 96,8 C100,6.3 104,5.3 108,5 C112,4 116,3 120,2" stroke="#059669" stroke-width="1.5" fill="none" stroke-linecap="round"/>
</svg>
</div>
</div>
<div class="perf-card">
<div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:8px;">Build Progress</div>
<div class="perf-value">60%</div>
<div class="perf-change" style="color:#4338CA;">↑ Taskly on track</div>
<div class="perf-sublabel">Payment milestone due Mar 30</div>
<div class="perf-chart-wrap">
<div style="height:6px;background:#E5E7EB;border-radius:4px;overflow:hidden;margin-top:20px;">
<div style="width:60%;height:100%;background:linear-gradient(90deg,#6366F1,#8B5CF6);border-radius:4px;"></div>
</div>
<div style="display:flex;justify-content:space-between;margin-top:7px;">
<span style="font-size:10.5px;color:var(--muted);">3 of 5 milestones done</span>
<span style="font-size:10.5px;color:#4338CA;font-weight:600;">Due Mar 30</span>
</div>
</div>
</div>
</div>
<!-- 4. Next milestones -->
<div class="dash-section-title">Next milestones</div>
<div class="content-card" style="margin-bottom:36px;">
<div class="card-body" style="padding:0;">
<!-- Taskly: current milestone -->
<div style="display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:16px;padding:16px 20px;border-bottom:1px solid var(--border);">
<div style="display:flex;align-items:center;gap:12px;min-width:0;">
<div style="width:8px;height:8px;border-radius:50%;background:#6366F1;flex-shrink:0;animation:pulse 2s ease infinite;"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);">Payment integration</div>
<div style="font-size:11.5px;color:var(--muted);margin-top:2px;">Taskly · Stripe checkout</div>
</div>
</div>
<span style="font-size:11.5px;font-weight:600;color:#4338CA;background:#EDE9FE;padding:3px 9px;border-radius:5px;white-space:nowrap;">In progress</span>
<div style="text-align:right;">
<div style="font-size:12px;font-weight:600;color:var(--ink);">Mar 30</div>
<div style="font-size:10.5px;color:var(--amber);font-weight:600;">7 days left</div>
</div>
</div>
<!-- Taskly: next upcoming -->
<div style="display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:16px;padding:16px 20px;border-bottom:1px solid var(--border);">
<div style="display:flex;align-items:center;gap:12px;min-width:0;">
<div style="width:8px;height:8px;border-radius:50%;background:#D1D5DB;flex-shrink:0;"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);">Launch &amp; handoff</div>
<div style="font-size:11.5px;color:var(--muted);margin-top:2px;">Taskly · Beta Labs delivery</div>
</div>
</div>
<span style="font-size:11.5px;font-weight:500;color:var(--muted);background:#F3F4F6;padding:3px 9px;border-radius:5px;white-space:nowrap;">Upcoming</span>
<div style="text-align:right;">
<div style="font-size:12px;font-weight:600;color:var(--ink);">Mar 31</div>
<div style="font-size:10.5px;color:var(--muted);">8 days left</div>
</div>
</div>
<!-- Launchpad: growth goal -->
<div style="display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:16px;padding:16px 20px;border-bottom:1px solid var(--border);">
<div style="display:flex;align-items:center;gap:12px;min-width:0;">
<div style="width:8px;height:8px;border-radius:50%;background:var(--green);flex-shrink:0;"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);">Reach 200 active users</div>
<div style="font-size:11.5px;color:var(--muted);margin-top:2px;">Launchpad · Currently 142</div>
</div>
</div>
<span style="font-size:11.5px;font-weight:500;color:var(--green);background:var(--green-dim);padding:3px 9px;border-radius:5px;white-space:nowrap;">On track</span>
<div style="text-align:right;">
<div style="font-size:12px;font-weight:600;color:var(--ink);">Apr 15</div>
<div style="font-size:10.5px;color:var(--muted);">23 days left</div>
</div>
</div>
<!-- Notion Clone: setup -->
<div style="display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:16px;padding:16px 20px;">
<div style="display:flex;align-items:center;gap:12px;min-width:0;">
<div style="width:8px;height:8px;border-radius:50%;background:#D1D5DB;flex-shrink:0;"></div>
<div>
<div style="font-size:13px;font-weight:600;color:var(--ink);">Complete project setup</div>
<div style="font-size:11.5px;color:var(--muted);margin-top:2px;">Notion Clone · Define &amp; scope</div>
</div>
</div>
<span style="font-size:11.5px;font-weight:500;color:var(--muted);background:#F3F4F6;padding:3px 9px;border-radius:5px;white-space:nowrap;">Not started</span>
<div style="text-align:right;">
<div style="font-size:12px;color:var(--muted);">No date</div>
</div>
</div>
</div>
</div>
<!-- 5. Helpful resources -->
<div class="dash-section-title">Helpful resources</div>
<div class="article-grid">
<div class="article-card">
<div class="article-emoji">📊</div>
<div class="article-title">SaaS Metrics 101</div>
<div class="article-desc">Learn the key numbers every SaaS founder should track — MRR, churn, LTV, CAC, and what they actually mean for your business.</div>
<button class="article-cta">Read more →</button>
</div>
<div class="article-card">
<div class="article-emoji">🚀</div>
<div class="article-title">From idea to MVP</div>
<div class="article-desc">A step-by-step guide to turning a rough concept into a working product people will pay for — without overbuilding or wasting time.</div>
<button class="article-cta">Read more →</button>
</div>
<div class="article-card">
<div class="article-emoji">💰</div>
<div class="article-title">Pricing your SaaS</div>
<div class="article-desc">How to pick a pricing model, set your first price, and increase it over time — with real examples from indie makers who got it right.</div>
<button class="article-cta">Read more →</button>
</div>
</div>
</div>
</div><!-- /ws-dashboard -->
<!-- ════════════════════════════════════════
LAUNCHPAD — Live, personal product
════════════════════════════════════════ -->
<div id="ws-launchpad" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<div class="ws-header-identity">
<div data-project-color="launchpad" style="width:38px;height:38px;border-radius:10px;background:#6366F1;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:16px;font-weight:700;color:#FFFFFF;flex-shrink:0;">L</div>
<h1 class="f proj-name-heading" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Launchpad</h1>
<span class="pill pill-live" style="font-size:11px;padding:3px 9px;"><span class="dot-live"></span>Live</span>
<a href="#" style="display:flex;align-items:center;gap:3px;font-size:12px;color:var(--muted);text-decoration:none;font-weight:500;transition:color 0.15s;" onmouseover="this.style.color='#6366F1'" onmouseout="this.style.color='#9CA3AF'">
<svg width="11" height="11" viewBox="0 0 14 14" fill="none"><path d="M5 2H2a1 1 0 00-1 1v9a1 1 0 001 1h9a1 1 0 001-1V9M8 1h5m0 0v5m0-5L6 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
launchpad.vibn.app
</a>
</div>
<p class="ws-header-desc">AI-powered launch page builder for indie makers</p>
</div>
<div class="ws-header-actions">
<button class="btn-secondary">Build</button>
<button class="btn-secondary">Grow</button>
<button class="btn-primary">Open project ↗</button>
</div>
</div>
<div class="priority-card">
<div class="priority-icon">📈</div>
<div style="flex:1;">
<div class="priority-label">What to do next</div>
<div class="f priority-title">Focus on conversion this week</div>
<p class="priority-desc">You're pulling 2,400 visitors per month but only 6% convert to paying users. Improving your pricing page or onboarding flow could unlock significant growth — even a 2% lift adds $168/mo in MRR.</p>
<button class="btn-primary" style="font-size:12.5px;padding:9px 20px;">Improve pricing page</button>
</div>
</div>
<div class="metrics-row">
<div class="metric-card"><div class="metric-label">Monthly revenue</div><div class="metric-value">$840</div><div class="trend-up">↑ +$60 this month</div></div>
<div class="metric-card"><div class="metric-label">Active users</div><div class="metric-value">142</div><div class="metric-sub">3 new this week</div></div>
<div class="metric-card"><div class="metric-label">Visitors / month</div><div class="metric-value">2,400</div><div class="trend-neutral">→ Stable</div></div>
<div class="metric-card metric-card-up"><div class="metric-label">Conversion rate</div><div class="metric-value">8%</div><div class="trend-up">↑ from 6% last month</div></div>
</div>
<div class="cards-grid">
<div class="content-card">
<div class="card-head"><span class="card-title">Site performance</span><button class="btn-ghost" style="font-size:11.5px;">View analytics</button></div>
<div class="card-body">
<div class="health-row"><span class="health-icon"></span><div><div class="health-title">Traffic is stable</div><div class="health-sub">2,400 visitors/mo — no drop detected</div></div></div>
<div class="health-row"><span class="health-icon">📈</span><div><div class="health-title">MRR growing +7.7%</div><div class="health-sub">$780 → $840 vs last month</div></div></div>
<div class="health-row"><span class="health-icon">👥</span><div><div class="health-title">3 new paying users</div><div class="health-sub">This week · 0 churn this month</div></div></div>
<div class="health-row"><span class="health-icon">📈</span><div><div class="health-title" style="color:#059669;">Conversion improving</div><div class="health-sub">8% vs 6% last month</div></div></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Recent activity</span></div>
<div class="card-body">
<div class="activity-row"><div class="activity-dot" style="background:var(--indigo);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">Blog post published</div><div style="font-size:11px;color:var(--muted);">"How to launch faster with AI"</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">2h ago</span></div>
<div class="activity-row"><div class="activity-dot" style="background:var(--green);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">New signup</div><div style="font-size:11px;color:var(--muted);">marcus@email.com</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">5h ago</span></div>
<div class="activity-row"><div class="activity-dot" style="background:var(--muted);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">Newsletter #12 scheduled</div><div style="font-size:11px;color:var(--muted);">Sends tomorrow at 9am</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">Yesterday</span></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Revenue summary</span></div>
<div class="card-body">
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Monthly recurring revenue</span><span class="f" style="font-size:16px;font-weight:700;">$840</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Unbilled</span><span style="font-size:13px;font-weight:600;color:var(--green);">$0 — all clear</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Billing type</span><span style="font-size:13px;color:var(--muted);">Personal product</span></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Recommendations</span></div>
<div class="card-body">
<div class="rec-block"><div style="font-size:12px;font-weight:600;margin-bottom:5px;">💡 Run an A/B test on pricing</div><div style="font-size:12.5px;color:var(--mid);line-height:1.55;margin-bottom:8px;">Industry conversion for your category is 812%. At 6%, a better pricing page could add $100200/mo.</div><button class="btn-secondary" style="font-size:12px;padding:6px 14px;">Set up A/B test</button></div>
<div class="rec-block"><div style="font-size:12px;font-weight:600;margin-bottom:5px;">📦 Consider annual pricing</div><div style="font-size:12.5px;color:var(--mid);line-height:1.55;">An annual plan typically improves LTV by 30% and gives you better cash flow predictability.</div></div>
</div>
</div>
</div>
</div>
</div><!-- /ws-launchpad -->
<!-- ════════════════════════════════════════
FLOWMATIC — Live, client: Acme Corp
════════════════════════════════════════ -->
<div id="ws-flowmatic" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<div class="ws-header-identity">
<div data-project-color="flowmatic" style="width:38px;height:38px;border-radius:10px;background:#8B5CF6;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:16px;font-weight:700;color:#FFFFFF;flex-shrink:0;">F</div>
<h1 class="f proj-name-heading" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Flowmatic</h1>
<span class="pill pill-live" style="font-size:11px;padding:3px 9px;"><span class="dot-live"></span>Live</span>
<span data-client-name="acme" style="font-size:12px;color:var(--ink);font-weight:500;background:var(--border);padding:2px 9px;border-radius:4px;">Acme Corp</span>
<a href="#" style="display:flex;align-items:center;gap:3px;font-size:12px;color:var(--muted);text-decoration:none;font-weight:500;" onmouseover="this.style.color='#6366F1'" onmouseout="this.style.color='#9CA3AF'">
<svg width="11" height="11" viewBox="0 0 14 14" fill="none"><path d="M5 2H2a1 1 0 00-1 1v9a1 1 0 001 1h9a1 1 0 001-1V9M8 1h5m0 0v5m0-5L6 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
flowmatic.app
</a>
</div>
<p class="ws-header-desc">Workflow automation tool built for Acme Corp</p>
</div>
<div class="ws-header-actions">
<button class="btn-secondary" onclick="selectView('invoices')">Invoice Acme Corp</button>
<button class="btn-primary">Open project ↗</button>
</div>
</div>
<div class="priority-card">
<div class="priority-icon">💰</div>
<div style="flex:1;">
<div class="priority-label">Ready to bill</div>
<div class="f priority-title">$48.20 unbilled — invoice Acme Corp</div>
<p class="priority-desc">This month's costs are ready to bill. Sending Acme Corp's invoice now ensures you get paid on time before month end.</p>
<button class="btn-primary" style="font-size:12.5px;padding:9px 20px;" onclick="selectView('invoices')">Create invoice →</button>
</div>
</div>
<div class="metrics-row">
<div class="metric-card"><div class="metric-label">Monthly revenue</div><div class="metric-value">$210</div><div class="trend-neutral">→ Stable</div></div>
<div class="metric-card"><div class="metric-label">Active users</div><div class="metric-value">38</div><div class="metric-sub">Acme Corp team</div></div>
<div class="metric-card"><div class="metric-label">Visitors / month</div><div class="metric-value">620</div><div class="trend-neutral">→ Stable</div></div>
<div class="metric-card metric-card-flat"><div class="metric-label">Conversion rate</div><div class="metric-value">6.1%</div><div class="trend-neutral">→ Stable</div></div>
</div>
<div class="cards-grid">
<div class="content-card">
<div class="card-head"><span class="card-title">Site performance</span></div>
<div class="card-body">
<div class="health-row"><span class="health-icon"></span><div><div class="health-title">Product is live and stable</div><div class="health-sub">No downtime reported</div></div></div>
<div class="health-row"><span class="health-icon">👥</span><div><div class="health-title">38 active users</div><div class="health-sub">Acme Corp team actively using the product</div></div></div>
<div class="health-row"><span class="health-icon">⚠️</span><div><div class="health-title" style="color:#92400E;">Invoice not sent</div><div class="health-sub">$48.20 has not been billed yet</div></div></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Costs &amp; billing</span></div>
<div class="card-body">
<div style="background:var(--indigo-dim);border:1px solid var(--indigo-border);border-radius:9px;padding:14px 16px;margin-bottom:16px;display:flex;align-items:center;justify-content:space-between;gap:12px;">
<div><div style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--indigo);margin-bottom:3px;">Unbilled this month</div><div class="f" style="font-size:22px;font-weight:700;color:var(--ink);">$48.20</div></div>
<button class="btn-secondary" style="font-size:12px;padding:8px 14px;" onclick="selectView('invoices')">Invoice Acme</button>
</div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">LLM usage</span><span style="font-size:13px;font-weight:500;">$29.20</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Compute</span><span style="font-size:13px;font-weight:500;">$11.60</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Other</span><span style="font-size:13px;font-weight:500;">$7.40</span></div>
</div>
</div>
</div>
</div>
</div><!-- /ws-flowmatic -->
<!-- ════════════════════════════════════════
TASKLY — Building, client: Beta Labs
════════════════════════════════════════ -->
<div id="ws-taskly" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<div class="ws-header-identity">
<div data-project-color="taskly" style="width:38px;height:38px;border-radius:10px;background:#06B6D4;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:16px;font-weight:700;color:#FFFFFF;flex-shrink:0;">T</div>
<h1 class="f proj-name-heading" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Taskly</h1>
<span class="pill pill-building" style="font-size:11px;padding:3px 9px;"><span class="dot-building"></span>Building</span>
<span data-client-name="betalabs" style="font-size:12px;color:var(--ink);font-weight:500;background:var(--border);padding:2px 9px;border-radius:4px;">Beta Labs</span>
</div>
<p class="ws-header-desc">Task management tool for distributed remote teams</p>
</div>
<div class="ws-header-actions">
<button class="btn-primary">Continue building →</button>
</div>
</div>
<div class="priority-card">
<div class="priority-icon">⚙️</div>
<div style="flex:1;">
<div class="priority-label">What to do next</div>
<div class="f priority-title">Complete payment integration — you're almost there</div>
<p class="priority-desc">Payment is the last major feature before launch. Finishing it this week keeps you on track for the March 30 release date and gets Beta Labs live on time. You've already completed 3 of 5 milestones.</p>
<button class="btn-primary" style="font-size:12.5px;padding:9px 20px;">Continue building</button>
</div>
</div>
<div class="metrics-row">
<div class="metric-card"><div class="metric-label">Build progress</div><div class="metric-value">60%</div><div class="progress-bar"><div class="progress-fill" style="width:60%;"></div></div></div>
<div class="metric-card"><div class="metric-label">Current milestone</div><div class="metric-value" style="font-size:18px;margin-top:2px;">Payment</div><div class="metric-sub">Stripe integration</div></div>
<div class="metric-card"><div class="metric-label">Days active</div><div class="metric-value">14</div><div class="metric-sub">Since Mar 9</div></div>
</div>
<div style="margin-bottom:16px;">
<div class="content-card">
<div class="card-head"><span class="card-title">Milestone roadmap</span><span style="font-size:11.5px;color:var(--indigo);font-weight:600;">3 of 5 done · Due Mar 30</span></div>
<div class="card-body">
<div class="milestone-row"><div class="m-check done"></div><div style="flex:1;"><div style="font-size:13px;font-weight:500;color:var(--mid);">Discover &amp; design</div></div><span style="font-size:11px;color:var(--muted);">Mar 9</span></div>
<div class="milestone-row"><div class="m-check done"></div><div style="flex:1;"><div style="font-size:13px;font-weight:500;color:var(--mid);">Authentication &amp; user accounts</div></div><span style="font-size:11px;color:var(--muted);">Mar 13</span></div>
<div class="milestone-row"><div class="m-check done"></div><div style="flex:1;"><div style="font-size:13px;font-weight:500;color:var(--mid);">Core task features</div></div><span style="font-size:11px;color:var(--muted);">Mar 19</span></div>
<div class="milestone-row is-current"><div class="m-check current"></div><div style="flex:1;"><div style="font-size:13px;font-weight:600;color:var(--ink);">Payment integration</div><div style="font-size:11.5px;color:var(--muted);margin-top:2px;">Stripe checkout · In progress</div></div><span style="font-size:11px;color:var(--indigo);font-weight:600;">Due Mar 30</span></div>
<div class="milestone-row"><div class="m-check pending"></div><div style="flex:1;opacity:0.45;"><div style="font-size:13px;color:var(--mid);">Launch &amp; handoff to Beta Labs</div></div><span style="font-size:11px;color:var(--muted);opacity:0.45;">Mar 31</span></div>
</div>
</div>
</div>
<div class="cards-grid">
<div class="content-card">
<div class="card-head"><span class="card-title">Recent activity</span></div>
<div class="card-body">
<div class="activity-row"><div class="activity-dot" style="background:var(--indigo);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">Checkout page deployed</div><div style="font-size:11px;color:var(--muted);">LLM generated — $1.24</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">6h ago</span></div>
<div class="activity-row"><div class="activity-dot" style="background:var(--indigo);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">Auth flow completed</div><div style="font-size:11px;color:var(--muted);">Login, register &amp; reset working</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">Yesterday</span></div>
<div class="activity-row"><div class="activity-dot" style="background:var(--muted);"></div><div style="flex:1;"><div style="font-size:12.5px;color:var(--ink);">Design approved by Beta Labs</div><div style="font-size:11px;color:var(--muted);">Ready to proceed</div></div><span style="font-size:10.5px;color:var(--muted);white-space:nowrap;">Mar 12</span></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Costs &amp; billing</span></div>
<div class="card-body">
<div style="background:#F8FAFC;border:1px solid var(--border);border-radius:9px;padding:14px 16px;margin-bottom:16px;display:flex;align-items:center;justify-content:space-between;gap:12px;">
<div>
<div style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:3px;">Accrued costs</div>
<div class="f" style="font-size:22px;font-weight:700;color:var(--ink);">$12.40</div>
<div style="font-size:11px;color:var(--muted);margin-top:3px;">Billed at next milestone delivery</div>
</div>
</div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">LLM usage</span><span style="font-size:13px;font-weight:500;">$9.20</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Compute</span><span style="font-size:13px;font-weight:500;">$3.20</span></div>
<div class="fin-row"><span style="font-size:13px;color:var(--mid);">Other</span><span style="font-size:13px;color:var(--muted);">$0.00</span></div>
</div>
</div>
</div>
</div>
</div><!-- /ws-taskly -->
<!-- ════════════════════════════════════════
NOTION CLONE — Draft, personal
════════════════════════════════════════ -->
<div id="ws-notion" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<div class="ws-header-identity">
<div data-project-color="notion" style="width:38px;height:38px;border-radius:10px;background:#9CA3AF;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:16px;font-weight:700;color:#FFFFFF;flex-shrink:0;">N</div>
<h1 class="f proj-name-heading" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Notion Clone</h1>
<span class="pill pill-draft" style="font-size:11px;padding:3px 9px;">Draft</span>
</div>
<p class="ws-header-desc">Personal knowledge base and note-taking tool — idea stage</p>
</div>
<div class="ws-header-actions">
<button class="btn-primary">Start building</button>
</div>
</div>
<div class="priority-card">
<div class="priority-icon">💡</div>
<div style="flex:1;">
<div class="priority-label">What to do next</div>
<div class="f priority-title">Define your project before you start building</div>
<p class="priority-desc">A clear concept saves weeks of rework. Before writing a single line of code, get clear on who this is for, what problem it solves, and what makes it different.</p>
<button class="btn-primary" style="font-size:12.5px;padding:9px 20px;">Describe your project</button>
</div>
</div>
<div class="metrics-row">
<div class="metric-card"><div class="metric-label">Stage</div><div class="metric-value" style="font-size:19px;margin-top:2px;">Idea</div><div class="metric-sub">Not started yet</div></div>
<div class="metric-card"><div class="metric-label">Created</div><div class="metric-value" style="font-size:19px;margin-top:2px;">Mar 21</div><div class="metric-sub">2 days ago</div></div>
<div class="metric-card"><div class="metric-label">Setup progress</div><div class="metric-value" style="font-size:19px;margin-top:2px;">20%</div><div class="progress-bar"><div class="progress-fill-gray" style="width:20%;"></div></div></div>
</div>
<div class="cards-grid">
<div class="content-card">
<div class="card-head"><span class="card-title">Getting started</span><span style="font-size:11.5px;color:var(--muted);">1 of 5 done</span></div>
<div class="card-body">
<div class="setup-row"><div class="s-check done"></div><div><div style="font-size:13px;color:var(--mid);text-decoration:line-through;">Name &amp; description</div><div style="font-size:11px;color:var(--muted);">Added Mar 21</div></div></div>
<div class="setup-row"><div class="s-check"></div><div><div style="font-size:13px;font-weight:500;">Define your target audience</div><div style="font-size:11px;color:var(--muted);">Who is this built for, specifically?</div></div></div>
<div class="setup-row"><div class="s-check"></div><div><div style="font-size:13px;font-weight:500;">List your core features</div><div style="font-size:11px;color:var(--muted);">What makes this different from Notion?</div></div></div>
<div class="setup-row"><div class="s-check"></div><div><div style="font-size:13px;font-weight:500;">Choose your tech stack</div></div></div>
<div class="setup-row"><div class="s-check"></div><div><div style="font-size:13px;font-weight:500;">Set your first milestone</div></div></div>
</div>
</div>
<div class="content-card">
<div class="card-head"><span class="card-title">Things to think about</span></div>
<div class="card-body">
<div class="rec-block"><div style="font-size:12px;font-weight:600;margin-bottom:5px;">🎯 Be specific about your audience</div><div style="font-size:12.5px;color:var(--mid);line-height:1.55;">"People who take notes" is too broad. Try "freelance designers who manage client projects in one place."</div></div>
<div class="rec-block"><div style="font-size:12px;font-weight:600;margin-bottom:5px;">🔍 Find your unfair advantage</div><div style="font-size:12.5px;color:var(--mid);line-height:1.55;">What does Notion do wrong? That's where your positioning lives.</div></div>
<div class="rec-block"><div style="font-size:12px;font-weight:600;margin-bottom:5px;">📦 Keep your MVP tiny</div><div style="font-size:12.5px;color:var(--mid);line-height:1.55;">Launch with one core use case done exceptionally well.</div></div>
</div>
</div>
</div>
</div>
</div><!-- /ws-notion -->
<!-- ════════════════════════════════════════
CLIENTS
════════════════════════════════════════ -->
<div id="ws-clients" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<h1 class="f" style="font-size:22px;font-weight:700;letter-spacing:-0.02em;margin-bottom:4px;">Clients</h1>
<p style="font-size:13px;color:var(--muted);">2 active clients · 2 projects</p>
</div>
<div class="ws-header-actions">
<button class="btn-secondary" onclick="openAddClientModal()">+ Add client</button>
</div>
</div>
<div class="clients-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
<!-- Acme Corp -->
<div class="content-card">
<div class="client-card-header" style="padding:20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;">
<div style="width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,#64748B,#475569);display:flex;align-items:center;justify-content:center;flex-shrink:0;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="7" r="4" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<div>
<div class="f" id="client-name-acme" style="font-size:16px;font-weight:600;" data-client-name="acme">Acme Corp</div>
<div id="client-email-acme" style="font-size:12px;color:var(--muted);">contact@acme.com</div>
</div>
<button class="client-edit-btn" onclick="openClientEditPopover(event,'acme')" title="Edit client"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
<div class="card-body">
<div style="display:flex;gap:7px;flex-wrap:wrap;margin-bottom:16px;">
<span data-project-color="flowmatic" style="font-size:12px;background:#8B5CF6;color:#FFFFFF;padding:3px 9px;border-radius:5px;font-weight:600;">Flowmatic</span>
<span class="pill pill-live"><span class="dot-live"></span>Live</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px;">
<div style="background:#FAFAFA;border:1px solid var(--border);border-radius:8px;padding:11px 13px;"><div style="font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:var(--muted);margin-bottom:3px;">MRR</div><div class="f" style="font-size:18px;font-weight:700;">$210</div></div>
<div style="background:var(--amber-dim);border:1px solid var(--amber-border);border-radius:8px;padding:11px 13px;"><div style="font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:#92400E;margin-bottom:3px;">Unbilled</div><div class="f" style="font-size:18px;font-weight:700;color:#92400E;">$48.20</div></div>
</div>
<div style="display:flex;gap:8px;">
<button class="btn-secondary" style="flex:1;font-size:12px;padding:8px;" onclick="selectProject('flowmatic')">View project</button>
<button class="btn-secondary" style="flex:1;font-size:12px;padding:8px;" onclick="selectView('invoices')">Invoice</button>
</div>
</div>
</div>
<!-- Beta Labs -->
<div class="content-card">
<div class="client-card-header" style="padding:20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;">
<div style="width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,#64748B,#475569);display:flex;align-items:center;justify-content:center;flex-shrink:0;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="7" r="4" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>
<div>
<div class="f" id="client-name-betalabs" style="font-size:16px;font-weight:600;" data-client-name="betalabs">Beta Labs</div>
<div id="client-email-betalabs" style="font-size:12px;color:var(--muted);">hello@betalabs.io</div>
</div>
<button class="client-edit-btn" onclick="openClientEditPopover(event,'betalabs')" title="Edit client"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>
</div>
<div class="card-body">
<div style="display:flex;gap:7px;flex-wrap:wrap;margin-bottom:16px;">
<span data-project-color="taskly" style="font-size:12px;background:#06B6D4;color:#FFFFFF;padding:3px 9px;border-radius:5px;font-weight:600;">Taskly</span>
<span class="pill pill-building"><span class="dot-building"></span>Building</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px;">
<div style="background:#FAFAFA;border:1px solid var(--border);border-radius:8px;padding:11px 13px;"><div style="font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:var(--muted);margin-bottom:3px;">Progress</div><div class="f" style="font-size:18px;font-weight:700;">60%</div></div>
<div style="background:var(--green-dim);border:1px solid #BBF7D0;border-radius:8px;padding:11px 13px;"><div style="font-size:10px;text-transform:uppercase;letter-spacing:0.06em;color:var(--green);margin-bottom:3px;">Unbilled</div><div class="f" style="font-size:18px;font-weight:700;color:var(--green);">$0</div></div>
</div>
<div style="display:flex;gap:8px;">
<button class="btn-secondary" style="flex:1;font-size:12px;padding:8px;" onclick="selectProject('taskly')">View project</button>
</div>
</div>
</div>
</div>
</div>
</div><!-- /ws-clients -->
<!-- ════════════════════════════════════════
INVOICES
════════════════════════════════════════ -->
<div id="ws-invoices" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<h1 class="f" style="font-size:22px;font-weight:700;letter-spacing:-0.02em;margin-bottom:4px;">Invoices</h1>
<p style="font-size:13px;color:var(--muted);">$48.20 ready to bill across 1 client</p>
</div>
<div class="ws-header-actions">
<button class="btn-primary">+ Create invoice</button>
</div>
</div>
<!-- Unbilled alert -->
<div style="background:var(--amber-dim);border:1px solid var(--amber-border);border-radius:12px;padding:18px 22px;display:flex;align-items:center;gap:16px;margin-bottom:28px;">
<div style="font-size:22px;">💰</div>
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#92400E;margin-bottom:2px;">$48.20 unbilled this month</div><div style="font-size:12.5px;color:#B45309;">1 client project has costs ready to invoice. Send it before month end.</div></div>
<button class="btn-amber">Bill all clients</button>
</div>
<!-- Unbilled table -->
<div style="margin-bottom:10px;display:flex;align-items:center;justify-content:space-between;">
<div class="dash-section-title" style="margin-bottom:0;">Pending invoices</div>
</div>
<div class="content-card" style="margin-bottom:24px;">
<table class="sec-table">
<thead><tr><th>Project / Client</th><th>Period</th><th class="mob-col-hide">LLM</th><th class="mob-col-hide">Compute</th><th>Total</th><th>Status</th><th></th></tr></thead>
<tbody>
<tr>
<td><div style="font-size:13.5px;font-weight:600;">Flowmatic</div><div style="font-size:11.5px;color:var(--muted);">Acme Corp</div></td>
<td style="color:var(--mid);">March 2026</td>
<td class="mob-col-hide" style="color:var(--mid);">$29.20</td>
<td class="mob-col-hide" style="color:var(--mid);">$11.60</td>
<td><span class="f" style="font-size:15px;font-weight:700;">$48.20</span></td>
<td><span style="font-size:11px;font-weight:600;background:var(--amber-dim);color:#92400E;border:1px solid var(--amber-border);padding:3px 9px;border-radius:4px;">Unbilled</span></td>
<td><button class="btn-amber" style="font-size:12px;padding:6px 14px;">Invoice</button></td>
</tr>
</tbody>
</table>
</div>
<!-- Past invoices -->
<div class="dash-section-title">Past invoices</div>
<div class="content-card">
<table class="sec-table">
<thead><tr><th>Project / Client</th><th>Period</th><th>Total</th><th>Status</th><th></th></tr></thead>
<tbody>
<tr>
<td><div style="font-size:13.5px;font-weight:600;">Flowmatic</div><div style="font-size:11.5px;color:var(--muted);">Acme Corp</div></td>
<td style="color:var(--mid);">February 2026</td>
<td><span class="f" style="font-size:15px;font-weight:700;">$34.70</span></td>
<td><span style="font-size:11px;font-weight:600;background:var(--green-dim);color:var(--green);padding:3px 9px;border-radius:4px;">Paid</span></td>
<td><button class="btn-ghost" style="font-size:12px;">View</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!-- /ws-invoices -->
<!-- ════════════════════════════════════════
COSTS
════════════════════════════════════════ -->
<div id="ws-costs" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<h1 class="f" style="font-size:22px;font-weight:700;letter-spacing:-0.02em;margin-bottom:4px;">Cost tracker</h1>
<p style="font-size:13px;color:var(--muted);">$57.40 spent this month across all projects</p>
</div>
</div>
<!-- Summary -->
<div class="metrics-row" style="margin-bottom:28px;">
<div class="metric-card"><div class="metric-label">Total this month</div><div class="metric-value">$57.40</div><div class="trend-down">↑ +18% vs last month</div></div>
<div class="metric-card"><div class="metric-label">LLM usage</div><div class="metric-value">$38.40</div><div class="metric-sub">67% of total costs</div></div>
<div class="metric-card"><div class="metric-label">Compute</div><div class="metric-value">$14.80</div><div class="metric-sub">26% of total costs</div></div>
<div class="metric-card"><div class="metric-label">Other</div><div class="metric-value">$4.20</div><div class="metric-sub">Email &amp; services</div></div>
</div>
<!-- Breakdown by project -->
<div class="dash-section-title">By project</div>
<div class="content-card" style="margin-bottom:24px;">
<table class="sec-table">
<thead><tr><th>Project</th><th>LLM</th><th>Compute</th><th>Other</th><th>Total</th><th>Billable to</th></tr></thead>
<tbody>
<tr>
<td><div style="display:flex;align-items:center;gap:9px;"><div data-project-color="launchpad" style="width:24px;height:24px;border-radius:6px;background:#6366F1;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:10px;font-weight:700;color:#FFFFFF;">L</div><span style="font-size:13.5px;font-weight:600;">Launchpad</span></div></td>
<td style="color:var(--mid);">$12.80</td><td style="color:var(--mid);">$4.20</td><td style="color:var(--mid);">$0.40</td>
<td><span style="font-size:13.5px;font-weight:700;">$17.40</span></td>
<td><span style="font-size:11.5px;color:var(--muted);">Personal</span></td>
</tr>
<tr>
<td><div style="display:flex;align-items:center;gap:9px;"><div data-project-color="flowmatic" style="width:24px;height:24px;border-radius:6px;background:#8B5CF6;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:10px;font-weight:700;color:#FFFFFF;">F</div><span style="font-size:13.5px;font-weight:600;">Flowmatic</span></div></td>
<td style="color:var(--mid);">$17.00</td><td style="color:var(--mid);">$8.00</td><td style="color:var(--mid);">$3.20</td>
<td><span style="font-size:13.5px;font-weight:700;">$28.20</span></td>
<td><span style="font-size:11px;font-weight:600;color:#92400E;background:var(--amber-dim);border:1px solid var(--amber-border);padding:2px 8px;border-radius:4px;">Acme Corp</span></td>
</tr>
<tr>
<td><div style="display:flex;align-items:center;gap:9px;"><div data-project-color="taskly" style="width:24px;height:24px;border-radius:6px;background:#06B6D4;display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-size:10px;font-weight:700;color:#FFFFFF;">T</div><span style="font-size:13.5px;font-weight:600;">Taskly</span></div></td>
<td style="color:var(--mid);">$8.60</td><td style="color:var(--mid);">$2.60</td><td style="color:var(--mid);">$0.60</td>
<td><span style="font-size:13.5px;font-weight:700;">$11.80</span></td>
<td><span style="font-size:11px;font-weight:600;color:#92400E;background:var(--amber-dim);border:1px solid var(--amber-border);padding:2px 8px;border-radius:4px;">Beta Labs</span></td>
</tr>
</tbody>
</table>
</div>
<!-- Recent charges -->
<div class="dash-section-title">Recent charges</div>
<div class="content-card">
<table class="sec-table">
<thead><tr><th>Time</th><th>Description</th><th>Project</th><th>Cost</th></tr></thead>
<tbody>
<tr><td style="color:var(--muted);">2h ago</td><td>LLM: Homepage copy generation</td><td><span class="pill pill-live" style="font-size:10px;">Flowmatic</span></td><td style="font-weight:600;">$0.82</td></tr>
<tr><td style="color:var(--muted);">3h ago</td><td>LLM: Checkout page code</td><td><span class="pill pill-building" style="font-size:10px;">Taskly</span></td><td style="font-weight:600;">$1.24</td></tr>
<tr><td style="color:var(--muted);">5h ago</td><td>LLM: Newsletter draft</td><td><span class="pill pill-live" style="font-size:10px;">Flowmatic</span></td><td style="font-weight:600;">$0.43</td></tr>
<tr><td style="color:var(--muted);">6h ago</td><td>Compute: Build pipeline run</td><td><span class="pill pill-building" style="font-size:10px;">Taskly</span></td><td style="font-weight:600;">$0.18</td></tr>
<tr><td style="color:var(--muted);">Yesterday</td><td>Email delivery · 240 recipients</td><td><span class="pill pill-live" style="font-size:10px;">Launchpad</span></td><td style="font-weight:600;">$0.96</td></tr>
</tbody>
</table>
</div>
</div>
</div><!-- /ws-costs -->
<!-- ════════════════════════════════════════
SETTINGS
════════════════════════════════════════ -->
<div id="ws-settings" class="ws-section">
<div class="ws-inner">
<div class="ws-header">
<div class="ws-header-left">
<h1 class="f" style="font-size:22px;font-weight:700;letter-spacing:-0.02em;margin-bottom:4px;">Account settings</h1>
<p style="font-size:13px;color:var(--muted);">Manage your profile, plan, and preferences</p>
</div>
<div class="ws-header-actions">
<button id="settings-edit-btn" class="btn-secondary" onclick="enterSettingsEdit()" style="font-size:13px;">Edit</button>
</div>
</div>
<!-- Unsaved changes bar (hidden by default) -->
<div id="settings-save-bar" style="display:none;background:var(--cream);border:1px solid var(--border);border-radius:10px;padding:12px 16px;display:none;align-items:center;justify-content:space-between;margin-bottom:20px;gap:12px;">
<span style="font-size:13px;color:var(--ink);font-weight:500;">You have unsaved changes</span>
<div style="display:flex;gap:8px;">
<button class="btn-secondary" onclick="cancelSettingsEdit()" style="font-size:12.5px;padding:7px 14px;">Cancel</button>
<button class="btn-primary" onclick="saveSettingsEdit()" style="font-size:12.5px;padding:7px 16px;">Save changes</button>
</div>
</div>
<!-- Profile -->
<div class="dash-section-title">Profile</div>
<div class="content-card" style="margin-bottom:24px;">
<div class="card-body">
<div class="fin-row">
<span style="font-size:13px;color:var(--mid);">Full name</span>
<span class="settings-view" style="font-size:13px;color:var(--ink);font-weight:500;">Jane Doe</span>
<input class="settings-input" type="text" value="Jane Doe" style="display:none;font-family:var(--sans);font-size:13px;color:var(--ink);border:1px solid var(--border);border-radius:7px;padding:5px 10px;background:var(--white);outline:none;width:220px;transition:border-color 0.15s;" onfocus="this.style.borderColor='var(--indigo)'" onblur="this.style.borderColor='var(--border)'">
</div>
<div class="fin-row">
<span style="font-size:13px;color:var(--mid);">Email</span>
<span class="settings-view" style="font-size:13px;color:var(--ink);font-weight:500;">jane@example.com</span>
<input class="settings-input" type="email" value="jane@example.com" style="display:none;font-family:var(--sans);font-size:13px;color:var(--ink);border:1px solid var(--border);border-radius:7px;padding:5px 10px;background:var(--white);outline:none;width:220px;transition:border-color 0.15s;" onfocus="this.style.borderColor='var(--indigo)'" onblur="this.style.borderColor='var(--border)'">
</div>
<div class="fin-row" style="border-bottom:none;">
<span style="font-size:13px;color:var(--mid);">Password</span>
<button class="btn-ghost" style="font-size:12.5px;padding:4px 8px;">Change password →</button>
</div>
</div>
</div>
<!-- Plan -->
<div class="dash-section-title">Plan &amp; billing</div>
<div class="content-card" style="margin-bottom:24px;">
<div class="card-body">
<div class="fin-row">
<span style="font-size:13px;color:var(--mid);">Current plan</span>
<div style="display:flex;align-items:center;gap:10px;">
<span style="font-size:13px;font-weight:600;color:var(--indigo);">Pro</span>
<button class="btn-ghost" onclick="openPlanModal()" style="font-size:12px;padding:4px 9px;">Change plan →</button>
</div>
</div>
<div class="fin-row">
<span style="font-size:13px;color:var(--mid);">Credits remaining</span>
<span style="font-size:13px;color:var(--ink);font-weight:500;">448 credits</span>
</div>
<div class="fin-row" style="border-bottom:none;">
<span style="font-size:13px;color:var(--mid);">Next billing date</span>
<span style="font-size:13px;color:var(--ink);font-weight:500;">Apr 1, 2026</span>
</div>
</div>
</div>
<!-- Preferences -->
<div class="dash-section-title">Preferences</div>
<div class="content-card">
<div class="card-body">
<div class="fin-row" style="border-bottom:none;">
<span style="font-size:13px;color:var(--mid);">Appearance</span>
<button id="theme-toggle-settings" class="btn-secondary" onclick="toggleTheme()" style="font-size:12.5px;padding:7px 14px;">🌙 Dark mode</button>
</div>
</div>
</div>
</div>
</div><!-- /ws-settings -->
<!-- ════════════════════════════════════════
MOBILE PROJECTS VIEW (bottom tab)
════════════════════════════════════════ -->
<div id="ws-mobile-projects" class="ws-section">
<div class="ws-inner">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:24px;">
<h1 class="f" style="font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;">Projects</h1>
<button class="btn-primary" onclick="openModal()" style="font-size:12px;padding:8px 14px;">+ New</button>
</div>
<div style="display:flex;flex-direction:column;gap:10px;">
<div class="mob-proj-card" onclick="selectProject('launchpad')">
<div data-project-color="launchpad" style="width:44px;height:44px;border-radius:11px;background:#6366F1;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#FFFFFF;flex-shrink:0;">L</div>
<div style="flex:1;min-width:0;">
<div style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Launchpad</div>
<div style="font-size:12px;color:var(--muted);">Personal</div>
</div>
<span class="pill pill-live"><span class="dot-live"></span>Live</span>
</div>
<div class="mob-proj-card" onclick="selectProject('flowmatic')">
<div data-project-color="flowmatic" style="width:44px;height:44px;border-radius:11px;background:#8B5CF6;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#FFFFFF;flex-shrink:0;">F</div>
<div style="flex:1;min-width:0;">
<div style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Flowmatic</div>
<div style="font-size:12px;color:var(--muted);">Acme Corp</div>
</div>
<span class="pill pill-live"><span class="dot-live"></span>Live</span>
</div>
<div class="mob-proj-card" onclick="selectProject('taskly')">
<div data-project-color="taskly" style="width:44px;height:44px;border-radius:11px;background:#06B6D4;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#FFFFFF;flex-shrink:0;">T</div>
<div style="flex:1;min-width:0;">
<div style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Taskly</div>
<div style="font-size:12px;color:var(--muted);">Beta Labs</div>
</div>
<span class="pill pill-building"><span class="dot-building"></span>Building</span>
</div>
<div class="mob-proj-card" onclick="selectProject('notion')">
<div data-project-color="notion" style="width:44px;height:44px;border-radius:11px;background:#9CA3AF;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:#FFFFFF;flex-shrink:0;">N</div>
<div style="flex:1;min-width:0;">
<div style="font-size:14px;font-weight:600;color:var(--ink);margin-bottom:3px;">Notion Clone</div>
<div style="font-size:12px;color:var(--muted);">Personal</div>
</div>
<span class="pill pill-draft">Draft</span>
</div>
</div>
</div>
</div><!-- /ws-mobile-projects -->
</main>
</div><!-- /app-shell -->
<!-- ── PROJECT EDIT POPOVER ── -->
<div id="proj-edit-popover">
<div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin-bottom:8px;">Edit project</div>
<input id="proj-edit-name" type="text" placeholder="Project name" onkeydown="if(event.key==='Enter'){saveProjectEdit();}if(event.key==='Escape'){closeEditPopover();}">
<div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--muted);margin:10px 0 6px;">Colour</div>
<div id="proj-edit-swatches" style="display:grid;grid-template-columns:repeat(5,1fr);gap:6px;"></div>
<div style="display:flex;gap:6px;margin-top:12px;">
<button onclick="closeEditPopover()" style="flex:1;padding:6px 0;border:1px solid var(--border);border-radius:7px;background:transparent;font-family:var(--sans);font-size:12px;font-weight:500;color:var(--mid);cursor:pointer;">Cancel</button>
<button onclick="saveProjectEdit()" style="flex:1;padding:6px 0;border:none;border-radius:7px;background:var(--indigo);font-family:var(--sans);font-size:12px;font-weight:600;color:#fff;cursor:pointer;">Save</button>
</div>
</div>
<!-- ── CLIENT EDIT POPOVER ── -->
<div id="client-edit-popover" style="display:none;"></div>
<!-- ── Client edit modal ── -->
<div class="modal-overlay" id="client-edit-modal" onclick="if(event.target===this)closeClientEditPopover()">
<div class="modal-card" style="max-width:400px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;">
<h3 class="f" style="font-size:17px;font-weight:700;color:var(--ink);">Edit client</h3>
<button onclick="closeClientEditPopover()" style="background:none;border:none;font-size:20px;color:var(--muted);cursor:pointer;line-height:1;padding:4px;">×</button>
</div>
<div style="margin-bottom:14px;">
<label class="client-edit-label">Client name</label>
<input id="client-edit-name" class="client-edit-field" type="text" placeholder="e.g. Acme Corp" onkeydown="if(event.key==='Enter')saveClientEdit();if(event.key==='Escape')closeClientEditPopover();">
</div>
<div style="margin-bottom:14px;">
<label class="client-edit-label">Contact email</label>
<input id="client-edit-email" class="client-edit-field" type="email" placeholder="e.g. hello@acme.com" onkeydown="if(event.key==='Enter')saveClientEdit();if(event.key==='Escape')closeClientEditPopover();">
</div>
<div style="margin-bottom:22px;">
<label class="client-edit-label">Contact name</label>
<input id="client-edit-contact" class="client-edit-field" type="text" placeholder="e.g. Jane Smith" style="margin-bottom:0;" onkeydown="if(event.key==='Enter')saveClientEdit();if(event.key==='Escape')closeClientEditPopover();">
</div>
<div style="display:flex;gap:8px;">
<button class="btn-secondary" onclick="closeClientEditPopover()" style="flex:1;font-size:13px;padding:9px;">Cancel</button>
<button class="btn-primary" onclick="saveClientEdit()" style="flex:2;font-size:13px;padding:9px;justify-content:center;display:flex;">Save changes</button>
</div>
</div>
</div>
<!-- ── Add client modal ── -->
<div class="modal-overlay" id="add-client-modal" onclick="if(event.target===this)closeAddClientModal()">
<div class="modal-card" style="max-width:400px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;">
<h3 class="f" style="font-size:17px;font-weight:700;color:var(--ink);">Add a client</h3>
<button onclick="closeAddClientModal()" style="background:none;border:none;font-size:20px;color:var(--muted);cursor:pointer;line-height:1;padding:4px;">×</button>
</div>
<div style="margin-bottom:14px;">
<label class="client-edit-label">Company name</label>
<input id="add-client-name" class="client-edit-field" type="text" placeholder="e.g. Globex Corp" onkeydown="if(event.key==='Escape')closeAddClientModal();">
</div>
<div style="margin-bottom:14px;">
<label class="client-edit-label">Contact email</label>
<input id="add-client-email" class="client-edit-field" type="email" placeholder="e.g. hello@globex.com" onkeydown="if(event.key==='Escape')closeAddClientModal();">
</div>
<div style="margin-bottom:22px;">
<label class="client-edit-label">Contact name</label>
<input id="add-client-contact" class="client-edit-field" type="text" placeholder="e.g. Jane Smith" style="margin-bottom:0;" onkeydown="if(event.key==='Escape')closeAddClientModal();">
</div>
<div style="display:flex;gap:8px;">
<button class="btn-secondary" onclick="closeAddClientModal()" style="flex:1;font-size:13px;padding:9px;">Cancel</button>
<button class="btn-primary" onclick="saveNewClient()" style="flex:2;font-size:13px;padding:9px;justify-content:center;display:flex;">Add client</button>
</div>
</div>
</div>
<!-- ── MOBILE BOTTOM TAB BAR ── -->
<nav class="mob-tab-bar" id="mob-tab-bar">
<button class="mob-tab active" id="mobtab-dashboard" onclick="selectView('dashboard')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M3 12L12 3l9 9M5 10v9a1 1 0 001 1h4v-5h4v5h4a1 1 0 001-1v-9" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>Home</span>
</button>
<button class="mob-tab" id="mobtab-projects" onclick="selectView('mobile-projects')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.8"/><rect x="14" y="3" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.8"/><rect x="3" y="14" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.8"/><rect x="14" y="14" width="7" height="7" rx="1.5" stroke="currentColor" stroke-width="1.8"/></svg>
<span>Projects</span>
</button>
<button class="mob-tab" id="mobtab-clients" onclick="selectView('clients')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="9" cy="7" r="4" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>Clients</span>
</button>
<button class="mob-tab" id="mobtab-invoices" onclick="selectView('invoices')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
<span>Invoices</span>
</button>
<button class="mob-tab" id="mobtab-settings" onclick="selectView('settings')">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="1.8"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z" stroke="currentColor" stroke-width="1.8"/></svg>
<span>Settings</span>
</button>
</nav>
<!-- ── NEW PROJECT MODAL ── -->
<div class="modal-overlay" id="modal-new" onclick="handleOverlayClick(event)">
<div class="modal-card">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:22px;">
<h3 class="f" style="font-size:18px;font-weight:700;color:var(--ink);">New project</h3>
<button onclick="closeModal()" style="background:none;border:none;font-size:20px;color:var(--muted);cursor:pointer;line-height:1;padding:4px;">×</button>
</div>
<div style="margin-bottom:16px;">
<label style="font-size:12px;font-weight:600;color:var(--mid);display:block;margin-bottom:6px;">Project name</label>
<input class="modal-input" type="text" placeholder="e.g. My SaaS App">
</div>
<div style="margin-bottom:20px;">
<label style="font-size:12px;font-weight:600;color:var(--mid);display:block;margin-bottom:8px;">This project is for…</label>
<div style="display:flex;gap:8px;">
<div class="for-card sel" id="for-myself" onclick="selectFor(this,'myself')"><div style="font-size:20px;margin-bottom:5px;">🧑‍💻</div><div style="font-size:12.5px;font-weight:600;color:var(--ink);">Myself</div><div style="font-size:11px;color:var(--muted);margin-top:2px;">My own product</div></div>
<div class="for-card" id="for-client" onclick="selectFor(this,'client')"><div style="font-size:20px;margin-bottom:5px;">🤝</div><div style="font-size:12.5px;font-weight:600;color:var(--ink);">A client</div><div style="font-size:11px;color:var(--muted);margin-top:2px;">Client project</div></div>
</div>
</div>
<!-- Client picker — shown only when "A client" is selected -->
<div id="client-picker-section" style="display:none;margin-bottom:20px;">
<label style="font-size:12px;font-weight:600;color:var(--mid);display:block;margin-bottom:8px;">Select client</label>
<div id="client-picker-list" style="display:flex;flex-direction:column;gap:6px;"></div>
<!-- New client inline form -->
<div id="new-client-row" style="margin-top:6px;">
<button id="new-client-toggle" onclick="toggleNewClientForm()" style="background:none;border:1.5px dashed var(--border);border-radius:8px;width:100%;padding:9px 14px;font-family:var(--sans);font-size:13px;color:var(--muted);cursor:pointer;text-align:left;transition:border-color 0.15s,color 0.15s;" onmouseover="this.style.borderColor='var(--indigo)';this.style.color='var(--indigo)';" onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--muted)';">+ New client</button>
<div id="new-client-form" style="display:none;margin-top:8px;padding:12px;background:var(--cream);border-radius:9px;border:1px solid var(--border);">
<input id="new-client-name-inline" class="modal-input" type="text" placeholder="Company name" style="margin-bottom:8px;">
<input id="new-client-email-inline" class="modal-input" type="email" placeholder="Contact email (optional)">
</div>
</div>
</div>
<button class="btn-primary" onclick="createProject()" style="width:100%;justify-content:center;display:flex;align-items:center;gap:6px;font-size:14px;padding:12px;">Create project →</button>
</div>
</div>
<!-- ── Plan picker modal ── -->
<div class="modal-overlay" id="modal-plan" onclick="if(event.target===this)closePlanModal()">
<div class="modal-card" style="max-width:480px;">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
<h3 class="f" style="font-size:18px;font-weight:700;color:var(--ink);">Change plan</h3>
<button onclick="closePlanModal()" style="background:none;border:none;font-size:20px;color:var(--muted);cursor:pointer;line-height:1;padding:4px;">×</button>
</div>
<p style="font-size:13px;color:var(--muted);margin-bottom:22px;">Your current plan is <strong style="color:var(--indigo);">Pro</strong>. Select a plan below to switch.</p>
<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:24px;">
<!-- Starter -->
<div class="plan-option" id="plan-starter" onclick="selectPlan('starter')" style="border:1.5px solid var(--border);border-radius:10px;padding:14px 16px;cursor:pointer;transition:border-color 0.15s,background 0.15s;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<div>
<div style="font-size:14px;font-weight:700;color:var(--ink);">Starter</div>
<div style="font-size:12px;color:var(--muted);margin-top:2px;">For solo builders just getting started</div>
</div>
<div style="text-align:right;">
<div style="font-size:16px;font-weight:700;color:var(--ink);">Free</div>
<div style="font-size:11px;color:var(--muted);">forever</div>
</div>
</div>
</div>
<!-- Pro (current) -->
<div class="plan-option plan-option-current" id="plan-pro" onclick="selectPlan('pro')" style="border:1.5px solid var(--indigo);border-radius:10px;padding:14px 16px;cursor:pointer;background:rgba(99,102,241,0.04);transition:border-color 0.15s,background 0.15s;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<div>
<div style="display:flex;align-items:center;gap:7px;"><span style="font-size:14px;font-weight:700;color:var(--ink);">Pro</span><span style="font-size:10px;font-weight:700;background:var(--indigo);color:#fff;padding:2px 7px;border-radius:4px;">Current</span></div>
<div style="font-size:12px;color:var(--muted);margin-top:2px;">For growing products and small teams</div>
</div>
<div style="text-align:right;">
<div style="font-size:16px;font-weight:700;color:var(--ink);">$29<span style="font-size:12px;font-weight:400;color:var(--muted);">/mo</span></div>
<div style="font-size:11px;color:var(--muted);">500 credits/mo</div>
</div>
</div>
</div>
<!-- Business -->
<div class="plan-option" id="plan-business" onclick="selectPlan('business')" style="border:1.5px solid var(--border);border-radius:10px;padding:14px 16px;cursor:pointer;transition:border-color 0.15s,background 0.15s;">
<div style="display:flex;align-items:center;justify-content:space-between;">
<div>
<div style="font-size:14px;font-weight:700;color:var(--ink);">Business</div>
<div style="font-size:12px;color:var(--muted);margin-top:2px;">For agencies and larger projects</div>
</div>
<div style="text-align:right;">
<div style="font-size:16px;font-weight:700;color:var(--ink);">$79<span style="font-size:12px;font-weight:400;color:var(--muted);">/mo</span></div>
<div style="font-size:11px;color:var(--muted);">Unlimited credits</div>
</div>
</div>
</div>
</div>
<div style="display:flex;gap:10px;">
<button class="btn-secondary" onclick="closePlanModal()" style="flex:1;font-size:13px;padding:10px;">Cancel</button>
<button id="plan-confirm-btn" class="btn-primary" onclick="confirmPlanChange()" style="flex:2;font-size:13px;padding:10px;justify-content:center;display:flex;">Confirm change</button>
</div>
</div>
</div>
<script>
// ── Mobile tab sync ──
function syncMobTab(view) {
const map = { dashboard:'dashboard', 'mobile-projects':'projects', clients:'clients', invoices:'invoices', settings:'settings' };
const tabKey = map[view] || 'projects';
document.querySelectorAll('.mob-tab').forEach(t => t.classList.remove('active'));
const tab = document.getElementById('mobtab-' + tabKey);
if (tab) tab.classList.add('active');
}
// ── View routing ──
function selectView(view) {
document.querySelectorAll('.ws-section').forEach(s => s.classList.remove('active'));
const section = document.getElementById('ws-' + view);
if (section) section.classList.add('active');
document.querySelectorAll('.nav-item-btn').forEach(b => b.classList.remove('active'));
const btn = document.getElementById('nav-' + view);
if (btn) btn.classList.add('active');
const projectViews = ['launchpad','flowmatic','taskly','notion'];
if (!projectViews.includes(view)) {
document.querySelectorAll('.proj-row').forEach(r => r.classList.remove('active'));
}
document.getElementById('workspace').scrollTop = 0;
syncMobTab(view);
}
function selectProject(id) {
document.querySelectorAll('.ws-section').forEach(s => s.classList.remove('active'));
const section = document.getElementById('ws-' + id);
if (section) section.classList.add('active');
document.querySelectorAll('.proj-row').forEach(r => r.classList.remove('active'));
const row = document.getElementById('row-' + id);
if (row) row.classList.add('active');
document.querySelectorAll('.nav-item-btn').forEach(b => b.classList.remove('active'));
document.getElementById('workspace').scrollTop = 0;
syncMobTab('mobile-projects');
}
function updateSearchVisibility() {
const count = document.querySelectorAll('.proj-row[data-name]').length;
document.getElementById('proj-search-wrap').style.display = count > 3 ? '' : 'none';
}
function filterProjects(q) {
const query = q.toLowerCase().trim();
document.querySelectorAll('.proj-row[data-name]').forEach(row => {
row.style.display = (!query || (row.dataset.name || '').toLowerCase().includes(query)) ? '' : 'none';
});
}
function openModal() {
document.getElementById('modal-new').classList.add('open');
// Reset to "Myself" state
document.querySelectorAll('.for-card').forEach(c => c.classList.remove('sel'));
document.getElementById('for-myself').classList.add('sel');
document.getElementById('client-picker-section').style.display = 'none';
document.getElementById('new-client-form').style.display = 'none';
document.getElementById('new-client-toggle').style.display = '';
var nameInput = document.querySelector('#modal-new .modal-input[type="text"]:not(#new-client-name-inline)');
if (nameInput) { nameInput.value = ''; setTimeout(function(){ nameInput.focus(); }, 50); }
}
function closeModal() { document.getElementById('modal-new').classList.remove('open'); }
function handleOverlayClick(e) { if (e.target === e.currentTarget) closeModal(); }
function selectFor(el, mode) {
document.querySelectorAll('.for-card').forEach(c => c.classList.remove('sel'));
el.classList.add('sel');
var section = document.getElementById('client-picker-section');
if (mode === 'client') {
section.style.display = 'block';
renderClientPicker();
} else {
section.style.display = 'none';
}
}
function renderClientPicker() {
var list = document.getElementById('client-picker-list');
list.innerHTML = '';
Object.keys(CLIENT_DATA).forEach(function(id) {
var d = CLIENT_DATA[id];
var initials = d.name.split(' ').map(function(w){ return w[0]; }).join('').slice(0,2).toUpperCase();
var div = document.createElement('div');
div.className = 'client-picker-option';
div.dataset.clientId = id;
div.innerHTML = '<div style="width:28px;height:28px;border-radius:7px;background:linear-gradient(135deg,#64748B,#475569);display:flex;align-items:center;justify-content:center;flex-shrink:0;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="7" r="4" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>'
+ '<span style="font-size:13px;font-weight:500;color:var(--ink);">'+d.name+'</span>';
div.onclick = function() {
document.querySelectorAll('.client-picker-option').forEach(function(o){ o.classList.remove('sel'); });
div.classList.add('sel');
// Hide new client form when an existing client is chosen
document.getElementById('new-client-form').style.display = 'none';
document.getElementById('new-client-toggle').style.display = '';
};
list.appendChild(div);
});
}
function toggleNewClientForm() {
var form = document.getElementById('new-client-form');
var toggle = document.getElementById('new-client-toggle');
var open = form.style.display !== 'none';
form.style.display = open ? 'none' : 'block';
toggle.style.display = open ? '' : 'none';
if (!open) {
document.querySelectorAll('.client-picker-option').forEach(function(o){ o.classList.remove('sel'); });
setTimeout(function(){ document.getElementById('new-client-name-inline').focus(); }, 50);
}
}
function createProject() {
// Validate name
var nameInput = document.querySelector('#modal-new .modal-input[type="text"]:not(#new-client-name-inline)');
if (!nameInput || !nameInput.value.trim()) { if(nameInput) nameInput.focus(); return; }
// If client mode + new client form open, register client first
var forClient = document.getElementById('for-client').classList.contains('sel');
if (forClient) {
var newForm = document.getElementById('new-client-form');
if (newForm.style.display !== 'none') {
var cn = document.getElementById('new-client-name-inline').value.trim();
if (!cn) { document.getElementById('new-client-name-inline').focus(); return; }
var cid = 'client-' + Date.now();
CLIENT_DATA[cid] = { name: cn, email: document.getElementById('new-client-email-inline').value.trim(), contact: '' };
}
}
closeModal();
}
// ── Project edit popover ──
const PROJECT_COLORS = { launchpad:'#6366F1', flowmatic:'#8B5CF6', taskly:'#06B6D4', notion:'#9CA3AF' };
const COLOR_PALETTE = ['#6366F1','#8B5CF6','#06B6D4','#9CA3AF','#EC4899','#F59E0B','#10B981','#EF4444','#F97316','#14B8A6'];
let activeEditProject = null;
let pendingEditColor = null;
function openEditPopover(e, projectId) {
e.stopPropagation();
activeEditProject = projectId;
pendingEditColor = PROJECT_COLORS[projectId];
// Populate name field from nav row
const row = document.getElementById('row-' + projectId);
const nameNode = row ? row.querySelector('.proj-row-name') : null;
const currentName = nameNode ? nameNode.childNodes[0].textContent.trim() : '';
document.getElementById('proj-edit-name').value = currentName;
// Render colour swatches
document.getElementById('proj-edit-swatches').innerHTML = COLOR_PALETTE.map(color =>
`<div class="color-swatch${pendingEditColor===color?' active':''}" style="background:${color};" onclick="selectPendingColor('${color}',this)"></div>`
).join('');
// Position below the button
const popover = document.getElementById('proj-edit-popover');
const rect = e.currentTarget.getBoundingClientRect();
popover.style.left = Math.min(rect.left, window.innerWidth - 224) + 'px';
popover.style.top = (rect.bottom + 6) + 'px';
popover.style.display = 'block';
setTimeout(() => document.getElementById('proj-edit-name').focus(), 0);
}
function selectPendingColor(color, el) {
pendingEditColor = color;
document.querySelectorAll('#proj-edit-swatches .color-swatch').forEach(s => s.classList.remove('active'));
el.classList.add('active');
}
function saveProjectEdit() {
if (!activeEditProject) return;
const newName = document.getElementById('proj-edit-name').value.trim();
// Apply colour
if (pendingEditColor) {
PROJECT_COLORS[activeEditProject] = pendingEditColor;
document.querySelectorAll(`[data-project-color="${activeEditProject}"]`).forEach(el => {
el.style.background = pendingEditColor;
});
}
// Apply name
if (newName) {
const h1 = document.querySelector(`#ws-${activeEditProject} .proj-name-heading`);
if (h1) h1.textContent = newName;
const row = document.getElementById('row-' + activeEditProject);
if (row) {
const nameEl = row.querySelector('.proj-row-name');
if (nameEl) nameEl.childNodes[0].textContent = newName + ' ';
row.dataset.name = newName.toLowerCase();
}
}
closeEditPopover();
}
function closeEditPopover() {
document.getElementById('proj-edit-popover').style.display = 'none';
activeEditProject = null;
pendingEditColor = null;
}
// ── Client edit modal ──
var activeEditClient = null;
var CLIENT_DATA = {
acme: { name:'Acme Corp', email:'hello@acme.com', contact:'John Smith' },
betalabs: { name:'Beta Labs', email:'hello@betalabs.io', contact:'Sarah K.' }
};
function openClientEditPopover(e, clientId) {
e.stopPropagation();
activeEditClient = clientId;
var data = CLIENT_DATA[clientId] || {};
document.getElementById('client-edit-name').value = data.name || '';
document.getElementById('client-edit-email').value = data.email || '';
document.getElementById('client-edit-contact').value = data.contact || '';
document.getElementById('client-edit-modal').classList.add('open');
setTimeout(function(){ document.getElementById('client-edit-name').focus(); }, 50);
}
function closeClientEditPopover() {
document.getElementById('client-edit-modal').classList.remove('open');
activeEditClient = null;
}
// ── Add client modal ──
function openAddClientModal() {
document.getElementById('add-client-name').value = '';
document.getElementById('add-client-email').value = '';
document.getElementById('add-client-contact').value = '';
document.getElementById('add-client-modal').classList.add('open');
setTimeout(function(){ document.getElementById('add-client-name').focus(); }, 50);
}
function closeAddClientModal() {
document.getElementById('add-client-modal').classList.remove('open');
}
function saveNewClient() {
var name = document.getElementById('add-client-name').value.trim();
var email = document.getElementById('add-client-email').value.trim();
var contact = document.getElementById('add-client-contact').value.trim();
if (!name) { document.getElementById('add-client-name').focus(); return; }
var id = 'client-' + Date.now();
var initials = name.split(' ').map(function(w){ return w[0]; }).join('').slice(0,2).toUpperCase();
// Register in CLIENT_DATA
CLIENT_DATA[id] = { name: name, email: email, contact: contact };
// Build card HTML
var card = document.createElement('div');
card.className = 'content-card';
card.innerHTML =
'<div class="client-card-header" style="padding:20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;position:relative;">'
+ '<div style="width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,#64748B,#475569);display:flex;align-items:center;justify-content:center;flex-shrink:0;"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="7" r="4" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>'
+ '<div><div class="f" id="client-name-'+id+'" style="font-size:16px;font-weight:600;" data-client-name="'+id+'">'+name+'</div>'
+ '<div id="client-email-'+id+'" style="font-size:12px;color:var(--muted);">'+email+'</div></div>'
+ '<button class="client-edit-btn" onclick="openClientEditPopover(event,\''+id+'\')" title="Edit client"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 114 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg></button>'
+ '</div>'
+ '<div class="card-body">'
+ '<p style="font-size:13px;color:var(--muted);text-align:center;padding:10px 0;">No projects yet</p>'
+ '</div>';
document.querySelector('.clients-grid').appendChild(card);
// Update header count
var sub = document.querySelector('#ws-clients .ws-header-left p');
if (sub) {
var count = document.querySelectorAll('.clients-grid .content-card').length;
sub.textContent = count + ' active client' + (count !== 1 ? 's' : '');
}
closeAddClientModal();
}
function saveClientEdit() {
if (!activeEditClient) return;
var newName = document.getElementById('client-edit-name').value.trim();
var newEmail = document.getElementById('client-edit-email').value.trim();
var newContact = document.getElementById('client-edit-contact').value.trim();
if (!newName) { document.getElementById('client-edit-name').focus(); return; }
CLIENT_DATA[activeEditClient] = { name: newName, email: newEmail, contact: newContact };
// Update all name references
document.querySelectorAll('[data-client-name="'+activeEditClient+'"]').forEach(function(el){
el.textContent = newName;
});
// Update email shown in card header
var emailEl = document.getElementById('client-email-' + activeEditClient);
if (emailEl) emailEl.textContent = newEmail;
closeClientEditPopover();
}
document.addEventListener('click', e => {
const popover = document.getElementById('proj-edit-popover');
if (popover.style.display === 'block' && !popover.contains(e.target)) closeEditPopover();
});
// ── Generic inline edit ──
function startInlineEdit(el, onCommit) {
const currentText = el.textContent.trim();
const input = document.createElement('input');
input.type = 'text';
input.value = currentText;
input.className = 'editable-text-input';
input.style.width = Math.max(currentText.length * 8, 40) + 'px';
el.replaceWith(input);
input.focus();
input.select();
function commit() {
const newText = input.value.trim() || currentText;
el.textContent = newText;
input.replaceWith(el);
onCommit(newText);
}
input.addEventListener('blur', commit);
input.addEventListener('keydown', e => {
if (e.key === 'Enter') { e.preventDefault(); input.blur(); }
if (e.key === 'Escape') { input.value = currentText; input.blur(); }
});
input.addEventListener('input', () => {
input.style.width = Math.max(input.value.length * 8, 40) + 'px';
});
}
// ── Rename client ──
function startClientRename(el, clientId) {
startInlineEdit(el, newName => {
document.querySelectorAll(`[data-client-name="${clientId}"]`).forEach(node => {
node.textContent = newName;
});
// update proj-row-metric in side nav
const rows = document.querySelectorAll(`.proj-row-metric[data-client-id="${clientId}"]`);
rows.forEach(r => r.textContent = newName);
});
}
function startEmailEdit(el) {
startInlineEdit(el, () => {});
}
// ── Rename project ──
function startRename(h1El, projectId) {
const currentName = h1El.textContent.trim();
const input = document.createElement('input');
input.type = 'text';
input.value = currentName;
input.className = 'proj-name-input';
input.style.width = Math.max(currentName.length * 13, 80) + 'px';
h1El.replaceWith(input);
input.focus();
input.select();
function commit() {
const newName = input.value.trim() || currentName;
const newH1 = document.createElement('h1');
newH1.className = 'f proj-name-heading';
newH1.style.cssText = 'font-size:22px;font-weight:700;color:var(--ink);letter-spacing:-0.02em;';
newH1.textContent = newName;
newH1.title = 'Click to rename';
newH1.onclick = () => startRename(newH1, projectId);
input.replaceWith(newH1);
// Update proj-row name in side nav (text node before the pill span)
const row = document.getElementById('row-' + projectId);
if (row) {
const nameEl = row.querySelector('.proj-row-name');
if (nameEl) {
const pill = nameEl.querySelector('span');
nameEl.childNodes[0].textContent = newName + ' ';
}
row.dataset.name = newName.toLowerCase();
}
}
input.addEventListener('blur', commit);
input.addEventListener('keydown', e => {
if (e.key === 'Enter') { e.preventDefault(); input.blur(); }
if (e.key === 'Escape') { input.value = currentName; input.blur(); }
});
input.addEventListener('input', () => {
input.style.width = Math.max(input.value.length * 13, 80) + 'px';
});
}
// ── Dark mode ──
function setThemeLabel(isDark) {
const label = isDark ? '☀️ Light mode' : '🌙 Dark mode';
document.getElementById('theme-toggle').textContent = label;
const s = document.getElementById('theme-toggle-settings');
if (s) s.textContent = label;
}
function toggleTheme() {
const html = document.documentElement;
const isDark = html.dataset.theme === 'dark';
html.dataset.theme = isDark ? '' : 'dark';
setThemeLabel(isDark ? false : true);
localStorage.setItem('vibn-theme', isDark ? '' : 'dark');
}
if (localStorage.getItem('vibn-theme') === 'dark') {
document.documentElement.dataset.theme = 'dark';
setThemeLabel(true);
}
// ── Plan modal ──
var selectedPlan = 'pro';
function openPlanModal() {
selectedPlan = 'pro';
document.querySelectorAll('.plan-option').forEach(function(el){ el.classList.remove('plan-option-selected'); });
document.getElementById('plan-pro').classList.add('plan-option-selected');
document.getElementById('plan-confirm-btn').textContent = 'Confirm change';
document.getElementById('modal-plan').classList.add('open');
}
function closePlanModal() {
document.getElementById('modal-plan').classList.remove('open');
}
function selectPlan(plan) {
selectedPlan = plan;
document.querySelectorAll('.plan-option').forEach(function(el){ el.classList.remove('plan-option-selected'); });
document.getElementById('plan-' + plan).classList.add('plan-option-selected');
var labels = {starter:'Free forever', pro:'Pro — $29/mo', business:'Business — $79/mo'};
document.getElementById('plan-confirm-btn').textContent = plan === 'pro' ? 'Confirm change' : 'Switch to ' + labels[plan];
}
function confirmPlanChange() {
var labels = {starter:'Starter', pro:'Pro', business:'Business'};
document.querySelector('#ws-settings .fin-row span[style*="color:var(--indigo)"]').textContent = labels[selectedPlan];
closePlanModal();
}
// ── Settings edit mode ──
function enterSettingsEdit() {
document.querySelectorAll('#ws-settings .settings-view').forEach(function(el){ el.style.display='none'; });
document.querySelectorAll('#ws-settings .settings-input').forEach(function(el){ el.style.display=''; });
document.getElementById('settings-edit-btn').style.display='none';
var bar = document.getElementById('settings-save-bar');
bar.style.display='flex';
}
function cancelSettingsEdit() {
document.querySelectorAll('#ws-settings .settings-input').forEach(function(el){ el.style.display='none'; });
document.querySelectorAll('#ws-settings .settings-view').forEach(function(el){ el.style.display=''; });
document.getElementById('settings-edit-btn').style.display='';
document.getElementById('settings-save-bar').style.display='none';
}
function saveSettingsEdit() {
document.querySelectorAll('#ws-settings .settings-input').forEach(function(input){
var view = input.previousElementSibling;
if(view && view.classList.contains('settings-view')) view.textContent = input.value;
});
cancelSettingsEdit();
}
updateSearchVisibility();
// ── Time-based greeting ──
const h = new Date().getHours();
const greeting = h < 12 ? 'Good morning' : h < 18 ? 'Good afternoon' : 'Good evening';
document.getElementById('greeting-text').textContent = greeting + ', Jane.';
</script>
</body>
</html>