Input
{
"patchText": "*** Begin Patch\n*** Add File: /tmp/opencode/rickroll-sip/leadfinder-saas/index.html\n+<!doctype html>\n+<html lang=\"en\">\n+ <head>\n+ <meta charset=\"utf-8\" />\n+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n+ <title>SignalScout | AI Lead Finder</title>\n+ <link rel=\"stylesheet\" href=\"styles.css\" />\n+ </head>\n+ <body>\n+ <main class=\"shell\">\n+ <section class=\"hero\">\n+ <div>\n+ <p class=\"eyebrow\">SignalScout</p>\n+ <h1>Find the companies most likely to buy.</h1>\n+ <p class=\"subhead\">\n+ Paste a list of companies. SignalScout ranks them, explains why they fit,\n+ and writes a first email your sales team can use today.\n+ </p>\n+ </div>\n+ <div class=\"hero-card\">\n+ <span class=\"metric\">42%</span>\n+ <p>less time wasted on bad-fit accounts</p>\n+ </div>\n+ </section>\n+\n+ <section class=\"workspace\">\n+ <form id=\"lead-form\" class=\"panel input-panel\">\n+ <div class=\"panel-heading\">\n+ <p class=\"eyebrow\">Step 1</p>\n+ <h2>Describe your buyer</h2>\n+ </div>\n+\n+ <label>\n+ What you sell\n+ <input id=\"offer\" name=\"offer\" value=\"AI customer support automation\" />\n+ </label>\n+\n+ <label>\n+ Best industries\n+ <input id=\"industries\" name=\"industries\" value=\"SaaS, ecommerce, fintech\" />\n+ </label>\n+\n+ <label>\n+ Buying signals\n+ <input id=\"signals\" name=\"signals\" value=\"hiring support agents, fast growth, many tickets, Zendesk\" />\n+ </label>\n+\n+ <label>\n+ Company list\n+ <textarea id=\"companies\" name=\"companies\" rows=\"9\">Acme Cart | ecommerce brand hiring 12 support agents, uses Shopify and Zendesk, 180 employees\nNorthstar Ledger | fintech accounting platform, raised Series B, 95 employees, support team expanding\nBrightDesk | HR software for small teams, steady growth, 35 employees\nUrban Crate | marketplace with thousands of monthly customer questions, 240 employees\nPaperTrail Co | local print shop, 18 employees, low online volume</textarea>\n+ </label>\n+\n+ <button type=\"submit\">Rank leads</button>\n+ </form>\n+\n+ <section class=\"panel results-panel\">\n+ <div class=\"panel-heading split\">\n+ <div>\n+ <p class=\"eyebrow\">Step 2</p>\n+ <h2>Best accounts</h2>\n+ </div>\n+ <button id=\"copy-button\" class=\"ghost\" type=\"button\">Copy email</button>\n+ </div>\n+ <div id=\"results\" class=\"results\"></div>\n+ </section>\n+ </section>\n+ </main>\n+\n+ <script src=\"app.js\"></script>\n+ </body>\n+</html>\n*** Add File: /tmp/opencode/rickroll-sip/leadfinder-saas/styles.css\n+:root {\n+ color-scheme: dark;\n+ --bg: #0b1020;\n+ --panel: rgba(255, 255, 255, 0.08);\n+ --panel-strong: rgba(255, 255, 255, 0.14);\n+ --text: #f8fafc;\n+ --muted: #a8b3cf;\n+ --accent: #7dd3fc;\n+ --accent-2: #c084fc;\n+ --good: #86efac;\n+ --warn: #fde68a;\n+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n+}\n+\n+* {\n+ box-sizing: border-box;\n+}\n+\n+body {\n+ margin: 0;\n+ min-height: 100vh;\n+ background:\n+ radial-gradient(circle at top left, rgba(125, 211, 252, 0.28), transparent 30rem),\n+ radial-gradient(circle at 80% 10%, rgba(192, 132, 252, 0.28), transparent 26rem),\n+ var(--bg);\n+ color: var(--text);\n+}\n+\n+.shell {\n+ width: min(1180px, calc(100% - 32px));\n+ margin: 0 auto;\n+ padding: 48px 0;\n+}\n+\n+.hero {\n+ display: grid;\n+ grid-template-columns: 1fr 280px;\n+ gap: 24px;\n+ align-items: end;\n+ margin-bottom: 28px;\n+}\n+\n+.eyebrow {\n+ margin: 0 0 8px;\n+ color: var(--accent);\n+ font-size: 0.78rem;\n+ font-weight: 800;\n+ letter-spacing: 0.16em;\n+ text-transform: uppercase;\n+}\n+\n+h1,\n+h2,\n+p {\n+ margin-top: 0;\n+}\n+\n+h1 {\n+ max-width: 760px;\n+ margin-bottom: 16px;\n+ font-size: clamp(2.8rem, 8vw, 6.8rem);\n+ line-height: 0.88;\n+ letter-spacing: -0.08em;\n+}\n+\n+h2 {\n+ margin-bottom: 0;\n+ font-size: clamp(1.4rem, 3vw, 2rem);\n+ letter-spacing: -0.04em;\n+}\n+\n+.subhead {\n+ max-width: 650px;\n+ color: var(--muted);\n+ font-size: 1.1rem;\n+ line-height: 1.6;\n+}\n+\n+.hero-card,\n+.panel {\n+ border: 1px solid rgba(255, 255, 255, 0.14);\n+ border-radius: 28px;\n+ background: linear-gradient(145deg, var(--panel), rgba(255, 255, 255, 0.04));\n+ box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);\n+ backdrop-filter: blur(22px);\n+}\n+\n+.hero-card {\n+ padding: 24px;\n+}\n+\n+.metric {\n+ display: block;\n+ margin-bottom: 10px;\n+ font-size: 4rem;\n+ font-weight: 900;\n+ letter-spacing: -0.08em;\n+}\n+\n+.hero-card p {\n+ margin-bottom: 0;\n+ color: var(--muted);\n+}\n+\n+.workspace {\n+ display: grid;\n+ grid-template-columns: minmax(320px, 430px) 1fr;\n+ gap: 24px;\n+}\n+\n+.panel {\n+ padding: 24px;\n+}\n+\n+.panel-heading {\n+ margin-bottom: 22px;\n+}\n+\n+.split {\n+ display: flex;\n+ justify-content: space-between;\n+ gap: 16px;\n+ align-items: start;\n+}\n+\n+label {\n+ display: block;\n+ margin-bottom: 16px;\n+ color: var(--muted);\n+ font-size: 0.92rem;\n+ font-weight: 700;\n+}\n+\n+input,\n+textarea {\n+ display: block;\n+ width: 100%;\n+ margin-top: 8px;\n+ border: 1px solid rgba(255, 255, 255, 0.14);\n+ border-radius: 16px;\n+ background: rgba(2, 6, 23, 0.62);\n+ color: var(--text);\n+ font: inherit;\n+ padding: 14px 16px;\n+ outline: none;\n+}\n+\n+textarea {\n+ resize: vertical;\n+}\n+\n+input:focus,\n+textarea:focus {\n+ border-color: var(--accent);\n+ box-shadow: 0 0 0 4px rgba(125, 211, 252, 0.13);\n+}\n+\n+button {\n+ border: 0;\n+ border-radius: 999px;\n+ background: linear-gradient(135deg, var(--accent), var(--accent-2));\n+ color: #08111f;\n+ cursor: pointer;\n+ font: inherit;\n+ font-weight: 900;\n+ padding: 14px 20px;\n+}\n+\n+.ghost {\n+ border: 1px solid rgba(255, 255, 255, 0.16);\n+ background: rgba(255, 255, 255, 0.08);\n+ color: var(--text);\n+}\n+\n+.results {\n+ display: grid;\n+ gap: 14px;\n+}\n+\n+.lead-card {\n+ display: grid;\n+ grid-template-columns: 96px 1fr;\n+ gap: 16px;\n+ padding: 18px;\n+ border: 1px solid rgba(255, 255, 255, 0.12);\n+ border-radius: 22px;\n+ background: rgba(2, 6, 23, 0.36);\n+}\n+\n+.score {\n+ display: grid;\n+ place-items: center;\n+ width: 80px;\n+ height: 80px;\n+ border-radius: 50%;\n+ background: conic-gradient(var(--good) var(--score), rgba(255, 255, 255, 0.12) 0);\n+ color: #08111f;\n+ font-size: 1.35rem;\n+ font-weight: 950;\n+}\n+\n+.score span {\n+ display: grid;\n+ place-items: center;\n+ width: 62px;\n+ height: 62px;\n+ border-radius: 50%;\n+ background: var(--text);\n+}\n+\n+.lead-card h3 {\n+ margin: 0 0 8px;\n+ font-size: 1.2rem;\n+}\n+\n+.reason {\n+ color: var(--muted);\n+ line-height: 1.5;\n+}\n+\n+.tags {\n+ display: flex;\n+ flex-wrap: wrap;\n+ gap: 8px;\n+ margin-top: 12px;\n+}\n+\n+.tag {\n+ border-radius: 999px;\n+ background: var(--panel-strong);\n+ color: var(--warn);\n+ font-size: 0.78rem;\n+ font-weight: 800;\n+ padding: 6px 10px;\n+}\n+\n+.email {\n+ margin-top: 14px;\n+ border-left: 3px solid var(--accent);\n+ color: #dbeafe;\n+ line-height: 1.55;\n+ padding-left: 12px;\n+}\n+\n+@media (max-width: 850px) {\n+ .hero,\n+ .workspace {\n+ grid-template-columns: 1fr;\n+ }\n+\n+ .shell {\n+ padding-top: 28px;\n+ }\n+\n+ .lead-card {\n+ grid-template-columns: 1fr;\n+ }\n+}\n*** Add File: /tmp/opencode/rickroll-sip/leadfinder-saas/app.js\n+const form = document.querySelector(\"#lead-form\");\n+const results = document.querySelector(\"#results\");\n+const copyButton = document.querySelector(\"#copy-button\");\n+\n+let topEmail = \"\";\n+\n+function wordsFrom(value) {\n+ return value\n+ .toLowerCase()\n+ .split(/[^a-z0-9]+/)\n+ .filter((word) => word.length > 2);\n+}\n+\n+function parseCompanies(value) {\n+ return value\n+ .split(\"\\n\")\n+ .map((line) => line.trim())\n+ .filter(Boolean)\n+ .map((line) => {\n+ const [name, ...details] = line.split(\"|\").map((part) => part.trim());\n+ return { name, details: details.join(\" \") || line };\n+ });\n+}\n+\n+function scoreCompany(company, industries, signals) {\n+ const text = `${company.name} ${company.details}`.toLowerCase();\n+ const industryHits = industries.filter((word) => text.includes(word));\n+ const signalHits = signals.filter((word) => text.includes(word));\n+ const employeeMatch = text.match(/(\\d+)\\s*employees?/);\n+ const employees = employeeMatch ? Number(employeeMatch[1]) : 0;\n+ const sizeScore = employees >= 50 && employees <= 500 ? 18 : employees > 500 ? 10 : employees >= 20 ? 8 : 0;\n+ const growthScore = /(hiring|raised|growth|expanding|thousands|many|series)/.test(text) ? 18 : 0;\n+ const score = Math.min(98, 22 + industryHits.length * 14 + signalHits.length * 10 + sizeScore + growthScore);\n+\n+ return {\n+ ...company,\n+ score,\n+ tags: [...new Set([...industryHits, ...signalHits])].slice(0, 6),\n+ reason: buildReason(company, score, industryHits, signalHits, employees, growthScore),\n+ };\n+}\n+\n+function buildReason(company, score, industryHits, signalHits, employees, growthScore) {\n+ const reasons = [];\n+\n+ if (industryHits.length) reasons.push(`matches your target market: ${industryHits.join(\", \")}`);\n+ if (signalHits.length) reasons.push(`shows buying signals: ${signalHits.join(\", \")}`);\n+ if (employees) reasons.push(`has enough team size to feel the pain (${employees} employees)`);\n+ if (growthScore) reasons.push(\"looks like it is growing or adding workload\");\n+ if (!reasons.length) reasons.push(\"has limited fit based on the details provided\");\n+\n+ return `${company.name} scored ${score}/100 because it ${reasons.join(\" and \")}.`;\n+}\n+\n+function makeEmail(company, offer) {\n+ return `Subject: quick idea for ${company.name}\\n\\nHi there,\\n\\nNoticed ${company.name} looks like a strong fit for ${offer}. If your team is dealing with more customer conversations, we can help cut the manual work and keep replies fast.\\n\\nWorth a 15-minute chat this week?`;\n+}\n+\n+function render() {\n+ const data = new FormData(form);\n+ const offer = data.get(\"offer\").trim();\n+ const industries = wordsFrom(data.get(\"industries\"));\n+ const signals = wordsFrom(data.get(\"signals\"));\n+ const ranked = parseCompanies(data.get(\"companies\"))\n+ .map((company) => scoreCompany(company, industries, signals))\n+ .sort((a, b) => b.score - a.score);\n+\n+ topEmail = ranked[0] ? makeEmail(ranked[0], offer) : \"\";\n+\n+ results.innerHTML = ranked\n+ .map((company, index) => {\n+ const email = index === 0 ? makeEmail(company, offer) : \"\";\n+ return `\n+ <article class=\"lead-card\">\n+ <div class=\"score\" style=\"--score: ${company.score}%\"><span>${company.score}</span></div>\n+ <div>\n+ <h3>${company.name}</h3>\n+ <p class=\"reason\">${company.reason}</p>\n+ <div class=\"tags\">${company.tags.map((tag) => `<span class=\"tag\">${tag}</span>`).join(\"\") || '<span class=\"tag\">needs more data</span>'}</div>\n+ ${email ? `<p class=\"email\">${email.replaceAll(\"\\n\", \"<br />\")}</p>` : \"\"}\n+ </div>\n+ </article>\n+ `;\n+ })\n+ .join(\"\");\n+}\n+\n+form.addEventListener(\"submit\", (event) => {\n+ event.preventDefault();\n+ render();\n+});\n+\n+copyButton.addEventListener(\"click\", async () => {\n+ if (!topEmail) return;\n+ await navigator.clipboard.writeText(topEmail);\n+ copyButton.textContent = \"Copied\";\n+ setTimeout(() => {\n+ copyButton.textContent = \"Copy email\";\n+ }, 1400);\n+});\n+\n+render();\n*** Add File: /tmp/opencode/rickroll-sip/leadfinder-saas/README.md\n+# SignalScout\n+\n+AI-style sales lead finder for B2B teams.\n+\n+## What It Does\n+\n+Paste companies, describe your best customer, and get:\n+\n+- Lead fit scores\n+- Reasons each company is or is not a good fit\n+- Buying signal tags\n+- A first outreach email for the top account\n+\n+## Run It\n+\n+Open `index.html` in a browser.\n+\n+No install. No account. No setup.\n+\n+## Next Useful Upgrade\n+\n+Connect a real company data source and an AI writing service so new leads can be found automatically instead of pasted manually.\n*** End Patch"
}