WM01 / risk.html
AndyKandy26's picture
Upload 9 files
00e4c29 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FinWise — Risk Analyzer</title>
<link rel="stylesheet" href="shared.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
.quiz-card { margin-bottom: 16px; transition: opacity 0.3s; }
.quiz-card.inactive { opacity: 0.4; pointer-events: none; }
.question-num {
font-size: 11px; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.1em; color: var(--cyan); margin-bottom: 6px;
}
.question-text { font-size: 16px; font-weight: 600; margin-bottom: 14px; line-height: 1.4; }
.answer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.answer-btn {
padding: 12px 14px;
background: var(--bg3);
border: 1px solid var(--border);
border-radius: var(--r-sm);
color: var(--text2);
font-family: var(--font-body);
font-size: 13px;
font-weight: 500;
cursor: pointer;
text-align: left;
transition: all var(--transition);
line-height: 1.3;
}
.answer-btn:hover { border-color: var(--border2); color: var(--text); background: var(--card2); }
.answer-btn.selected { border-color: var(--cyan); background: rgba(34,211,238,0.10); color: var(--cyan); }
/* Risk Gauge */
.gauge-container { position: relative; width: 220px; height: 120px; margin: 0 auto; }
.gauge-svg { width: 220px; height: 120px; }
.gauge-needle {
transform-origin: 110px 110px;
transition: transform 1.2s cubic-bezier(.34,1.56,.64,1);
}
.gauge-center-text {
position: absolute;
bottom: 0; left: 50%;
transform: translateX(-50%);
text-align: center;
}
.gauge-score { font-family: var(--font-head); font-size: 32px; font-weight: 800; }
.gauge-label { font-size: 12px; color: var(--text2); }
/* Heatmap */
.heatmap-grid {
display: grid;
gap: 3px;
}
.heatmap-cell {
height: 40px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 700;
color: white;
transition: transform var(--transition);
cursor: default;
}
.heatmap-cell:hover { transform: scale(1.05); }
.rebal-item {
display: flex;
align-items: center;
gap: 14px;
padding: 14px;
background: var(--bg3);
border-radius: var(--r-sm);
border: 1px solid var(--border);
margin-bottom: 10px;
transition: all var(--transition);
}
.rebal-item:hover { border-color: var(--border2); }
.rebal-action {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 3px;
}
.rebal-desc { font-size: 13px; color: var(--text2); }
.rebal-arrow { font-size: 20px; margin-left: auto; }
.risk-breakdown { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.rb-item {
background: var(--bg3);
border-radius: var(--r-sm);
padding: 14px;
text-align: center;
}
.rb-val { font-family: var(--font-head); font-size: 22px; font-weight: 800; }
.rb-label { font-size: 11px; color: var(--text2); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.06em; }
.volatility-bar-wrap { margin-bottom: 12px; }
.vol-header { display: flex; justify-content: space-between; font-size: 13px; margin-bottom: 5px; }
.vol-name { color: var(--text2); font-weight: 600; }
.score-ring {
width: 80px; height: 80px;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-family: var(--font-head);
font-size: 24px;
font-weight: 800;
margin: 0 auto 12px;
position: relative;
}
.score-ring::before {
content: '';
position: absolute;
inset: 4px;
border-radius: 50%;
background: var(--bg2);
}
.score-ring span { position: relative; z-index: 1; }
.scenario-card {
background: var(--bg3);
border-radius: var(--r-sm);
padding: 16px;
border: 1px solid var(--border);
transition: all var(--transition);
}
.scenario-card:hover { border-color: var(--border2); }
.scenario-icon { font-size: 28px; margin-bottom: 8px; }
.scenario-title { font-weight: 700; font-size: 14px; margin-bottom: 6px; }
.scenario-impact { font-size: 13px; }
</style>
</head>
<body>
<div class="app-shell">
<nav class="sidebar">
<div class="sidebar-logo">
<div class="logo-mark">
<div class="logo-icon">📈</div>
<div><div class="logo-text">FinWise</div><div class="logo-sub">Smart Investing</div></div>
</div>
</div>
<div class="nav-section">
<div class="nav-label">Main</div>
<a href="index.html" class="nav-item"><span class="nav-icon">🏠</span> Dashboard</a>
<a href="portfolio.html" class="nav-item"><span class="nav-icon">📊</span> Portfolio Builder</a>
<a href="risk.html" class="nav-item"><span class="nav-icon">🎯</span> Risk Analyzer</a>
<a href="tracker.html" class="nav-item"><span class="nav-icon">📈</span> Tracker</a>
<div class="nav-label">Tools</div>
<a href="calculators.html" class="nav-item"><span class="nav-icon">🧮</span> Calculators</a>
<a href="insights.html" class="nav-item"><span class="nav-icon">💡</span> Insights</a>
</div>
<div class="sidebar-footer">
<div class="market-ticker">Live Market</div>
<div id="sidebar-tickers"></div>
</div>
</nav>
<main class="main-content">
<div class="page-header fade-in">
<div class="page-title">Risk <span>Analyzer</span></div>
<div class="page-subtitle">Understand and optimize your portfolio's risk profile</div>
</div>
<div class="grid-60-40">
<!-- Left Column -->
<div>
<!-- Quiz -->
<div class="card fade-in" id="quiz-section">
<div class="section-title">🧠 Risk Tolerance Assessment</div>
<div class="text-muted text-sm" style="margin-bottom:20px">Answer 5 quick questions — no typing needed</div>
<div id="quiz-container"></div>
<div id="quiz-result" class="hidden" style="margin-top:16px">
<div style="text-align:center;padding:20px">
<div style="font-size:48px;margin-bottom:8px" id="result-icon">⚖️</div>
<div style="font-family:var(--font-head);font-size:24px;font-weight:800;margin-bottom:8px" id="result-title">Moderate Investor</div>
<div style="color:var(--text2);font-size:14px;max-width:360px;margin:0 auto" id="result-desc"></div>
</div>
</div>
<div class="flex gap-12" style="margin-top:16px">
<button class="btn btn-ghost btn-sm" onclick="resetQuiz()">↺ Retake</button>
<button class="btn btn-primary" id="analyze-btn" onclick="runAnalysis()">Analyze My Risk →</button>
</div>
</div>
<!-- Volatility Breakdown -->
<div class="card fade-in fade-in-2" style="margin-top:20px">
<div class="section-title">📊 Asset Volatility</div>
<div id="volatility-bars"></div>
</div>
<!-- Scenarios -->
<div class="card fade-in fade-in-3" style="margin-top:20px">
<div class="section-title">🌪️ Scenario Simulation</div>
<div class="text-muted text-sm" style="margin-bottom:16px">How would your portfolio perform in these scenarios?</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px" id="scenarios-grid"></div>
</div>
</div>
<!-- Right Column -->
<div>
<!-- Risk Gauge -->
<div class="card fade-in-1">
<div class="card-title">🎯 Risk Score</div>
<div class="gauge-container">
<svg class="gauge-svg" viewBox="0 0 220 120">
<!-- Background arcs -->
<path d="M 20 110 A 90 90 0 0 1 200 110" fill="none" stroke="var(--bg3)" stroke-width="18" stroke-linecap="round"/>
<!-- Colored sections -->
<path d="M 20 110 A 90 90 0 0 1 65 29" fill="none" stroke="#10b981" stroke-width="18" stroke-linecap="round" opacity="0.8"/>
<path d="M 65 29 A 90 90 0 0 1 110 20" fill="none" stroke="#22d3ee" stroke-width="18" opacity="0.8"/>
<path d="M 110 20 A 90 90 0 0 1 155 29" fill="none" stroke="#f59e0b" stroke-width="18" opacity="0.8"/>
<path d="M 155 29 A 90 90 0 0 1 200 110" fill="none" stroke="#f43f5e" stroke-width="18" stroke-linecap="round" opacity="0.8"/>
<!-- Needle -->
<g class="gauge-needle" id="gauge-needle" style="transform:rotate(-90deg)">
<line x1="110" y1="110" x2="110" y2="30" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<circle cx="110" cy="110" r="6" fill="white"/>
</g>
</svg>
<div class="gauge-center-text">
<div class="gauge-score" id="gauge-score"></div>
<div class="gauge-label">Risk Score</div>
</div>
</div>
<div style="text-align:center;margin-top:16px">
<span class="badge" id="gauge-badge" style="font-size:13px;padding:6px 16px">Calculating...</span>
</div>
<div class="divider"></div>
<div class="risk-breakdown">
<div class="rb-item">
<div class="rb-val" id="rb-div" style="color:var(--emerald)"></div>
<div class="rb-label">Diversification</div>
</div>
<div class="rb-item">
<div class="rb-val" id="rb-concentrate" style="color:var(--amber)"></div>
<div class="rb-label">Concentration</div>
</div>
<div class="rb-item">
<div class="rb-val" id="rb-equity" style="color:var(--violet)"></div>
<div class="rb-label">Equity %</div>
</div>
<div class="rb-item">
<div class="rb-val" id="rb-safe" style="color:var(--cyan)"></div>
<div class="rb-label">Safe Assets</div>
</div>
</div>
</div>
<!-- Rebalancing Suggestions -->
<div class="card fade-in-2" style="margin-top:20px">
<div class="card-title">⚖️ Rebalancing Suggestions</div>
<div id="rebal-list">
<div style="color:var(--text2);font-size:13px;text-align:center;padding:20px">
Complete the risk assessment to see suggestions
</div>
</div>
</div>
<!-- Allocation Type Chart -->
<div class="card fade-in-3" style="margin-top:20px">
<div class="card-title">🏦 Asset Type Breakdown</div>
<div style="height:180px;position:relative">
<canvas id="typeChart"></canvas>
</div>
</div>
</div>
</div>
</main>
</div>
<nav class="bottom-nav">
<div class="bottom-nav-inner">
<a href="index.html" class="bottom-nav-item"><span class="bnav-icon">🏠</span>Home</a>
<a href="portfolio.html" class="bottom-nav-item"><span class="bnav-icon">📊</span>Portfolio</a>
<a href="risk.html" class="bottom-nav-item"><span class="bnav-icon">🎯</span>Risk</a>
<a href="tracker.html" class="bottom-nav-item"><span class="bnav-icon">📈</span>Track</a>
<a href="calculators.html" class="bottom-nav-item"><span class="bnav-icon">🧮</span>Calc</a>
<a href="insights.html" class="bottom-nav-item"><span class="bnav-icon">💡</span>Insights</a>
</div>
</nav>
<script src="shared.js"></script>
<script>
const QUESTIONS = [
{
q: "How long do you plan to keep your investments?",
answers: [
{ text: "⏱️ Less than 1 year", score: 1 },
{ text: "📅 1–3 years", score: 2 },
{ text: "📆 3–10 years", score: 4 },
{ text: "🗓️ 10+ years", score: 5 },
]
},
{
q: "If your portfolio dropped 20% suddenly, you would:",
answers: [
{ text: "😱 Sell everything immediately", score: 1 },
{ text: "😟 Sell some to reduce exposure", score: 2 },
{ text: "😐 Hold and wait for recovery", score: 4 },
{ text: "😏 Buy more at lower prices", score: 5 },
]
},
{
q: "What's your primary investment objective?",
answers: [
{ text: "🛡️ Preserve what I have", score: 1 },
{ text: "🌱 Steady, modest growth", score: 2 },
{ text: "⚖️ Balance growth and safety", score: 3 },
{ text: "🚀 Maximum long-term growth", score: 5 },
]
},
{
q: "What % of your monthly income do you invest?",
answers: [
{ text: "💸 Less than 5%", score: 1 },
{ text: "💰 5–10%", score: 2 },
{ text: "📈 10–25%", score: 4 },
{ text: "🏦 More than 25%", score: 5 },
]
},
{
q: "Which describes your investing experience?",
answers: [
{ text: "🐣 Complete beginner", score: 1 },
{ text: "📖 Read a bit about it", score: 2 },
{ text: "🤓 Have some investments", score: 3 },
{ text: "💹 Active investor / trader", score: 5 },
]
},
];
let answers = new Array(QUESTIONS.length).fill(null);
let quizComplete = false;
function renderQuiz() {
const container = document.getElementById('quiz-container');
container.innerHTML = QUESTIONS.map((q, qi) => `
<div class="card quiz-card ${answers[qi] === null && qi > 0 && answers[qi-1] === null ? 'inactive' : ''}"
id="quiz-card-${qi}" style="padding:16px;margin-bottom:12px;background:var(--bg3);border:1px solid var(--border)">
<div class="question-num">Question ${qi+1} of ${QUESTIONS.length}</div>
<div class="question-text">${q.q}</div>
<div class="answer-grid">
${q.answers.map((a, ai) => `
<button class="answer-btn ${answers[qi] === ai ? 'selected' : ''}"
onclick="selectAnswer(${qi}, ${ai})">${a.text}</button>
`).join('')}
</div>
</div>
`).join('');
}
function selectAnswer(qi, ai) {
answers[qi] = ai;
document.querySelectorAll(`#quiz-card-${qi} .answer-btn`).forEach((btn, i) => {
btn.classList.toggle('selected', i === ai);
});
const next = document.getElementById('quiz-card-' + (qi+1));
if (next) next.classList.remove('inactive');
quizComplete = answers.every(a => a !== null);
if (quizComplete) {
document.getElementById('analyze-btn').style.background = 'linear-gradient(135deg,var(--emerald-d),var(--emerald))';
}
}
function resetQuiz() {
answers.fill(null);
quizComplete = false;
renderQuiz();
document.getElementById('quiz-result').classList.add('hidden');
}
function getTotalScore() {
return answers.reduce((s, ai, qi) => s + (ai !== null ? QUESTIONS[qi].answers[ai].score : 0), 0);
}
const RISK_RESULTS = [
null,
{ icon:'🐢', title:'Very Conservative', desc:'You prefer capital safety above all. Bonds and stable assets suit you best. Low risk, low return.', color:'var(--emerald)' },
{ icon:'🛡️', title:'Conservative', desc:'Modest growth with downside protection. A mix of bonds and blue-chip stocks works for you.', color:'var(--cyan)' },
{ icon:'⚖️', title:'Moderate', desc:'Balanced approach. You accept some volatility for reasonable long-term gains.', color:'var(--amber)' },
{ icon:'🚀', title:'Aggressive', desc:'Growth-focused investor. You can stomach volatility and aim for superior long-term returns.', color:'var(--rose)' },
{ icon:'🦁', title:'Very Aggressive', desc:'Maximum growth seeker. High risk, high reward. Concentrated in equities and high-growth assets.', color:'var(--rose)' },
];
function getProfileFromScore(score) {
if (score <= 8) return RISK_RESULTS[1];
if (score <= 12) return RISK_RESULTS[2];
if (score <= 16) return RISK_RESULTS[3];
if (score <= 20) return RISK_RESULTS[4];
return RISK_RESULTS[5];
}
function runAnalysis() {
if (!quizComplete) { showToast('Please answer all 5 questions first', 'error'); return; }
const score = getTotalScore();
const profile = getProfileFromScore(score);
document.getElementById('quiz-result').classList.remove('hidden');
document.getElementById('result-icon').textContent = profile.icon;
document.getElementById('result-title').textContent = profile.title;
document.getElementById('result-desc').textContent = profile.desc;
const portfolio = getPortfolio();
const riskScore = calcRiskScore(portfolio);
const divScore = calcDiversification(portfolio);
// Gauge
const deg = -90 + (riskScore / 100) * 180;
document.getElementById('gauge-needle').style.transform = `rotate(${deg}deg)`;
document.getElementById('gauge-score').textContent = riskScore;
const riskColors = ['badge-emerald','badge-cyan','badge-amber','badge-amber','badge-rose'];
const riskNames = ['Low Risk','Moderate-Low','Moderate','Moderate-High','High Risk'];
const rIdx = Math.floor(riskScore / 25);
const badge = document.getElementById('gauge-badge');
badge.className = 'badge ' + riskColors[rIdx];
badge.textContent = riskNames[rIdx];
// Breakdown
const equityPct = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0);
const safePct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
const maxPct = Math.max(...portfolio.assets.map(a=>a.pct));
document.getElementById('rb-div').textContent = divScore + '%';
document.getElementById('rb-concentrate').textContent = maxPct + '%';
document.getElementById('rb-equity').textContent = equityPct + '%';
document.getElementById('rb-safe').textContent = safePct + '%';
renderRebalSuggestions(portfolio, riskScore, equityPct);
renderVolatility(portfolio);
renderScenarios(portfolio);
renderTypeChart(portfolio);
}
function renderRebalSuggestions(portfolio, riskScore, equityPct) {
const list = document.getElementById('rebal-list');
const suggestions = [];
const maxAsset = portfolio.assets.reduce((m, a) => a.pct > m.pct ? a : m, portfolio.assets[0]);
if (maxAsset.pct > 35) suggestions.push({
type:'REDUCE', color:'var(--rose)',
action: `Reduce ${maxAsset.ticker}`,
desc: `${maxAsset.ticker} is ${maxAsset.pct}% of your portfolio — consider trimming to under 30% for better balance.`,
arrow: '↓'
});
const bondPct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
if (bondPct < 10 && riskScore < 60) suggestions.push({
type:'ADD', color:'var(--emerald)',
action: 'Add Bonds (BND)',
desc: 'Your portfolio has little fixed income. Adding 10-15% bonds reduces volatility significantly.',
arrow: '+'
});
if (equityPct > 85) suggestions.push({
type:'DIVERSIFY', color:'var(--amber)',
action: 'Add Alternative Assets',
desc: 'Over 85% in equities. Consider Gold (GLD) or REITs for non-correlated returns.',
arrow: '↗'
});
const hasIntl = portfolio.assets.some(a=>a.ticker==='VEA'||a.ticker==='VXUS');
if (!hasIntl) suggestions.push({
type:'CONSIDER', color:'var(--cyan)',
action: 'Consider International Exposure',
desc: 'Adding 10-15% international ETFs (VEA, VXUS) can reduce US-market concentration risk.',
arrow: '🌍'
});
if (suggestions.length === 0) suggestions.push({
type:'OK', color:'var(--emerald)',
action: '✅ Portfolio looks healthy!',
desc: 'Your diversification and risk levels are well-balanced. Keep up with regular contributions.',
arrow: '👍'
});
list.innerHTML = suggestions.map(s => `
<div class="rebal-item">
<div>
<div class="rebal-action" style="color:${s.color}">${s.type}</div>
<div style="font-weight:700;font-size:14px;margin-bottom:4px">${s.action}</div>
<div class="rebal-desc">${s.desc}</div>
</div>
<div class="rebal-arrow">${s.arrow}</div>
</div>
`).join('');
}
const VOLATILITY_DATA = {
'VOO': { vol: 15, beta: 1.00, color: '#22d3ee' },
'QQQ': { vol: 22, beta: 1.18, color: '#8b5cf6' },
'NVDA': { vol: 48, beta: 1.85, color: '#10b981' },
'AAPL': { vol: 25, beta: 1.22, color: '#f59e0b' },
'BND': { vol: 4, beta: 0.10, color: '#6366f1' },
'GLD': { vol: 12, beta: 0.05, color: '#fbbf24' },
'AMZN': { vol: 30, beta: 1.35, color: '#0ea5e9' },
'VTI': { vol: 15, beta: 1.00, color: '#34d399' },
'TSLA': { vol: 62, beta: 2.10, color: '#f43f5e' },
'WMT': { vol: 8, beta: 0.55, color: '#34d399' },
'MCD': { vol: 9, beta: 0.70, color: '#fb923c' },
};
function renderVolatility(portfolio) {
const container = document.getElementById('volatility-bars');
container.innerHTML = portfolio.assets.map(a => {
const vdata = VOLATILITY_DATA[a.ticker] || { vol: 20, beta: 1.0, color: '#22d3ee' };
const volColor = vdata.vol < 10 ? '#10b981' : vdata.vol < 25 ? '#f59e0b' : '#f43f5e';
return `
<div class="volatility-bar-wrap">
<div class="vol-header">
<span class="vol-name">${a.ticker} <span style="color:var(--text3);font-weight:400;font-size:11px">— ${a.name || ''}</span></span>
<span style="color:${volColor};font-family:var(--font-mono);font-size:12px">±${vdata.vol}% vol · β ${vdata.beta}</span>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width:${Math.min(vdata.vol*1.2,100)}%;background:${volColor}"></div>
</div>
</div>
`;
}).join('');
}
function renderScenarios(portfolio) {
const equity = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0)/100;
const bond = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0)/100;
const gold = portfolio.assets.filter(a=>a.type==='Commodity').reduce((s,a)=>s+a.pct,0)/100;
const scenarios = [
{ icon:'📉', title:'2008 Financial Crisis', impact: ((-38*equity) + (5*bond) + (8*gold)).toFixed(1), desc:'Worst-case equity selloff' },
{ icon:'🦠', title:'2020 COVID Crash', impact: ((-30*equity) + (8*bond) + (5*gold)).toFixed(1), desc:'Fast drop, rapid recovery' },
{ icon:'🔥', title:'Inflation Spike (10%)', impact: ((-15*equity) + (-8*bond) + (20*gold)).toFixed(1), desc:'Rising rates environment' },
{ icon:'🚀', title:'Bull Market (+30%)', impact: ((30*equity) + (3*bond) + (8*gold)).toFixed(1), desc:'Strong economic growth' },
];
document.getElementById('scenarios-grid').innerHTML = scenarios.map(s => {
const isPos = parseFloat(s.impact) >= 0;
return `
<div class="scenario-card">
<div class="scenario-icon">${s.icon}</div>
<div class="scenario-title">${s.title}</div>
<div class="scenario-impact" style="color:${isPos?'var(--emerald)':'var(--rose)'};font-family:var(--font-mono);font-size:18px;font-weight:700">
${isPos?'+':''}${s.impact}%
</div>
<div style="font-size:11px;color:var(--text2);margin-top:4px">${s.desc}</div>
</div>
`;
}).join('');
}
function renderTypeChart(portfolio) {
const types = { ETF:0, Stock:0, Bond:0, Commodity:0 };
portfolio.assets.forEach(a => { types[a.type] = (types[a.type]||0) + a.pct; });
const ctx = document.getElementById('typeChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: Object.keys(types),
datasets: [{
data: Object.values(types),
backgroundColor: ['rgba(34,211,238,0.7)','rgba(16,185,129,0.7)','rgba(99,102,241,0.7)','rgba(245,158,11,0.7)'],
borderRadius: 6,
borderSkipped: false,
}]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { display: false } },
y: { grid: { color: 'rgba(34,211,238,0.06)' }, ticks: { callback: v => v + '%' } }
}
}
});
}
document.addEventListener('DOMContentLoaded', () => {
applyChartDefaults();
renderQuiz();
// Auto-run analysis from saved portfolio
const portfolio = getPortfolio();
const riskScore = calcRiskScore(portfolio);
const deg = -90 + (riskScore/100)*180;
setTimeout(() => {
document.getElementById('gauge-needle').style.transform = `rotate(${deg}deg)`;
document.getElementById('gauge-score').textContent = riskScore;
const rIdx = Math.floor(riskScore/25);
const badge = document.getElementById('gauge-badge');
badge.className = 'badge ' + ['badge-emerald','badge-cyan','badge-amber','badge-amber','badge-rose'][rIdx];
badge.textContent = ['Low Risk','Moderate-Low','Moderate','Moderate-High','High Risk'][rIdx];
const equityPct = portfolio.assets.filter(a=>a.type==='Stock'||a.type==='ETF').reduce((s,a)=>s+a.pct,0);
const safePct = portfolio.assets.filter(a=>a.type==='Bond').reduce((s,a)=>s+a.pct,0);
const maxPct = Math.max(...portfolio.assets.map(a=>a.pct));
document.getElementById('rb-div').textContent = calcDiversification(portfolio) + '%';
document.getElementById('rb-concentrate').textContent = maxPct + '%';
document.getElementById('rb-equity').textContent = equityPct + '%';
document.getElementById('rb-safe').textContent = safePct + '%';
renderRebalSuggestions(portfolio, riskScore, equityPct);
renderVolatility(portfolio);
renderScenarios(portfolio);
renderTypeChart(portfolio);
}, 400);
});
</script>
</body>
</html>