Insurance — Policy Dashboard
A policyholder dashboard with summary stat cards, active policy cards showing premium, renewal date and renewal-soon badges, a next-payment-due panel with an inline pay flow, open claims tracking, coverage-at-a-glance bars and quick actions to file a claim, pay or download an ID card.
MCP
Code
:root {
--blue: #2563eb;
--blue-d: #1d4ed8;
--blue-50: #eef4ff;
--green: #15a06b;
--green-50: #e6f6ee;
--amber: #d97706;
--amber-50: #fef3e2;
--red: #dc2626;
--ink: #0f1a2b;
--muted: #5a6b82;
--bg: #f3f7fc;
--white: #ffffff;
--line: #e4ecf6;
--radius: 16px;
--radius-sm: 11px;
--shadow: 0 1px 2px rgba(15, 26, 43, .04), 0 8px 24px rgba(15, 26, 43, .06);
--font: 'Inter', system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font);
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
padding: 28px 18px 56px;
}
.dash { max-width: 1080px; margin: 0 auto; }
/* Header */
.dash__head {
display: flex; align-items: center; justify-content: space-between;
gap: 16px; flex-wrap: wrap; margin-bottom: 22px;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand__mark {
width: 46px; height: 46px; border-radius: 13px; flex: none;
background: linear-gradient(135deg, var(--blue), var(--blue-d));
color: #fff; display: grid; place-items: center;
box-shadow: 0 6px 16px rgba(37, 99, 235, .3);
}
.brand__name { font-size: .8rem; font-weight: 600; color: var(--muted); letter-spacing: .02em; }
.brand__welcome { font-size: 1.4rem; font-weight: 800; letter-spacing: -.02em; }
.member { display: flex; align-items: center; gap: 12px; }
.member__id { font-size: .82rem; color: var(--muted); font-weight: 500; }
.member__avatar {
width: 40px; height: 40px; border-radius: 50%;
background: var(--blue-50); color: var(--blue-d);
display: grid; place-items: center; font-weight: 700; font-size: .85rem;
}
/* Stats */
.stats {
display: grid; grid-template-columns: repeat(4, 1fr);
gap: 14px; margin-bottom: 18px;
}
.stat {
background: var(--white); border: 1px solid var(--line);
border-radius: var(--radius); padding: 16px;
display: flex; align-items: center; gap: 13px; box-shadow: var(--shadow);
}
.stat__icon {
width: 40px; height: 40px; border-radius: 11px; flex: none;
display: grid; place-items: center;
}
.stat__icon--blue { background: var(--blue-50); color: var(--blue-d); }
.stat__icon--green { background: var(--green-50); color: var(--green); }
.stat__icon--amber { background: var(--amber-50); color: var(--amber); }
.stat__value { font-size: 1.45rem; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.stat__label { font-size: .78rem; color: var(--muted); font-weight: 500; }
/* Layout grid */
.grid {
display: grid; grid-template-columns: 1.55fr 1fr;
gap: 18px; margin-bottom: 18px;
}
.side { display: flex; flex-direction: column; gap: 18px; }
/* Panels */
.panel {
background: var(--white); border: 1px solid var(--line);
border-radius: var(--radius); padding: 20px; box-shadow: var(--shadow);
}
.panel__head {
display: flex; align-items: center; justify-content: space-between;
gap: 10px; margin-bottom: 16px;
}
.panel__title { font-size: 1.02rem; font-weight: 700; letter-spacing: -.01em; }
.link-btn {
border: 0; background: none; color: var(--blue-d);
font: inherit; font-weight: 600; font-size: .85rem; cursor: pointer;
padding: 4px 6px; border-radius: 7px;
}
.link-btn:hover { background: var(--blue-50); }
/* Policies */
.policies { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.policy {
display: flex; align-items: center; gap: 14px;
border: 1px solid var(--line); border-radius: var(--radius-sm);
padding: 14px 16px; transition: border-color .15s, box-shadow .15s, transform .15s;
}
.policy:hover { border-color: #cfe0f6; box-shadow: 0 4px 14px rgba(15, 26, 43, .06); transform: translateY(-1px); }
.policy__icon {
width: 44px; height: 44px; border-radius: 12px; flex: none;
background: var(--blue-50); color: var(--blue-d);
display: grid; place-items: center;
}
.policy__main { flex: 1; min-width: 0; }
.policy__type { font-weight: 700; font-size: .96rem; }
.policy__num { font-size: .78rem; color: var(--muted); }
.policy__renew { font-size: .78rem; color: var(--muted); margin-top: 3px; }
.policy__renew strong { color: var(--ink); font-weight: 600; }
.policy__right { text-align: right; flex: none; }
.policy__premium { font-weight: 800; font-size: 1rem; letter-spacing: -.01em; }
.policy__premium span { font-size: .72rem; font-weight: 500; color: var(--muted); }
/* Badges */
.badge {
display: inline-flex; align-items: center; gap: 5px;
font-size: .72rem; font-weight: 600; padding: 3px 9px;
border-radius: 999px; margin-top: 6px; white-space: nowrap;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.badge--active { background: var(--green-50); color: var(--green); }
.badge--soon { background: var(--amber-50); color: var(--amber); animation: pulse 1.8s ease-in-out infinite; }
.badge--lapsed { background: #fee2e2; color: var(--red); }
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(217, 119, 6, .35); }
50% { box-shadow: 0 0 0 5px rgba(217, 119, 6, 0); }
}
/* Payment panel */
.pay { background: linear-gradient(160deg, #fff, #f7fbff); }
.pay__chip {
font-size: .72rem; font-weight: 600; color: var(--amber);
background: var(--amber-50); padding: 4px 10px; border-radius: 999px;
}
.pay__amount { font-size: 2.1rem; font-weight: 800; letter-spacing: -.03em; }
.pay__meta { font-size: .82rem; color: var(--muted); margin: 4px 0 16px; }
.pay__meta strong { color: var(--ink); font-weight: 600; }
.pay__actions { display: flex; gap: 10px; flex-wrap: wrap; }
.pay__confirm p { font-size: .92rem; margin-bottom: 14px; }
.pay--done .pay__amount { color: var(--green); }
/* Buttons */
.btn {
font: inherit; font-weight: 600; font-size: .88rem;
border-radius: 10px; padding: 10px 16px; cursor: pointer;
border: 1px solid transparent; transition: background .15s, border-color .15s, transform .1s;
}
.btn:active { transform: scale(.98); }
.btn--primary { background: var(--blue); color: #fff; }
.btn--primary:hover { background: var(--blue-d); }
.btn--ghost { background: #fff; border-color: var(--line); color: var(--ink); }
.btn--ghost:hover { border-color: #cfe0f6; background: var(--blue-50); }
/* Quick actions */
.qa { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.qa__btn {
display: flex; flex-direction: column; align-items: center; gap: 8px;
border: 1px solid var(--line); border-radius: var(--radius-sm);
background: #fff; padding: 16px 8px; cursor: pointer;
font: inherit; font-weight: 600; font-size: .8rem; color: var(--ink);
transition: border-color .15s, background .15s, transform .15s;
}
.qa__btn:hover { border-color: #cfe0f6; background: var(--blue-50); transform: translateY(-2px); }
.qa__icon { color: var(--blue-d); }
/* Coverage bars */
.coverage { list-style: none; display: flex; flex-direction: column; gap: 15px; }
.cov__top { display: flex; justify-content: space-between; font-size: .84rem; margin-bottom: 6px; }
.cov__name { font-weight: 600; }
.cov__nums { color: var(--muted); font-weight: 500; }
.cov__track { height: 8px; border-radius: 999px; background: var(--blue-50); overflow: hidden; }
.cov__fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--blue), var(--blue-d)); width: 0; transition: width .9s cubic-bezier(.4, 0, .2, 1); }
.cov__fill--high { background: linear-gradient(90deg, #f59e0b, var(--amber)); }
/* Claims */
.claims { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.claim {
border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 15px 16px;
}
.claim__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.claim__title { font-weight: 700; font-size: .94rem; }
.claim__sub { font-size: .78rem; color: var(--muted); }
.claim__amount { font-weight: 700; font-size: .95rem; }
.steps { display: flex; align-items: center; gap: 0; margin-top: 14px; }
.step { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; position: relative; }
.step:not(:last-child)::after {
content: ""; position: absolute; top: 9px; left: 50%; width: 100%; height: 2px;
background: var(--line); z-index: 0;
}
.step--done:not(:last-child)::after { background: var(--green); }
.step__dot {
width: 20px; height: 20px; border-radius: 50%; background: #fff;
border: 2px solid var(--line); z-index: 1; display: grid; place-items: center;
}
.step--done .step__dot { background: var(--green); border-color: var(--green); }
.step--active .step__dot { border-color: var(--blue); box-shadow: 0 0 0 4px var(--blue-50); }
.step__dot svg { width: 11px; height: 11px; color: #fff; }
.step__label { font-size: .68rem; color: var(--muted); font-weight: 500; text-align: center; }
.step--done .step__label, .step--active .step__label { color: var(--ink); font-weight: 600; }
/* Toast */
.toast {
position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(12px);
background: var(--ink); color: #fff; padding: 12px 20px; border-radius: 12px;
font-size: .88rem; font-weight: 500; box-shadow: 0 10px 30px rgba(15, 26, 43, .25);
opacity: 0; transition: opacity .25s, transform .25s; z-index: 50;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Focus */
button:focus-visible, .link-btn:focus-visible {
outline: 2px solid var(--blue); outline-offset: 2px;
}
/* Responsive */
@media (max-width: 820px) {
.stats { grid-template-columns: repeat(2, 1fr); }
.grid { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
body { padding: 18px 12px 48px; }
.stats { grid-template-columns: 1fr 1fr; gap: 10px; }
.stat { padding: 13px; }
.stat__value { font-size: 1.25rem; }
.policy { flex-wrap: wrap; }
.policy__right { text-align: left; width: 100%; display: flex; align-items: center; justify-content: space-between; }
.policy__premium { order: 1; }
.badge { margin-top: 0; }
.qa { grid-template-columns: 1fr; }
.pay__amount { font-size: 1.8rem; }
.step__label { font-size: .62rem; }
}(function () {
"use strict";
var fmt = function (n) { return "$" + n.toLocaleString("en-US", { minimumFractionDigits: 0 }); };
/* ---- Data ---- */
var policies = [
{
type: "Auto Insurance", num: "AU-7741-203", premium: 168, status: "active",
renew: "Aug 14, 2026", days: 53,
icon: '<path d="M5 13l1.5-4.5A2 2 0 0 1 8.4 7h7.2a2 2 0 0 1 1.9 1.5L19 13"/><path d="M5 13h14v4a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1H8v1a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1z"/><circle cx="7.5" cy="15.5" r=".5"/><circle cx="16.5" cy="15.5" r=".5"/>'
},
{
type: "Home Insurance", num: "HO-5520-118", premium: 142, status: "soon",
renew: "Jul 02, 2026", days: 10,
icon: '<path d="M3 11l9-7 9 7"/><path d="M5 10v9a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-9"/><path d="M10 20v-5h4v5"/>'
},
{
type: "Term Life", num: "LF-9034-077", premium: 102, status: "active",
renew: "Mar 30, 2027", days: 281,
icon: '<path d="M12 21s-7-4.35-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 11c0 5.65-7 10-7 10z"/>'
}
];
var coverage = [
{ name: "Auto liability", used: 4200, limit: 50000 },
{ name: "Home dwelling", used: 18000, limit: 320000 },
{ name: "Deductible used (yr)", used: 750, limit: 1000 }
];
var claims = [
{
title: "Windshield replacement", id: "CLM-22841", date: "Filed Jun 09, 2026",
amount: 480, step: 2,
steps: ["Submitted", "Reviewing", "Approved", "Paid"]
},
{
title: "Roof hail damage", id: "CLM-21097", date: "Filed Apr 18, 2026",
amount: 3250, step: 4,
steps: ["Submitted", "Reviewing", "Approved", "Paid"]
}
];
/* ---- Render policies ---- */
var polEl = document.getElementById("policies");
var badgeMap = {
active: '<span class="badge badge--active">Active</span>',
soon: '<span class="badge badge--soon">Renewing soon</span>',
lapsed: '<span class="badge badge--lapsed">Lapsed</span>'
};
policies.forEach(function (p) {
var li = document.createElement("li");
li.className = "policy";
li.innerHTML =
'<span class="policy__icon" aria-hidden="true"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + p.icon + '</svg></span>' +
'<div class="policy__main">' +
'<p class="policy__type">' + p.type + '</p>' +
'<p class="policy__num">' + p.num + '</p>' +
'<p class="policy__renew">Renews <strong>' + p.renew + '</strong>' + (p.status === "soon" ? " · in " + p.days + " days" : "") + '</p>' +
'</div>' +
'<div class="policy__right">' +
'<p class="policy__premium">' + fmt(p.premium) + '<span>/mo</span></p>' +
badgeMap[p.status] +
'</div>';
polEl.appendChild(li);
});
/* ---- Render coverage ---- */
var covEl = document.getElementById("coverage");
coverage.forEach(function (c) {
var pct = Math.round((c.used / c.limit) * 100);
var high = pct >= 70;
var li = document.createElement("li");
li.innerHTML =
'<div class="cov__top"><span class="cov__name">' + c.name + '</span>' +
'<span class="cov__nums">' + fmt(c.used) + ' / ' + fmt(c.limit) + '</span></div>' +
'<div class="cov__track"><div class="cov__fill' + (high ? " cov__fill--high" : "") + '"></div></div>';
covEl.appendChild(li);
var fill = li.querySelector(".cov__fill");
requestAnimationFrame(function () { fill.style.width = Math.min(pct, 100) + "%"; });
});
/* ---- Render claims ---- */
var check = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
var claimsEl = document.getElementById("claims");
claims.forEach(function (cl) {
var done = cl.step >= cl.steps.length;
var li = document.createElement("li");
li.className = "claim";
var stepsHtml = cl.steps.map(function (s, i) {
var state = (i + 1) < cl.step ? "step--done" : (i + 1) === cl.step ? "step--active" : "";
if (i + 1 < cl.step) state = "step--done";
var dot = (i + 1) < cl.step ? check : "";
return '<div class="step ' + state + '"><span class="step__dot" aria-hidden="true">' + dot + '</span><span class="step__label">' + s + '</span></div>';
}).join("");
li.innerHTML =
'<div class="claim__top">' +
'<div><p class="claim__title">' + cl.title + '</p><p class="claim__sub">' + cl.id + ' · ' + cl.date + '</p></div>' +
'<div style="text-align:right"><p class="claim__amount">' + fmt(cl.amount) + '</p>' +
'<span class="badge ' + (done ? "badge--active" : "badge--soon") + '">' + (done ? "Paid out" : "In progress") + '</span></div>' +
'</div>' +
'<div class="steps">' + stepsHtml + '</div>';
claimsEl.appendChild(li);
});
/* ---- Toast ---- */
var toast = document.getElementById("toast");
var toastTimer;
function showToast(msg) {
toast.textContent = msg;
toast.hidden = false;
requestAnimationFrame(function () { toast.classList.add("show"); });
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toast.classList.remove("show");
setTimeout(function () { toast.hidden = true; }, 300);
}, 2600);
}
/* ---- Pay flow ---- */
var payBody = document.getElementById("pay-body");
var payConfirm = document.getElementById("pay-confirm");
var payPanel = document.querySelector(".pay");
document.getElementById("pay-now").addEventListener("click", function () {
payBody.hidden = true;
payConfirm.hidden = false;
});
document.getElementById("pay-confirm-no").addEventListener("click", function () {
payConfirm.hidden = true;
payBody.hidden = false;
});
document.getElementById("pay-confirm-yes").addEventListener("click", function () {
payPanel.classList.add("pay--done");
document.getElementById("pay-chip").textContent = "Paid";
document.getElementById("pay-chip").style.color = "var(--green)";
document.getElementById("pay-chip").style.background = "var(--green-50)";
document.getElementById("pay-amount").textContent = "$0.00";
payConfirm.innerHTML = '<p style="color:var(--green);font-weight:600">Payment received — thank you! Next bill: Jul 28, 2026.</p>';
showToast("Payment of $412.00 confirmed");
});
/* ---- Quick actions ---- */
var actionMsg = {
claim: "Starting a new claim…",
pay: "Opening payment center…",
card: "Downloading insurance ID card (PDF)…"
};
document.querySelectorAll(".qa__btn").forEach(function (btn) {
btn.addEventListener("click", function () {
showToast(actionMsg[btn.dataset.action] || "Opening…");
});
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Insurance — Policy Dashboard</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="dash" role="main" aria-labelledby="dash-title">
<header class="dash__head">
<div class="brand">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</span>
<div>
<p class="brand__name">Meridian Mutual</p>
<h1 id="dash-title" class="brand__welcome">Welcome back, Dana</h1>
</div>
</div>
<div class="member">
<span class="member__id">Member #84-201-558</span>
<span class="member__avatar" aria-hidden="true">DM</span>
</div>
</header>
<!-- Summary stats -->
<section class="stats" aria-label="Account summary">
<article class="stat">
<span class="stat__icon stat__icon--blue" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</span>
<div>
<p class="stat__value" id="stat-policies">3</p>
<p class="stat__label">Active policies</p>
</div>
</article>
<article class="stat">
<span class="stat__icon stat__icon--green" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
</span>
<div>
<p class="stat__value" id="stat-premium">$412</p>
<p class="stat__label">Monthly premium</p>
</div>
</article>
<article class="stat">
<span class="stat__icon stat__icon--amber" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
</span>
<div>
<p class="stat__value" id="stat-claims">1</p>
<p class="stat__label">Open claim</p>
</div>
</article>
<article class="stat">
<span class="stat__icon stat__icon--blue" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
</span>
<div>
<p class="stat__value">Aug 14</p>
<p class="stat__label">Next renewal</p>
</div>
</article>
</section>
<div class="grid">
<!-- Policies -->
<section class="panel" aria-labelledby="policies-h">
<div class="panel__head">
<h2 id="policies-h" class="panel__title">Your policies</h2>
<button class="link-btn" type="button">Manage</button>
</div>
<ul class="policies" id="policies"></ul>
</section>
<!-- Sidebar -->
<div class="side">
<!-- Next payment -->
<section class="panel pay" aria-labelledby="pay-h">
<div class="panel__head">
<h2 id="pay-h" class="panel__title">Next payment due</h2>
<span class="pay__chip" id="pay-chip">Due in 6 days</span>
</div>
<div class="pay__body" id="pay-body">
<p class="pay__amount" id="pay-amount">$412.00</p>
<p class="pay__meta">Auto-pay from Visa •••• 4471 · <strong>Jun 28, 2026</strong></p>
<div class="pay__actions">
<button class="btn btn--primary" id="pay-now" type="button">Pay now</button>
<button class="btn btn--ghost" type="button">Edit auto-pay</button>
</div>
</div>
<div class="pay__confirm" id="pay-confirm" hidden>
<p>Charge <strong>$412.00</strong> to Visa •••• 4471?</p>
<div class="pay__actions">
<button class="btn btn--primary" id="pay-confirm-yes" type="button">Confirm payment</button>
<button class="btn btn--ghost" id="pay-confirm-no" type="button">Cancel</button>
</div>
</div>
</section>
<!-- Quick actions -->
<section class="panel" aria-labelledby="qa-h">
<div class="panel__head"><h2 id="qa-h" class="panel__title">Quick actions</h2></div>
<div class="qa">
<button class="qa__btn" type="button" data-action="claim">
<span class="qa__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/></svg>
</span>
File a claim
</button>
<button class="qa__btn" type="button" data-action="pay">
<span class="qa__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="5" width="20" height="14" rx="2"/><line x1="2" y1="10" x2="22" y2="10"/></svg>
</span>
Pay a bill
</button>
<button class="qa__btn" type="button" data-action="card">
<span class="qa__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
</span>
ID card
</button>
</div>
</section>
<!-- Coverage -->
<section class="panel" aria-labelledby="cov-h">
<div class="panel__head"><h2 id="cov-h" class="panel__title">Coverage at a glance</h2></div>
<ul class="coverage" id="coverage"></ul>
</section>
</div>
</div>
<!-- Claims -->
<section class="panel" aria-labelledby="claims-h">
<div class="panel__head">
<h2 id="claims-h" class="panel__title">Open & recent claims</h2>
<button class="link-btn" type="button">View all</button>
</div>
<ul class="claims" id="claims"></ul>
</section>
<p class="toast" id="toast" role="status" aria-live="polite" hidden></p>
</main>
<script src="script.js"></script>
</body>
</html>Policy Dashboard
A reassuring, single-screen home for a policyholder. The top row of stat cards sums up active policies, total monthly premium, open claims and next renewal. Below, each active policy renders as a rounded card with its type icon, premium, status badge and renewal date — policies inside the renewal window pick up a pulsing Renewing soon badge.
A prominent next-payment panel shows the amount and due date with an inline Pay now flow that confirms before marking the bill paid and updating the summary. Open claims list their stage on a progress track, coverage limits render as at-a-glance usage bars, and a quick-actions row exposes file-a-claim, pay and download-ID-card buttons. Everything is vanilla JS — no libraries.
Illustrative UI only — not for real insurance, financial or legal use.