Widget:Solvency2 BalanceSheet
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Solvency II Balance Sheet</title> <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=IBM+Plex+Sans:wght@300;400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet"> <style>
:root {
--bg: #0c1018;
--surface: #141b27;
--surface2: #1a2234;
--border: #253044;
--text: #e2e8f0;
--text-dim: #8896ab;
--text-muted: #5a6a80;
--accent-blue: #4a9eff;
--accent-cyan: #22d3ee;
--accent-emerald: #34d399;
--accent-amber: #fbbf24;
--accent-rose: #fb7185;
--accent-violet: #a78bfa;
--accent-orange: #fb923c;
/* Balance sheet colors */
--assets-color: #4a9eff;
--bel-color: #fb923c;
--rm-color: #fbbf24;
--scr-color: #fb7185;
--mcr-color: #e879a0;
--surplus-color: #34d399;
--own-funds-color: #22d3ee;
--tp-color: #f59e42;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: 'IBM Plex Sans', sans-serif;
min-height: 100vh;
overflow-x: hidden;
}
/* Grain overlay */
body::before {
content: ;
position: fixed;
inset: 0;
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 999;
}
.container {
max-width: 1280px;
margin: 0 auto;
padding: 40px 32px 60px;
}
/* Header */
header {
text-align: center;
margin-bottom: 48px;
animation: fadeUp 0.8s ease-out;
}
header .eyebrow {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--accent-cyan);
margin-bottom: 16px;
opacity: 0.8;
}
header h1 {
font-family: 'DM Serif Display', serif;
font-size: clamp(28px, 5vw, 48px);
font-weight: 400;
line-height: 1.15;
letter-spacing: -0.5px;
background: linear-gradient(135deg, #e2e8f0 30%, var(--accent-cyan) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 12px;
}
header p {
font-size: 15px;
color: var(--text-dim);
max-width: 640px;
margin: 0 auto;
line-height: 1.65;
font-weight: 300;
}
/* Main layout */
.main-grid {
display: grid;
grid-template-columns: 1fr 360px;
gap: 32px;
align-items: start;
animation: fadeUp 0.8s ease-out 0.15s both;
}
@media (max-width: 960px) {
.main-grid { grid-template-columns: 1fr; }
}
/* Balance sheet visual */
.bs-visual {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 36px;
position: relative;
overflow: hidden;
}
.bs-visual::before {
content: ;
position: absolute;
top: -1px;
left: 40px;
right: 40px;
height: 1px;
background: linear-gradient(90deg, transparent, var(--accent-cyan), transparent);
opacity: 0.4;
}
.bs-title-row {
display: flex;
justify-content: space-between;
margin-bottom: 28px;
}
.bs-col-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
letter-spacing: 2.5px;
text-transform: uppercase;
color: var(--text-muted);
}
.bs-columns {
display: grid;
grid-template-columns: 1fr 32px 1fr;
gap: 0;
min-height: 520px;
}
.bs-col {
display: flex;
flex-direction: column;
gap: 3px;
}
.bs-separator {
display: flex;
align-items: center;
justify-content: center;
}
.bs-separator .line {
width: 1px;
height: 100%;
background: var(--border);
opacity: 0.5;
}
/* Blocks */
.bs-block {
border-radius: 10px;
padding: 16px 18px;
position: relative;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
border: 1px solid transparent;
}
.bs-block::before {
content: ;
position: absolute;
inset: 0;
opacity: 0.08;
transition: opacity 0.3s ease;
}
.bs-block:hover {
transform: translateX(3px);
border-color: rgba(255,255,255,0.08);
}
.bs-block:hover::before { opacity: 0.14; }
.bs-block.active {
border-color: rgba(255,255,255,0.15);
box-shadow: 0 0 24px rgba(0,0,0,0.3);
transform: scale(1.02);
z-index: 2;
}
.bs-block .label {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.2px;
margin-bottom: 3px;
position: relative;
}
.bs-block .sublabel {
font-size: 11px;
opacity: 0.6;
font-weight: 400;
position: relative;
}
.bs-block .value {
font-family: 'IBM Plex Mono', monospace;
font-size: 15px;
font-weight: 500;
margin-top: 6px;
position: relative;
}
/* Block specific colors */
.block-assets {
background: rgba(74, 158, 255, 0.12);
border-color: rgba(74, 158, 255, 0.15);
}
.block-assets::before { background: var(--assets-color); }
.block-assets .value { color: var(--assets-color); }
.block-bel {
background: rgba(251, 146, 60, 0.1);
}
.block-bel::before { background: var(--bel-color); }
.block-bel .value { color: var(--bel-color); }
.block-rm {
background: rgba(251, 191, 36, 0.1);
}
.block-rm::before { background: var(--rm-color); }
.block-rm .value { color: var(--rm-color); }
.block-scr {
background: rgba(251, 113, 133, 0.1);
}
.block-scr::before { background: var(--scr-color); }
.block-scr .value { color: var(--scr-color); }
.block-mcr {
background: rgba(167, 139, 250, 0.1);
}
.block-mcr::before { background: var(--accent-violet); }
.block-mcr .value { color: var(--accent-violet); }
.block-surplus {
background: rgba(52, 211, 153, 0.1);
}
.block-surplus::before { background: var(--surplus-color); }
.block-surplus .value { color: var(--surplus-color); }
.block-tp {
background: rgba(245, 158, 66, 0.08);
border-color: rgba(245, 158, 66, 0.12);
}
.block-of {
background: rgba(34, 211, 238, 0.08);
border-color: rgba(34, 211, 238, 0.12);
}
/* Bracket annotations */
.bracket-group {
position: absolute;
display: flex;
align-items: center;
pointer-events: none;
}
/* Connector lines */
.connectors {
position: absolute;
inset: 0;
pointer-events: none;
}
/* Side panel */
.side-panel {
display: flex;
flex-direction: column;
gap: 20px;
}
.info-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
padding: 24px;
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.info-card .card-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
letter-spacing: 2px;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 14px;
}
.info-card h3 {
font-family: 'DM Serif Display', serif;
font-size: 22px;
font-weight: 400;
margin-bottom: 10px;
line-height: 1.3;
transition: color 0.3s ease;
}
.info-card p {
font-size: 13.5px;
line-height: 1.7;
color: var(--text-dim);
font-weight: 300;
}
.info-card .formula {
margin-top: 14px;
background: rgba(34, 211, 238, 0.06);
border: 1px solid rgba(34, 211, 238, 0.12);
border-radius: 8px;
padding: 12px 16px;
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
color: var(--accent-cyan);
letter-spacing: 0.3px;
}
/* Solvency ratio gauge */
.gauge-card {
text-align: center;
padding: 28px 24px;
}
.gauge-wrapper {
position: relative;
width: 160px;
height: 90px;
margin: 0 auto 16px;
overflow: hidden;
}
.gauge-bg, .gauge-fill {
position: absolute;
width: 160px;
height: 160px;
border-radius: 50%;
border: 14px solid transparent;
}
.gauge-bg {
border-top-color: var(--border);
border-left-color: var(--border);
border-right-color: var(--border);
transform: rotate(0deg);
}
.gauge-fill {
border-top-color: var(--accent-emerald);
border-left-color: var(--accent-emerald);
border-right-color: transparent;
transform: rotate(0deg);
transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.gauge-value {
font-family: 'IBM Plex Mono', monospace;
font-size: 28px;
font-weight: 600;
color: var(--accent-emerald);
margin-bottom: 4px;
}
.gauge-label {
font-size: 12px;
color: var(--text-muted);
font-weight: 500;
}
.gauge-thresholds {
display: flex;
justify-content: space-between;
margin-top: 12px;
padding: 0 4px;
}
.gauge-thresholds span {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
color: var(--text-muted);
}
/* Slider controls */
.controls-card {
padding: 24px;
}
.slider-group {
margin-bottom: 18px;
}
.slider-group:last-child { margin-bottom: 0; }
.slider-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.slider-header label {
font-size: 12.5px;
font-weight: 500;
color: var(--text-dim);
}
.slider-header .slider-val {
font-family: 'IBM Plex Mono', monospace;
font-size: 12px;
font-weight: 500;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 4px;
border-radius: 2px;
background: var(--border);
outline: none;
cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent-cyan);
box-shadow: 0 0 10px rgba(34, 211, 238, 0.4);
cursor: pointer;
transition: transform 0.15s ease;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
}
/* Legend items below chart */
.legend-strip {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 24px;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
padding: 5px 10px;
background: rgba(255,255,255,0.03);
border: 1px solid var(--border);
border-radius: 6px;
font-size: 11px;
color: var(--text-dim);
cursor: pointer;
transition: all 0.2s ease;
}
.legend-item:hover {
background: rgba(255,255,255,0.06);
color: var(--text);
}
.legend-dot {
width: 8px;
height: 8px;
border-radius: 2px;
flex-shrink: 0;
}
/* Bracket annotations on liabilities side */
.bracket-area {
position: relative;
}
.bracket-label {
position: absolute;
right: -28px;
writing-mode: vertical-rl;
text-orientation: mixed;
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--text-muted);
opacity: 0.6;
}
/* Animations */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
from { opacity: 0; transform: translateX(-8px); }
to { opacity: 1; transform: translateX(0); }
}
.bs-block {
animation: slideIn 0.5s ease-out both;
}
.bs-col:first-child .bs-block:nth-child(1) { animation-delay: 0.2s; }
.bs-col:last-child .bs-block:nth-child(1) { animation-delay: 0.3s; }
.bs-col:last-child .bs-block:nth-child(2) { animation-delay: 0.4s; }
.bs-col:last-child .bs-block:nth-child(3) { animation-delay: 0.5s; }
.bs-col:last-child .bs-block:nth-child(4) { animation-delay: 0.6s; }
/* Tooltip */
.tooltip {
position: fixed;
background: #1e293b;
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px 14px;
font-size: 12px;
color: var(--text);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s ease;
max-width: 220px;
z-index: 100;
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}
.tooltip.show { opacity: 1; }
/* Grouped brackets */
.group-bracket {
position: absolute;
display: flex;
align-items: center;
pointer-events: none;
z-index: 3;
}
.group-bracket .bracket-line {
width: 2px;
background: currentColor;
border-radius: 1px;
opacity: 0.4;
}
.group-bracket .bracket-text {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
letter-spacing: 1px;
text-transform: uppercase;
writing-mode: vertical-rl;
text-orientation: mixed;
padding: 0 6px;
opacity: 0.5;
}
/* Flow arrow between assets and liab */
.flow-arrow {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
color: var(--text-muted);
font-size: 10px;
font-family: 'IBM Plex Mono', monospace;
}
.flow-arrow svg {
opacity: 0.3;
}
/* Small badge */
.tier-badge {
display: inline-block;
padding: 2px 7px;
border-radius: 4px;
font-family: 'IBM Plex Mono', monospace;
font-size: 9px;
font-weight: 600;
letter-spacing: 0.5px;
margin-top: 4px;
}
.tier-1 { background: rgba(52, 211, 153, 0.15); color: var(--accent-emerald); }
.tier-2 { background: rgba(251, 191, 36, 0.15); color: var(--accent-amber); }
.tier-3 { background: rgba(251, 113, 133, 0.15); color: var(--accent-rose); }
/* Status bar */
.status-bar {
display: flex;
gap: 24px;
justify-content: center;
margin-top: 16px;
flex-wrap: wrap;
}
.status-item {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 6px;
height: 6px;
border-radius: 50%;
}
.status-dot.green { background: var(--accent-emerald); box-shadow: 0 0 8px rgba(52,211,153,0.5); }
.status-dot.amber { background: var(--accent-amber); box-shadow: 0 0 8px rgba(251,191,36,0.5); }
.status-dot.red { background: var(--accent-rose); box-shadow: 0 0 8px rgba(251,113,133,0.5); }
.status-item span {
font-size: 11px;
color: var(--text-dim);
font-weight: 500;
}
</style> </head> <body>
<header>
Solvency II Balance Sheet
An interactive breakdown of the market-value balance sheet under the EU Solvency II Directive — explore how assets, technical provisions, and capital requirements interconnect.
</header>
Assets Liabilities & Own Funds
100% min 150% 200%+
Hover over a block
Click or hover on any component in the balance sheet to see its definition, purpose, and how it connects to other elements.
<script> const data = {
assets: 150, bel: 85, rm: 8, scr: 35, mcrPct: 35
};
const descriptions = {
assets: {
title: 'Market Value of Assets',
desc: 'All assets held by the insurer valued at fair (market) value under Solvency II. This includes bonds, equities, property, cash, reinsurance recoverables, and other investments. Market-consistent valuation is a core SII principle.',
formula: null
},
bel: {
title: 'Best Estimate Liabilities (BEL)',
desc: 'The probability-weighted average of future cash flows for insurance obligations, discounted using the relevant risk-free interest rate term structure prescribed by EIOPA. It represents the expected cost of meeting policyholder obligations.',
formula: 'BEL = Σ PV(expected future cash flows)'
},
rm: {
title: 'Risk Margin',
desc: 'An additional amount over the BEL to ensure technical provisions are sufficient. Calculated as the cost of holding eligible own funds equal to the SCR over the lifetime of the obligations, using a prescribed cost-of-capital rate (currently 6%).',
formula: 'RM = CoC × Σ SCR(t) / (1 + r(t))^t'
},
tp: {
title: 'Technical Provisions (TP)',
desc: 'The total value of insurance liabilities — the sum of the Best Estimate Liabilities and the Risk Margin. This represents the full amount the insurer must reserve to meet policyholder obligations.',
formula: 'TP = BEL + Risk Margin'
},
scr: {
title: 'Solvency Capital Requirement',
desc: 'The capital buffer required to absorb significant unforeseen losses over a 1-year period with a 99.5% confidence level (i.e. a 1-in-200 year event). Can be calculated via the Standard Formula or an approved Internal Model.',
formula: 'SCR = VaR₉₉.₅%(Basic Own Funds) over 1 year'
},
mcr: {
title: 'Minimum Capital Requirement',
desc: 'The minimum level of security below which the amount of financial resources should not fall. Breach triggers ultimate supervisory intervention — the insurer\'s license may be withdrawn. Bounded between 25%–45% of SCR.',
formula: 'MCR = max(25% × SCR, min(45% × SCR, linear MCR))'
},
surplus: {
title: 'Free Surplus',
desc: 'Own funds in excess of the SCR — the capital cushion above regulatory requirements. A healthy surplus signals strong financial resilience and may support dividend distributions or growth strategies.',
formula: 'Surplus = Own Funds − SCR'
},
ownfunds: {
title: 'Eligible Own Funds',
desc: 'Total own funds available to cover the SCR and MCR. Classified into Tier 1 (highest quality — equity, retained earnings), Tier 2 (subordinated debt), and Tier 3 (limited eligibility). Tiering limits apply when covering SCR/MCR.',
formula: 'Own Funds = Assets − Technical Provisions'
}
};
const legendItems = [
{ id: 'assets', label: 'Assets', color: 'var(--assets-color)' },
{ id: 'bel', label: 'BEL', color: 'var(--bel-color)' },
{ id: 'rm', label: 'Risk Margin', color: 'var(--rm-color)' },
{ id: 'scr', label: 'SCR', color: 'var(--scr-color)' },
{ id: 'mcr', label: 'MCR', color: 'var(--accent-violet)' },
{ id: 'surplus', label: 'Surplus', color: 'var(--surplus-color)' },
];
function compute() {
const tp = data.bel + data.rm;
const ownFunds = Math.max(0, data.assets - tp);
const mcr = Math.round(data.scr * data.mcrPct / 100);
const surplus = Math.max(0, ownFunds - data.scr);
const ratio = data.scr > 0 ? (ownFunds / data.scr * 100) : 0;
return { tp, ownFunds, mcr, surplus, ratio };
}
function render() {
const { tp, ownFunds, mcr, surplus, ratio } = compute();
const total = data.assets;
const totalLiab = tp + data.scr + Math.max(0, surplus);
// Height proportions (use asset total as reference) const ref = Math.max(total, totalLiab, 1); const totalH = 480; const pxPer = totalH / ref;
// Assets column
const assetsCol = document.getElementById('assetsCol');
assetsCol.innerHTML = ;
const assetBlock = makeBlock('assets', 'block-assets', 'Total Assets', `Market value`, `€${data.assets}bn`, totalH);
assetsCol.appendChild(assetBlock);
// Liabilities column
const liabCol = document.getElementById('liabCol');
liabCol.innerHTML = ;
// BEL
const belH = Math.max(32, data.bel * pxPer);
liabCol.appendChild(makeBlock('bel', 'block-bel', 'Best Estimate Liabilities', 'Discounted expected cash flows', `€${data.bel}bn`, belH));
// Risk Margin
const rmH = Math.max(28, data.rm * pxPer);
liabCol.appendChild(makeBlock('rm', 'block-rm', 'Risk Margin', 'Cost-of-capital provision', `€${data.rm}bn`, rmH));
// SCR (show MCR within)
const scrH = Math.max(40, data.scr * pxPer);
const scrBlock = makeBlock('scr', 'block-scr', 'SCR', `Solvency Capital Req.`, `€${data.scr}bn`, scrH);
// MCR badge inside SCR
const mcrBadge = document.createElement('div');
mcrBadge.className = 'tier-badge tier-3';
mcrBadge.textContent = `MCR €${mcr}bn`;
mcrBadge.style.position = 'relative';
mcrBadge.style.cursor = 'pointer';
mcrBadge.dataset.block = 'mcr';
scrBlock.appendChild(mcrBadge);
liabCol.appendChild(scrBlock);
// Surplus
if (surplus > 0) {
const surpH = Math.max(28, surplus * pxPer);
liabCol.appendChild(makeBlock('surplus', 'block-surplus', 'Free Surplus', 'Excess own funds', `€${surplus}bn`, surpH));
} else if (ownFunds < data.scr) {
const deficitH = 32;
const defBlock = makeBlock('surplus', 'block-scr', 'Capital Shortfall', 'Own funds < SCR', `€${Math.round(data.scr - ownFunds)}bn deficit`, deficitH);
defBlock.style.border = '1px dashed var(--accent-rose)';
liabCol.appendChild(defBlock);
}
// Ratio bar
const rVal = document.getElementById('ratioValue');
const rBar = document.getElementById('ratioBar');
rVal.textContent = `${Math.round(ratio)}%`;
const barW = Math.min(100, ratio / 3);
rBar.style.width = barW + '%';
if (ratio >= 150) {
rVal.style.color = 'var(--accent-emerald)';
rBar.style.background = 'var(--accent-emerald)';
} else if (ratio >= 100) {
rVal.style.color = 'var(--accent-amber)';
rBar.style.background = 'var(--accent-amber)';
} else {
rVal.style.color = 'var(--accent-rose)';
rBar.style.background = 'var(--accent-rose)';
}
// Status bar
const sb = document.getElementById('statusBar');
const scrStatus = ownFunds >= data.scr;
const mcrStatus = ownFunds >= mcr;
sb.innerHTML = `
SCR ${scrStatus ? 'Covered' : 'Breached'}
MCR ${mcrStatus ? 'Covered' : 'Breached'}
Ratio: ${Math.round(ratio)}%
Own Funds: €${Math.round(ownFunds)}bn
`;
// Legend
const legend = document.getElementById('legend');
legend.innerHTML = ;
legendItems.forEach(l => {
const li = document.createElement('div');
li.className = 'legend-item';
li.innerHTML = `${l.label}`;
li.onclick = () => showDetail(l.id);
legend.appendChild(li);
});
// Add TP and Own Funds to legend
[{ id: 'tp', label: 'Tech. Provisions', color: 'var(--tp-color)' },
{ id: 'ownfunds', label: 'Own Funds', color: 'var(--own-funds-color)' }
].forEach(l => {
const li = document.createElement('div');
li.className = 'legend-item';
li.innerHTML = `${l.label}`;
li.onclick = () => showDetail(l.id);
legend.appendChild(li);
});
}
function makeBlock(id, cls, label, sublabel, value, height) {
const el = document.createElement('div');
el.className = `bs-block ${cls}`;
el.style.height = height + 'px';
el.dataset.block = id;
el.innerHTML = `
${height > 40 ? `
` : }
`;
el.addEventListener('mouseenter', () => showDetail(id));
el.addEventListener('click', () => showDetail(id));
return el;
}
function showDetail(id) {
const info = descriptions[id];
if (!info) return;
document.getElementById('detailTitle').textContent = info.title;
document.getElementById('detailDesc').textContent = info.desc;
const fEl = document.getElementById('detailFormula');
if (info.formula) {
fEl.style.display = 'block';
fEl.textContent = info.formula;
} else {
fEl.style.display = 'none';
}
// Highlight active block
document.querySelectorAll('.bs-block').forEach(b => b.classList.remove('active'));
document.querySelectorAll(`.bs-block[data-block="${id}"]`).forEach(b => b.classList.add('active'));
}
// Slider bindings function bindSlider(sliderId, valId, key, suffix = ) {
const slider = document.getElementById(sliderId);
const valEl = document.getElementById(valId);
slider.addEventListener('input', () => {
const v = parseInt(slider.value);
data[key] = v;
valEl.textContent = suffix ? v + suffix : v;
render();
});
}
bindSlider('sliderAssets', 'valAssets', 'assets'); bindSlider('sliderBEL', 'valBEL', 'bel'); bindSlider('sliderRM', 'valRM', 'rm'); bindSlider('sliderSCR', 'valSCR', 'scr'); bindSlider('sliderMCR', 'valMCR', 'mcrPct', '%');
// Initial render render(); </script> </body> </html>