[object Object]

← back to Ventura Claw

services hub: 31 small-biz services + collapsible left chat + smart-router (local-first, Claude opt-in)

103d3279386ffe79e7ea45cc9977d896f64c4c38 · 2026-05-06 13:27:40 -0700 · Steve

Files touched

Diff

commit 103d3279386ffe79e7ea45cc9977d896f64c4c38
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed May 6 13:27:40 2026 -0700

    services hub: 31 small-biz services + collapsible left chat + smart-router (local-first, Claude opt-in)
---
 server/lib/smart-router.js  | 122 +++++++++
 server/public/services.html | 586 ++++++++++++++++++++++++++++++++++++++++++++
 server/server.js            |  38 +++
 3 files changed, 746 insertions(+)

diff --git a/server/lib/smart-router.js b/server/lib/smart-router.js
new file mode 100644
index 0000000..d3efe88
--- /dev/null
+++ b/server/lib/smart-router.js
@@ -0,0 +1,122 @@
+// VenturaClaw — Smart LLM Router
+// Goal: route prompts to the cheapest viable model. Local Ollama for the easy 80%,
+// Claude/GPT only for the hard 20%. Saves Anthropic spend without sacrificing UX.
+//
+// Wiring:
+//   const router = require("./lib/smart-router");
+//   const { answer, routed_to, est_cost_usd } = await router.route(prompt, { allowAnthropic: true });
+//
+// Toggle env:
+//   SMART_ROUTER_ALLOW_ANTHROPIC=1   - opt-in for Claude fallback (default: false)
+//   SMART_ROUTER_ALLOW_OPENAI=1      - opt-in for OpenAI fallback (default: false)
+//
+// Hard rule: never spawn `claude` CLI from this module without explicit opt-in.
+
+const OLLAMA_URL   = process.env.OLLAMA_URL   || "http://192.168.1.133:11434";
+const OLLAMA_MODEL = process.env.OLLAMA_MODEL || "qwen3:14b";
+
+// Tiers, ordered cheapest → most capable.
+const TIERS = [
+  { id: "local-fast", label: "Ollama qwen3:14b (Mac1)", url: OLLAMA_URL, model: OLLAMA_MODEL, cost_per_1k: 0,      max_tokens: 800 },
+  { id: "local-big",  label: "Ollama deepseek-r1:14b", url: OLLAMA_URL, model: "deepseek-r1:14b",                cost_per_1k: 0,      max_tokens: 1200 },
+  { id: "anthropic",  label: "Claude (via CLI)",        url: null,       model: "claude-sonnet-4-6",              cost_per_1k: 0.003,  max_tokens: 4000 },
+];
+
+// Estimate complexity 0..1 from a prompt without calling any LLM. Heuristic, not perfect — but free.
+function estimateComplexity(prompt) {
+  if (!prompt) return 0;
+  const len = prompt.length;
+  let score = 0;
+  if (len > 200) score += 0.15;
+  if (len > 600) score += 0.20;
+  if (len > 1500) score += 0.25;
+  // signals of complex synthesis / reasoning / code
+  const keywords = /\b(legal|contract|tax|liability|jurisdiction|comply|implications|architecture|migration|debug|refactor|design|tradeoff|why does|prove|optimize|because)\b/i;
+  if (keywords.test(prompt)) score += 0.20;
+  // signals of coding / technical depth
+  if (/\bcode|function|regex|algorithm|complexity|big-o|recursion|async\b/i.test(prompt)) score += 0.20;
+  // signals of nuance / multi-step / comparison
+  if (/\b(vs\.?|compare|differ|pros|cons|alternatives?|deciding between)\b/i.test(prompt)) score += 0.15;
+  // signals of simple factual lookup → keep low
+  if (/^(what is|how do i|where can i|when is|who is|is there)/i.test(prompt) && len < 120) score -= 0.10;
+  return Math.max(0, Math.min(1, score));
+}
+
+function pickTier(complexity, opts = {}) {
+  const allowAnthropic = opts.allowAnthropic ?? (process.env.SMART_ROUTER_ALLOW_ANTHROPIC === "1");
+  // Tuned for "qwen3:14b is pre-warmed, deepseek-r1 cold-loads ~45s on Mac1".
+  // Stay on the warm model for ~90% of traffic.
+  if (complexity < 0.55) return TIERS[0];                 // pre-warmed local
+  if (complexity < 0.80) return TIERS[1];                 // bigger local — accept cold load risk
+  if (allowAnthropic)    return TIERS[2];                 // Claude only for the genuinely hardest prompts
+  return TIERS[0];                                        // fall back to fast/warm if Claude not allowed
+}
+
+async function callOllama(tier, prompt, opts = {}) {
+  const r = await fetch(`${tier.url}/api/generate`, {
+    method: "POST",
+    headers: { "Content-Type": "application/json" },
+    body: JSON.stringify({
+      model: tier.model,
+      prompt,
+      stream: false,
+      keep_alive: "30m",
+      options: { temperature: opts.temperature ?? 0.3, num_predict: opts.maxTokens || tier.max_tokens },
+    }),
+    signal: AbortSignal.timeout(opts.timeoutMs || 60000),
+  });
+  if (!r.ok) throw new Error(`ollama ${r.status}: ${(await r.text()).slice(0, 200)}`);
+  const d = await r.json();
+  return (d.response || "").trim();
+}
+
+// Claude fallback — uses the Max plan via the `claude` CLI to avoid burning Anthropic API credits.
+// Spawns one-shot, never persists a session. Strips ANTHROPIC_API_KEY env to ensure CLI uses Max plan.
+async function callClaudeCLI(prompt, opts = {}) {
+  const { spawn } = require("child_process");
+  return new Promise((resolve, reject) => {
+    const env = { ...process.env };
+    delete env.ANTHROPIC_API_KEY;
+    delete env.ANTHROPIC_AUTH_TOKEN;
+    const child = spawn("claude", ["-p", "--output-format", "text"], { env });
+    let out = "", err = "";
+    child.stdout.on("data", d => out += d);
+    child.stderr.on("data", d => err += d);
+    child.on("close", code => code === 0 ? resolve(out.trim()) : reject(new Error(`claude CLI exit ${code}: ${err.slice(0, 200)}`)));
+    child.on("error", reject);
+    const timer = setTimeout(() => { child.kill(); reject(new Error("claude CLI timeout")); }, opts.timeoutMs || 90000);
+    child.on("close", () => clearTimeout(timer));
+    child.stdin.end(prompt);
+  });
+}
+
+async function route(prompt, opts = {}) {
+  const start = Date.now();
+  const complexity = estimateComplexity(prompt);
+  const tier = pickTier(complexity, opts);
+  let answer, error;
+  try {
+    if (tier.id === "anthropic") {
+      answer = await callClaudeCLI(prompt, opts);
+    } else {
+      answer = await callOllama(tier, prompt, opts);
+    }
+  } catch (e) {
+    error = e.message;
+    // graceful fallback: if local-fast fails, try local-big; if local-big fails, give up (don't escalate to Claude on error — bill control).
+    if (tier.id === "local-fast") {
+      try { answer = await callOllama(TIERS[1], prompt, opts); } catch (e2) { error += " · also " + e2.message; }
+    }
+  }
+  return {
+    answer: answer || `(error) ${error}`,
+    routed_to: tier.id,
+    routed_to_label: tier.label,
+    complexity_score: complexity,
+    est_cost_usd: tier.cost_per_1k * Math.ceil((prompt.length + (answer || "").length) / 4 / 1000),
+    elapsed_ms: Date.now() - start,
+    error: error || null,
+  };
+}
+
+module.exports = { route, estimateComplexity, pickTier, TIERS };
diff --git a/server/public/services.html b/server/public/services.html
new file mode 100644
index 0000000..097bf1b
--- /dev/null
+++ b/server/public/services.html
@@ -0,0 +1,586 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width,initial-scale=1" />
+<title>Small-Business Services — VenturaClaw</title>
+<meta name="description" content="Form an LLC, register a DBA, file your BOI, open a business bank account, get insured, and 30+ other small-business services. Free DIY guides, small flat-fee filing, and an AI assistant on every page." />
+<style>
+  :root {
+    --bg: #0e0e10; --bg-2: #15151a; --bg-3: #1c1c22; --bg-4: #25252e;
+    --rule: #2a2a32; --rule-2: #3a3a45;
+    --ink: #f4f1ea; --ink-soft: #d8d2c5; --ink-mute: #8b857a; --ink-faint: #5d574c;
+    --gold: #d4a04a; --gold-glow: #e6b96a; --gold-soft: rgba(212,160,74,0.12);
+    --good: #6ec081; --warn: #d4a04a; --bad: #c66c4d;
+    --serif: "Cormorant Garamond", Georgia, serif;
+    --mono: "JetBrains Mono", "SFMono-Regular", Menlo, monospace;
+    --sans: -apple-system, "SF Pro Text", system-ui, sans-serif;
+    --chat-w: 360px;
+    --chat-w-collapsed: 44px;
+  }
+  *, *::before, *::after { box-sizing: border-box; }
+  html, body { margin: 0; background: var(--bg); color: var(--ink); font-family: var(--sans); font-weight: 300; line-height: 1.6; min-height: 100vh; }
+  ::selection { background: var(--gold); color: var(--bg); }
+  a { color: var(--gold); text-decoration: none; }
+  a:hover { color: var(--gold-glow); }
+
+  /* CHAT PANEL — fixed left, collapsible */
+  .chat-panel {
+    position: fixed; top: 0; left: 0; bottom: 0;
+    width: var(--chat-w);
+    background: linear-gradient(180deg, var(--bg-2), var(--bg));
+    border-right: 1px solid var(--rule);
+    display: flex; flex-direction: column;
+    z-index: 100;
+    transition: width 250ms cubic-bezier(.2,.8,.2,1);
+  }
+  .chat-panel.collapsed { width: var(--chat-w-collapsed); }
+  .chat-panel.collapsed .chat-body,
+  .chat-panel.collapsed .chat-input-wrap,
+  .chat-panel.collapsed .chat-header > *:not(.chat-toggle) { display: none; }
+  .chat-header {
+    display: flex; align-items: center; justify-content: space-between;
+    padding: 14px 14px 14px 18px;
+    border-bottom: 1px solid var(--rule);
+    flex-shrink: 0;
+  }
+  .chat-title {
+    font-family: var(--serif); font-size: 17px; font-weight: 500; color: var(--ink);
+    display: flex; align-items: center; gap: 8px; letter-spacing: -0.005em;
+  }
+  .chat-title .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--good); box-shadow: 0 0 8px var(--good); animation: pulse 2.4s infinite; }
+  @keyframes pulse { 50% { opacity: .55; } }
+  .chat-toggle {
+    background: var(--bg-3); color: var(--ink-soft); border: 1px solid var(--rule);
+    width: 28px; height: 28px; border-radius: 4px;
+    cursor: pointer; font-family: var(--mono); font-size: 14px;
+    display: flex; align-items: center; justify-content: center;
+    transition: all 200ms;
+  }
+  .chat-toggle:hover { color: var(--gold); border-color: var(--gold); }
+  .chat-panel.collapsed .chat-toggle {
+    margin: 0 auto;
+  }
+  .chat-body {
+    flex: 1; overflow-y: auto;
+    padding: 14px 18px;
+    font-size: 14px;
+  }
+  .chat-body::-webkit-scrollbar { width: 6px; }
+  .chat-body::-webkit-scrollbar-thumb { background: var(--rule-2); border-radius: 3px; }
+  .chat-msg { margin-bottom: 14px; padding: 12px 14px; border-radius: 6px; line-height: 1.55; }
+  .chat-msg.user { background: var(--gold-soft); border: 1px solid var(--gold); color: var(--ink); }
+  .chat-msg.assistant { background: var(--bg-3); border: 1px solid var(--rule); color: var(--ink-soft); }
+  .chat-msg.assistant a { color: var(--gold); }
+  .chat-msg.assistant.thinking { color: var(--ink-mute); font-style: italic; }
+  .chat-msg .who {
+    font-family: var(--mono); font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase;
+    color: var(--ink-mute); margin-bottom: 4px;
+  }
+  .chat-suggestions {
+    display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;
+  }
+  .chat-suggest {
+    background: var(--bg-3); border: 1px solid var(--rule);
+    color: var(--ink-soft); font-family: var(--mono); font-size: 10px; letter-spacing: 0.04em;
+    padding: 6px 10px; border-radius: 999px; cursor: pointer;
+    transition: all 200ms;
+  }
+  .chat-suggest:hover { color: var(--gold); border-color: var(--gold); background: var(--gold-soft); }
+  .chat-input-wrap {
+    border-top: 1px solid var(--rule);
+    padding: 12px;
+    background: var(--bg-2);
+    flex-shrink: 0;
+  }
+  .chat-input {
+    width: 100%; min-height: 60px; max-height: 160px;
+    background: var(--bg); color: var(--ink);
+    border: 1px solid var(--rule); border-radius: 4px;
+    padding: 10px 12px;
+    font-family: var(--sans); font-size: 13px; font-weight: 300;
+    resize: none; outline: none;
+    transition: border-color 200ms;
+  }
+  .chat-input:focus { border-color: var(--gold); box-shadow: 0 0 0 2px var(--gold-soft); }
+  .chat-actions { display: flex; justify-content: space-between; margin-top: 8px; align-items: center; }
+  .chat-hint { font-family: var(--mono); font-size: 9px; letter-spacing: 0.12em; color: var(--ink-faint); text-transform: uppercase; }
+  .chat-send {
+    background: var(--gold); color: var(--bg); border: 0;
+    padding: 8px 14px; font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 600;
+    cursor: pointer; border-radius: 3px;
+    transition: background 200ms;
+  }
+  .chat-send:hover { background: var(--gold-glow); }
+  .chat-send:disabled { opacity: 0.5; cursor: not-allowed; }
+
+  /* MAIN */
+  main {
+    margin-left: var(--chat-w);
+    transition: margin-left 250ms cubic-bezier(.2,.8,.2,1);
+    min-height: 100vh;
+  }
+  body.chat-collapsed main { margin-left: var(--chat-w-collapsed); }
+
+  .topbar {
+    padding: 22px 36px;
+    display: flex; justify-content: space-between; align-items: center;
+    border-bottom: 1px solid var(--rule);
+    background: rgba(14,14,16,0.85);
+    backdrop-filter: blur(8px);
+    position: sticky; top: 0; z-index: 50;
+  }
+  .brand { display: flex; gap: 12px; align-items: baseline; }
+  .brand .logo-dot {
+    width: 12px; height: 12px; border-radius: 50%;
+    background: radial-gradient(circle at 30% 30%, var(--gold-glow), var(--gold) 60%, #7a5a26);
+    box-shadow: 0 0 14px rgba(212, 160, 74, 0.45);
+    align-self: center;
+  }
+  .brand .name { font-family: var(--serif); font-size: 22px; font-weight: 500; }
+  .brand .name em { color: var(--gold); font-style: italic; }
+  .brand .crumb { font-family: var(--mono); font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-mute); }
+  .brand .crumb::before { content: "/ "; color: var(--ink-faint); }
+  .topbar nav { display: flex; gap: 22px; align-items: center; }
+  .topbar nav a { font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-mute); }
+  .topbar nav a:hover { color: var(--gold); }
+
+  .hero {
+    padding: 64px 48px 40px; max-width: 1100px;
+  }
+  .eyebrow {
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
+    color: var(--ink-mute); margin-bottom: 18px;
+    display: flex; align-items: center; gap: 10px;
+  }
+  .eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--good); box-shadow: 0 0 10px var(--good); }
+  .hero h1 {
+    font-family: var(--serif); font-weight: 400; line-height: 1.05; letter-spacing: -0.012em;
+    font-size: clamp(40px, 5.5vw, 76px); margin: 0 0 20px;
+  }
+  .hero h1 em { color: var(--gold); font-style: italic; }
+  .hero .lede {
+    font-size: 18px; line-height: 1.6; color: var(--ink-soft); max-width: 720px;
+  }
+  .hero .lede em { color: var(--gold); font-style: italic; }
+  .hero .stats { display: flex; gap: 36px; margin-top: 32px; flex-wrap: wrap; }
+  .hero .stat {
+    border-left: 2px solid var(--gold);
+    padding-left: 14px;
+  }
+  .hero .stat .num { font-family: var(--serif); font-size: 32px; color: var(--gold); font-weight: 500; }
+  .hero .stat .lbl { font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-mute); }
+
+  /* Category sections */
+  .cat-section { padding: 36px 48px; max-width: 1400px; }
+  .cat-section .cat-head {
+    display: flex; align-items: baseline; justify-content: space-between;
+    border-bottom: 1px solid var(--rule); padding-bottom: 14px; margin-bottom: 28px;
+    gap: 20px; flex-wrap: wrap;
+  }
+  .cat-section .cat-head h2 {
+    font-family: var(--serif); font-weight: 400; font-size: 32px; letter-spacing: -0.005em; margin: 0;
+  }
+  .cat-section .cat-head h2 em { color: var(--gold); font-style: italic; }
+  .cat-section .cat-head .cat-icon {
+    font-family: var(--mono); font-size: 11px; color: var(--gold); letter-spacing: 0.16em; text-transform: uppercase;
+  }
+  .cat-section .cat-head .cat-blurb {
+    font-size: 13px; color: var(--ink-mute); flex: 1; max-width: 520px; text-align: right;
+  }
+
+  .svc-grid {
+    display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px;
+  }
+  .svc {
+    background: var(--bg-2); border: 1px solid var(--rule); border-left: 3px solid var(--rule-2);
+    padding: 20px 22px;
+    transition: all 200ms;
+    cursor: pointer;
+    display: flex; flex-direction: column;
+    position: relative;
+  }
+  .svc:hover {
+    border-left-color: var(--gold);
+    background: var(--bg-3);
+    transform: translateX(2px);
+  }
+  .svc .svc-num {
+    font-family: var(--mono); font-size: 9px; letter-spacing: 0.14em;
+    color: var(--ink-faint); margin-bottom: 6px;
+  }
+  .svc .svc-name {
+    font-family: var(--serif); font-size: 19px; font-weight: 500; color: var(--ink);
+    margin-bottom: 6px; letter-spacing: -0.005em;
+  }
+  .svc .svc-desc {
+    font-size: 13px; color: var(--ink-mute); line-height: 1.55;
+    flex: 1; margin-bottom: 16px;
+  }
+  .svc .svc-pricing {
+    display: flex; gap: 14px; align-items: center;
+    border-top: 1px dashed var(--rule); padding-top: 12px;
+    flex-wrap: wrap;
+  }
+  .svc .price-tag {
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.06em;
+    display: flex; flex-direction: column; gap: 2px;
+  }
+  .svc .price-tag .lbl { color: var(--ink-faint); font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; }
+  .svc .price-tag .val { color: var(--ink); font-size: 13px; font-family: var(--serif); font-weight: 500; }
+  .svc .price-tag.free .val { color: var(--good); }
+  .svc .price-tag.gold .val { color: var(--gold); }
+  .svc .ask-link {
+    margin-left: auto;
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
+    color: var(--ink-mute);
+  }
+  .svc:hover .ask-link { color: var(--gold); }
+
+  /* Visual flair: floating shapes for hero */
+  .hero { position: relative; overflow: hidden; }
+  .hero::before, .hero::after {
+    content: ""; position: absolute; border-radius: 50%; filter: blur(60px); opacity: 0.5; z-index: -1;
+  }
+  .hero::before {
+    width: 380px; height: 380px; right: -100px; top: -120px;
+    background: radial-gradient(circle, var(--gold), transparent 70%);
+  }
+  .hero::after {
+    width: 280px; height: 280px; left: 30%; bottom: -180px;
+    background: radial-gradient(circle, rgba(110,192,129,0.4), transparent 70%);
+  }
+
+  /* Footer */
+  footer {
+    padding: 40px 48px 60px; border-top: 1px solid var(--rule);
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-mute);
+    display: flex; justify-content: space-between; flex-wrap: wrap; gap: 14px;
+    margin-top: 60px;
+  }
+  footer a { color: var(--ink-mute); }
+  footer a:hover { color: var(--gold); }
+
+  /* Mobile — chat collapses to bottom drawer */
+  @media (max-width: 820px) {
+    .chat-panel { width: 100%; height: 50vh; top: auto; }
+    .chat-panel.collapsed { width: 100%; height: 50px; }
+    main { margin-left: 0; margin-bottom: 50vh; }
+    body.chat-collapsed main { margin-left: 0; margin-bottom: 50px; }
+    .hero { padding: 36px 24px 28px; }
+    .cat-section { padding: 28px 24px; }
+    .topbar { padding: 18px 24px; }
+  }
+
+  /* Money saved badge in hero */
+  .savings-badge {
+    display: inline-flex; align-items: center; gap: 8px;
+    background: linear-gradient(90deg, rgba(110,192,129,0.15), transparent);
+    border: 1px solid var(--good); border-radius: 999px;
+    padding: 6px 14px;
+    font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--good);
+    margin-top: 24px;
+  }
+  .savings-badge .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--good); box-shadow: 0 0 8px var(--good); }
+</style>
+</head>
+<body>
+
+<!-- COLLAPSIBLE CHAT PANEL -->
+<aside class="chat-panel" id="chatPanel">
+  <div class="chat-header">
+    <div class="chat-title"><span class="dot"></span><span>Ask anything</span></div>
+    <button class="chat-toggle" id="chatToggle" title="collapse / expand">&laquo;</button>
+  </div>
+  <div class="chat-body" id="chatBody">
+    <div class="chat-msg assistant">
+      <div class="who">VenturaClaw</div>
+      Hi — I'm here to help you start, run, and protect your business. Ask me anything: <em>"Should I form an LLC or stay sole prop?"</em>, <em>"How do I get an EIN?"</em>, <em>"What's a BOI filing?"</em>
+    </div>
+    <div class="chat-suggestions">
+      <div class="chat-suggest" data-q="Do I need an LLC or can I stay sole prop?">LLC vs sole prop?</div>
+      <div class="chat-suggest" data-q="How do I get an EIN for free?">Free EIN?</div>
+      <div class="chat-suggest" data-q="What is a BOI filing and do I need to file one?">BOI filing?</div>
+      <div class="chat-suggest" data-q="Best business bank account for a new LLC?">Best bank?</div>
+      <div class="chat-suggest" data-q="Do I need a DBA if I have an LLC?">DBA + LLC?</div>
+      <div class="chat-suggest" data-q="What insurance does a one-person consulting business need?">Insurance?</div>
+    </div>
+  </div>
+  <div class="chat-input-wrap">
+    <textarea class="chat-input" id="chatInput" placeholder="ask anything about your business — taxes, legal, banking, insurance…" rows="2"></textarea>
+    <div class="chat-actions">
+      <span class="chat-hint">⌘↵ to send · runs on a local model</span>
+      <button class="chat-send" id="chatSend">Send →</button>
+    </div>
+  </div>
+</aside>
+
+<main>
+
+<header class="topbar">
+  <div class="brand">
+    <span class="logo-dot"></span>
+    <span class="name">Ventura<em>Claw</em></span>
+    <span class="crumb">Small-Business Services</span>
+  </div>
+  <nav>
+    <a href="/">Home</a>
+    <a href="/connectors">Connectors</a>
+    <a href="/pricing">Pricing</a>
+    <a href="/login">Sign in</a>
+  </nav>
+</header>
+
+<section class="hero">
+  <div class="eyebrow"><span class="dot"></span><span>30+ services · 6 categories · plain English</span></div>
+  <h1>Start, register, and <em>protect</em> your business — without the legal-zoom upsell maze.</h1>
+  <p class="lede">
+    Forming an LLC, filing a DBA, getting an EIN, opening a business bank account, BOI compliance, sales tax permits — most of it is <em>free</em> if you know the form. Where it's not, we file for you at a small flat fee. The chat on the left answers anything, anytime, on a local model that doesn't see your data.
+  </p>
+  <span class="savings-badge"><span class="dot"></span>Save $500–$3,000 vs. LegalZoom / ZenBusiness on a typical bundle</span>
+  <div class="stats">
+    <div class="stat"><div class="num">31</div><div class="lbl">Services covered</div></div>
+    <div class="stat"><div class="num">$0</div><div class="lbl">DIY tier on most</div></div>
+    <div class="stat"><div class="num">$29–99</div><div class="lbl">If we file for you</div></div>
+    <div class="stat"><div class="num">24/7</div><div class="lbl">AI assistant</div></div>
+  </div>
+</section>
+
+<!-- FORMATION -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 01 · FORMATION</span>
+      <h2>Get the <em>legal entity</em> right.</h2>
+    </div>
+    <div class="cat-blurb">Choose your structure, file with the state, get your tax ID, register your trade name. Most of this is free if you do it yourself — we'll walk you through, or file it for you at a small flat fee.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="LLC formation"><div class="svc-num">01-A</div><div class="svc-name">LLC formation</div><div class="svc-desc">File Articles of Organization with your state. Sole-member LLC takes ~15 min. We handle the form, pay the state fee separately.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$99 + state fee</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="DBA / fictitious business name"><div class="svc-num">01-B</div><div class="svc-name">DBA registration</div><div class="svc-desc">Operate under a name that isn't your legal name. County or state level. ~10 min once you know which form.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$49 + county fee</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="EIN / federal tax ID"><div class="svc-num">01-C</div><div class="svc-name">EIN application</div><div class="svc-desc">Free directly from the IRS at irs.gov/ein. We'll show you the exact path. <strong>Never pay anyone for this.</strong></div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Always free</span><span class="val">$0</span></div><div class="price-tag"><span class="lbl">Walkthrough</span><span class="val">Free</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="S-Corp election"><div class="svc-num">01-D</div><div class="svc-name">S-Corp tax election</div><div class="svc-desc">Form 2553 to elect S-Corp tax treatment. Saves on self-employment tax once you cross ~$60K profit. Timing matters.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$79</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Sole proprietorship registration"><div class="svc-num">01-E</div><div class="svc-name">Sole prop registration</div><div class="svc-desc">Already a sole prop the moment you start working. Some states/counties require local registration. We tell you which.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$29</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Operating agreement"><div class="svc-num">01-F</div><div class="svc-name">Operating agreement</div><div class="svc-desc">LLC's internal rulebook. Not always required by state, always required by banks. We draft from a vetted template.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Template</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Custom</span><span class="val">$49</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<!-- BANKING -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 02 · BANKING & PAYMENTS</span>
+      <h2>Open the <em>right accounts</em>, the first time.</h2>
+    </div>
+    <div class="cat-blurb">Business checking, payments processor, payroll, accounting. We pre-vet the providers that don't have surprise fees and integrate with the connectors VenturaClaw already speaks.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="business bank account"><div class="svc-num">02-A</div><div class="svc-name">Business bank account</div><div class="svc-desc">Mercury, Relay, Bluevine — no monthly fee, online only, opens in ~15 min once your LLC + EIN are in hand.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Recommendation</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Concierge open</span><span class="val">$39</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Stripe / Square setup"><div class="svc-num">02-B</div><div class="svc-name">Payments (Stripe/Square)</div><div class="svc-desc">Pick the right processor for your model — recurring, one-time, in-person. We help you avoid the 2.9%+30¢ surprise.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Setup</span><span class="val">$49</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Payroll setup (Gusto/Justworks)"><div class="svc-num">02-C</div><div class="svc-name">Payroll setup</div><div class="svc-desc">Gusto for most, Justworks for PEO needs. We handle Form 941 and state unemployment registration.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We set up</span><span class="val">$79</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Business credit card"><div class="svc-num">02-D</div><div class="svc-name">Business credit card</div><div class="svc-desc">Personal-credit-only options for new LLCs (Brex, Mercury IO, Capital One Spark). We compare cash-back vs. travel.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Guidance</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Apply</span><span class="val">Self-serve</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Bookkeeping / accounting setup"><div class="svc-num">02-E</div><div class="svc-name">Accounting setup</div><div class="svc-desc">QuickBooks for tax-ready, Wave for free, Xero for international. Chart of accounts seeded for your industry.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Concierge</span><span class="val">$59</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<!-- COMPLIANCE -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 03 · COMPLIANCE</span>
+      <h2>Stay <em>in good standing</em>, year after year.</h2>
+    </div>
+    <div class="cat-blurb">BOI/CTA, annual reports, business licenses, sales tax. The boring stuff that costs you the LLC if you forget. We track due dates and send reminders.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="BOI / FinCEN beneficial ownership"><div class="svc-num">03-A</div><div class="svc-name">BOI filing (FinCEN)</div><div class="svc-desc">Beneficial Ownership Information report — required for most LLCs/Corps under the Corporate Transparency Act. Free at fincen.gov.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$39</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Annual report / Statement of Information"><div class="svc-num">03-B</div><div class="svc-name">Annual report</div><div class="svc-desc">Most states require a yearly filing. Miss it and your LLC gets administratively dissolved. We track it.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Reminder</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$39 + state</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Business license (city/county)"><div class="svc-num">03-C</div><div class="svc-name">Business license</div><div class="svc-desc">City- or county-level. Required by most municipalities; rules vary wildly. We research yours.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Research</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$79</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Sales tax permit (state seller's permit)"><div class="svc-num">03-D</div><div class="svc-name">Sales tax permit</div><div class="svc-desc">If you sell goods (or some services), you need a seller's permit per state. We file in all 45 sales-tax states.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$69 / state</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Registered agent service"><div class="svc-num">03-E</div><div class="svc-name">Registered agent</div><div class="svc-desc">Required by every state for LLCs/corps. We don't sell this — we recommend Northwest at $125/yr (cheaper than LegalZoom).</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Recommendation</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Northwest</span><span class="val">$125/yr</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<!-- TAXES -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 04 · TAXES</span>
+      <h2>Pay <em>only</em> what you owe.</h2>
+    </div>
+    <div class="cat-blurb">Quarterly estimates, Schedule C walkthroughs, 1099-NEC for contractors, IRS payment plans. Mostly free guidance plus a CPA referral when it gets weird.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="Quarterly estimated tax filings"><div class="svc-num">04-A</div><div class="svc-name">Quarterly estimates</div><div class="svc-desc">If you'll owe more than $1,000 at year-end, you owe quarterly. We calculate and remind. Most underpay.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Calc + reminders</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">CPA file</span><span class="val">Referral</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Schedule C / Schedule E walkthrough"><div class="svc-num">04-B</div><div class="svc-name">Schedule C walkthrough</div><div class="svc-desc">Sole props and single-member LLCs file Schedule C. We help you find every deduction without crossing audit lines.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Walkthrough</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">CPA</span><span class="val">Referral</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="1099-NEC for contractors"><div class="svc-num">04-C</div><div class="svc-name">1099-NEC filing</div><div class="svc-desc">Pay any contractor over $600 in a year and you owe them (and the IRS) a 1099-NEC by Jan 31. We file them.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$9 / form</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="IRS payment plan / installment agreement"><div class="svc-num">04-D</div><div class="svc-name">IRS payment plan</div><div class="svc-desc">Owe more than you can pay? You qualify for an installment agreement up to $50K, online, no interview.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Walkthrough</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$49</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="CPA referral"><div class="svc-num">04-E</div><div class="svc-name">CPA referral</div><div class="svc-desc">When the chat says "ask a CPA" — we connect you to a vetted small-business CPA in your state. No kickback.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Intro</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">CPA fees</span><span class="val">~$300+</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<!-- INSURANCE -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 05 · INSURANCE</span>
+      <h2>Cover the <em>predictable disasters.</em></h2>
+    </div>
+    <div class="cat-blurb">General liability, professional liability (E&O), workers' comp, cyber, BOP. Routed through brokers we've vetted — no surprise commissions hidden in your premium.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="General liability insurance"><div class="svc-num">05-A</div><div class="svc-name">General liability</div><div class="svc-desc">Slip-and-fall, property damage, libel. Most clients require it. ~$30–60/mo for a one-person business.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Quote routing</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Broker</span><span class="val">~$30–60/mo</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Professional liability / E&O"><div class="svc-num">05-B</div><div class="svc-name">Professional liability (E&O)</div><div class="svc-desc">Errors & omissions — for consultants, designers, agencies. Covers "I gave bad advice" claims.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Quote routing</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Broker</span><span class="val">~$40–100/mo</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Workers comp insurance"><div class="svc-num">05-C</div><div class="svc-name">Workers' comp</div><div class="svc-desc">Required in most states the moment you have one W-2 employee. Sometimes required for sole props in construction.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Quote routing</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Carrier</span><span class="val">Varies</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Cyber liability insurance"><div class="svc-num">05-D</div><div class="svc-name">Cyber liability</div><div class="svc-desc">Customer-data breach coverage. Cheap for solos (~$25/mo), critical the moment you store SSNs or card data.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Quote routing</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Carrier</span><span class="val">~$25–60/mo</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="BOP / business owners policy"><div class="svc-num">05-E</div><div class="svc-name">Business Owner's Policy</div><div class="svc-desc">Bundle: GL + property + biz interruption. Cheaper than buying separate. Standard for retail, food, salons.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Quote routing</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Carrier</span><span class="val">~$50–150/mo</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<!-- IP & OPERATIONS -->
+<section class="cat-section">
+  <div class="cat-head">
+    <div>
+      <span class="cat-icon">▲ 06 · IP & OPERATIONS</span>
+      <h2>Protect the <em>name, the work, and the inbox.</em></h2>
+    </div>
+    <div class="cat-blurb">Trademark, copyright, domain + email, contracts, privacy policy. The pieces of "running a business" that aren't filings but feel like them.</div>
+  </div>
+  <div class="svc-grid">
+    <div class="svc" data-svc="Trademark search and filing"><div class="svc-num">06-A</div><div class="svc-name">Trademark search + filing</div><div class="svc-desc">USPTO TESS search to confirm your name is clean, then a Class-035 filing. Most attorneys charge $700+; we do it for $79 + USPTO fee.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Search</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$79 + $250 USPTO</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Copyright registration"><div class="svc-num">06-B</div><div class="svc-name">Copyright registration</div><div class="svc-desc">For your written/visual/audio work. Free legally on creation, but registration is required to sue. eCO portal at copyright.gov.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">DIY</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We file</span><span class="val">$49 + $65 USCO</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Domain + business email setup"><div class="svc-num">06-C</div><div class="svc-name">Domain + email</div><div class="svc-desc">Register a .com, point DNS, and set up info@yourbiz.com with SPF/DKIM/DMARC so you don't land in spam.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Walkthrough</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">We set up</span><span class="val">$39</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Virtual mailbox / business address"><div class="svc-num">06-D</div><div class="svc-name">Virtual mailbox</div><div class="svc-desc">Real street address (not a PO Box) so your home doesn't show up on every filing. iPostal1 / Earth Class Mail.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Recommendation</span><span class="val">Free</span></div><div class="price-tag"><span class="lbl">Provider</span><span class="val">~$10–25/mo</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Privacy policy and terms generator"><div class="svc-num">06-E</div><div class="svc-name">Privacy policy + ToS</div><div class="svc-desc">Generated from a vetted CCPA/GDPR/COPPA template, customized to your data flow. Don't copy a competitor's.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Generate</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Custom</span><span class="val">$39</span></div><span class="ask-link">Ask the chat →</span></div></div>
+    <div class="svc" data-svc="Contract templates"><div class="svc-num">06-F</div><div class="svc-name">Contract templates</div><div class="svc-desc">MSA, NDA, contractor agreement, statement of work, payment terms. Free library; lawyer-vetted before download.</div><div class="svc-pricing"><div class="price-tag free"><span class="lbl">Library</span><span class="val">Free</span></div><div class="price-tag gold"><span class="lbl">Custom edit</span><span class="val">$29</span></div><span class="ask-link">Ask the chat →</span></div></div>
+  </div>
+</section>
+
+<footer>
+  <span>© 2026 VenturaClaw · Steve Abrams · <a href="mailto:info@venturaclaw.com">info@venturaclaw.com</a></span>
+  <span>
+    <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a> · <a href="/about">About</a>
+  </span>
+</footer>
+
+</main>
+
+<script>
+  // ----- chat panel state -----
+  const panel  = document.getElementById('chatPanel');
+  const toggle = document.getElementById('chatToggle');
+  const body   = document.getElementById('chatBody');
+  const input  = document.getElementById('chatInput');
+  const send   = document.getElementById('chatSend');
+
+  function setCollapsed(v) {
+    panel.classList.toggle('collapsed', v);
+    document.body.classList.toggle('chat-collapsed', v);
+    toggle.innerHTML = v ? '&raquo;' : '&laquo;';
+    try { localStorage.setItem('vc-chat-collapsed', v ? '1' : '0'); } catch {}
+  }
+  setCollapsed(localStorage.getItem('vc-chat-collapsed') === '1');
+  toggle.addEventListener('click', () => setCollapsed(!panel.classList.contains('collapsed')));
+
+  // suggested-question pills
+  document.querySelectorAll('.chat-suggest').forEach(el => {
+    el.addEventListener('click', () => {
+      input.value = el.dataset.q;
+      input.focus();
+      send.click();
+    });
+  });
+
+  // service-card click → seed chat with question about that service
+  document.querySelectorAll('.svc').forEach(el => {
+    el.addEventListener('click', () => {
+      if (panel.classList.contains('collapsed')) setCollapsed(false);
+      input.value = `Tell me about ${el.dataset.svc} — do I need it, what's it cost, and what's the catch?`;
+      input.focus();
+      send.click();
+    });
+  });
+
+  // restore prior conversation from localStorage
+  const HISTORY_KEY = 'vc-services-chat';
+  function loadHistory() {
+    try {
+      const raw = localStorage.getItem(HISTORY_KEY);
+      if (!raw) return;
+      const msgs = JSON.parse(raw);
+      // keep the welcome message + suggestions; append history below
+      msgs.forEach(m => appendMsg(m.role, m.content, false));
+    } catch {}
+  }
+  function saveHistory() {
+    try {
+      const msgs = Array.from(body.querySelectorAll('.chat-msg.user, .chat-msg.assistant:not(.welcome):not(.thinking)')).slice(-20).map(el => ({
+        role: el.classList.contains('user') ? 'user' : 'assistant',
+        content: el.dataset.raw || el.textContent.replace(/^VenturaClaw|^You/, '').trim()
+      }));
+      localStorage.setItem(HISTORY_KEY, JSON.stringify(msgs));
+    } catch {}
+  }
+
+  function appendMsg(role, text, save = true) {
+    const d = document.createElement('div');
+    d.className = 'chat-msg ' + role;
+    d.dataset.raw = text;
+    const who = document.createElement('div');
+    who.className = 'who';
+    who.textContent = role === 'user' ? 'You' : 'VenturaClaw';
+    d.appendChild(who);
+    const c = document.createElement('div');
+    // very simple markdown-ish rendering: line breaks + **bold** + *italic*
+    c.innerHTML = text
+      .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+      .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
+      .replace(/\*(.+?)\*/g, '<em>$1</em>')
+      .replace(/\n/g, '<br>');
+    d.appendChild(c);
+    body.appendChild(d);
+    body.scrollTop = body.scrollHeight;
+    if (save) saveHistory();
+    return d;
+  }
+
+  let isSending = false;
+  async function sendMsg() {
+    const q = input.value.trim();
+    if (!q || isSending) return;
+    isSending = true;
+    send.disabled = true;
+    input.value = '';
+    appendMsg('user', q);
+
+    const thinking = appendMsg('assistant', 'thinking…', false);
+    thinking.classList.add('thinking');
+
+    try {
+      const r = await fetch('/api/services-chat', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({ message: q, history: [] })
+      });
+      const j = await r.json();
+      thinking.remove();
+      appendMsg('assistant', j.answer || j.error || 'No response.');
+    } catch (e) {
+      thinking.remove();
+      appendMsg('assistant', 'Network error: ' + e.message);
+    } finally {
+      isSending = false;
+      send.disabled = false;
+    }
+  }
+
+  send.addEventListener('click', sendMsg);
+  input.addEventListener('keydown', e => {
+    if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); sendMsg(); }
+  });
+
+  loadHistory();
+</script>
+
+</body>
+</html>
diff --git a/server/server.js b/server/server.js
index 29d3e43..954f079 100644
--- a/server/server.js
+++ b/server/server.js
@@ -509,6 +509,7 @@ app.get("/", (req, res) => {
   res.sendFile(path.join(PUB, "homepage.html"));
 });
 app.get("/login",   (req, res) => res.sendFile(path.join(PUB, "login.html")));
+app.get("/services",    (req, res) => res.sendFile(path.join(PUB, "services.html")));
 app.get("/chat",        requireAuthPage, (req, res) => res.sendFile(path.join(PUB, "chat.html")));
 app.get("/connections", requireAuthPage, (req, res) => res.sendFile(path.join(PUB, "connections.html")));
 app.get("/connections/import", requireAuthPage, (req, res) => res.sendFile(path.join(PUB, "connections-import.html")));
@@ -651,6 +652,43 @@ app.post("/api/demo-classify", demoLimiter, express.json({ limit: "2kb" }), asyn
     res.status(500).json({ error: "classify_failed" });
   }
 });
+// Public services-chat endpoint — answers small-business questions on the /services page.
+// Routes via smart-router (local Ollama default, Claude only if SMART_ROUTER_ALLOW_ANTHROPIC=1).
+const _smartRouter = require("./lib/smart-router");
+const servicesChatLimiter = rateLimit({
+  windowMs: 60 * 1000, max: 20, standardHeaders: true, legacyHeaders: false,
+  message: { error: "rate_limited", msg: "Slow down — 20/min." }
+});
+app.post("/api/services-chat", servicesChatLimiter, express.json({ limit: "8kb" }), async (req, res) => {
+  const { message, history } = req.body || {};
+  if (typeof message !== "string" || message.length < 3 || message.length > 1500) {
+    return res.status(400).json({ error: "bad_input", msg: "Message must be 3–1500 characters." });
+  }
+  const sys = `You are VenturaClaw's small-business advisor. You help solo founders and small businesses
+understand entity formation, taxes, banking, compliance, insurance, and IP. Be specific, plain-English, and
+honest. Cite costs in USD. When something is FREE directly from the IRS or a state agency, say so loudly —
+warn the user not to pay middlemen for free things (especially EIN). When the user is in genuinely complex
+territory (multi-state, foreign income, partnership disputes, audits), recommend they consult a CPA or
+attorney. Keep answers under ~200 words unless the question demands depth. Never invent specific state filing
+fees — say "varies by state" if you're not sure. Format with short paragraphs and bullets where helpful.
+
+User question:
+${message}
+
+Answer:`;
+  try {
+    const out = await _smartRouter.route(sys, { allowAnthropic: false, maxTokens: 700, timeoutMs: 45000 });
+    res.json({
+      answer: out.answer,
+      routed_to: out.routed_to_label,
+      complexity: Math.round(out.complexity_score * 100),
+      elapsed_ms: out.elapsed_ms,
+    });
+  } catch (e) {
+    res.status(500).json({ error: "chat_failed", msg: e.message.slice(0, 200) });
+  }
+});
+
 // (removed: duplicate /robots.txt handler — first match wins, real handler at line ~478 has the Sitemap line)
 
 // Login rate-limit: 5 attempts / 15 min / IP. Trips return 429.

← b15fb3e competitor matrix: 8 platforms crawled, 10 differentiation v  ·  back to Ventura Claw  ·  /services: cut workers-comp + IRS-payment-plan; ship bold /l 28a107c →