Banking — Balance Card
A trust-first fintech balance card you can drop into any banking dashboard. Shows account name and type, a masked card number, and a balance set in tabular figures with a mini sparkline trend. A per-card and global hide/show toggle blurs sensitive numbers, status pills flag activity and due dates, and quick actions sit one tap away. Ships as three real-feeling variants — checking, high-yield savings, and a credit card with a utilisation bar — in a responsive grid, vanilla JS only.
MCP
Code
:root {
--navy: #0e1b3a;
--navy-2: #16264d;
--ink: #0e1726;
--ink-2: #3a4660;
--muted: #697089;
--accent: #3b6ef6;
--accent-d: #2a55cc;
--accent-50: #eaf0ff;
--teal: #0fb5a6;
--violet: #7c5cff;
--bg: #f5f7fb;
--surface: #ffffff;
--line: rgba(14, 27, 58, 0.10);
--line-2: rgba(14, 27, 58, 0.18);
--ok: #1f9d62;
--warn: #d9982b;
--danger: #d4493e;
--credit: #1f9d62;
--debit: #0e1726;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-1: 0 1px 2px rgba(14, 27, 58, 0.06);
--sh-2: 0 6px 18px rgba(14, 27, 58, 0.08);
--sh-3: 0 18px 44px rgba(14, 27, 58, 0.14);
}
* {
box-sizing: border-box;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(1200px 540px at 85% -10%, rgba(59, 110, 246, 0.10), transparent 60%),
radial-gradient(900px 480px at 0% 0%, rgba(124, 92, 255, 0.07), transparent 55%),
var(--bg);
min-height: 100vh;
}
.mono {
font-variant-numeric: tabular-nums;
}
/* ---------- Layout ---------- */
.wrap {
max-width: 1080px;
margin: 0 auto;
padding: 40px 22px 56px;
}
.page-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 18px;
margin-bottom: 26px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
margin: 0 0 8px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--accent-d);
}
.eyebrow .dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--teal);
box-shadow: 0 0 0 4px rgba(15, 181, 166, 0.16);
}
.page-head h1 {
margin: 0;
font-size: clamp(22px, 3.4vw, 30px);
font-weight: 800;
letter-spacing: -0.02em;
color: var(--navy);
}
.sub {
margin: 6px 0 0;
font-size: 14px;
color: var(--muted);
}
/* ---------- Ghost toggle ---------- */
.btn-ghost {
display: inline-flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
padding: 9px 14px;
font: inherit;
font-size: 13px;
font-weight: 600;
color: var(--ink-2);
background: var(--surface);
border: 1px solid var(--line);
border-radius: 999px;
box-shadow: var(--sh-1);
cursor: pointer;
transition: border-color 0.18s, color 0.18s, transform 0.06s, box-shadow 0.18s;
}
.btn-ghost:hover {
border-color: var(--line-2);
color: var(--ink);
box-shadow: var(--sh-2);
}
.btn-ghost:active {
transform: translateY(1px);
}
.btn-ghost[aria-pressed="true"] {
color: var(--accent-d);
border-color: rgba(59, 110, 246, 0.45);
background: var(--accent-50);
}
.btn-ghost .ico {
display: inline-flex;
}
/* ---------- Grid ---------- */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
}
/* ---------- Balance card ---------- */
.bal-card {
position: relative;
display: flex;
flex-direction: column;
padding: 20px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
box-shadow: var(--sh-2);
overflow: hidden;
transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 0.2s;
}
.bal-card::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 4px;
background: var(--accent);
}
.bal-card--checking::before { background: linear-gradient(90deg, var(--accent), var(--accent-d)); }
.bal-card--savings::before { background: linear-gradient(90deg, var(--teal), #0a8b80); }
.bal-card--credit::before { background: linear-gradient(90deg, var(--violet), #5b3fd6); }
.bal-card:hover {
transform: translateY(-4px);
box-shadow: var(--sh-3);
}
.bal-card.is-hidden .bal-amount,
.bal-card.is-hidden .spark,
.bal-card.is-hidden .credit-bar,
.bal-card.is-hidden .credit-line .mono {
filter: blur(8px);
user-select: none;
}
.bal-card.is-flash .bal-amount {
animation: amountFlash 0.5s ease;
}
@keyframes amountFlash {
0% { transform: scale(1); }
40% { transform: scale(1.04); color: var(--accent-d); }
100% { transform: scale(1); }
}
/* top row */
.bal-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 10px;
margin-bottom: 18px;
}
.bal-id {
display: flex;
align-items: center;
gap: 11px;
min-width: 0;
}
.bal-emblem {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 12px;
background: var(--accent-50);
color: var(--accent-d);
}
.bal-card--savings .bal-emblem { background: rgba(15, 181, 166, 0.12); color: #0a8b80; }
.bal-card--credit .bal-emblem { background: rgba(124, 92, 255, 0.12); color: #5b3fd6; }
.bal-name {
margin: 0;
font-size: 14px;
font-weight: 700;
color: var(--ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.bal-num {
margin: 2px 0 0;
font-size: 12.5px;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--muted);
font-variant-numeric: tabular-nums;
}
.bal-num .mask {
letter-spacing: 0.12em;
}
/* pills */
.pill {
display: inline-flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
padding: 4px 9px;
font-size: 11.5px;
font-weight: 700;
border-radius: 999px;
white-space: nowrap;
}
.pill-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
}
.pill--ok { color: var(--ok); background: rgba(31, 157, 98, 0.12); }
.pill--warn { color: var(--warn); background: rgba(217, 152, 43, 0.14); }
.pill--info { color: var(--accent-d); background: var(--accent-50); }
/* body */
.bal-body {
margin-bottom: 4px;
}
.bal-label {
margin: 0 0 4px;
font-size: 12px;
font-weight: 600;
color: var(--muted);
}
.bal-amount {
margin: 0;
font-size: clamp(26px, 4vw, 30px);
font-weight: 800;
letter-spacing: -0.02em;
color: var(--credit);
font-variant-numeric: tabular-nums;
transition: filter 0.22s ease, color 0.2s, transform 0.2s;
}
.bal-amount--debit {
color: var(--debit);
}
.bal-meta {
margin: 6px 0 0;
font-size: 12.5px;
color: var(--muted);
}
.trend {
display: inline-flex;
align-items: center;
gap: 3px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.trend--up { color: var(--ok); }
.trend--down { color: var(--danger); }
.bal-meta-sep { margin: 0 4px; opacity: 0.6; }
/* sparkline */
.spark {
width: 100%;
height: 56px;
margin: 14px 0 4px;
display: block;
overflow: visible;
transition: filter 0.22s ease;
}
.spark .spark-area {
fill: rgba(59, 110, 246, 0.10);
}
.spark .spark-line {
fill: none;
stroke: var(--accent);
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.spark .spark-dot {
fill: var(--surface);
stroke: var(--accent);
stroke-width: 2.4;
}
.bal-card--savings .spark .spark-area { fill: rgba(15, 181, 166, 0.10); }
.bal-card--savings .spark .spark-line,
.bal-card--savings .spark .spark-dot { stroke: var(--teal); }
/* credit utilisation */
.credit-bar {
height: 7px;
margin: 16px 0 7px;
border-radius: 999px;
background: rgba(124, 92, 255, 0.14);
overflow: hidden;
transition: filter 0.22s ease;
}
.credit-bar-fill {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, var(--violet), #5b3fd6);
transition: width 0.5s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.credit-line {
margin: 0 0 2px;
font-size: 12px;
color: var(--muted);
}
.credit-line .mono {
color: var(--ink);
font-weight: 700;
}
/* actions */
.bal-actions {
display: flex;
align-items: center;
gap: 8px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--line);
}
.act {
flex: 1;
padding: 9px 10px;
font: inherit;
font-size: 13px;
font-weight: 600;
color: var(--ink-2);
background: #f1f4fa;
border: 1px solid transparent;
border-radius: var(--r-sm);
cursor: pointer;
transition: background 0.16s, color 0.16s, transform 0.06s, box-shadow 0.16s;
}
.act:hover {
background: #e7ecf6;
color: var(--ink);
}
.act:active {
transform: translateY(1px);
}
.act--primary {
color: #fff;
background: var(--accent);
box-shadow: 0 4px 12px rgba(59, 110, 246, 0.28);
}
.act--primary:hover {
background: var(--accent-d);
}
.act--icon {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 38px;
padding: 0;
color: var(--muted);
}
.act:focus-visible,
.btn-ghost:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
/* ---------- Footer ---------- */
.page-foot {
display: flex;
align-items: center;
justify-content: center;
gap: 7px;
margin-top: 30px;
font-size: 12.5px;
font-weight: 500;
color: var(--muted);
}
.page-foot .lock {
display: inline-flex;
color: var(--ok);
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 24px);
max-width: calc(100% - 32px);
padding: 11px 18px;
font-size: 13.5px;
font-weight: 600;
color: #fff;
background: var(--navy);
border-radius: 999px;
box-shadow: var(--sh-3);
opacity: 0;
pointer-events: none;
transition: opacity 0.24s ease, transform 0.24s cubic-bezier(0.2, 0.7, 0.3, 1);
z-index: 50;
}
.toast.is-show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ---------- Responsive ---------- */
@media (max-width: 880px) {
.grid {
grid-template-columns: 1fr;
max-width: 460px;
margin: 0 auto;
}
}
@media (max-width: 520px) {
.wrap {
padding: 28px 16px 44px;
}
.page-head {
flex-direction: column;
gap: 14px;
}
.btn-ghost {
align-self: flex-start;
}
.bal-card {
padding: 18px;
}
.bal-amount {
font-size: 27px;
}
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2200);
}
/* ---------- Currency formatting ---------- */
var fmt = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
function renderAmount(card) {
var el = card.querySelector("[data-amount]");
if (!el) return;
var raw = parseFloat(card.getAttribute("data-balance")) || 0;
// Credit balances are stored negative but shown as the absolute amount owed.
el.textContent = fmt.format(Math.abs(raw));
}
/* ---------- Sparkline builder ---------- */
function buildSpark(svg) {
var raw = svg.getAttribute("data-points");
if (!raw) return;
var coords = raw.trim().split(/\s+/).map(function (p) {
var xy = p.split(",");
return { x: parseFloat(xy[0]), y: parseFloat(xy[1]) };
});
if (coords.length < 2) return;
var line = coords
.map(function (c, i) {
return (i === 0 ? "M" : "L") + c.x + " " + c.y;
})
.join(" ");
var first = coords[0];
var last = coords[coords.length - 1];
var area = "M" + first.x + " 64 L" + line.slice(1) + " L" + last.x + " 64 Z";
var NS = "http://www.w3.org/2000/svg";
var areaEl = document.createElementNS(NS, "path");
areaEl.setAttribute("class", "spark-area");
areaEl.setAttribute("d", area);
var lineEl = document.createElementNS(NS, "path");
lineEl.setAttribute("class", "spark-line");
lineEl.setAttribute("d", line);
var dotEl = document.createElementNS(NS, "circle");
dotEl.setAttribute("class", "spark-dot");
dotEl.setAttribute("cx", last.x);
dotEl.setAttribute("cy", last.y);
dotEl.setAttribute("r", "3.2");
svg.appendChild(areaEl);
svg.appendChild(lineEl);
svg.appendChild(dotEl);
// Draw-in animation on the line.
var len = lineEl.getTotalLength ? lineEl.getTotalLength() : 0;
if (len) {
lineEl.style.strokeDasharray = len;
lineEl.style.strokeDashoffset = len;
lineEl.getBoundingClientRect(); // reflow
lineEl.style.transition = "stroke-dashoffset 0.9s ease 0.1s";
lineEl.style.strokeDashoffset = "0";
}
}
/* ---------- Per-card hide/show ---------- */
var STORAGE_KEY = "nw-balances-hidden";
var cards = Array.prototype.slice.call(document.querySelectorAll(".bal-card"));
function setHidden(card, hidden) {
card.classList.toggle("is-hidden", hidden);
var amt = card.querySelector("[data-amount]");
if (amt) amt.setAttribute("aria-hidden", hidden ? "true" : "false");
}
function allHidden() {
return cards.length > 0 && cards.every(function (c) {
return c.classList.contains("is-hidden");
});
}
/* ---------- Global toggle ---------- */
var globalBtn = document.getElementById("globalToggle");
var globalLabel = document.getElementById("globalToggleLabel");
function syncGlobalToggle() {
if (!globalBtn) return;
var hidden = allHidden();
globalBtn.setAttribute("aria-pressed", hidden ? "true" : "false");
if (globalLabel) globalLabel.textContent = hidden ? "Show balances" : "Hide balances";
}
if (globalBtn) {
globalBtn.addEventListener("click", function () {
var hideAll = !allHidden();
cards.forEach(function (c) {
setHidden(c, hideAll);
});
syncGlobalToggle();
saveState();
toast(hideAll ? "Balances hidden" : "Balances visible");
});
}
/* ---------- Persistence ---------- */
function saveState() {
try {
var state = cards.map(function (c) {
return c.classList.contains("is-hidden") ? 1 : 0;
});
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (e) {
/* storage unavailable — ignore */
}
}
function loadState() {
try {
var raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return;
var state = JSON.parse(raw);
cards.forEach(function (c, i) {
if (state[i]) setHidden(c, true);
});
} catch (e) {
/* malformed — ignore */
}
}
/* ---------- Quick actions ---------- */
var actionMessages = {
send: "Send money — enter a recipient to continue",
request: "Request created — share the link to get paid",
deposit: "Schedule a deposit to High-Yield Savings",
goals: "Open savings goals",
pay: "Pay card — choose an amount and date",
statement: "Opening your latest statement (PDF)",
request_money: "Request created",
};
cards.forEach(function (card) {
renderAmount(card);
var spark = card.querySelector(".spark");
if (spark) buildSpark(spark);
var nameEl = card.querySelector(".bal-name");
var accountName = nameEl ? nameEl.textContent.trim() : "account";
card.querySelectorAll("[data-action]").forEach(function (btn) {
btn.addEventListener("click", function () {
var action = btn.getAttribute("data-action");
if (action === "more") {
// Quick "more" = toggle this single card's visibility.
var nowHidden = !card.classList.contains("is-hidden");
setHidden(card, nowHidden);
syncGlobalToggle();
saveState();
toast(
(nowHidden ? "Hidden: " : "Showing: ") + accountName
);
return;
}
// Brief flash on the amount as feedback.
card.classList.remove("is-flash");
void card.offsetWidth;
card.classList.add("is-flash");
toast(actionMessages[action] || "Action: " + action);
});
});
// Keyboard affordance: Space/Enter on focused card body toggles via "more".
});
loadState();
syncGlobalToggle();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Banking — Balance Card</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">
<header class="page-head">
<div>
<p class="eyebrow">
<span class="dot" aria-hidden="true"></span> Northwind Bank
</p>
<h1>Accounts overview</h1>
<p class="sub">Tuesday, 16 June — all balances secured with 2FA.</p>
</div>
<button id="globalToggle" class="btn-ghost" type="button" aria-pressed="false">
<span class="ico" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg>
</span>
<span id="globalToggleLabel">Hide balances</span>
</button>
</header>
<section class="grid" aria-label="Account balance cards">
<!-- CHECKING -->
<article class="bal-card bal-card--checking" data-account="checking" data-balance="8421.57" data-trend="up">
<div class="bal-top">
<div class="bal-id">
<span class="bal-emblem" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="5" width="20" height="14" rx="2"/><path d="M2 10h20"/></svg>
</span>
<div>
<p class="bal-name">Everyday Checking</p>
<p class="bal-num"><span class="mask">••••</span> 4242</p>
</div>
</div>
<span class="pill pill--ok">
<span class="pill-dot" aria-hidden="true"></span> Active
</span>
</div>
<div class="bal-body">
<p class="bal-label">Available balance</p>
<p class="bal-amount" data-amount aria-live="polite">$8,421.57</p>
<p class="bal-meta">
<span class="trend trend--up" aria-label="Up 2.4 percent this month">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 15 6-6 6 6"/></svg>
2.4%
</span>
<span class="bal-meta-sep">·</span> vs. last month
</p>
</div>
<svg class="spark" viewBox="0 0 280 64" preserveAspectRatio="none" aria-hidden="true"
data-points="30,46 60,40 90,44 120,30 150,34 180,22 210,26 240,16 270,12"></svg>
<div class="bal-actions">
<button class="act act--primary" type="button" data-action="send">Send</button>
<button class="act" type="button" data-action="request">Request</button>
<button class="act act--icon" type="button" data-action="more" aria-label="More options">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="5" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/></svg>
</button>
</div>
</article>
<!-- SAVINGS -->
<article class="bal-card bal-card--savings" data-account="savings" data-balance="24690.00" data-trend="up">
<div class="bal-top">
<div class="bal-id">
<span class="bal-emblem" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 5c-1.5 0-2.8 1.4-3 2-3.5-1.5-11-.3-11 5 0 1.8 0 3 2 4.5V20h4v-2h3v2h4v-4c1-.5 1.7-1 2-2h2v-4h-2c0-1-.5-1.5-1-2V5Z"/><path d="M2 9v1"/><path d="M9 6V5a2 2 0 0 1 2-2h3"/></svg>
</span>
<div>
<p class="bal-name">High-Yield Savings</p>
<p class="bal-num"><span class="mask">••••</span> 9180</p>
</div>
</div>
<span class="pill pill--info">
4.30% APY
</span>
</div>
<div class="bal-body">
<p class="bal-label">Total saved</p>
<p class="bal-amount" data-amount aria-live="polite">$24,690.00</p>
<p class="bal-meta">
<span class="trend trend--up" aria-label="Up 88 dollars in interest">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 15 6-6 6 6"/></svg>
+$88.41
</span>
<span class="bal-meta-sep">·</span> interest this month
</p>
</div>
<svg class="spark" viewBox="0 0 280 64" preserveAspectRatio="none" aria-hidden="true"
data-points="30,50 60,48 90,42 120,40 150,33 180,30 210,24 240,18 270,10"></svg>
<div class="bal-actions">
<button class="act act--primary" type="button" data-action="deposit">Deposit</button>
<button class="act" type="button" data-action="goals">Goals</button>
<button class="act act--icon" type="button" data-action="more" aria-label="More options">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="5" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/></svg>
</button>
</div>
</article>
<!-- CREDIT -->
<article class="bal-card bal-card--credit" data-account="credit" data-balance="-1247.30" data-trend="down" data-limit="6000">
<div class="bal-top">
<div class="bal-id">
<span class="bal-emblem" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M2 9h20"/><path d="M6 15h4"/></svg>
</span>
<div>
<p class="bal-name">Platinum Rewards</p>
<p class="bal-num"><span class="mask">••••</span> 0077</p>
</div>
</div>
<span class="pill pill--warn">
<span class="pill-dot" aria-hidden="true"></span> Due in 9d
</span>
</div>
<div class="bal-body">
<p class="bal-label">Current balance</p>
<p class="bal-amount bal-amount--debit" data-amount aria-live="polite">$1,247.30</p>
<p class="bal-meta">
<span class="trend trend--down" aria-label="Down, more spent">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
$312.00
</span>
<span class="bal-meta-sep">·</span> minimum due
</p>
</div>
<div class="credit-bar" aria-hidden="true">
<div class="credit-bar-fill" style="width:20.8%"></div>
</div>
<p class="credit-line">
<span class="mono">$1,247</span> of <span class="mono">$6,000</span> limit used
</p>
<div class="bal-actions">
<button class="act act--primary" type="button" data-action="pay">Pay card</button>
<button class="act" type="button" data-action="statement">Statement</button>
<button class="act act--icon" type="button" data-action="more" aria-label="More options">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="5" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/></svg>
</button>
</div>
</article>
</section>
<footer class="page-foot">
<span class="lock" aria-hidden="true">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="11" width="16" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
</span>
Bank-grade encryption · Member FDIC (illustrative)
</footer>
</main>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Balance Card
A reusable account balance card built for banking and fintech dashboards. Each card pairs an account emblem, name, and type with a masked number (•••• 4242) and a large balance rendered in tabular figures so digits never shift width. A compact SVG sparkline draws in on load to show the recent trend, and a small meta line surfaces the month-over-month change, interest earned, or minimum payment due.
Three variants ship in a responsive grid: an Everyday Checking account with credits in green, a High-Yield Savings account showing its APY, and a Platinum Rewards credit card with a utilisation bar and a colour-coded due-date pill. Each card carries its own status pill (active, APY, due in 9d) and a row of quick actions — Send, Request, Deposit, Pay card — with a primary call to action and an overflow button.
Privacy is built in. A header toggle hides or reveals every balance at once by blurring the sensitive numbers, sparkline, and utilisation bar, while the per-card overflow action hides a single account. The chosen state persists in localStorage, a small toast() helper confirms each action, and everything stays keyboard-usable with visible focus rings, ARIA live regions, and AA-contrast colour. The layout collapses to a single column and stays legible down to 360px.
Illustrative UI only — not real banking software or financial advice.