async function runAnalysis() { const query = document.getElementById('query').value; const lastPrivate = document.getElementById('last-private').value; // NEW STRUCTURING INPUTS const ipoDiscount = document.getElementById('ipo-discount').value; const greenshoe = document.getElementById('greenshoe').checked; const primaryShares = document.getElementById('primary-shares').value; const loader = document.getElementById('loader'); const dashboard = document.getElementById('dashboard'); // UI State: Loading dashboard.style.display = 'none'; loader.style.display = 'block'; // Prepare form data const formData = new FormData(); formData.append('query', query); if (lastPrivate) formData.append('last_private', lastPrivate); // Append Structuring Levers formData.append('ipo_discount', ipoDiscount); formData.append('greenshoe', greenshoe); formData.append('primary_shares', primaryShares); // NEW: Capture Target Raise const targetRaise = document.getElementById('target-raise').value; formData.append('target_raise', targetRaise); try { const response = await fetch('/analyze', { method: 'POST', body: formData }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Server Error (${response.status}): ${errorText}`); } const data = await response.json(); if (data.error) { alert("Analysis failed: " + data.error); return; } updateDashboard(data); // UI State: Done loader.style.display = 'none'; dashboard.style.display = 'flex'; // Flex layout } catch (e) { console.error(e); alert("System Error: " + e.message); loader.style.display = 'none'; } } function updateDashboard(data) { // 1. Executive Commentary if (data.advisory) { document.getElementById('exec-summary-content').innerHTML = data.advisory.commentary; document.getElementById('m-price').textContent = `$${data.advisory.low} - $${data.advisory.high}`; const statusEl = document.getElementById('m-status'); statusEl.textContent = data.advisory.sentiment; statusEl.style.color = data.advisory.color; // --- METRICS --- document.getElementById('m-momentum').textContent = (data.metrics.avg_momentum ? data.metrics.avg_momentum.toFixed(1) + "%" : "--"); document.getElementById('m-beta').textContent = (data.metrics.avg_beta ? data.metrics.avg_beta.toFixed(2) : "--"); document.getElementById('m-rule-40').textContent = (data.metrics.avg_rule_40 ? data.metrics.avg_rule_40.toFixed(0) : "--"); document.getElementById('m-vix').textContent = (data.macro ? data.macro.vix.toFixed(2) : "--"); // --- RISK CHECKLIST --- const riskBody = document.querySelector('#risk-table tbody'); if (riskBody && data.advisory.risk_matrix) { riskBody.innerHTML = ''; data.advisory.risk_matrix.forEach(r => { const row = ` ${r.factor} ${r.status} ${r.impact} `; riskBody.innerHTML += row; }); } } // 2. IPO STRUCTURING (The Pro Layer) if (data.structure) { document.getElementById('s-final-price').textContent = `$${data.structure.final_price.toFixed(2)}`; document.getElementById('s-raise').textContent = `$${data.structure.capital_raised.toFixed(0)}M`; // Down-Round Alert const drAlert = document.getElementById('dr-alert'); if (data.down_round && data.down_round.is_active) { drAlert.style.display = 'block'; drAlert.innerHTML = data.down_round.text; } else { drAlert.style.display = 'none'; } // --- VISUALIZATION: PIE CHART & TABLE --- const existingShares = data.structure.ownership["Existing Shareholders"]; const newShares = data.structure.ownership["New Public Investors"]; const totalShares = data.structure.total_shares; // 1. Generate Table HTML const tableHTML = `
Group Shares (M) % Own
Existing ${existingShares.toFixed(2)} ${((existingShares / totalShares) * 100).toFixed(1)}%
New Investors ${newShares.toFixed(2)} ${((newShares / totalShares) * 100).toFixed(1)}%
Total ${totalShares.toFixed(2)} 100%
`; document.getElementById('ownership-table').innerHTML = tableHTML; // 2. Render Pie Chart (Navy & Gold) const ownerData = [{ values: [existingShares, newShares], labels: ['Existing Holders', 'New Public Investors'], type: 'pie', marker: { colors: ['#001F3F', '#D4AF37'] }, // Navy vs Gold textinfo: 'percent', hoverinfo: 'label+value+percent', hole: 0.6 }]; const ownerLayout = { paper_bgcolor: 'rgba(0,0,0,0)', plot_bgcolor: 'rgba(0,0,0,0)', font: { color: '#ccc', family: 'Inter' }, showlegend: false, margin: { t: 0, b: 0, l: 0, r: 0 }, height: 220 }; Plotly.newPlot('ownership-chart', ownerData, ownerLayout, { responsive: true, displayModeBar: false }); } // 3. Main Chart const layout = { plot_bgcolor: '#0E1117', paper_bgcolor: '#1E1E1E', font: { color: '#FAFAFA' }, margin: { t: 20, r: 20, b: 40, l: 40 }, xaxis: { showgrid: false }, yaxis: { showgrid: true, gridcolor: '#333' }, height: 350, showlegend: true, legend: { orientation: 'h', y: 1.1 } }; Plotly.newPlot('main-chart', data.chart_json, layout, { responsive: true }); // 4. Table const tbody = document.querySelector('#comps-table tbody'); tbody.innerHTML = ''; if (data.comparables) { data.comparables.forEach(c => { const r40Color = c.rule_40 < 40 ? '#fa5c5c' : '#5cfa85'; const row = ` ${c.ticker} $${(c.market_cap / 1e9).toFixed(1)}B ${c.ev_rev ? c.ev_rev.toFixed(1) + 'x' : 'N/A'} ${c.rule_40 ? c.rule_40.toFixed(0) : '--'} ${c.growth ? (c.growth * 100).toFixed(0) + '%' : 'N/A'} ${c.beta ? c.beta.toFixed(2) : '1.00'} `; tbody.innerHTML += row; }); } }