Widget:Solvency2 BalanceSheet: Difference between revisions
Content deleted Content added
No edit summary |
No edit summary |
||
Line 1:
<!-- Solvency II Balance Sheet — Interactive Module for MediaWiki -->
<div id="insurerbrain-module-solvency2">
<div class="s2-header">
<h2 class="s2-title">Solvency II Balance Sheet</h2>
<p class="s2-subtitle">Adjust the sliders to explore how changes in assets and liabilities affect the solvency position.</p>
</div>
<div class="s2-dashboard">
<!-- Solvency Ratio Indicator -->
<div class="s2-ratio-panel">
<div class="s2-ratio-ring-wrap">
<svg class="s2-ratio-ring" viewBox="0 0 120 120">
<circle class="s2-ring-bg" cx="60" cy="60" r="52" />
<circle class="s2-ring-fg" cx="60" cy="60" r="52" stroke-dasharray="326.73" stroke-dashoffset="326.73" />
</svg>
<div class="s2-ratio-label">
<span class="s2-ratio-value" id="s2-ratio-value">0%</span>
<span class="s2-ratio-caption">Solvency Ratio</span>
</div>
</div>
<div class="s2-ratio-badges">
<span class="s2-badge" id="s2-badge-scr">SCR Coverage: —</span>
<span class="s2-badge" id="s2-badge-mcr">MCR Coverage: —</span>
</div>
<div class="s2-status-bar" id="s2-status-bar">Calculating…</div>
</div>
<!-- Balance Sheet Visual -->
<div class="s2-sheet-wrap">
<div class="s2-col s2-col-assets">
<h3 class="s2-col-head">Assets</h3>
<div class="s2-bar-stack" id="s2-asset-bars"></div>
<div class="s2-col-total">Total: <strong id="s2-asset-total">0</strong> €m</div>
</div>
<div class="s2-col s2-col-liabilities">
<h3 class="s2-col-head">Liabilities & Own Funds</h3>
<div class="s2-bar-stack" id="s2-liability-bars"></div>
<div class="s2-col-total">Total: <strong id="s2-liability-total">0</strong> €m</div>
</div>
</div>
</div>
<div class="s2-controls">
<fieldset class="s2-fieldset">
<legend>Assets</legend>
<div class="s2-slider-grid" id="s2-asset-sliders"></div>
</fieldset>
<fieldset class="s2-fieldset">
<legend>Liabilities</legend>
<div class="s2-slider-grid" id="s2-liability-sliders"></div>
</fieldset>
</div>
<!-- Summary Table (uses wikitable class for native MediaWiki styling) -->
<table class="wikitable s2-summary-table" id="s2-summary-table">
<caption>Solvency II — Key Figures (€ millions)</caption>
<thead>
<tr><th>Item</th><th>Value</th><th>Category</th></tr>
<tbody id="s2-summary-tbody"></tbody>
</table>
<p class="s2-footnote">This module is for educational purposes only and uses simplified, illustrative figures. Actual Solvency II reporting follows EIOPA technical standards.</p>
</div>
<style>
/* ===== STRICT SCOPING — every rule prefixed ===== */
#insurerbrain-module-solvency2 {
--s2-accent: #1a6b4e;
--s2-accent-light: #e3f2ec;
--s2-warn: #c0760a;
--s2-warn-light: #fdf3e1;
--s2-danger: #b52a2a;
--s2-danger-light: #fce8e8;
--s2-border: #c8ccd1;
--s2-text: #202122;
--s2-text-muted: #54595d;
--s2-surface: #f8f9fa;
--s2-white: #ffffff;
--s2-radius: 0.35rem;
max-width: 64rem;
margin: 1.5rem auto;
padding: 0 0.75rem;
}
/* ---- Header ---- */
#insurerbrain-module-solvency2 .s2-header {
margin-bottom: 1.25rem;
}
#insurerbrain-module-solvency2 .s2-title {
margin: 0 0 0.25rem;
border-bottom: none;
}
#insurerbrain-module-solvency2 .s2-subtitle {
margin: 0;
color: var(--s2-text-muted);
}
/* ---- Dashboard ---- */
#insurerbrain-module-solvency2 .s2-dashboard {
flex-wrap: wrap;
margin-bottom: 1.5rem;
/* -- Ratio Panel -- */
#insurerbrain-module-solvency2 .s2-ratio-panel {
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.6rem;
padding: 1rem;
border: 1px solid var(--s2-border);
border-radius: var(--s2-radius);
background: var(--s2-surface);
}
#insurerbrain-module-solvency2 .s2-ratio-ring-wrap {
position: relative;
width: 7.5rem;
height: 7.5rem;
}
#insurerbrain-module-solvency2 .s2-ratio-ring {
width: 100%;
height: 100%;
transform: rotate(-90deg);
}
#insurerbrain-module-solvency2 .s2-ring-bg {
fill: none;
stroke: var(--s2-border);
stroke-width: 8;
}
#insurerbrain-module-solvency2 .s2-ring-fg {
fill: none;
stroke: var(--s2-accent);
stroke-width: 8;
stroke-linecap: round;
transition: stroke-dashoffset 0.5s ease, stroke 0.4s ease;
}
#insurerbrain-module-solvency2 .s2-ratio-label {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#insurerbrain-module-solvency2 .s2-ratio-value {
font-size: 1.5rem;
font-weight: 700;
line-height: 1.1;
color: var(--s2-text);
}
#insurerbrain-module-solvency2 .s2-ratio-caption {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--s2-text-muted);
}
#insurerbrain-module-solvency2 .s2-ratio-badges {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
justify-content: center;
}
#insurerbrain-module-solvency2 .s2-badge {
font-size: 0.72rem;
padding: 0.15rem 0.45rem;
border-radius: 999px;
background: var(--s2-accent-light);
color: var(--s2-accent);
white-space: nowrap;
}
#insurerbrain-module-solvency2 .s2-status-bar {
font-size: 0.78rem;
font-weight: 600;
padding: 0.3rem 0.7rem;
border-radius: var(--s2-radius);
text-align: center;
transition: background 0.3s, color 0.3s;
}
/* -- Balance Sheet Columns -- */
#insurerbrain-module-solvency2 .s2-sheet-wrap {
gap: 0.5rem;
min-height: 18rem;
}
#insurerbrain-module-solvency2 .s2-col {
flex: 1;
display: flex;
flex-direction: column;
border: 1px solid var(--s2-border);
border-radius: var(--s2-radius);
overflow: hidden;
background: var(--s2-white);
}
#insurerbrain-module-solvency2 .s2-col-head {
margin: 0;
padding: 0.45rem 0.6rem;
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.04em;
border-bottom: 1px solid var(--s2-border);
background: var(--s2-surface);
}
#insurerbrain-module-solvency2 .s2-bar-stack {
flex: 1;
display: flex;
flex-direction: column;
padding: 0.25rem;
gap: 2px;
}
#insurerbrain-module-solvency2 .s2-bar-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.25rem 0.45rem;
border-radius: 3px;
font-size: 0.75rem;
color: var(--s2-white);
transition: flex-grow 0.45s ease;
overflow: hidden;
min-height: 1.4rem;
}
#insurerbrain-module-solvency2 .s2-bar-item span:last-child {
font-weight: 600;
margin-left: 0.3rem;
white-space: nowrap;
}
#insurerbrain-module-solvency2 .s2-col-total {
padding: 0.35rem 0.6rem;
font-size: 0.82rem;
border-top: 1px solid var(--s2-border);
background: var(--s2-surface);
text-align: right;
}
/* ---- Controls ---- */
#insurerbrain-module-solvency2 .s2-controls {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin-bottom: 1.25rem;
}
#insurerbrain-module-solvency2 .s2-fieldset {
flex: 1 1 18rem;
border: 1px solid var(--s2-border);
border-radius: var(--s2-radius);
padding: 0.6rem 0.8rem 0.8rem;
margin: 0;
background: var(--s2-surface);
}
#insurerbrain-module-solvency2 .s2-fieldset legend {
font-weight: 600;
font-size: 0.85rem;
padding: 0 0.3rem;
}
#insurerbrain-module-solvency2 .s2-slider-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
gap: 0.55rem;
}
#insurerbrain-module-solvency2 .s2-slider-group {
display: flex;
flex-direction: column;
gap: 0.15rem;
}
#insurerbrain-module-solvency2 .s2-slider-label {
display: flex;
justify-content: space-between;
font-size: 0.78rem;
color: var(--s2-text-muted);
}
#insurerbrain-module-solvency2 .s2-slider-label strong {
color: var(--s2-text);
}
#insurerbrain-module-solvency2 .s2-slider-group input[type="range"] {
width: 100%;
cursor: pointer;
accent-color: var(--s2-accent);
}
#insurerbrain-module-solvency2 .s2-summary-table {
}
/* ---- Footnote ---- */
#insurerbrain-module-solvency2 .s2-footnote {
color: var(--s2-text-muted);
margin-top: 0.5rem;
}
/* ---- Status colours ---- */
#insurerbrain-module-solvency2 .s2-status-good {
background: var(--s2-accent-light);
color: var(--s2-accent);
}
#insurerbrain-module-solvency2 .s2-status-warn {
background: var(--s2-warn-light);
color: var(--s2-warn);
}
#insurerbrain-module-solvency2 .s2-status-danger {
background: var(--s2-danger-light);
color: var(--s2-danger);
}
@media (max-width: 48rem) {
#insurerbrain-module-solvency2 .s2-dashboard {
flex-direction: column;
}
#insurerbrain-module-solvency2 .s2-ratio-panel {
flex-wrap: wrap;
}
#insurerbrain-module-solvency2 .s2-sheet-wrap {
}
}
</style>
<script>
(function () {
'use strict';
/* ============ DATA MODEL ============ */
var assetItems = [
{ key: 'gov_bonds', label: 'Government Bonds', value: 350, min: 0, max: 800, color: '#1a6b4e' },
{ key: 'corp_bonds', label: 'Corporate Bonds', value: 220, min: 0, max: 600, color: '#2a8c68' },
{ key: 'equities', label: 'Equities', value: 120, min: 0, max: 400, color: '#3bae85' },
{ key: 'property', label: 'Property', value: 80, min: 0, max: 300, color: '#5bc4a0' },
{ key: 'reins_recv', label: 'Reinsurance Recoverables',value: 60, min: 0, max: 200, color: '#85d4b8' },
{ key: 'cash', label: 'Cash & Equivalents', value: 40, min: 0, max: 200, color: '#abd9c9' }
];
var liabilityItems = [
{ key: 'best_est', label: 'Best Estimate Liabilities', value: 480, min: 100, max: 900, color: '#8b3a3a' },
{ key: 'risk_margin', label: 'Risk Margin', value: 45, min: 5, max: 150, color: '#b35656' },
{ key: 'other_liab', label: 'Other Liabilities', value: 55, min: 0, max: 200, color: '#cc8080' },
{ key: 'scr', label: 'SCR (Own Funds Buffer)', value: 180, min: 20, max: 400, color: '#1b5e90' },
{ key: 'mcr', label: 'MCR (Minimum Capital)', value: 70, min: 10, max: 200, color: '#3a8bc2' }
];
/*
var root = document.getElementById('insurerbrain-module-solvency2');
var assetSliders = root.querySelector('#s2-asset-sliders');
var liabSliders = root.querySelector('#s2-liability-sliders');
var assetBars = root.querySelector('#s2-asset-bars');
var liabBars = root.querySelector('#s2-liability-bars');
var assetTotalEl = root.querySelector('#s2-asset-total');
var liabTotalEl = root.querySelector('#s2-liability-total');
var ratioValueEl = root.querySelector('#s2-ratio-value');
var ringFg = root.querySelector('.s2-ring-fg');
var statusBar = root.querySelector('#s2-status-bar');
var badgeSCR = root.querySelector('#s2-badge-scr');
var badgeMCR = root.querySelector('#s2-badge-mcr');
var tbody = root.querySelector('#s2-summary-tbody');
var CIRCUMFERENCE = 2 * Math.PI * 52; // matches r=52
/*
function buildSliders(items, container) {
items.forEach(function (item) {
var group = document.createElement('div');
group.className = 's2-slider-group';
var lbl = document.createElement('div');
lbl.className = 's2-slider-label';
lbl.innerHTML = '<span>' + item.label + '</span><strong id="s2-val-' + item.key + '">' + item.value + '</strong>';
var inp = document.createElement('input');
inp.type = 'range';
inp.min = item.min;
inp.max = item.max;
inp.value = item.value;
inp.id = 's2-range-' + item.key;
inp.setAttribute('aria-label', item.label + ' (€m)');
inp.addEventListener('input', function () {
item.value = Number(this.value);
root.querySelector('#s2-val-' + item.key).textContent = item.value;
group.appendChild(lbl);
group.appendChild(inp);
container.appendChild(group);
});
}
/* ============ BUILD BAR ITEMS (once) ============ */
function buildBars(items, container) {
items.forEach(function (item) {
var bar = document.createElement('div');
bar.className = 's2-bar-item';
bar.id = 's2-bar-' + item.key;
bar.style.background = item.color;
bar.innerHTML = '<span>' + item.label + '</span><span></span>';
container.appendChild(bar);
});
}
/* ============ UPDATE ============ */
function update() {
var totalAssets = assetItems.reduce(function (s, i) { return s + i.value; }, 0);
var techProv = liabilityItems[0].value + liabilityItems[1].value; // BE + RM
var otherLiab = liabilityItems[2].value;
var scrReq
var mcrReq = liabilityItems[4].value;
var totalLiabSide = techProv + otherLiab + scrReq + mcrReq;
// Eligible Own Funds = Assets - Technical Provisions - Other Liabilities
var eof = totalAssets - techProv - otherLiab;
if (eof < 0) eof = 0;
var solvencyRatio = scrReq > 0 ? (eof / scrReq) * 100 : 0;
var mcrRatio = mcrReq > 0 ? (eof / mcrReq) * 100 : 0;
// Ratio ring
var capped = Math.min(solvencyRatio, 250);
var offset = CIRCUMFERENCE - (CIRCUMFERENCE * capped / 250);
ringFg.style.strokeDashoffset = offset;
var ringColor;
if (solvencyRatio >= 150) ringColor = '#1a6b4e';
else if (solvencyRatio >= 100) ringColor = '#c0760a';
else ringColor = '#b52a2a';
ringFg.style.stroke = ringColor;
ratioValueEl.textContent = Math.round(solvencyRatio) + '%';
badgeSCR.textContent = 'SCR Coverage: ' + Math.round(solvencyRatio) + '%';
badgeMCR.textContent = 'MCR Coverage: ' + Math.round(mcrRatio) + '%';
// Status
statusBar.classList.remove('s2-status-good', 's2-status-warn', 's2-status-danger');
if (solvencyRatio >= 150) {
statusBar.textContent = 'Comfortable — well above SCR';
statusBar.classList.add('s2-status-good');
} else if (solvencyRatio >= 100) {
statusBar.textContent = 'Caution — approaching SCR threshold';
statusBar.classList.add('s2-status-warn');
} else {
statusBar.textContent = 'Breach — own funds below SCR';
statusBar.classList.add('s2-status-danger');
}
// Asset bars
assetItems.forEach(function (item) {
var bar = root.querySelector('#s2-bar-' + item.key);
bar.style.flexGrow = item.value || 0.01;
bar.querySelector('span:last-child').textContent = item.value + ' €m';
});
assetTotalEl.textContent = totalAssets;
// Liability bars
liabilityItems.forEach(function (item) {
var bar = root.querySelector('#s2-bar-' + item.key);
bar.style.flexGrow = item.value || 0.01;
bar.querySelector('span:last-child').textContent = item.value + ' €m';
}
liabTotalEl.textContent = totalLiabSide;
// Summary table
var rows = [];
assetItems.forEach(function (i) { rows.push([i.label, i.value, 'Asset']); });
rows.push(['<strong>Total Assets</strong>', '<strong>' + totalAssets + '</strong>', '']);
liabilityItems.forEach(function (i) { rows.push([i.label, i.value, 'Liability / Capital']); });
rows.push(['<strong>Technical Provisions</strong>', '<strong>' + techProv + '</strong>', '']);
rows.push(['<strong>Eligible Own Funds</strong>', '<strong>' + Math.round(eof) + '</strong>', '']);
rows.push(['<strong>Solvency Ratio (EOF / SCR)</strong>', '<strong>' + Math.round(solvencyRatio) + '%</strong>', '']);
tbody.innerHTML = rows.map(function
return '<tr><td>' + r[0] + '</td><td style="text-align:right">' + r[1] + '</td><td>' + r[2] + '</td></tr>';
}).join('');
}
/* ============ INIT ============ */
buildSliders(assetItems, assetSliders);
buildSliders(liabilityItems, liabSliders);
buildBars(assetItems, assetBars);
buildBars(liabilityItems, liabBars);
update();
})();
</script>
| |||