Widget:Solvency2 BalanceSheet: Difference between revisions
Created page with "<!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; --tex..." |
No edit summary |
||
| Line 5: | Line 5: | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||
<title>Solvency II Balance Sheet</title> |
<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> |
<style> |
||
:root { |
:root { |
||
--bg: # |
--bg: #ffffff; |
||
--surface: # |
--surface: #f8f9fa; |
||
--surface2: # |
--surface2: #eaecf0; |
||
--border: # |
--border: #a2a9b1; |
||
-- |
--border-heavy: #202122; |
||
--text |
--text: #202122; |
||
--text- |
--text-dim: #54595d; |
||
-- |
--text-muted: #72777d; |
||
-- |
--link: #000099; |
||
--accent-emerald: #34d399; |
|||
/* Monochrome block palette — dark-to-light for visual hierarchy */ |
|||
--accent-amber: #fbbf24; |
|||
-- |
--assets-fill: #202122; |
||
-- |
--bel-fill: #54595d; |
||
-- |
--rm-fill: #72777d; |
||
--scr-fill: #a2a9b1; |
|||
/* Balance sheet colors */ |
|||
-- |
--mcr-fill: #c8ccd1; |
||
-- |
--surplus-fill: #eaecf0; |
||
--rm-color: #fbbf24; |
|||
--scr-color: #fb7185; |
|||
--mcr-color: #e879a0; |
|||
--surplus-color: #34d399; |
|||
--own-funds-color: #22d3ee; |
|||
--tp-color: #f59e42; |
|||
} |
} |
||
| Line 38: | Line 31: | ||
background: var(--bg); |
background: var(--bg); |
||
color: var(--text); |
color: var(--text); |
||
font-family: |
font-family: sans-serif; |
||
line-height: 1.6; |
|||
-webkit-font-smoothing: auto; |
|||
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 { |
.container { |
||
max-width: |
max-width: 900px; |
||
margin: 0 auto; |
margin: 0 auto; |
||
padding: |
padding: 24px 16px 60px; |
||
} |
} |
||
/* Header */ |
/* ---- Header ---- */ |
||
header { |
header { |
||
border-bottom: 2px solid var(--border-heavy); |
|||
text-align: center; |
|||
padding-bottom: 10px; |
|||
margin-bottom: 20px; |
|||
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 { |
header h1 { |
||
font- |
font-size: 1.8em; |
||
font- |
font-weight: bold; |
||
color: var(--text); |
|||
line-height: 1. |
line-height: 1.25; |
||
margin: 0; |
|||
background: linear-gradient(135deg, #e2e8f0 30%, var(--accent-cyan) 100%); |
|||
-webkit-background-clip: text; |
|||
-webkit-text-fill-color: transparent; |
|||
margin-bottom: 12px; |
|||
} |
} |
||
header p { |
header p { |
||
font-size: |
font-size: 0.88em; |
||
color: var(--text-dim); |
color: var(--text-dim); |
||
margin-top: 4px; |
|||
line-height: 1.6; |
|||
line-height: 1.65; |
|||
font-weight: 300; |
|||
} |
} |
||
/* |
/* ---- Two-column master layout ---- */ |
||
.main-grid { |
.main-grid { |
||
display: grid; |
display: grid; |
||
grid-template-columns: 1fr |
grid-template-columns: 1fr 300px; |
||
gap: |
gap: 24px; |
||
align-items: start; |
align-items: start; |
||
animation: fadeUp 0.8s ease-out 0.15s both; |
|||
} |
} |
||
@media (max-width: 760px) { |
|||
@media (max-width: 960px) { |
|||
.main-grid { grid-template-columns: 1fr; } |
.main-grid { grid-template-columns: 1fr; } |
||
} |
} |
||
/* |
/* ---- Balance-sheet visual ---- */ |
||
.bs-visual { |
.bs-visual { |
||
background: var(--surface); |
|||
border: 1px solid var(--border); |
border: 1px solid var(--border); |
||
background: var(--bg); |
|||
padding: |
padding: 20px 24px 16px; |
||
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; |
|||
} |
} |
||
| Line 135: | Line 85: | ||
display: flex; |
display: flex; |
||
justify-content: space-between; |
justify-content: space-between; |
||
margin-bottom: |
margin-bottom: 14px; |
||
} |
} |
||
.bs-col-label { |
.bs-col-label { |
||
font- |
font-size: 0.78em; |
||
font- |
font-weight: bold; |
||
letter-spacing: 0.06em; |
|||
letter-spacing: 2.5px; |
|||
text-transform: uppercase; |
text-transform: uppercase; |
||
color: var(--text-muted); |
color: var(--text-muted); |
||
| Line 149: | Line 98: | ||
.bs-columns { |
.bs-columns { |
||
display: grid; |
display: grid; |
||
grid-template-columns: 1fr |
grid-template-columns: 1fr 24px 1fr; |
||
min-height: 480px; |
|||
min-height: 520px; |
|||
} |
} |
||
| Line 157: | Line 105: | ||
display: flex; |
display: flex; |
||
flex-direction: column; |
flex-direction: column; |
||
gap: |
gap: 2px; |
||
} |
} |
||
.bs-separator { |
.bs-separator { |
||
display: flex; |
display: flex; |
||
align-items: |
align-items: stretch; |
||
justify-content: center; |
justify-content: center; |
||
} |
} |
||
.bs-separator .line { |
.bs-separator .line { |
||
width: 1px; |
width: 1px; |
||
height: 100%; |
|||
background: var(--border); |
background: var(--border); |
||
opacity: 0.5; |
|||
} |
} |
||
/* Blocks */ |
/* ---- Blocks ---- */ |
||
.bs-block { |
.bs-block { |
||
padding: 12px 14px; |
|||
padding: 16px 18px; |
|||
position: relative; |
position: relative; |
||
cursor: pointer; |
cursor: pointer; |
||
transition: |
transition: background 0.2s ease, box-shadow 0.2s ease; |
||
overflow: hidden; |
|||
display: flex; |
display: flex; |
||
flex-direction: column; |
flex-direction: column; |
||
justify-content: center; |
justify-content: center; |
||
border: 1px solid transparent; |
border: 1px solid transparent; |
||
color: #fff; |
|||
} |
|||
.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 { |
.bs-block .label { |
||
font-size: |
font-size: 0.82em; |
||
font-weight: |
font-weight: bold; |
||
line-height: 1.3; |
|||
margin-bottom: 3px; |
|||
position: relative; |
|||
} |
} |
||
.bs-block .sublabel { |
.bs-block .sublabel { |
||
font-size: |
font-size: 0.72em; |
||
opacity: 0. |
opacity: 0.75; |
||
margin-top: 1px; |
|||
position: relative; |
|||
} |
} |
||
.bs-block .value { |
.bs-block .value { |
||
font- |
font-size: 0.88em; |
||
font- |
font-weight: bold; |
||
margin-top: 4px; |
|||
font-variant-numeric: tabular-nums; |
|||
margin-top: 6px; |
|||
position: relative; |
|||
} |
} |
||
.bs-block:hover { |
|||
/* Block specific colors */ |
|||
box-shadow: 0 0 0 2px var(--border-heavy); |
|||
.block-assets { |
|||
z-index: 2; |
|||
background: rgba(74, 158, 255, 0.12); |
|||
border-color: rgba(74, 158, 255, 0.15); |
|||
} |
} |
||
.bs-block.active { |
|||
.block-assets::before { background: var(--assets-color); } |
|||
box-shadow: 0 0 0 2.5px var(--border-heavy); |
|||
z-index: 3; |
|||
.block-bel { |
|||
background: rgba(251, 146, 60, 0.1); |
|||
} |
} |
||
.block-bel::before { background: var(--bel-color); } |
|||
.block-bel .value { color: var(--bel-color); } |
|||
/* Individual block fills */ |
|||
background: |
.block-assets { background: var(--assets-fill); } |
||
.block-bel { background: var(--bel-fill); } |
|||
} |
|||
.block-rm |
.block-rm { background: var(--rm-fill); } |
||
.block- |
.block-scr { background: var(--scr-fill); color: var(--text); } |
||
.block-mcr { background: var(--mcr-fill); color: var(--text); } |
|||
.block-surplus { background: var(--surplus-fill); color: var(--text); border: 1px solid var(--border); } |
|||
/* ---- Legend ---- */ |
|||
.block-scr { |
|||
.legend-strip { |
|||
background: rgba(251, 113, 133, 0.1); |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 4px; |
|||
margin-top: 16px; |
|||
border-top: 1px solid var(--border); |
|||
padding-top: 12px; |
|||
} |
} |
||
.legend-item { |
|||
.block-scr::before { background: var(--scr-color); } |
|||
display: flex; |
|||
.block-scr .value { color: var(--scr-color); } |
|||
align-items: center; |
|||
gap: 5px; |
|||
.block-mcr { |
|||
padding: 3px 8px; |
|||
background: rgba(167, 139, 250, 0.1); |
|||
font-size: 0.75em; |
|||
color: var(--text-dim); |
|||
cursor: pointer; |
|||
border: 1px solid transparent; |
|||
border-radius: 2px; |
|||
transition: border-color 0.15s ease; |
|||
} |
} |
||
. |
.legend-item:hover { border-color: var(--border); } |
||
.legend-dot { |
|||
.block-mcr .value { color: var(--accent-violet); } |
|||
width: 10px; height: 10px; |
|||
border-radius: 1px; |
|||
.block-surplus { |
|||
flex-shrink: 0; |
|||
background: rgba(52, 211, 153, 0.1); |
|||
} |
} |
||
.block-surplus::before { background: var(--surplus-color); } |
|||
.block-surplus .value { color: var(--surplus-color); } |
|||
/* ---- Status bar ---- */ |
|||
.block-tp { |
|||
.status-bar { |
|||
background: rgba(245, 158, 66, 0.08); |
|||
display: flex; |
|||
border-color: rgba(245, 158, 66, 0.12); |
|||
gap: 16px; |
|||
} |
|||
flex-wrap: wrap; |
|||
margin-top: 12px; |
|||
.block-of { |
|||
font-size: 0.8em; |
|||
color: var(--text-dim); |
|||
} |
} |
||
.status-item { |
|||
/* Bracket annotations */ |
|||
.bracket-group { |
|||
position: absolute; |
|||
display: flex; |
display: flex; |
||
align-items: center; |
align-items: center; |
||
gap: 6px; |
|||
} |
} |
||
.status-dot { |
|||
width: 7px; height: 7px; |
|||
/* Connector lines */ |
|||
border-radius: 50%; |
|||
.connectors { |
|||
flex-shrink: 0; |
|||
inset: 0; |
|||
pointer-events: none; |
|||
} |
} |
||
.status-dot.ok { background: var(--text); } |
|||
.status-dot.warn { background: var(--text-muted); } |
|||
.status-dot.fail { border: 2px solid var(--text); background: transparent; } |
|||
/* Side panel */ |
/* ---- Side panel ---- */ |
||
.side-panel { |
.side-panel { |
||
display: flex; |
display: flex; |
||
flex-direction: column; |
flex-direction: column; |
||
gap: |
gap: 16px; |
||
} |
} |
||
.info-card { |
.info-card { |
||
background: var(--surface); |
|||
border: 1px solid var(--border); |
border: 1px solid var(--border); |
||
background: var(--bg); |
|||
padding: |
padding: 16px 18px; |
||
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1); |
|||
} |
} |
||
.card-label { |
|||
font- |
font-size: 0.7em; |
||
font- |
font-weight: bold; |
||
letter-spacing: |
letter-spacing: 0.08em; |
||
text-transform: uppercase; |
text-transform: uppercase; |
||
color: var(--text-muted); |
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; |
margin-bottom: 10px; |
||
line-height: 1.3; |
|||
transition: color 0.3s ease; |
|||
} |
} |
||
/* ---- Gauge ---- */ |
|||
.info-card p { |
|||
.gauge-card { text-align: center; padding: 18px; } |
|||
font-size: 13.5px; |
|||
line-height: 1.7; |
|||
color: var(--text-dim); |
|||
font-weight: 300; |
|||
} |
|||
. |
.gauge-value { |
||
font-size: 2em; |
|||
font-weight: bold; |
|||
background: rgba(34, 211, 238, 0.06); |
|||
color: var(--text); |
|||
border: 1px solid rgba(34, 211, 238, 0.12); |
|||
line-height: 1.1; |
|||
padding: 12px 16px; |
|||
font-family: 'IBM Plex Mono', monospace; |
|||
font-size: 12px; |
|||
color: var(--accent-cyan); |
|||
letter-spacing: 0.3px; |
|||
} |
} |
||
.gauge-label { |
|||
font-size: 0.78em; |
|||
/* Solvency ratio gauge */ |
|||
color: var(--text-muted); |
|||
.gauge-card { |
|||
margin-top: 2px; |
|||
padding: 28px 24px; |
|||
} |
} |
||
.gauge-bar-track { |
|||
margin-top: 14px; |
|||
.gauge-wrapper { |
|||
height: 6px; |
|||
background: var(--surface2); |
|||
border-radius: 3px; |
|||
margin: 0 auto 16px; |
|||
overflow: hidden; |
overflow: hidden; |
||
} |
} |
||
.gauge-bar-fill { |
|||
height: 100%; |
|||
.gauge-bg, .gauge-fill { |
|||
border-radius: 3px; |
|||
background: var(--text); |
|||
transition: width 0.6s ease; |
|||
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 { |
.gauge-thresholds { |
||
display: flex; |
display: flex; |
||
justify-content: space-between; |
justify-content: space-between; |
||
margin-top: |
margin-top: 6px; |
||
font-size: 0.68em; |
|||
} |
|||
.gauge-thresholds span { |
|||
font-family: 'IBM Plex Mono', monospace; |
|||
font-size: 10px; |
|||
color: var(--text-muted); |
color: var(--text-muted); |
||
} |
} |
||
/* |
/* ---- Sliders ---- */ |
||
.slider-group { margin-bottom: 14px; } |
|||
.controls-card { |
|||
padding: 24px; |
|||
} |
|||
.slider-group { |
|||
margin-bottom: 18px; |
|||
} |
|||
.slider-group:last-child { margin-bottom: 0; } |
.slider-group:last-child { margin-bottom: 0; } |
||
.slider-header { |
.slider-header { |
||
display: flex; |
display: flex; |
||
justify-content: space-between; |
justify-content: space-between; |
||
align-items: |
align-items: baseline; |
||
margin-bottom: |
margin-bottom: 5px; |
||
} |
} |
||
.slider-header label { |
.slider-header label { |
||
font-size: |
font-size: 0.8em; |
||
font-weight: 500; |
|||
color: var(--text-dim); |
color: var(--text-dim); |
||
} |
} |
||
.slider-val { |
|||
font-size: 0.8em; |
|||
.slider-header .slider-val { |
|||
font- |
font-weight: bold; |
||
color: var(--text); |
|||
font- |
font-variant-numeric: tabular-nums; |
||
} |
} |
||
| Line 444: | Line 296: | ||
-webkit-appearance: none; |
-webkit-appearance: none; |
||
width: 100%; |
width: 100%; |
||
height: |
height: 3px; |
||
background: var(--surface2); |
|||
border-radius: 2px; |
border-radius: 2px; |
||
background: var(--border); |
|||
outline: none; |
outline: none; |
||
cursor: pointer; |
cursor: pointer; |
||
} |
} |
||
input[type="range"]::-webkit-slider-thumb { |
input[type="range"]::-webkit-slider-thumb { |
||
-webkit-appearance: none; |
-webkit-appearance: none; |
||
width: |
width: 14px; height: 14px; |
||
height: 16px; |
|||
border-radius: 50%; |
border-radius: 50%; |
||
background: var(-- |
background: var(--text); |
||
box-shadow: 0 0 10px rgba(34, 211, 238, 0.4); |
|||
cursor: pointer; |
cursor: pointer; |
||
border: 2px solid #fff; |
|||
box-shadow: 0 0 0 1px var(--border); |
|||
} |
} |
||
input[type="range"]::-moz-range-thumb { |
|||
width: 14px; height: 14px; |
|||
input[type="range"]::-webkit-slider-thumb:hover { |
|||
border-radius: 50%; |
|||
background: var(--text); |
|||
} |
|||
/* 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; |
cursor: pointer; |
||
border: 2px solid #fff; |
|||
box-shadow: 0 0 0 1px var(--border); |
|||
} |
} |
||
/* ---- Detail card ---- */ |
|||
.legend-item:hover { |
|||
.info-card h3 { |
|||
background: rgba(255,255,255,0.06); |
|||
font-size: 1.05em; |
|||
font-weight: bold; |
|||
color: var(--text); |
color: var(--text); |
||
margin-bottom: 6px; |
|||
line-height: 1.3; |
|||
} |
} |
||
.info-card p { |
|||
font-size: 0.84em; |
|||
.legend-dot { |
|||
color: var(--text-dim); |
|||
height: |
line-height: 1.6; |
||
border-radius: 2px; |
|||
flex-shrink: 0; |
|||
} |
} |
||
.formula { |
|||
margin-top: 10px; |
|||
/* Bracket annotations on liabilities side */ |
|||
padding: 8px 12px; |
|||
.bracket-area { |
|||
background: var(--surface); |
|||
border: 1px solid var(--surface2); |
|||
} |
|||
font-family: "Nimbus Roman No9 L", "Times New Roman", Times, serif; |
|||
font-size: 0.88em; |
|||
.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); |
color: var(--text); |
||
letter-spacing: 0.01em; |
|||
opacity: 0; |
|||
transition: opacity 0.2s ease; |
|||
max-width: 220px; |
|||
z-index: 100; |
|||
box-shadow: 0 8px 32px rgba(0,0,0,0.4); |
|||
} |
} |
||
/* ---- MCR badge inside SCR ---- */ |
|||
.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 { |
.tier-badge { |
||
display: inline-block; |
display: inline-block; |
||
padding: |
padding: 1px 6px; |
||
border-radius: |
border-radius: 2px; |
||
font- |
font-size: 0.72em; |
||
font- |
font-weight: bold; |
||
margin-top: 3px; |
|||
background: rgba(255,255,255,0.18); |
|||
color: inherit; |
|||
cursor: pointer; |
|||
} |
} |
||
.block-scr .tier-badge { background: rgba(0,0,0,0.08); } |
|||
/* ---- Deficit block ---- */ |
|||
.tier-1 { background: rgba(52, 211, 153, 0.15); color: var(--accent-emerald); } |
|||
.block-deficit { |
|||
.tier-2 { background: rgba(251, 191, 36, 0.15); color: var(--accent-amber); } |
|||
background: #fff; |
|||
border: 2px dashed var(--text); |
|||
color: var(--text); |
|||
/* Status bar */ |
|||
.status-bar { |
|||
display: flex; |
|||
gap: 24px; |
|||
justify-content: center; |
|||
margin-top: 16px; |
|||
flex-wrap: wrap; |
|||
} |
} |
||
/* ---- Print ---- */ |
|||
.status-item { |
|||
@media print { |
|||
display: flex; |
|||
.side-panel { display: none; } |
|||
.main-grid { grid-template-columns: 1fr; } |
|||
gap: 8px; |
|||
.container { padding: 0; } |
|||
} |
|||
.bs-visual { border: 1px solid #000; } |
|||
.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> |
</style> |
||
| Line 652: | Line 377: | ||
<div class="container"> |
<div class="container"> |
||
<header> |
<header> |
||
<div class="eyebrow">Insurance Regulation Framework</div> |
|||
<h1>Solvency II Balance Sheet</h1> |
<h1>Solvency II Balance Sheet</h1> |
||
<p> |
<p>Interactive breakdown of the market-value balance sheet under the EU Solvency II Directive. Adjust the sliders and click any block to explore how assets, technical provisions, and capital requirements interconnect.</p> |
||
</header> |
</header> |
||
<div class="main-grid"> |
<div class="main-grid"> |
||
<!-- Left |
<!-- Left column: balance-sheet diagram --> |
||
<div> |
<div> |
||
<div class="bs-visual" id="bsVisual"> |
<div class="bs-visual" id="bsVisual"> |
||
<div class="bs-title-row"> |
<div class="bs-title-row"> |
||
<span class="bs-col-label">Assets</span> |
<span class="bs-col-label">Assets</span> |
||
<span class="bs-col-label">Liabilities & Own Funds</span> |
<span class="bs-col-label">Liabilities & Own Funds</span> |
||
</div> |
</div> |
||
<div class="bs-columns" id="bsColumns"> |
<div class="bs-columns" id="bsColumns"> |
||
<!-- Assets column --> |
|||
<div class="bs-col" id="assetsCol"></div> |
<div class="bs-col" id="assetsCol"></div> |
||
< |
<div class="bs-separator"><div class="line"></div></div> |
||
<div class="bs-separator"> |
|||
<div class="line"></div> |
|||
</div> |
|||
<!-- Liabilities column --> |
|||
<div class="bs-col" id="liabCol"></div> |
<div class="bs-col" id="liabCol"></div> |
||
</div> |
</div> |
||
<div class="legend-strip" id="legend"></div> |
<div class="legend-strip" id="legend"></div> |
||
</div> |
</div> |
||
<div class="status-bar" id="statusBar"></div> |
<div class="status-bar" id="statusBar"></div> |
||
</div> |
</div> |
||
<!-- Right: |
<!-- Right column: controls & info --> |
||
<div class="side-panel"> |
<div class="side-panel"> |
||
<!-- Solvency ratio --> |
<!-- Solvency ratio --> |
||
<div class="info-card gauge-card"> |
<div class="info-card gauge-card"> |
||
<div class="card-label">Solvency Ratio</div> |
<div class="card-label">Solvency Ratio</div> |
||
<div class="gauge-value" id="ratioValue"> |
<div class="gauge-value" id="ratioValue">—</div> |
||
<div class="gauge-label">Eligible Own Funds / SCR</div> |
<div class="gauge-label">Eligible Own Funds / SCR</div> |
||
<div class="gauge-bar-track"><div class="gauge-bar-fill" id="ratioBar"></div></div> |
|||
<div class="gauge-thresholds"> |
<div class="gauge-thresholds"> |
||
<span |
<span>0%</span> |
||
<span |
<span>100% min</span> |
||
<span |
<span>200%</span> |
||
</ |
<span>300%</span> |
||
<div style="margin-top:14px; height:6px; border-radius:3px; background:var(--border); overflow:hidden;"> |
|||
<div id="ratioBar" style="height:100%; border-radius:3px; transition: width 0.8s ease, background 0.5s ease;"></div> |
|||
</div> |
</div> |
||
</div> |
</div> |
||
<!-- |
<!-- Sliders --> |
||
<div class="info |
<div class="info-card"> |
||
<div class="card-label">Adjust Values ( |
<div class="card-label">Adjust Values (€ bn)</div> |
||
<div class="slider-group"> |
<div class="slider-group"> |
||
<div class="slider-header"> |
<div class="slider-header"> |
||
<label>Total Assets</label> |
<label>Total Assets</label> |
||
<span class="slider-val" id="valAssets |
<span class="slider-val" id="valAssets">150</span> |
||
</div> |
</div> |
||
<input type="range" id="sliderAssets" min="80" max="250" value="150"> |
<input type="range" id="sliderAssets" min="80" max="250" value="150"> |
||
| Line 714: | Line 430: | ||
<div class="slider-header"> |
<div class="slider-header"> |
||
<label>Best Estimate Liabilities</label> |
<label>Best Estimate Liabilities</label> |
||
<span class="slider-val" id="valBEL |
<span class="slider-val" id="valBEL">85</span> |
||
</div> |
</div> |
||
<input type="range" id="sliderBEL" min="30" max="180" value="85"> |
<input type="range" id="sliderBEL" min="30" max="180" value="85"> |
||
| Line 722: | Line 438: | ||
<div class="slider-header"> |
<div class="slider-header"> |
||
<label>Risk Margin</label> |
<label>Risk Margin</label> |
||
<span class="slider-val" id="valRM |
<span class="slider-val" id="valRM">8</span> |
||
</div> |
</div> |
||
<input type="range" id="sliderRM" min="1" max="30" value="8"> |
<input type="range" id="sliderRM" min="1" max="30" value="8"> |
||
| Line 730: | Line 446: | ||
<div class="slider-header"> |
<div class="slider-header"> |
||
<label>SCR</label> |
<label>SCR</label> |
||
<span class="slider-val" id="valSCR |
<span class="slider-val" id="valSCR">35</span> |
||
</div> |
</div> |
||
<input type="range" id="sliderSCR" min="10" max="80" value="35"> |
<input type="range" id="sliderSCR" min="10" max="80" value="35"> |
||
| Line 738: | Line 454: | ||
<div class="slider-header"> |
<div class="slider-header"> |
||
<label>MCR (% of SCR)</label> |
<label>MCR (% of SCR)</label> |
||
<span class="slider-val" id="valMCR |
<span class="slider-val" id="valMCR">35%</span> |
||
</div> |
</div> |
||
<input type="range" id="sliderMCR" min="20" max="50" value="35"> |
<input type="range" id="sliderMCR" min="20" max="50" value="35"> |
||
| Line 747: | Line 463: | ||
<div class="info-card" id="detailCard"> |
<div class="info-card" id="detailCard"> |
||
<div class="card-label">Component Detail</div> |
<div class="card-label">Component Detail</div> |
||
<h3 id="detailTitle"> |
<h3 id="detailTitle">Select a component</h3> |
||
<p id="detailDesc">Click or hover on any |
<p id="detailDesc">Click or hover on any block in the balance sheet to see its definition, purpose, and relationship to other elements.</p> |
||
<div class="formula" id="detailFormula" style="display:none;"></div> |
<div class="formula" id="detailFormula" style="display:none;"></div> |
||
</div> |
</div> |
||
| Line 754: | Line 470: | ||
</div> |
</div> |
||
</div> |
</div> |
||
<div class="tooltip" id="tooltip"></div> |
|||
<script> |
<script> |
||
const data = { |
const data = { assets: 150, bel: 85, rm: 8, scr: 35, mcrPct: 35 }; |
||
assets: 150, |
|||
bel: 85, |
|||
rm: 8, |
|||
scr: 35, |
|||
mcrPct: 35 |
|||
}; |
|||
const descriptions = { |
const descriptions = { |
||
| Line 775: | Line 483: | ||
title: 'Best Estimate Liabilities (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.', |
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 = |
formula: 'BEL = \u03A3 PV(expected future cash flows)' |
||
}, |
}, |
||
rm: { |
rm: { |
||
title: 'Risk Margin', |
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%).', |
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 |
formula: 'RM = CoC \u00D7 \u03A3 SCR(t) / (1 + r(t))^t' |
||
}, |
}, |
||
tp: { |
tp: { |
||
title: 'Technical Provisions (TP)', |
title: 'Technical Provisions (TP)', |
||
desc: 'The total value of insurance liabilities |
desc: 'The total value of insurance liabilities \u2014 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' |
formula: 'TP = BEL + Risk Margin' |
||
}, |
}, |
||
| Line 790: | Line 498: | ||
title: 'Solvency Capital Requirement', |
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.', |
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 = |
formula: 'SCR = VaR\u2089\u2089.\u2085%(Basic Own Funds) over 1 year' |
||
}, |
}, |
||
mcr: { |
mcr: { |
||
title: 'Minimum Capital Requirement', |
title: 'Minimum Capital Requirement', |
||
desc: 'The minimum level of security below which |
desc: 'The minimum level of security below which financial resources should not fall. Breach triggers ultimate supervisory intervention \u2014 the insurer\u2019s licence may be withdrawn. Bounded between 25\u201345% of SCR.', |
||
formula: 'MCR = max(25% |
formula: 'MCR = max(25% \u00D7 SCR, min(45% \u00D7 SCR, linear MCR))' |
||
}, |
}, |
||
surplus: { |
surplus: { |
||
title: 'Free Surplus', |
title: 'Free Surplus', |
||
desc: 'Own funds in excess of the SCR |
desc: 'Own funds in excess of the SCR \u2014 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 |
formula: 'Surplus = Own Funds \u2212 SCR' |
||
}, |
}, |
||
ownfunds: { |
ownfunds: { |
||
title: 'Eligible Own Funds', |
title: 'Eligible Own Funds', |
||
desc: 'Total own funds available to cover the SCR and MCR. Classified into Tier 1 (highest quality |
desc: 'Total own funds available to cover the SCR and MCR. Classified into Tier 1 (highest quality \u2014 equity, retained earnings), Tier 2 (subordinated debt), and Tier 3 (limited eligibility). Tiering limits apply when covering SCR/MCR.', |
||
formula: 'Own Funds = Assets |
formula: 'Own Funds = Assets \u2212 Technical Provisions' |
||
} |
} |
||
}; |
}; |
||
const legendItems = [ |
const legendItems = [ |
||
{ id: 'assets', label: 'Assets', color: 'var(--assets- |
{ id: 'assets', label: 'Assets', color: 'var(--assets-fill)' }, |
||
{ id: 'bel', label: 'BEL', color: 'var(--bel- |
{ id: 'bel', label: 'BEL', color: 'var(--bel-fill)' }, |
||
{ id: 'rm', label: 'Risk Margin', color: 'var(--rm- |
{ id: 'rm', label: 'Risk Margin', color: 'var(--rm-fill)' }, |
||
{ id: 'scr', label: 'SCR', color: 'var(--scr- |
{ id: 'scr', label: 'SCR', color: 'var(--scr-fill)' }, |
||
{ id: ' |
{ id: 'surplus', label: 'Surplus', color: 'var(--surplus-fill)' }, |
||
{ id: ' |
{ id: 'tp', label: 'Tech. Prov.', color: '#72777d' }, |
||
{ id: 'ownfunds', label: 'Own Funds', color: '#c8ccd1' }, |
|||
]; |
]; |
||
| Line 831: | Line 540: | ||
const total = data.assets; |
const total = data.assets; |
||
const totalLiab = tp + data.scr + Math.max(0, surplus); |
const totalLiab = tp + data.scr + Math.max(0, surplus); |
||
// Height proportions (use asset total as reference) |
|||
const ref = Math.max(total, totalLiab, 1); |
const ref = Math.max(total, totalLiab, 1); |
||
const totalH = 480; |
const totalH = 480; |
||
const pxPer = totalH / ref; |
const pxPer = totalH / ref; |
||
// Assets |
// Assets |
||
const |
const ac = document.getElementById('assetsCol'); |
||
ac.innerHTML = ''; |
|||
ac.appendChild(makeBlock('assets', 'block-assets', 'Total Assets', 'Market value', '\u20AC' + data.assets + 'bn', totalH)); |
|||
// Liabilities |
|||
const assetBlock = makeBlock('assets', 'block-assets', 'Total Assets', `Market value`, `€${data.assets}bn`, totalH); |
|||
const lc = document.getElementById('liabCol'); |
|||
assetsCol.appendChild(assetBlock); |
|||
lc.innerHTML = ''; |
|||
// Liabilities column |
|||
const liabCol = document.getElementById('liabCol'); |
|||
liabCol.innerHTML = ''; |
|||
// BEL |
|||
const belH = Math.max(32, data.bel * pxPer); |
const belH = Math.max(32, data.bel * pxPer); |
||
lc.appendChild(makeBlock('bel', 'block-bel', 'Best Estimate Liabilities', 'Discounted expected cash flows', '\u20AC' + data.bel + 'bn', belH)); |
|||
const rmH = Math.max(26, data.rm * pxPer); |
|||
// Risk Margin |
|||
lc.appendChild(makeBlock('rm', 'block-rm', 'Risk Margin', 'Cost-of-capital provision', '\u20AC' + data.rm + 'bn', rmH)); |
|||
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 scrH = Math.max(40, data.scr * pxPer); |
||
const scrBlock = makeBlock('scr', 'block-scr', 'SCR', |
const scrBlock = makeBlock('scr', 'block-scr', 'SCR', 'Solvency Capital Req.', '\u20AC' + data.scr + 'bn', scrH); |
||
// MCR badge inside SCR |
|||
const mcrBadge = document.createElement('div'); |
const mcrBadge = document.createElement('div'); |
||
mcrBadge.className = 'tier-badge |
mcrBadge.className = 'tier-badge'; |
||
mcrBadge.textContent = |
mcrBadge.textContent = 'MCR \u20AC' + mcr + 'bn'; |
||
mcrBadge.style.position = 'relative'; |
|||
mcrBadge.style.cursor = 'pointer'; |
mcrBadge.style.cursor = 'pointer'; |
||
mcrBadge.dataset.block = 'mcr'; |
mcrBadge.dataset.block = 'mcr'; |
||
mcrBadge.addEventListener('click', function(e) { e.stopPropagation(); showDetail('mcr'); }); |
|||
scrBlock.appendChild(mcrBadge); |
scrBlock.appendChild(mcrBadge); |
||
lc.appendChild(scrBlock); |
|||
// Surplus |
|||
if (surplus > 0) { |
if (surplus > 0) { |
||
const surpH = Math.max( |
const surpH = Math.max(26, surplus * pxPer); |
||
lc.appendChild(makeBlock('surplus', 'block-surplus', 'Free Surplus', 'Excess own funds', '\u20AC' + surplus + 'bn', surpH)); |
|||
} else if (ownFunds < data.scr) { |
} else if (ownFunds < data.scr) { |
||
const defBlock = makeBlock('surplus', 'block-deficit', 'Capital Shortfall', 'Own funds < SCR', '\u20AC' + Math.round(data.scr - ownFunds) + 'bn deficit', 32); |
|||
const deficitH = 32; |
|||
lc.appendChild(defBlock); |
|||
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 |
// Ratio |
||
var rVal = document.getElementById('ratioValue'); |
|||
var rBar = document.getElementById('ratioBar'); |
|||
rVal.textContent = |
rVal.textContent = Math.round(ratio) + '%'; |
||
rBar.style.width = Math.min(100, ratio / 3) + '%'; |
|||
rBar.style. |
rBar.style.opacity = ratio < 100 ? '0.35' : '1'; |
||
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 |
// Status |
||
var sb = document.getElementById('statusBar'); |
|||
var scrOk = ownFunds >= data.scr; |
|||
var mcrOk = ownFunds >= mcr; |
|||
sb.innerHTML = |
sb.innerHTML = |
||
'<div class="status-item"><div class="status-dot ' + (scrOk ? 'ok' : 'fail') + '"></div><span>SCR ' + (scrOk ? 'covered' : 'breached') + '</span></div>' + |
|||
<div class="status-item"> |
|||
'<div class="status-item"><div class="status-dot ' + (mcrOk ? 'ok' : 'fail') + '"></div><span>MCR ' + (mcrOk ? 'covered' : 'breached') + '</span></div>' + |
|||
'<div class="status-item"><div class="status-dot ' + (ratio >= 150 ? 'ok' : ratio >= 100 ? 'warn' : 'fail') + '"></div><span>Ratio: ' + Math.round(ratio) + '%</span></div>' + |
|||
<span>SCR ${scrStatus ? 'Covered' : 'Breached'}</span> |
|||
'<div class="status-item" style="cursor:pointer" onclick="showDetail(\'ownfunds\')"><span style="font-weight:bold">Own Funds: \u20AC' + Math.round(ownFunds) + 'bn</span></div>'; |
|||
</div> |
|||
<div class="status-item"> |
|||
<div class="status-dot ${mcrStatus ? 'green' : 'red'}"></div> |
|||
<span>MCR ${mcrStatus ? 'Covered' : 'Breached'}</span> |
|||
</div> |
|||
<div class="status-item"> |
|||
<div class="status-dot ${ratio >= 150 ? 'green' : ratio >= 100 ? 'amber' : 'red'}"></div> |
|||
<span>Ratio: ${Math.round(ratio)}%</span> |
|||
</div> |
|||
<div class="status-item" style="cursor:pointer;" onclick="showDetail('ownfunds')"> |
|||
<div class="status-dot" style="background:var(--accent-cyan);box-shadow:0 0 8px rgba(34,211,238,0.5);"></div> |
|||
<span>Own Funds: €${Math.round(ownFunds)}bn</span> |
|||
</div> |
|||
`; |
|||
// Legend |
// Legend |
||
var lg = document.getElementById('legend'); |
|||
lg.innerHTML = ''; |
|||
legendItems.forEach(l |
legendItems.forEach(function(l) { |
||
var el = document.createElement('div'); |
|||
el.className = 'legend-item'; |
|||
el.innerHTML = '<span class="legend-dot" style="background:' + l.color + '"></span>' + l.label; |
|||
el.onclick = function() { showDetail(l.id); }; |
|||
lg.appendChild(el); |
|||
}); |
|||
// 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 = `<span class="legend-dot" style="background:${l.color}"></span>${l.label}`; |
|||
li.onclick = () => showDetail(l.id); |
|||
legend.appendChild(li); |
|||
}); |
}); |
||
} |
} |
||
function makeBlock(id, cls, label, sublabel, value, height) { |
function makeBlock(id, cls, label, sublabel, value, height) { |
||
var el = document.createElement('div'); |
|||
el.className = |
el.className = 'bs-block ' + cls; |
||
el.style.height = height + 'px'; |
el.style.height = height + 'px'; |
||
el.dataset.block = id; |
el.dataset.block = id; |
||
el.innerHTML = |
el.innerHTML = |
||
<div class="label"> |
'<div class="label">' + label + '</div>' + |
||
(height > 38 ? '<div class="sublabel">' + sublabel + '</div>' : '') + |
|||
<div class="value"> |
'<div class="value">' + value + '</div>'; |
||
el.addEventListener('mouseenter', function() { showDetail(id); }); |
|||
`; |
|||
el.addEventListener(' |
el.addEventListener('click', function() { showDetail(id); }); |
||
el.addEventListener('click', () => showDetail(id)); |
|||
return el; |
return el; |
||
} |
} |
||
function showDetail(id) { |
function showDetail(id) { |
||
var info = descriptions[id]; |
|||
if (!info) return; |
if (!info) return; |
||
document.getElementById('detailTitle').textContent = info.title; |
document.getElementById('detailTitle').textContent = info.title; |
||
document.getElementById('detailDesc').textContent = info.desc; |
document.getElementById('detailDesc').textContent = info.desc; |
||
var fEl = document.getElementById('detailFormula'); |
|||
if (info.formula) { |
if (info.formula) { fEl.style.display = 'block'; fEl.textContent = info.formula; } |
||
fEl.style.display = ' |
else { fEl.style.display = 'none'; } |
||
document.querySelectorAll('.bs-block').forEach(function(b) { b.classList.remove('active'); }); |
|||
fEl.textContent = info.formula; |
|||
document.querySelectorAll('.bs-block[data-block="' + id + '"]').forEach(function(b) { b.classList.add('active'); }); |
|||
} 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')); |
|||
} |
} |
||
function bindSlider(sid, vid, key, suffix) { |
|||
// Slider bindings |
|||
var s = document.getElementById(sid); |
|||
function bindSlider(sliderId, valId, key, suffix = '') { |
|||
var v = document.getElementById(vid); |
|||
s.addEventListener('input', function() { |
|||
const valEl = document.getElementById(valId); |
|||
data[key] = parseInt(s.value); |
|||
slider.addEventListener('input', () => { |
|||
v.textContent = suffix ? s.value + suffix : s.value; |
|||
data[key] = v; |
|||
valEl.textContent = suffix ? v + suffix : v; |
|||
render(); |
render(); |
||
}); |
}); |
||
} |
} |
||
bindSlider('sliderAssets', 'valAssets', 'assets'); |
bindSlider('sliderAssets', 'valAssets', 'assets', ''); |
||
bindSlider('sliderBEL', 'valBEL', 'bel'); |
bindSlider('sliderBEL', 'valBEL', 'bel', ''); |
||
bindSlider('sliderRM', 'valRM', 'rm'); |
bindSlider('sliderRM', 'valRM', 'rm', ''); |
||
bindSlider('sliderSCR', 'valSCR', 'scr'); |
bindSlider('sliderSCR', 'valSCR', 'scr', ''); |
||
bindSlider('sliderMCR', 'valMCR', 'mcrPct', '%'); |
bindSlider('sliderMCR', 'valMCR', 'mcrPct', '%'); |
||
// Initial render |
|||
render(); |
render(); |
||
</script> |
</script> |
||
Revision as of 10:01, 31 March 2026
<!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> <style>
:root {
--bg: #ffffff;
--surface: #f8f9fa;
--surface2: #eaecf0;
--border: #a2a9b1;
--border-heavy: #202122;
--text: #202122;
--text-dim: #54595d;
--text-muted: #72777d;
--link: #000099;
/* Monochrome block palette — dark-to-light for visual hierarchy */ --assets-fill: #202122; --bel-fill: #54595d; --rm-fill: #72777d; --scr-fill: #a2a9b1; --mcr-fill: #c8ccd1; --surplus-fill: #eaecf0; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: sans-serif;
line-height: 1.6;
-webkit-font-smoothing: auto;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 24px 16px 60px;
}
/* ---- Header ---- */
header {
border-bottom: 2px solid var(--border-heavy);
padding-bottom: 10px;
margin-bottom: 20px;
}
header h1 {
font-size: 1.8em;
font-weight: bold;
color: var(--text);
line-height: 1.25;
margin: 0;
}
header p {
font-size: 0.88em;
color: var(--text-dim);
margin-top: 4px;
line-height: 1.6;
}
/* ---- Two-column master layout ---- */
.main-grid {
display: grid;
grid-template-columns: 1fr 300px;
gap: 24px;
align-items: start;
}
@media (max-width: 760px) {
.main-grid { grid-template-columns: 1fr; }
}
/* ---- Balance-sheet visual ---- */
.bs-visual {
border: 1px solid var(--border);
background: var(--bg);
padding: 20px 24px 16px;
}
.bs-title-row {
display: flex;
justify-content: space-between;
margin-bottom: 14px;
}
.bs-col-label {
font-size: 0.78em;
font-weight: bold;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-muted);
}
.bs-columns {
display: grid;
grid-template-columns: 1fr 24px 1fr;
min-height: 480px;
}
.bs-col {
display: flex;
flex-direction: column;
gap: 2px;
}
.bs-separator {
display: flex;
align-items: stretch;
justify-content: center;
}
.bs-separator .line {
width: 1px;
background: var(--border);
}
/* ---- Blocks ---- */
.bs-block {
padding: 12px 14px;
position: relative;
cursor: pointer;
transition: background 0.2s ease, box-shadow 0.2s ease;
display: flex;
flex-direction: column;
justify-content: center;
border: 1px solid transparent;
color: #fff;
}
.bs-block .label {
font-size: 0.82em;
font-weight: bold;
line-height: 1.3;
}
.bs-block .sublabel {
font-size: 0.72em;
opacity: 0.75;
margin-top: 1px;
}
.bs-block .value {
font-size: 0.88em;
font-weight: bold;
margin-top: 4px;
font-variant-numeric: tabular-nums;
}
.bs-block:hover {
box-shadow: 0 0 0 2px var(--border-heavy);
z-index: 2;
}
.bs-block.active {
box-shadow: 0 0 0 2.5px var(--border-heavy);
z-index: 3;
}
/* Individual block fills */
.block-assets { background: var(--assets-fill); }
.block-bel { background: var(--bel-fill); }
.block-rm { background: var(--rm-fill); }
.block-scr { background: var(--scr-fill); color: var(--text); }
.block-mcr { background: var(--mcr-fill); color: var(--text); }
.block-surplus { background: var(--surplus-fill); color: var(--text); border: 1px solid var(--border); }
/* ---- Legend ---- */
.legend-strip {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 16px;
border-top: 1px solid var(--border);
padding-top: 12px;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
padding: 3px 8px;
font-size: 0.75em;
color: var(--text-dim);
cursor: pointer;
border: 1px solid transparent;
border-radius: 2px;
transition: border-color 0.15s ease;
}
.legend-item:hover { border-color: var(--border); }
.legend-dot {
width: 10px; height: 10px;
border-radius: 1px;
flex-shrink: 0;
}
/* ---- Status bar ---- */
.status-bar {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-top: 12px;
font-size: 0.8em;
color: var(--text-dim);
}
.status-item {
display: flex;
align-items: center;
gap: 6px;
}
.status-dot {
width: 7px; height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
.status-dot.ok { background: var(--text); }
.status-dot.warn { background: var(--text-muted); }
.status-dot.fail { border: 2px solid var(--text); background: transparent; }
/* ---- Side panel ---- */
.side-panel {
display: flex;
flex-direction: column;
gap: 16px;
}
.info-card {
border: 1px solid var(--border);
background: var(--bg);
padding: 16px 18px;
}
.card-label {
font-size: 0.7em;
font-weight: bold;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 10px;
}
/* ---- Gauge ---- */
.gauge-card { text-align: center; padding: 18px; }
.gauge-value {
font-size: 2em;
font-weight: bold;
color: var(--text);
line-height: 1.1;
}
.gauge-label {
font-size: 0.78em;
color: var(--text-muted);
margin-top: 2px;
}
.gauge-bar-track {
margin-top: 14px;
height: 6px;
background: var(--surface2);
border-radius: 3px;
overflow: hidden;
}
.gauge-bar-fill {
height: 100%;
border-radius: 3px;
background: var(--text);
transition: width 0.6s ease;
}
.gauge-thresholds {
display: flex;
justify-content: space-between;
margin-top: 6px;
font-size: 0.68em;
color: var(--text-muted);
}
/* ---- Sliders ---- */
.slider-group { margin-bottom: 14px; }
.slider-group:last-child { margin-bottom: 0; }
.slider-header {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 5px;
}
.slider-header label {
font-size: 0.8em;
color: var(--text-dim);
}
.slider-val {
font-size: 0.8em;
font-weight: bold;
color: var(--text);
font-variant-numeric: tabular-nums;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 3px;
background: var(--surface2);
border-radius: 2px;
outline: none;
cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 14px; height: 14px;
border-radius: 50%;
background: var(--text);
cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 0 0 1px var(--border);
}
input[type="range"]::-moz-range-thumb {
width: 14px; height: 14px;
border-radius: 50%;
background: var(--text);
cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 0 0 1px var(--border);
}
/* ---- Detail card ---- */
.info-card h3 {
font-size: 1.05em;
font-weight: bold;
color: var(--text);
margin-bottom: 6px;
line-height: 1.3;
}
.info-card p {
font-size: 0.84em;
color: var(--text-dim);
line-height: 1.6;
}
.formula {
margin-top: 10px;
padding: 8px 12px;
background: var(--surface);
border: 1px solid var(--surface2);
font-family: "Nimbus Roman No9 L", "Times New Roman", Times, serif;
font-size: 0.88em;
color: var(--text);
letter-spacing: 0.01em;
}
/* ---- MCR badge inside SCR ---- */
.tier-badge {
display: inline-block;
padding: 1px 6px;
border-radius: 2px;
font-size: 0.72em;
font-weight: bold;
margin-top: 3px;
background: rgba(255,255,255,0.18);
color: inherit;
cursor: pointer;
}
.block-scr .tier-badge { background: rgba(0,0,0,0.08); }
/* ---- Deficit block ---- */
.block-deficit {
background: #fff;
border: 2px dashed var(--text);
color: var(--text);
}
/* ---- Print ---- */
@media print {
.side-panel { display: none; }
.main-grid { grid-template-columns: 1fr; }
.container { padding: 0; }
.bs-visual { border: 1px solid #000; }
}
</style> </head> <body>
<header>
Solvency II Balance Sheet
Interactive breakdown of the market-value balance sheet under the EU Solvency II Directive. Adjust the sliders and click any block to explore how assets, technical provisions, and capital requirements interconnect.
</header>
Assets Liabilities & Own Funds
0% 100% min 200% 300%
Select a component
Click or hover on any block in the balance sheet to see its definition, purpose, and relationship 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 = \u03A3 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 \u00D7 \u03A3 SCR(t) / (1 + r(t))^t'
},
tp: {
title: 'Technical Provisions (TP)',
desc: 'The total value of insurance liabilities \u2014 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\u2089\u2089.\u2085%(Basic Own Funds) over 1 year'
},
mcr: {
title: 'Minimum Capital Requirement',
desc: 'The minimum level of security below which financial resources should not fall. Breach triggers ultimate supervisory intervention \u2014 the insurer\u2019s licence may be withdrawn. Bounded between 25\u201345% of SCR.',
formula: 'MCR = max(25% \u00D7 SCR, min(45% \u00D7 SCR, linear MCR))'
},
surplus: {
title: 'Free Surplus',
desc: 'Own funds in excess of the SCR \u2014 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 \u2212 SCR'
},
ownfunds: {
title: 'Eligible Own Funds',
desc: 'Total own funds available to cover the SCR and MCR. Classified into Tier 1 (highest quality \u2014 equity, retained earnings), Tier 2 (subordinated debt), and Tier 3 (limited eligibility). Tiering limits apply when covering SCR/MCR.',
formula: 'Own Funds = Assets \u2212 Technical Provisions'
}
};
const legendItems = [
{ id: 'assets', label: 'Assets', color: 'var(--assets-fill)' },
{ id: 'bel', label: 'BEL', color: 'var(--bel-fill)' },
{ id: 'rm', label: 'Risk Margin', color: 'var(--rm-fill)' },
{ id: 'scr', label: 'SCR', color: 'var(--scr-fill)' },
{ id: 'surplus', label: 'Surplus', color: 'var(--surplus-fill)' },
{ id: 'tp', label: 'Tech. Prov.', color: '#72777d' },
{ id: 'ownfunds', label: 'Own Funds', color: '#c8ccd1' },
];
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);
const ref = Math.max(total, totalLiab, 1);
const totalH = 480;
const pxPer = totalH / ref;
// Assets
const ac = document.getElementById('assetsCol');
ac.innerHTML = ;
ac.appendChild(makeBlock('assets', 'block-assets', 'Total Assets', 'Market value', '\u20AC' + data.assets + 'bn', totalH));
// Liabilities
const lc = document.getElementById('liabCol');
lc.innerHTML = ;
const belH = Math.max(32, data.bel * pxPer);
lc.appendChild(makeBlock('bel', 'block-bel', 'Best Estimate Liabilities', 'Discounted expected cash flows', '\u20AC' + data.bel + 'bn', belH));
const rmH = Math.max(26, data.rm * pxPer);
lc.appendChild(makeBlock('rm', 'block-rm', 'Risk Margin', 'Cost-of-capital provision', '\u20AC' + data.rm + 'bn', rmH));
const scrH = Math.max(40, data.scr * pxPer);
const scrBlock = makeBlock('scr', 'block-scr', 'SCR', 'Solvency Capital Req.', '\u20AC' + data.scr + 'bn', scrH);
const mcrBadge = document.createElement('div');
mcrBadge.className = 'tier-badge';
mcrBadge.textContent = 'MCR \u20AC' + mcr + 'bn';
mcrBadge.style.cursor = 'pointer';
mcrBadge.dataset.block = 'mcr';
mcrBadge.addEventListener('click', function(e) { e.stopPropagation(); showDetail('mcr'); });
scrBlock.appendChild(mcrBadge);
lc.appendChild(scrBlock);
if (surplus > 0) {
const surpH = Math.max(26, surplus * pxPer);
lc.appendChild(makeBlock('surplus', 'block-surplus', 'Free Surplus', 'Excess own funds', '\u20AC' + surplus + 'bn', surpH));
} else if (ownFunds < data.scr) {
const defBlock = makeBlock('surplus', 'block-deficit', 'Capital Shortfall', 'Own funds < SCR', '\u20AC' + Math.round(data.scr - ownFunds) + 'bn deficit', 32);
lc.appendChild(defBlock);
}
// Ratio
var rVal = document.getElementById('ratioValue');
var rBar = document.getElementById('ratioBar');
rVal.textContent = Math.round(ratio) + '%';
rBar.style.width = Math.min(100, ratio / 3) + '%';
rBar.style.opacity = ratio < 100 ? '0.35' : '1';
// Status
var sb = document.getElementById('statusBar');
var scrOk = ownFunds >= data.scr;
var mcrOk = ownFunds >= mcr;
sb.innerHTML =
'
' + '
' + '
' + '
';
// Legend
var lg = document.getElementById('legend');
lg.innerHTML = ;
legendItems.forEach(function(l) {
var el = document.createElement('div');
el.className = 'legend-item';
el.innerHTML = '' + l.label;
el.onclick = function() { showDetail(l.id); };
lg.appendChild(el);
});
}
function makeBlock(id, cls, label, sublabel, value, height) {
var el = document.createElement('div');
el.className = 'bs-block ' + cls;
el.style.height = height + 'px';
el.dataset.block = id;
el.innerHTML =
'
' + (height > 38 ? '
' : ) + '
';
el.addEventListener('mouseenter', function() { showDetail(id); });
el.addEventListener('click', function() { showDetail(id); });
return el;
}
function showDetail(id) {
var info = descriptions[id];
if (!info) return;
document.getElementById('detailTitle').textContent = info.title;
document.getElementById('detailDesc').textContent = info.desc;
var fEl = document.getElementById('detailFormula');
if (info.formula) { fEl.style.display = 'block'; fEl.textContent = info.formula; }
else { fEl.style.display = 'none'; }
document.querySelectorAll('.bs-block').forEach(function(b) { b.classList.remove('active'); });
document.querySelectorAll('.bs-block[data-block="' + id + '"]').forEach(function(b) { b.classList.add('active'); });
}
function bindSlider(sid, vid, key, suffix) {
var s = document.getElementById(sid);
var v = document.getElementById(vid);
s.addEventListener('input', function() {
data[key] = parseInt(s.value);
v.textContent = suffix ? s.value + suffix : s.value;
render();
});
}
bindSlider('sliderAssets', 'valAssets', 'assets', ); bindSlider('sliderBEL', 'valBEL', 'bel', ); bindSlider('sliderRM', 'valRM', 'rm', ); bindSlider('sliderSCR', 'valSCR', 'scr', ); bindSlider('sliderMCR', 'valMCR', 'mcrPct', '%');
render(); </script> </body> </html>