{"success":true,"output":"\n\n\n\n\nTHE GRIND \u2014 War Room<\/title>\n<style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n :root {\n --bg: #0a0a0f; --surface: #12121a; --border: #1e1e2e;\n --accent: #ff3c3c; --green: #00ff87; --yellow: #ffd700;\n --blue: #4da6ff; --muted: #555; --text: #e0e0e0; --text2: #888;\n }\n body { background: var(--bg); color: var(--text); font-family: 'Courier New', monospace; font-size: 13px; overflow-x: hidden; }\n\n #header {\n background: var(--surface); border-bottom: 1px solid var(--accent);\n padding: 10px 16px; display: flex; align-items: center; justify-content: space-between;\n position: sticky; top: 0; z-index: 100;\n }\n #header h1 { font-size: 16px; letter-spacing: 4px; color: var(--accent); }\n .status { color: var(--green); font-size: 11px; }\n .clock { color: var(--text2); font-size: 12px; }\n .refresh-indicator { width: 6px; height: 6px; background: var(--green); border-radius: 50%; display: inline-block; animation: pulse 2s infinite; }\n @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }\n\n .controls {\n padding: 8px 16px; background: var(--surface); border-bottom: 1px solid var(--border);\n display: flex; gap: 8px; align-items: center; flex-wrap: wrap;\n }\n .btn {\n background: transparent; border: 1px solid var(--accent); color: var(--accent);\n padding: 5px 12px; cursor: pointer; font-family: inherit; font-size: 11px;\n letter-spacing: 1px; transition: all 0.2s; text-transform: uppercase; white-space: nowrap;\n }\n .btn:hover { background: var(--accent); color: var(--bg); }\n .btn.green { border-color: var(--green); color: var(--green); }\n .btn.green:hover { background: var(--green); color: var(--bg); }\n .btn.blue { border-color: var(--blue); color: var(--blue); }\n .btn.blue:hover { background: var(--blue); color: var(--bg); }\n .btn:disabled { opacity: 0.4; cursor: not-allowed; }\n\n input, select {\n background: var(--bg); border: 1px solid var(--border); color: var(--text);\n padding: 5px 10px; font-family: inherit; font-size: 11px;\n }\n input:focus { border-color: var(--accent); outline: none; }\n\n .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1px; background: var(--border); }\n .panel {\n background: var(--surface); padding: 12px;\n border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);\n }\n .panel h3 {\n font-size: 10px; letter-spacing: 3px; color: var(--accent);\n text-transform: uppercase; margin-bottom: 10px; padding-bottom: 6px;\n border-bottom: 1px solid var(--border);\n }\n\n \/* \u2500\u2500 Business Carousel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n .biz-search {\n padding: 10px 16px; background: var(--surface); border-bottom: 1px solid var(--border);\n display: flex; gap: 8px; align-items: center; flex-wrap: wrap;\n }\n #bizQuery { width: 280px; }\n #bizLoc { width: 160px; }\n\n .carousel-wrap {\n background: var(--bg); padding: 10px 16px; overflow: hidden;\n border-bottom: 1px solid var(--border); min-height: 80px;\n }\n .carousel {\n display: flex; gap: 12px; overflow-x: auto; scroll-behavior: smooth;\n padding-bottom: 8px; -webkit-overflow-scrolling: touch;\n }\n .carousel::-webkit-scrollbar { height: 4px; }\n .carousel::-webkit-scrollbar-track { background: var(--bg); }\n .carousel::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }\n\n .biz-card {\n min-width: 220px; max-width: 220px; background: var(--surface);\n border: 1px solid var(--border); border-radius: 6px; cursor: pointer;\n transition: all 0.2s; flex-shrink: 0; overflow: hidden;\n }\n .biz-card:hover { border-color: var(--accent); transform: translateY(-2px); }\n .biz-card.selected { border-color: var(--accent); box-shadow: 0 0 12px rgba(255,60,60,0.2); }\n\n .biz-photo {\n width: 100%; height: 130px; object-fit: cover; background: var(--border);\n display: block;\n }\n .biz-photo-placeholder {\n width: 100%; height: 130px; background: var(--border);\n display: flex; align-items: center; justify-content: center;\n color: var(--muted); font-size: 24px;\n }\n .biz-info { padding: 8px 10px; }\n .biz-name { color: var(--yellow); font-weight: bold; font-size: 11px; margin-bottom: 3px;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n .biz-addr { color: var(--text2); font-size: 9px; line-height: 1.3;\n display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n .biz-meta { display: flex; gap: 6px; margin-top: 4px; font-size: 9px; }\n .biz-rating { color: var(--yellow); }\n .biz-type { color: var(--blue); text-transform: uppercase; }\n\n .biz-empty { color: var(--muted); font-size: 11px; padding: 20px; text-align: center; }\n\n \/* \u2500\u2500 Selected Business Detail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n .biz-detail {\n background: var(--surface); border-bottom: 1px solid var(--border);\n padding: 12px 16px; display: none;\n }\n .biz-detail.visible { display: block; }\n .biz-detail-grid { display: grid; grid-template-columns: 280px 1fr; gap: 16px; }\n .biz-detail-photos { display: flex; gap: 6px; overflow-x: auto; }\n .biz-detail-photos img { height: 160px; border-radius: 4px; object-fit: cover; }\n .biz-detail-info .row { display: flex; justify-content: space-between; padding: 3px 0;\n border-bottom: 1px solid var(--border); font-size: 11px; }\n .biz-detail-info .label { color: var(--text2); }\n .biz-detail-info .val { color: var(--text); font-weight: bold; }\n .biz-detail-info .val a { color: var(--blue); text-decoration: none; }\n .biz-actions { margin-top: 8px; display: flex; gap: 8px; }\n\n \/* \u2500\u2500 Agents \/ Signals \/ Oracle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n .stat-row { display: flex; justify-content: space-between; padding: 4px 0; border-bottom: 1px solid var(--border); }\n .stat-label { color: var(--text2); }\n .stat-val { font-weight: bold; }\n .stat-val.hot { color: var(--accent); }\n .stat-val.good { color: var(--green); }\n .stat-val.warn { color: var(--yellow); }\n\n .signal-feed { max-height: 200px; overflow-y: auto; }\n .signal-item { padding: 5px 8px; border-left: 2px solid var(--muted); margin-bottom: 3px; font-size: 11px; }\n .signal-item.priority-1, .signal-item.priority-2 { border-color: var(--accent); }\n .signal-item.priority-3 { border-color: var(--yellow); }\n .sig-type { color: var(--blue); font-weight: bold; }\n .sig-time { color: var(--text2); float: right; }\n\n .agent-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid var(--border); }\n .agent-name { color: var(--text); }\n .agent-tier { color: var(--text2); font-size: 10px; }\n .agent-status { font-size: 10px; padding: 2px 6px; border-radius: 10px; }\n .agent-status.active { background: rgba(0,255,135,0.15); color: var(--green); }\n .agent-status.error { background: rgba(255,60,60,0.15); color: var(--accent); }\n\n .oracle-msgs { max-height: 200px; overflow-y: auto; }\n .oracle-msg { padding: 8px; border-left: 3px solid var(--accent); margin-bottom: 6px; background: rgba(255,60,60,0.03); }\n .oracle-msg .headline { color: var(--yellow); font-weight: bold; margin-bottom: 3px; font-size: 12px; }\n .oracle-msg .body-text { color: var(--text2); font-size: 11px; }\n\n .pending-badge { background: var(--accent); color: var(--bg); border-radius: 10px; padding: 1px 6px; font-size: 10px; }\n .full-width { grid-column: 1 \/ -1; }\n .two-col { grid-column: span 2; }\n #loading { color: var(--text2); font-size: 11px; }\n\n ::-webkit-scrollbar { width: 4px; }\n ::-webkit-scrollbar-track { background: var(--bg); }\n ::-webkit-scrollbar-thumb { background: var(--border); }\n\n @media (max-width: 768px) {\n .grid { grid-template-columns: 1fr; }\n .two-col { grid-column: 1; }\n .biz-detail-grid { grid-template-columns: 1fr; }\n #bizQuery { width: 160px; }\n .biz-card { min-width: 180px; max-width: 180px; }\n }\n<\/style>\n<\/head>\n<body>\n\n<div id=\"header\">\n <h1>THE GRIND \/\/ WAR ROOM<\/h1>\n <div style=\"display:flex;gap:16px;align-items:center\">\n <span class=\"status\"><span class=\"refresh-indicator\"><\/span> LIVE<\/span>\n <span class=\"clock\" id=\"clock\">--:--:--<\/span>\n <span id=\"loading\"><\/span>\n <\/div>\n<\/div>\n\n<!-- Business Search -->\n<div class=\"biz-search\">\n <input id=\"bizQuery\" placeholder=\"Search businesses... (e.g. sober living Houston)\" onkeydown=\"if(event.key==='Enter')searchBiz()\">\n <input id=\"bizLoc\" placeholder=\"lat,lng (auto-detect)\" readonly style=\"color:var(--text2)\">\n <button class=\"btn blue\" onclick=\"searchBiz()\">SEARCH<\/button>\n <button class=\"btn\" onclick=\"detectLocation()\">GPS<\/button>\n <span id=\"biz-count\" style=\"color:var(--text2);font-size:10px\"><\/span>\n<\/div>\n\n<!-- Business Carousel -->\n<div class=\"carousel-wrap\">\n <div class=\"carousel\" id=\"carousel\">\n <div class=\"biz-empty\">Search for businesses above to browse them here. GPS + proximity scoring active.<\/div>\n <\/div>\n<\/div>\n\n<!-- Selected Business Detail -->\n<div class=\"biz-detail\" id=\"biz-detail\"><\/div>\n\n<!-- Main Controls -->\n<div class=\"controls\">\n <button class=\"btn green\" onclick=\"runCycle()\">RUN CYCLE<\/button>\n <select id=\"citySelect\" onchange=\"loadCityData()\">\n <option value=\"\">-- City --<\/option>\n <\/select>\n <button class=\"btn\" onclick=\"askOracle()\">ASK ORACLE<\/button>\n <span id=\"pending-count\" style=\"color:var(--text2);font-size:11px\"><\/span>\n<\/div>\n\n<div class=\"grid\">\n <!-- Agent Status -->\n <div class=\"panel\">\n <h3>Agent Status<\/h3>\n <div id=\"agent-list\">Loading...<\/div>\n <\/div>\n\n <!-- Signal Feed -->\n <div class=\"panel\">\n <h3>Signal Feed <span id=\"sig-pending\" class=\"pending-badge\">0<\/span><\/h3>\n <div class=\"signal-feed\" id=\"signal-feed\">Loading...<\/div>\n <\/div>\n\n <!-- Oracle Messages -->\n <div class=\"panel\">\n <h3>Oracle Intelligence<\/h3>\n <div class=\"oracle-msgs\" id=\"oracle-feed\">Waiting for Oracle...<\/div>\n <\/div>\n<\/div>\n\n<div class=\"grid\">\n <!-- Pipeline Stats -->\n <div class=\"panel two-col\" id=\"city-panel\">\n <h3>Pipeline Intelligence<\/h3>\n <div id=\"city-stats\">Select a city or search for businesses above<\/div>\n <\/div>\n <!-- Lead Counts -->\n <div class=\"panel\">\n <h3>Lead Pipeline<\/h3>\n <div id=\"lead-stats\">--<\/div>\n <\/div>\n<\/div>\n\n<script>\nconst API = '\/api\/api.php';\nconst PLACES = '\/api\/places.php';\nlet refreshTimer = null;\nlet selectedCity = null;\nlet selectedBiz = null;\nlet userLat = null, userLng = null;\n\n\/\/ \u2500\u2500 Clock \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nsetInterval(() => {\n document.getElementById('clock').textContent = new Date().toTimeString().slice(0,8);\n}, 1000);\n\n\/\/ \u2500\u2500 GPS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction detectLocation() {\n if (!navigator.geolocation) return;\n navigator.geolocation.getCurrentPosition(pos => {\n userLat = pos.coords.latitude.toFixed(6);\n userLng = pos.coords.longitude.toFixed(6);\n document.getElementById('bizLoc').value = `${userLat},${userLng}`;\n document.getElementById('bizLoc').style.color = 'var(--green)';\n }, () => {\n document.getElementById('bizLoc').value = 'GPS denied';\n document.getElementById('bizLoc').style.color = 'var(--accent)';\n });\n}\n\/\/ Auto-detect on load\ndetectLocation();\n\n\/\/ \u2500\u2500 API helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function api(action, data = {}) {\n document.getElementById('loading').textContent = '\\u27f3';\n try {\n const isGet = ['oracle_messages','city_status','hub_stats'].includes(action);\n const params = new URLSearchParams({action, ...data});\n const opts = isGet\n ? { method: 'GET' }\n : { method: 'POST', headers: {'Content-Type':'application\/json'}, body: JSON.stringify({action,...data}) };\n const url = isGet ? `${API}?${params}` : API;\n const r = await fetch(url, opts);\n const j = await r.json();\n return j.success ? j.data : (console.error(j.error), null);\n } finally {\n document.getElementById('loading').textContent = '';\n }\n}\n\n\/\/ \u2500\u2500 Business Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function searchBiz() {\n const q = document.getElementById('bizQuery').value.trim();\n if (!q) return;\n\n document.getElementById('carousel').innerHTML = '<div class=\"biz-empty\">Searching...<\/div>';\n const params = new URLSearchParams({ action: 'search', q });\n if (userLat && userLng) {\n params.append('lat', userLat);\n params.append('lng', userLng);\n }\n\n try {\n const r = await fetch(`${PLACES}?${params}`);\n const data = await r.json();\n const results = data.results || [];\n\n document.getElementById('biz-count').textContent = `${results.length} found`;\n\n if (!results.length) {\n document.getElementById('carousel').innerHTML = '<div class=\"biz-empty\">No businesses found. Try a different search.<\/div>';\n return;\n }\n\n \/\/ Calculate distance if GPS available\n results.forEach(biz => {\n if (userLat && userLng && biz.geometry?.location) {\n biz._dist = haversine(userLat, userLng, biz.geometry.location.lat, biz.geometry.location.lng);\n }\n });\n\n \/\/ Sort by distance if available\n if (userLat) results.sort((a, b) => (a._dist || 999) - (b._dist || 999));\n\n document.getElementById('carousel').innerHTML = results.map((biz, i) => `\n <div class=\"biz-card\" onclick=\"selectBiz(${i})\" data-idx=\"${i}\" id=\"biz-${i}\">\n ${biz.photo_url\n ? `<img class=\"biz-photo\" src=\"${biz.photo_url}\" alt=\"${esc(biz.name)}\" loading=\"lazy\" onerror=\"this.outerHTML='<div class=biz-photo-placeholder>?<\/div>'\">`\n : '<div class=\"biz-photo-placeholder\">?<\/div>'}\n <div class=\"biz-info\">\n <div class=\"biz-name\">${esc(biz.name)}<\/div>\n <div class=\"biz-addr\">${esc(biz.formatted_address || '')}<\/div>\n <div class=\"biz-meta\">\n ${biz.rating ? `<span class=\"biz-rating\">${biz.rating} ★<\/span>` : ''}\n ${biz.types?.[0] ? `<span class=\"biz-type\">${biz.types[0].replace(\/_\/g,' ')}<\/span>` : ''}\n ${biz._dist !== undefined ? `<span style=\"color:var(--green)\">${biz._dist.toFixed(1)}mi<\/span>` : ''}\n <\/div>\n <\/div>\n <\/div>\n `).join('');\n\n \/\/ Store results globally for detail lookup\n window._bizResults = results;\n } catch (e) {\n document.getElementById('carousel').innerHTML = `<div class=\"biz-empty\" style=\"color:var(--accent)\">Error: ${e.message}<\/div>`;\n }\n}\n\n\/\/ \u2500\u2500 Select Business (load details + photos) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function selectBiz(idx) {\n const biz = window._bizResults?.[idx];\n if (!biz) return;\n selectedBiz = biz;\n\n \/\/ Highlight selected card\n document.querySelectorAll('.biz-card').forEach(c => c.classList.remove('selected'));\n document.getElementById(`biz-${idx}`)?.classList.add('selected');\n\n const detail = document.getElementById('biz-detail');\n detail.classList.add('visible');\n detail.innerHTML = '<div style=\"color:var(--text2);font-size:11px\">Loading details...<\/div>';\n\n try {\n const r = await fetch(`${PLACES}?action=details&place_id=${encodeURIComponent(biz.place_id)}`);\n const data = await r.json();\n const d = data.result;\n if (!d) { detail.innerHTML = '<div style=\"color:var(--accent)\">Details unavailable<\/div>'; return; }\n\n \/\/ Merge detail data into selectedBiz so enrichBiz\/queueOutreach can use it\n selectedBiz.website = d.website || '';\n selectedBiz.phone = d.formatted_phone_number || '';\n selectedBiz.detailAddress = d.formatted_address || '';\n selectedBiz.detailRating = d.rating || 0;\n selectedBiz.detailTypes = d.types || [];\n selectedBiz.businessStatus = d.business_status || '';\n\n const photos = (d.photos || []).slice(0, 6);\n\n detail.innerHTML = `\n <div class=\"biz-detail-grid\">\n <div class=\"biz-detail-photos\">\n ${photos.length ? photos.map(p =>\n `<img src=\"${p.url}\" alt=\"photo\" loading=\"lazy\" onerror=\"this.style.display='none'\">`\n ).join('') : '<div style=\"color:var(--muted);padding:40px\">No photos available<\/div>'}\n <\/div>\n <div class=\"biz-detail-info\">\n <div style=\"color:var(--yellow);font-size:14px;font-weight:bold;margin-bottom:8px\">${esc(d.name)}<\/div>\n <div class=\"row\"><span class=\"label\">Address<\/span><span class=\"val\">${esc(d.formatted_address || 'N\/A')}<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Phone<\/span><span class=\"val\">${d.formatted_phone_number || 'N\/A'}<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Website<\/span><span class=\"val\">${d.website ? `<a href=\"${d.website}\" target=\"_blank\">${d.website.replace(\/^https?:\\\/\\\/\/, '').slice(0,40)}<\/a>` : 'None'}<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Rating<\/span><span class=\"val ${d.rating >= 4 ? 'good' : 'warn'}\">${d.rating || 'N\/A'} (${d.user_ratings_total || 0} reviews)<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Status<\/span><span class=\"val ${d.business_status === 'OPERATIONAL' ? 'good' : 'hot'}\">${d.business_status || 'Unknown'}<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Type<\/span><span class=\"val\">${(d.types || []).slice(0,3).join(', ').replace(\/_\/g,' ')}<\/span><\/div>\n <div class=\"row\"><span class=\"label\">Distance<\/span><span class=\"val good\">${biz._dist !== undefined ? biz._dist.toFixed(1) + ' mi' : 'GPS off'}<\/span><\/div>\n <div class=\"biz-actions\">\n <button class=\"btn green\" onclick=\"enrichBiz('${esc(d.website || '')}')\" >ENRICH (Hunter.io)<\/button>\n <button class=\"btn blue\" onclick=\"queueOutreach()\">QUEUE OUTREACH<\/button>\n <button class=\"btn\" onclick=\"buildSite()\">BUILD SITE<\/button>\n <\/div>\n <\/div>\n <\/div>\n `;\n } catch (e) {\n detail.innerHTML = `<div style=\"color:var(--accent)\">Error loading details: ${e.message}<\/div>`;\n }\n}\n\n\/\/ \u2500\u2500 Oracle API helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst ORACLE = '\/api\/oracle.php';\nasync function oracleCall(action, data = {}) {\n document.getElementById('loading').textContent = '\\u27f3';\n try {\n const r = await fetch(ORACLE, {\n method: 'POST',\n headers: {'Content-Type': 'application\/json'},\n body: JSON.stringify({action, ...data})\n });\n const j = await r.json();\n return j.success ? j.data : (console.error(j.error), null);\n } finally {\n document.getElementById('loading').textContent = '';\n }\n}\n\n\/\/ \u2500\u2500 Enrich Business via Hunter.io + Shodan \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function enrichBiz(passedWebsite) {\n if (!selectedBiz) return;\n const detail = document.getElementById('biz-detail');\n \/\/ Extract domain from website or try name\n let domain = '';\n const website = passedWebsite || selectedBiz.website || '';\n if (website) {\n try { domain = new URL(website.startsWith('http') ? website : 'https:\/\/' + website).hostname; }\n catch(e) { domain = website; }\n }\n if (!domain) {\n detail.innerHTML += `<div style=\"color:var(--accent);padding:8px;border-top:1px solid var(--border);margin-top:8px\">No website\/domain found for this business. Hunter.io needs a domain to search.<\/div>`;\n return;\n }\n\n detail.innerHTML += `<div id=\"enrich-status\" style=\"color:var(--blue);padding:8px;border-top:1px solid var(--border);margin-top:8px\">Enriching ${domain} via Hunter.io + Shodan...<\/div>`;\n\n const data = await oracleCall('enrich_domain', { domain });\n if (!data) { document.getElementById('enrich-status').innerHTML = '<span style=\"color:var(--accent)\">Enrichment failed<\/span>'; return; }\n\n const emails = data.hunter?.emails || [];\n const ports = data.shodan?.matches?.length || 0;\n\n document.getElementById('enrich-status').innerHTML = `\n <div style=\"color:var(--green);font-weight:bold;margin-bottom:6px\">ENRICHMENT: ${data.summary}<\/div>\n ${emails.length ? `<div style=\"font-size:11px;color:var(--text2);margin-bottom:4px\">TOP CONTACTS:<\/div>` : ''}\n ${emails.slice(0,5).map(e => `\n <div style=\"font-size:11px;padding:3px 0;border-bottom:1px solid var(--border)\">\n <span style=\"color:var(--yellow)\">${e.email}<\/span>\n <span style=\"color:var(--text2)\">${e.first_name} ${e.last_name} | ${e.position || e.department || 'unknown role'} | ${e.confidence}% conf<\/span>\n <\/div>\n `).join('')}\n ${ports > 0 ? `<div style=\"color:var(--accent);font-size:11px;margin-top:6px\">Shodan: ${ports} exposed services found (security upsell opportunity)<\/div>` : ''}\n `;\n}\n\n\/\/ \u2500\u2500 Queue SAM Outreach \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction queueOutreach() {\n if (!selectedBiz) return;\n \/\/ For now, show what would happen. Full SAM integration is next phase.\n const name = selectedBiz.name;\n alert(`SAM outreach sequence will be queued for: ${name}\\n\\nPipeline:\\n1. Hunter.io email lookup\\n2. 4-email AI personalized sequence\\n3. A\/B test subject lines\\n4. Reply analysis + scoring\\n\\nFull SAM integration deploying next.`);\n}\n\n\/\/ \u2500\u2500 Build Site via Atlas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction buildSite() {\n if (!selectedBiz) return;\n const slug = selectedBiz.name.toLowerCase().replace(\/[^a-z0-9]\/g,'').slice(0,30);\n alert(`Atlas site generation will deploy:\\n${slug}.surpreme.com\\n\\nPipeline:\\n1. Scrape business details\\n2. Generate full responsive site\\n3. Deploy to subdomain\\n4. Screenshot for outreach email\\n5. Stripe payment link\\n\\nFull Atlas integration deploying next.`);\n}\n\n\/\/ \u2500\u2500 Ask Oracle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function askOracle() {\n const question = prompt('Ask the Oracle anything about your pipeline, leads, or next move:');\n if (!question) return;\n\n const feed = document.getElementById('oracle-feed');\n feed.innerHTML = '<div style=\"color:var(--blue)\">Oracle thinking...<\/div>';\n\n const data = await oracleCall('ask', {\n question,\n lat: userLat || null,\n lng: userLng || null\n });\n\n if (!data) { feed.innerHTML = '<div style=\"color:var(--accent)\">Oracle offline<\/div>'; return; }\n\n feed.innerHTML = `\n <div class=\"oracle-msg\">\n <div class=\"headline\">ORACLE INTELLIGENCE<\/div>\n <div class=\"body-text\">${esc(data.response)}<\/div>\n <div style=\"color:var(--text2);font-size:9px;margin-top:6px\">${data.timestamp} | ${data.pipeline?.total_leads || 0} total leads<\/div>\n <\/div>\n ` + feed.innerHTML;\n}\n\n\/\/ \u2500\u2500 Load Pipeline Stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function loadPipelineStats() {\n const data = await oracleCall('pipeline_stats');\n if (!data) return;\n\n const el = document.getElementById('lead-stats');\n el.innerHTML = `\n <div class=\"stat-row\"><span class=\"stat-label\">TOTAL LEADS<\/span><span class=\"stat-val good\">${data.total_leads.toLocaleString()}<\/span><\/div>\n ${data.sources.map(s => `\n <div class=\"stat-row\">\n <span class=\"stat-label\">${s.source}<\/span>\n <span class=\"stat-val ${s.count < 0 ? 'hot' : ''}\">${s.count < 0 ? 'ERR' : s.count.toLocaleString()}<\/span>\n <\/div>\n `).join('')}\n `;\n}\n\n\/\/ \u2500\u2500 Hub Stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function loadHubStats() {\n const data = await api('hub_stats');\n if (!data) return;\n\n const agents = data.agents || [];\n document.getElementById('agent-list').innerHTML = agents.map(a => `\n <div class=\"agent-row\">\n <div>\n <div class=\"agent-name\">${a.name}<\/div>\n <div class=\"agent-tier\">${(a.tier||'').toUpperCase()} | ${a.signals_processed ?? 0} processed<\/div>\n <\/div>\n <span class=\"agent-status ${a.status}\">${a.status}<\/span>\n <\/div>\n `).join('') || '<div style=\"color:var(--text2)\">No agents. Run SEED first.<\/div>';\n\n const sigs = data.signal_stats || [];\n const pending = data.pending_signals || 0;\n document.getElementById('sig-pending').textContent = pending;\n document.getElementById('pending-count').textContent = `${pending} signals pending`;\n\n document.getElementById('signal-feed').innerHTML = sigs.map(s => `\n <div class=\"signal-item\">\n <span class=\"sig-type\">${s.signal_type}<\/span>\n <span class=\"sig-time\">${s.count}x<\/span>\n <div style=\"color:var(--text2);font-size:10px\">status: ${s.status} | retries: ${parseFloat(s.avg_retries||0).toFixed(1)}<\/div>\n <\/div>\n `).join('') || '<div style=\"color:var(--muted)\">No signals in last 24h<\/div>';\n}\n\n\/\/ \u2500\u2500 City Data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function loadCityData() {\n selectedCity = document.getElementById('citySelect').value;\n if (!selectedCity) return;\n const data = await api('city_status', { city_id: selectedCity });\n if (!data) return;\n const c = data.city;\n document.getElementById('city-stats').innerHTML = `\n <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n <div>\n <div class=\"stat-row\"><span class=\"stat-label\">City<\/span><span class=\"stat-val\">${c.name}, ${c.state}<\/span><\/div>\n <div class=\"stat-row\"><span class=\"stat-label\">Tier<\/span><span class=\"stat-val\">${(c.tier||'').toUpperCase()}<\/span><\/div>\n <div class=\"stat-row\"><span class=\"stat-label\">Heat<\/span><span class=\"stat-val ${parseFloat(c.heat_level)>=60?'hot':'good'}\">${parseFloat(c.heat_level).toFixed(1)}%<\/span><\/div>\n <div class=\"stat-row\"><span class=\"stat-label\">Economy<\/span><span class=\"stat-val good\">$${parseInt(c.economy).toLocaleString()}<\/span><\/div>\n <\/div>\n <div>\n ${(data.operatives||[]).slice(0,6).map(o => `\n <div style=\"display:flex;justify-content:space-between;padding:3px 0;font-size:11px;border-bottom:1px solid var(--border)\">\n <span style=\"color:var(--yellow)\">${o.handle}<\/span>\n <span style=\"color:var(--green)\">$${parseInt(o.cash).toLocaleString()}<\/span>\n <\/div>\n `).join('')}\n <\/div>\n <\/div>\n `;\n}\n\n\/\/ \u2500\u2500 Actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function runCycle() {\n const btn = event.target;\n btn.textContent = 'RUNNING...'; btn.disabled = true;\n const data = await api('run_agents');\n btn.textContent = 'RUN CYCLE'; btn.disabled = false;\n if (data) await refresh();\n}\n\nasync function loadCities() {\n const sel = document.getElementById('citySelect');\n const known = [{id:1,name:'Houston'},{id:2,name:'Dallas'},{id:3,name:'Miami'}];\n known.forEach(c => {\n const opt = document.createElement('option');\n opt.value = c.id; opt.textContent = c.name;\n sel.appendChild(opt);\n });\n}\n\n\/\/ \u2500\u2500 Haversine distance (miles) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction haversine(lat1, lon1, lat2, lon2) {\n const R = 3959;\n const dLat = (lat2 - lat1) * Math.PI \/ 180;\n const dLon = (lon2 - lon1) * Math.PI \/ 180;\n const a = Math.sin(dLat\/2)**2 + Math.cos(lat1*Math.PI\/180) * Math.cos(lat2*Math.PI\/180) * Math.sin(dLon\/2)**2;\n return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\n}\n\nfunction esc(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }\n\n\/\/ \u2500\u2500 Refresh \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function refresh() {\n await loadHubStats();\n if (selectedCity) await loadCityData();\n}\n\n\/\/ \u2500\u2500 Auto-load Oracle Intelligence on page load \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nasync function loadOracleIntel() {\n const feed = document.getElementById('oracle-feed');\n feed.innerHTML = '<div style=\"color:var(--text2);font-size:11px\">Oracle thinking...<\/div>';\n try {\n const r = await fetch('\/api\/oracle.php', {\n method: 'POST',\n headers: {'Content-Type': 'application\/json'},\n body: JSON.stringify({\n action: 'ask',\n question: 'Give me a 3-sentence status briefing. What are my top opportunities and what should I do next?'\n })\n });\n const data = await r.json();\n if (data.success && data.data) {\n const d = data.data;\n feed.innerHTML = `\n <div class=\"oracle-msg\">\n <div class=\"headline\">ORACLE INTELLIGENCE<\/div>\n <div class=\"body-text\" style=\"line-height:1.4\">${esc(d.response)}<\/div>\n ${d.pipeline ? `<div style=\"font-size:10px;color:var(--text2);margin-top:6px\">Pipeline: ${d.pipeline.total_leads} leads across ${d.pipeline.sources.length} sources<\/div>` : ''}\n <\/div>\n `;\n } else {\n feed.innerHTML = '<div style=\"color:var(--text2);font-size:11px\">Oracle offline<\/div>';\n }\n } catch(e) {\n feed.innerHTML = '<div style=\"color:var(--text2);font-size:11px\">Oracle offline<\/div>';\n }\n}\n\n\/\/ \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(async () => {\n await loadCities();\n await refresh();\n await loadPipelineStats();\n await loadOracleIntel();\n \/\/ Send GPS to Oracle on load\n if (userLat && userLng) {\n oracleCall('gps_update', { lat: parseFloat(userLat), lng: parseFloat(userLng) });\n }\n refreshTimer = setInterval(refresh, 10000);\n \/\/ Refresh pipeline stats every 30s\n setInterval(loadPipelineStats, 30000);\n \/\/ Refresh Oracle intelligence every 5 minutes\n setInterval(loadOracleIntel, 300000);\n})();\n<\/script>\n<\/body>\n<\/html>","return_code":0}