Insurance — Premium Breakdown
A reassuring premium breakdown card with a CSS stacked donut showing base cover, risk factors, add-ons, taxes and discounts, a line-item list with amounts, a savings-highlighted discounts section, and a billing-cycle toggle that recalculates the totals live.
MCP
Code
:root {
--blue: #2563eb;
--blue-d: #1d4ed8;
--green: #15a06b;
--blue-50: #eef4ff;
--ink: #0f1a2b;
--muted: #5a6b82;
--bg: #f3f7fc;
--white: #ffffff;
/* component colour keys */
--c-base: #2563eb;
--c-risk: #7c9cf6;
--c-addons: #15a06b;
--c-tax: #f59e0b;
--c-disc: #c7d6f5;
--line: #e4ecf7;
--radius: 18px;
--shadow: 0 10px 30px rgba(37, 99, 235, 0.10);
font-family: 'Inter', system-ui, -apple-system, sans-serif;
}
*,
*::before,
*::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: 'Inter', system-ui, -apple-system, sans-serif;
line-height: 1.45;
-webkit-font-smoothing: antialiased;
}
.wrap {
min-height: 100vh;
display: grid;
place-items: center;
padding: 32px 16px;
}
.card {
width: 100%;
max-width: 480px;
background: var(--white);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
padding: 26px;
}
.card__head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-bottom: 22px;
}
.eyebrow {
margin: 0 0 6px;
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--blue);
}
h1 {
margin: 0;
font-size: 1.32rem;
font-weight: 800;
letter-spacing: -0.01em;
}
.sub {
margin: 4px 0 0;
font-size: 0.85rem;
color: var(--muted);
}
/* billing toggle */
.toggle {
flex: none;
display: inline-flex;
background: var(--blue-50);
border-radius: 999px;
padding: 3px;
}
.toggle__btn {
border: 0;
background: transparent;
font: inherit;
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
padding: 7px 13px;
border-radius: 999px;
cursor: pointer;
transition: background 0.18s, color 0.18s, box-shadow 0.18s;
}
.toggle__btn.is-active {
background: var(--white);
color: var(--blue-d);
box-shadow: 0 2px 6px rgba(15, 26, 43, 0.10);
}
.toggle__btn:focus-visible {
outline: 2px solid var(--blue);
outline-offset: 2px;
}
/* chart */
.chart {
display: flex;
align-items: center;
gap: 22px;
padding: 6px 0 22px;
border-bottom: 1px solid var(--line);
margin-bottom: 6px;
}
.donut {
flex: none;
width: 156px;
height: 156px;
border-radius: 50%;
display: grid;
place-items: center;
background:
conic-gradient(var(--c-base) 0deg, var(--c-base) var(--a, 0deg), #e9eef7 var(--a, 0deg));
transition: background 0.5s ease;
}
.donut__hole {
width: 108px;
height: 108px;
border-radius: 50%;
background: var(--white);
box-shadow: inset 0 0 0 1px var(--line);
display: grid;
place-content: center;
text-align: center;
}
.donut__cap {
font-size: 0.66rem;
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--muted);
}
.donut__total {
display: block;
font-size: 1.55rem;
font-weight: 800;
letter-spacing: -0.02em;
color: var(--ink);
line-height: 1.1;
}
.donut__unit {
font-size: 0.72rem;
color: var(--muted);
}
.legend {
list-style: none;
margin: 0;
padding: 0;
flex: 1;
display: grid;
gap: 9px;
}
.legend li {
display: flex;
align-items: center;
gap: 9px;
font-size: 0.82rem;
}
.legend .dot {
width: 11px;
height: 11px;
border-radius: 3px;
flex: none;
}
.legend .name { color: var(--ink); font-weight: 500; }
.legend .pct { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
/* line items */
.section-title {
margin: 20px 0 10px;
font-size: 0.95rem;
font-weight: 700;
}
.items {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 2px;
}
.items li {
display: flex;
align-items: center;
gap: 12px;
padding: 11px 12px;
border-radius: 12px;
transition: background 0.15s;
}
.items li:hover { background: var(--blue-50); }
.items .key {
width: 10px;
height: 10px;
border-radius: 3px;
flex: none;
}
.items .label { font-size: 0.88rem; font-weight: 500; }
.items .note { display: block; font-size: 0.74rem; color: var(--muted); font-weight: 400; }
.items .amount {
margin-left: auto;
font-weight: 700;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.items .amount.is-credit { color: var(--green); }
/* savings panel */
.savings {
margin-top: 18px;
background: linear-gradient(160deg, #eafaf2, #f1fbf6);
border: 1px solid #c8edda;
border-radius: 14px;
padding: 16px 16px 12px;
}
.savings__head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.savings__title {
margin: 0;
font-size: 0.95rem;
font-weight: 700;
color: #0c7a51;
}
.savings__sub { margin: 3px 0 0; font-size: 0.78rem; color: #3f7d63; }
.savings__amt { text-align: right; flex: none; }
.savings__amt span { display: block; font-size: 0.7rem; color: #3f7d63; font-weight: 600; }
.savings__amt strong {
font-size: 1.35rem;
font-weight: 800;
color: var(--green);
letter-spacing: -0.01em;
font-variant-numeric: tabular-nums;
}
.savings__list {
list-style: none;
margin: 12px 0 0;
padding: 0;
display: grid;
gap: 2px;
}
.savings__list li {
display: flex;
align-items: center;
gap: 9px;
font-size: 0.82rem;
color: #14502f;
padding: 6px 2px;
}
.savings__list .check {
width: 17px;
height: 17px;
border-radius: 50%;
background: var(--green);
color: #fff;
display: grid;
place-items: center;
font-size: 0.66rem;
font-weight: 800;
flex: none;
}
.savings__list .save {
margin-left: auto;
font-weight: 700;
color: var(--green);
font-variant-numeric: tabular-nums;
}
/* footer */
.card__foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
margin-top: 22px;
padding-top: 18px;
border-top: 1px solid var(--line);
}
.foot__total span { font-size: 0.78rem; color: var(--muted); }
.foot__total strong {
display: block;
font-size: 1.6rem;
font-weight: 800;
letter-spacing: -0.02em;
font-variant-numeric: tabular-nums;
}
.pay-btn {
flex: none;
border: 0;
font: inherit;
font-weight: 700;
font-size: 0.92rem;
color: #fff;
background: var(--blue);
padding: 13px 22px;
border-radius: 12px;
cursor: pointer;
box-shadow: 0 6px 16px rgba(37, 99, 235, 0.30);
transition: background 0.18s, transform 0.1s, box-shadow 0.18s;
}
.pay-btn:hover { background: var(--blue-d); }
.pay-btn:active { transform: translateY(1px); }
.pay-btn:focus-visible { outline: 2px solid var(--blue-d); outline-offset: 3px; }
@media (max-width: 520px) {
.card { padding: 20px; }
.card__head { flex-direction: column; }
.chart { flex-direction: column; align-items: stretch; text-align: center; }
.donut { margin: 0 auto; }
.legend { width: 100%; }
.card__foot { flex-direction: column; align-items: stretch; }
.foot__total { display: flex; align-items: baseline; justify-content: space-between; }
.foot__total strong { display: inline; }
.pay-btn { width: 100%; }
}(function () {
'use strict';
// Annual figures (in dollars). Discount is a negative credit.
var COMPONENTS = [
{ key: 'base', label: 'Base cover', note: 'Liability + collision', color: 'var(--c-base)', amount: 980 },
{ key: 'risk', label: 'Risk factors', note: 'Driver age & area', color: 'var(--c-risk)', amount: 264 },
{ key: 'addons', label: 'Add-ons', note: 'Roadside + glass', color: 'var(--c-addons)', amount: 168 },
{ key: 'tax', label: 'Taxes & fees', note: 'State premium tax', color: 'var(--c-tax)', amount: 88 },
{ key: 'disc', label: 'Discounts', note: '3 applied', color: 'var(--c-disc)', amount: -216, credit: true }
];
var DISCOUNTS = [
{ label: 'Safe driver (5 yrs no claims)', amount: 118 },
{ label: 'Multi-policy bundle', amount: 64 },
{ label: 'Paid in full', amount: 34 }
];
var state = { cycle: 'annual' };
function money(n) {
var abs = Math.abs(n);
var s = abs.toFixed(2);
// drop .00 for whole dollars
if (s.slice(-3) === '.00') s = s.slice(0, -3);
s = s.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return (n < 0 ? '-$' : '$') + s;
}
function conv(n) {
return state.cycle === 'monthly' ? n / 12 : n;
}
var positives = COMPONENTS.filter(function (c) { return !c.credit; });
var grossAnnual = positives.reduce(function (s, c) { return s + c.amount; }, 0);
var creditAnnual = COMPONENTS
.filter(function (c) { return c.credit; })
.reduce(function (s, c) { return s + c.amount; }, 0); // negative
var netAnnual = grossAnnual + creditAnnual;
var savingsAnnual = -creditAnnual;
// ---- donut (only positive charge components fill the ring) ----
function buildDonut() {
var donut = document.getElementById('donut');
var stops = [];
var acc = 0;
positives.forEach(function (c) {
var startPct = (acc / grossAnnual) * 100;
acc += c.amount;
var endPct = (acc / grossAnnual) * 100;
stops.push(c.color + ' ' + startPct.toFixed(2) + '% ' + endPct.toFixed(2) + '%');
});
donut.style.background = 'conic-gradient(' + stops.join(', ') + ')';
}
function buildLegend() {
var ul = document.getElementById('legend');
ul.innerHTML = '';
positives.forEach(function (c) {
var pct = Math.round((c.amount / grossAnnual) * 100);
var li = document.createElement('li');
var dot = document.createElement('span');
dot.className = 'dot';
dot.style.background = c.color;
var name = document.createElement('span');
name.className = 'name';
name.textContent = c.label;
var p = document.createElement('span');
p.className = 'pct';
p.textContent = pct + '%';
li.appendChild(dot);
li.appendChild(name);
li.appendChild(p);
ul.appendChild(li);
});
}
function buildItems() {
var ul = document.getElementById('items');
ul.innerHTML = '';
COMPONENTS.forEach(function (c) {
var li = document.createElement('li');
var key = document.createElement('span');
key.className = 'key';
key.style.background = c.color;
var wrap = document.createElement('span');
var label = document.createElement('span');
label.className = 'label';
label.textContent = c.label;
var note = document.createElement('span');
note.className = 'note';
note.textContent = c.note;
wrap.appendChild(label);
wrap.appendChild(note);
var amt = document.createElement('span');
amt.className = 'amount' + (c.credit ? ' is-credit' : '');
amt.textContent = (c.credit ? '−' : '') + money(Math.abs(conv(c.amount)));
amt.dataset.base = c.amount;
li.appendChild(key);
li.appendChild(wrap);
li.appendChild(amt);
ul.appendChild(li);
});
}
function buildDiscounts() {
var ul = document.getElementById('discounts');
ul.innerHTML = '';
DISCOUNTS.forEach(function (d) {
var li = document.createElement('li');
var check = document.createElement('span');
check.className = 'check';
check.textContent = '✓';
check.setAttribute('aria-hidden', 'true');
var label = document.createElement('span');
label.textContent = d.label;
var save = document.createElement('span');
save.className = 'save';
save.textContent = '−' + money(conv(d.amount));
li.appendChild(check);
li.appendChild(label);
li.appendChild(save);
ul.appendChild(li);
});
}
function refreshTotals() {
var monthly = state.cycle === 'monthly';
var net = conv(netAnnual);
var save = conv(savingsAnnual);
document.getElementById('totalBig').textContent = money(net);
document.getElementById('totalUnit').textContent = monthly ? 'per month' : 'per year';
document.getElementById('saveBig').textContent = money(save);
document.getElementById('footBig').textContent = money(net);
document.getElementById('footUnit').textContent = monthly ? 'monthly' : 'annually';
}
function setCycle(cycle) {
state.cycle = cycle;
document.querySelectorAll('.toggle__btn').forEach(function (b) {
var on = b.dataset.cycle === cycle;
b.classList.toggle('is-active', on);
b.setAttribute('aria-pressed', on ? 'true' : 'false');
});
buildItems();
buildDiscounts();
refreshTotals();
}
document.querySelectorAll('.toggle__btn').forEach(function (b) {
b.addEventListener('click', function () { setCycle(b.dataset.cycle); });
});
document.querySelector('.pay-btn').addEventListener('click', function () {
var btn = this;
var original = btn.textContent;
btn.textContent = 'Payment confirmed ✓';
btn.style.background = 'var(--green)';
btn.disabled = true;
setTimeout(function () {
btn.textContent = original;
btn.style.background = '';
btn.disabled = false;
}, 1800);
});
// init
buildDonut();
buildLegend();
buildItems();
buildDiscounts();
refreshTotals();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Premium Breakdown</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="wrap">
<section class="card" aria-labelledby="bd-title">
<header class="card__head">
<div>
<p class="eyebrow">Auto policy · ER-48201</p>
<h1 id="bd-title">Your premium breakdown</h1>
<p class="sub">Coverage period 01 Jul 2026 – 30 Jun 2027</p>
</div>
<div class="toggle" role="group" aria-label="Billing cycle">
<button type="button" class="toggle__btn is-active" data-cycle="annual" aria-pressed="true">Annual</button>
<button type="button" class="toggle__btn" data-cycle="monthly" aria-pressed="false">Monthly</button>
</div>
</header>
<div class="chart">
<div class="donut" role="img" aria-label="Stacked donut chart of premium components" id="donut">
<div class="donut__hole">
<span class="donut__cap">You pay</span>
<strong class="donut__total" id="totalBig">$1,284</strong>
<span class="donut__unit" id="totalUnit">per year</span>
</div>
</div>
<ul class="legend" id="legend"></ul>
</div>
<h2 class="section-title">Line items</h2>
<ul class="items" id="items"></ul>
<div class="savings" aria-labelledby="sv-title">
<div class="savings__head">
<div>
<h2 id="sv-title" class="savings__title">Discounts applied</h2>
<p class="savings__sub">3 discounts qualified on this policy</p>
</div>
<div class="savings__amt">
<span>You save</span>
<strong id="saveBig">$216</strong>
</div>
</div>
<ul class="savings__list" id="discounts"></ul>
</div>
<footer class="card__foot">
<div class="foot__total">
<span>Total due <span id="footUnit">annually</span></span>
<strong id="footBig">$1,284</strong>
</div>
<button type="button" class="pay-btn">Confirm & pay</button>
</footer>
</section>
</main>
<script src="script.js"></script>
</body>
</html>Premium Breakdown
A calm, trust-forward summary of exactly what a customer is paying for. A pure-CSS stacked donut charts the five components of the premium — base cover, risk factors, add-ons, taxes and the discount credit — alongside a colour-keyed legend and a big confident annual figure in the middle.
Below the chart a clear line-item list breaks every charge down to the cent, and a dedicated discounts applied panel highlights the total savings in trust green with each qualifying discount listed. A monthly / annual billing toggle recalculates the headline number, the line items and the savings live, all in vanilla JS with no libraries.
Illustrative UI only — not a real insurance quote.