Banking — Card Detail
A trust-first card management screen for a fintech app, featuring an animated 3D card that flips to reveal its security code, a one-tap freeze and unfreeze control, a live monthly spending-limit slider with usage tracking, copy-to-clipboard card number, virtual card creation, granular controls for online, contactless, ATM and international use, and a card transaction feed with credit and debit amounts plus cleared, pending and failed status pills.
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-sm: 0 1px 2px rgba(14, 27, 58, 0.06), 0 1px 3px rgba(14, 27, 58, 0.05);
--sh-md: 0 6px 18px rgba(14, 27, 58, 0.08), 0 2px 6px rgba(14, 27, 58, 0.05);
--sh-lg: 0 18px 48px rgba(14, 27, 58, 0.18);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-variant-numeric: tabular-nums;
}
h1, h2 { margin: 0; }
.amt, .val, .limit-val, .tx-meta strong { font-variant-numeric: tabular-nums; }
.shell {
max-width: 1080px;
margin: 0 auto;
padding: 28px 20px 48px;
}
/* Topbar */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 24px;
}
.brand { display: flex; align-items: center; gap: 14px; }
.brand-mark {
width: 44px; height: 44px;
display: grid; place-items: center;
background: linear-gradient(145deg, var(--navy), var(--accent));
color: #fff; border-radius: var(--r-md);
font-size: 20px; box-shadow: var(--sh-md);
}
.topbar h1 { font-size: 21px; font-weight: 800; letter-spacing: -0.01em; }
.sub { margin: 0; color: var(--muted); font-size: 13px; }
.topbar-meta { display: flex; align-items: center; gap: 12px; }
.pill {
display: inline-flex; align-items: center; gap: 7px;
font-size: 12.5px; font-weight: 600;
padding: 6px 12px; border-radius: 999px;
}
.pill-ok { background: rgba(31, 157, 98, 0.12); color: var(--ok); }
.pill .dot {
width: 7px; height: 7px; border-radius: 50%; background: var(--ok);
box-shadow: 0 0 0 3px rgba(31, 157, 98, 0.18);
}
.icon-btn {
width: 40px; height: 40px; border-radius: var(--r-md);
border: 1px solid var(--line); background: var(--surface);
color: var(--ink-2); font-size: 17px; cursor: pointer;
transition: background .15s, transform .15s;
}
.icon-btn:hover { background: var(--accent-50); transform: translateY(-1px); }
/* Layout */
.layout {
display: grid;
grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
gap: 22px;
align-items: start;
}
.col-card, .col-detail { display: flex; flex-direction: column; gap: 18px; }
/* Card stage */
.card-stage { display: flex; flex-direction: column; gap: 16px; }
.bank-card { perspective: 1400px; }
.card-inner {
position: relative;
width: 100%;
aspect-ratio: 1.586 / 1;
border: 0; padding: 0; margin: 0; background: none;
cursor: pointer;
transform-style: preserve-3d;
transition: transform .6s cubic-bezier(.2, .8, .25, 1);
border-radius: var(--r-lg);
}
.bank-card.flipped .card-inner { transform: rotateY(180deg); }
.card-inner:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; border-radius: var(--r-lg); }
.card-face {
position: absolute; inset: 0;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
border-radius: var(--r-lg);
padding: 22px;
color: #fff;
box-shadow: var(--sh-lg);
overflow: hidden;
display: flex; flex-direction: column;
}
.card-front {
background:
radial-gradient(120% 120% at 85% 15%, rgba(124, 92, 255, 0.55), transparent 55%),
radial-gradient(120% 120% at 10% 90%, rgba(15, 181, 166, 0.45), transparent 55%),
linear-gradient(135deg, var(--navy) 0%, var(--navy-2) 60%, var(--accent-d) 130%);
text-align: left;
}
.card-front::after {
content: ""; position: absolute; inset: 0;
background: linear-gradient(115deg, transparent 40%, rgba(255, 255, 255, 0.10) 50%, transparent 60%);
}
.card-back {
transform: rotateY(180deg);
background: linear-gradient(135deg, var(--navy-2), var(--navy));
justify-content: space-between;
}
.card-top { display: flex; justify-content: space-between; align-items: flex-start; }
.card-brand { font-weight: 800; letter-spacing: 0.18em; font-size: 16px; }
.card-type { font-size: 11px; opacity: 0.78; font-weight: 500; letter-spacing: 0.04em; }
.card-chip {
width: 44px; height: 33px; margin: 16px 0 14px;
border-radius: 7px;
background: linear-gradient(135deg, #f4d27a, #c79b3d);
position: relative; z-index: 1;
}
.card-chip::before {
content: ""; position: absolute; inset: 6px 4px;
border: 1px solid rgba(0, 0, 0, 0.25); border-radius: 3px;
}
.card-pan {
display: flex; gap: 14px;
font-size: 19px; font-weight: 600; letter-spacing: 0.06em;
margin-bottom: auto; position: relative; z-index: 1;
}
.card-pan .mask { letter-spacing: 0.12em; opacity: 0.92; }
.card-bottom { display: flex; justify-content: space-between; gap: 12px; position: relative; z-index: 1; }
.card-field { display: flex; flex-direction: column; gap: 3px; }
.card-field .lbl { font-size: 9px; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.65; }
.card-field .val { font-size: 13px; font-weight: 600; letter-spacing: 0.03em; }
.frozen-badge {
position: absolute; top: 50%; left: 50%;
transform: translate(-50%, -50%) scale(.8);
background: rgba(255, 255, 255, 0.16);
border: 1px solid rgba(255, 255, 255, 0.35);
backdrop-filter: blur(2px);
padding: 8px 16px; border-radius: 999px;
font-weight: 700; font-size: 14px; letter-spacing: 0.04em;
opacity: 0; pointer-events: none; z-index: 3;
transition: opacity .35s, transform .35s;
}
.bank-card[data-frozen="true"] .card-front {
filter: grayscale(0.55) brightness(0.78);
}
.bank-card[data-frozen="true"] .frozen-badge {
opacity: 1; transform: translate(-50%, -50%) scale(1);
}
.card-stripe { height: 42px; background: #060c1c; margin: 4px -22px 18px; }
.card-cvv-row { display: flex; align-items: center; gap: 12px; }
.signbox {
flex: 1; height: 34px; border-radius: 5px;
background: repeating-linear-gradient(45deg, #e9ecf5, #e9ecf5 7px, #d6dbe9 7px, #d6dbe9 14px);
}
.cvv {
background: #fff; color: var(--ink);
border-radius: 5px; padding: 6px 12px;
display: flex; flex-direction: column; align-items: flex-end; min-width: 74px;
}
.cvv .lbl { font-size: 8px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }
.cvv .val { font-weight: 700; letter-spacing: 0.18em; }
.card-note { margin: 0; font-size: 11px; opacity: 0.7; }
/* Quick actions */
.card-quick { display: flex; gap: 10px; flex-wrap: wrap; }
.quick-btn {
flex: 1; min-width: 120px;
display: inline-flex; align-items: center; justify-content: center; gap: 7px;
padding: 11px 12px; border-radius: var(--r-md);
border: 1px solid var(--line); background: var(--surface);
color: var(--ink); font: inherit; font-size: 13px; font-weight: 600;
cursor: pointer; box-shadow: var(--sh-sm);
transition: transform .15s, background .15s, border-color .15s;
}
.quick-btn:hover { transform: translateY(-1px); border-color: var(--line-2); }
.quick-btn:active { transform: translateY(0); }
.quick-btn[aria-pressed="true"] { background: var(--accent-50); border-color: var(--accent); color: var(--accent-d); }
.quick-virtual { background: var(--accent); color: #fff; border-color: var(--accent); }
.quick-virtual:hover { background: var(--accent-d); }
/* Freeze panel */
.freeze-panel {
display: flex; align-items: center; justify-content: space-between; gap: 16px;
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-lg); padding: 18px 20px; box-shadow: var(--sh-sm);
transition: border-color .25s, background .25s;
}
.freeze-panel.frozen {
background: linear-gradient(135deg, #eef4ff, #e9f7ff);
border-color: rgba(59, 110, 246, 0.4);
}
.freeze-text h2 { font-size: 15px; font-weight: 700; }
.freeze-text p { margin: 2px 0 0; font-size: 13px; color: var(--muted); }
/* Toggles */
.toggle {
--w: 50px; --h: 28px;
width: var(--w); height: var(--h);
border-radius: 999px; border: 0;
background: var(--line-2); cursor: pointer; padding: 3px;
position: relative; flex: none;
transition: background .2s;
}
.toggle .toggle-knob {
display: block; width: calc(var(--h) - 6px); height: calc(var(--h) - 6px);
border-radius: 50%; background: #fff; box-shadow: var(--sh-sm);
transform: translateX(0); transition: transform .2s;
}
.toggle[aria-checked="true"], .toggle.on { background: var(--accent); }
.toggle[aria-checked="true"] .toggle-knob,
.toggle.on .toggle-knob { transform: translateX(calc(var(--w) - var(--h))); }
.toggle:focus-visible { outline: 3px solid var(--accent-50); outline-offset: 2px; }
.toggle-sm { --w: 44px; --h: 25px; }
/* Limit panel */
.limit-panel {
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-lg); padding: 18px 20px 20px; box-shadow: var(--sh-sm);
}
.limit-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 14px; }
.limit-head h2 { font-size: 15px; font-weight: 700; }
.limit-val { font-size: 22px; font-weight: 800; letter-spacing: -0.01em; }
.slider {
-webkit-appearance: none; appearance: none;
width: 100%; height: 6px; border-radius: 999px;
background: linear-gradient(90deg, var(--accent) var(--fill, 33%), var(--line-2) var(--fill, 33%));
cursor: pointer; outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none; appearance: none;
width: 22px; height: 22px; border-radius: 50%;
background: #fff; border: 3px solid var(--accent);
box-shadow: var(--sh-md); cursor: pointer;
}
.slider::-moz-range-thumb {
width: 22px; height: 22px; border-radius: 50%;
background: #fff; border: 3px solid var(--accent); box-shadow: var(--sh-md);
}
.slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px var(--accent-50); }
.limit-meta {
display: flex; justify-content: space-between; margin: 14px 0 8px;
font-size: 13px; color: var(--muted);
}
.limit-meta strong { color: var(--ink); font-weight: 700; }
.limit-pct { font-weight: 600; color: var(--ink-2); }
.limit-bar { height: 7px; background: var(--line); border-radius: 999px; overflow: hidden; }
.limit-bar span {
display: block; height: 100%; border-radius: 999px;
background: linear-gradient(90deg, var(--teal), var(--accent));
transition: width .35s ease, background .35s;
}
.limit-bar.over span { background: linear-gradient(90deg, var(--warn), var(--danger)); }
/* Panels */
.panel {
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-lg); box-shadow: var(--sh-sm); overflow: hidden;
}
.panel-title { font-size: 15px; font-weight: 700; }
.settings-panel { padding: 18px 20px 8px; }
.settings-list { list-style: none; margin: 14px 0 0; padding: 0; }
.setting {
display: flex; align-items: center; gap: 14px;
padding: 14px 0; border-top: 1px solid var(--line);
}
.setting:first-child { border-top: 0; }
.setting-icon {
width: 40px; height: 40px; flex: none; border-radius: var(--r-md);
background: var(--accent-50); display: grid; place-items: center; font-size: 18px;
}
.setting-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.s-name { font-weight: 600; font-size: 14px; }
.s-desc { font-size: 12.5px; color: var(--muted); }
/* Transactions */
.tx-panel { padding: 18px 20px 12px; }
.tx-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.tx-count { font-size: 12.5px; color: var(--muted); font-weight: 500; }
.tx-list { list-style: none; margin: 8px 0 0; padding: 0; }
.tx {
display: flex; align-items: center; gap: 13px;
padding: 12px 8px; margin: 0 -8px;
border-radius: var(--r-md);
border-top: 1px solid var(--line);
transition: background .15s;
}
.tx:first-child { border-top: 0; }
.tx:hover { background: var(--bg); }
.tx-logo {
width: 40px; height: 40px; flex: none; border-radius: 50%;
display: grid; place-items: center;
font-size: 13px; font-weight: 700; color: #fff;
background: var(--accent);
}
.tx-logo[data-c="teal"] { background: var(--teal); }
.tx-logo[data-c="violet"] { background: var(--violet); }
.tx-logo[data-c="ok"] { background: var(--ok); }
.tx-logo[data-c="accent"] { background: var(--accent); }
.tx-logo[data-c="danger"] { background: var(--danger); }
.tx-main { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.tx-name { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tx-meta { font-size: 12.5px; color: var(--muted); }
.tx-right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }
.amt { font-size: 14.5px; font-weight: 700; }
.amt.credit { color: var(--credit); }
.amt.debit { color: var(--debit); }
.status {
font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 999px;
letter-spacing: 0.01em;
}
.status.cleared { background: rgba(31, 157, 98, 0.12); color: var(--ok); }
.status.pending { background: rgba(217, 152, 43, 0.14); color: var(--warn); }
.status.failed { background: rgba(212, 73, 62, 0.12); color: var(--danger); }
/* Toast */
.toast {
position: fixed; left: 50%; bottom: 28px;
transform: translate(-50%, 24px);
background: var(--ink); color: #fff;
padding: 12px 20px; border-radius: var(--r-md);
font-size: 13.5px; font-weight: 500; box-shadow: var(--sh-lg);
opacity: 0; pointer-events: none; z-index: 50;
transition: opacity .25s, transform .25s;
max-width: calc(100% - 32px);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.toast-ok { background: var(--ok); }
.toast.toast-warn { background: var(--warn); }
/* Responsive */
@media (max-width: 880px) {
.layout { grid-template-columns: 1fr; }
.col-card { max-width: 460px; margin: 0 auto; width: 100%; }
}
@media (max-width: 520px) {
.shell { padding: 20px 14px 40px; }
.topbar h1 { font-size: 18px; }
.pill { display: none; }
.card-face { padding: 18px; }
.card-pan { font-size: 16px; gap: 10px; }
.card-quick { gap: 8px; }
.quick-btn { min-width: 0; flex: 1 1 100%; }
.quick-virtual { flex-basis: 100%; }
.limit-val { font-size: 19px; }
.col-card { max-width: none; }
}(function () {
"use strict";
var FULL_PAN = "5412 7634 9981 4242";
var REAL_CVV = "318";
var card = document.getElementById("bankCard");
var cardFlip = document.getElementById("cardFlip");
var cvvVal = document.getElementById("cvvVal");
var revealBtn = document.getElementById("revealBtn");
var copyBtn = document.getElementById("copyBtn");
var virtualBtn = document.getElementById("virtualBtn");
var freezeToggle = document.getElementById("freezeToggle");
var freezePanel = document.getElementById("freezePanel");
var freezeTitle = document.getElementById("freezeTitle");
var freezeDesc = document.getElementById("freezeDesc");
var slider = document.getElementById("limitSlider");
var limitVal = document.getElementById("limitVal");
var limitPct = document.getElementById("limitPct");
var limitBarFill = document.getElementById("limitBarFill");
var limitBar = limitBarFill.parentElement;
var SPENT = 1842;
/* ---- Toast helper ---- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg, kind) {
toastEl.textContent = msg;
toastEl.className = "toast show" + (kind ? " toast-" + kind : "");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.className = "toast";
}, 2400);
}
function money(n) {
return "$" + n.toLocaleString("en-US");
}
/* ---- Card flip + reveal CVV ---- */
function setRevealed(on) {
card.classList.toggle("flipped", on);
cvvVal.textContent = on ? REAL_CVV : "•••";
revealBtn.setAttribute("aria-pressed", on ? "true" : "false");
revealBtn.lastChild.textContent = on ? " Hide CVV" : " Reveal CVV";
}
function isRevealed() {
return card.classList.contains("flipped");
}
cardFlip.addEventListener("click", function () {
setRevealed(!isRevealed());
});
revealBtn.addEventListener("click", function () {
setRevealed(!isRevealed());
});
/* ---- Copy card number ---- */
copyBtn.addEventListener("click", function () {
function done() {
toast("Card number copied · •••• 4242", "ok");
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(FULL_PAN).then(done).catch(fallback);
} else {
fallback();
}
function fallback() {
var ta = document.createElement("textarea");
ta.value = FULL_PAN;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try { document.execCommand("copy"); } catch (e) {}
document.body.removeChild(ta);
done();
}
});
/* ---- Freeze / unfreeze ---- */
function setFrozen(frozen) {
card.setAttribute("data-frozen", frozen ? "true" : "false");
freezeToggle.setAttribute("aria-checked", frozen ? "true" : "false");
freezePanel.classList.toggle("frozen", frozen);
freezeTitle.textContent = frozen ? "Card is frozen" : "Card is active";
freezeDesc.textContent = frozen
? "All payments are temporarily blocked. Unfreeze any time."
: "Payments, ATM and online use are enabled.";
document.querySelectorAll(".quick-btn").forEach(function (b) {
if (b !== freezeToggle) {
b.disabled = frozen && b === virtualBtn ? false : b.disabled;
}
});
toast(frozen ? "Card frozen ❄" : "Card unfrozen — ready to use", frozen ? "warn" : "ok");
}
freezeToggle.addEventListener("click", function () {
setFrozen(card.getAttribute("data-frozen") !== "true");
});
/* ---- Spending limit slider ---- */
function updateLimit() {
var limit = parseInt(slider.value, 10);
limitVal.textContent = money(limit);
var sliderPct = ((limit - slider.min) / (slider.max - slider.min)) * 100;
slider.style.setProperty("--fill", sliderPct.toFixed(1) + "%");
var used = Math.min(100, Math.round((SPENT / limit) * 100));
limitPct.textContent = used + "% used";
limitBarFill.style.width = used + "%";
var over = SPENT > limit;
limitBar.classList.toggle("over", over || used >= 90);
limitPct.style.color = over ? "var(--danger)" : "var(--ink-2)";
}
slider.addEventListener("input", updateLimit);
slider.addEventListener("change", function () {
toast("Monthly limit set to " + money(parseInt(slider.value, 10)), "ok");
});
/* ---- Card controls toggles ---- */
document.querySelectorAll(".settings-list .toggle").forEach(function (tg) {
tg.addEventListener("click", function () {
var on = tg.getAttribute("aria-checked") !== "true";
tg.setAttribute("aria-checked", on ? "true" : "false");
tg.classList.toggle("on", on);
var name = tg.closest(".setting").querySelector(".s-name").textContent;
toast(name + (on ? " enabled" : " disabled"), on ? "ok" : "warn");
});
});
/* ---- Create virtual card ---- */
var virtualCount = 0;
virtualBtn.addEventListener("click", function () {
virtualCount++;
var last4 = String(1000 + Math.floor(Math.random() * 8999)).slice(-4);
toast("Virtual card •••• " + last4 + " created", "ok");
});
/* init */
updateLimit();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Banking — Card Detail</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="shell">
<header class="topbar">
<div class="brand">
<span class="brand-mark" aria-hidden="true">◈</span>
<div>
<h1>Card detail</h1>
<p class="sub">Manage limits, security and activity</p>
</div>
</div>
<div class="topbar-meta">
<span class="pill pill-ok"><span class="dot" aria-hidden="true"></span> Account secured</span>
<button class="icon-btn" type="button" aria-label="Account settings">⚙</button>
</div>
</header>
<div class="layout">
<!-- LEFT: card + controls -->
<section class="col-card" aria-label="Card overview">
<div class="card-stage">
<div class="bank-card" id="bankCard" data-frozen="false">
<button class="card-inner" id="cardFlip" type="button" aria-label="Flip card to reveal security code">
<!-- FRONT -->
<div class="card-face card-front">
<div class="card-top">
<span class="card-brand">AURUM</span>
<span class="card-type">Virtual · Visa</span>
</div>
<div class="card-chip" aria-hidden="true"></div>
<div class="card-pan" id="cardPan">
<span class="grp">5412</span>
<span class="grp mask">••••</span>
<span class="grp mask">••••</span>
<span class="grp" id="panLast">4242</span>
</div>
<div class="card-bottom">
<div class="card-field">
<span class="lbl">Card holder</span>
<span class="val">JORDAN A. RIVERS</span>
</div>
<div class="card-field">
<span class="lbl">Expires</span>
<span class="val">09 / 28</span>
</div>
</div>
<span class="frozen-badge" aria-hidden="true">❄ Frozen</span>
</div>
<!-- BACK -->
<div class="card-face card-back">
<div class="card-stripe" aria-hidden="true"></div>
<div class="card-cvv-row">
<span class="signbox" aria-hidden="true"></span>
<div class="cvv">
<span class="lbl">CVV</span>
<span class="val" id="cvvVal">•••</span>
</div>
</div>
<p class="card-note">Tap to flip · CVV hidden for your security</p>
</div>
</button>
</div>
<div class="card-quick">
<button class="quick-btn" id="copyBtn" type="button">
<span aria-hidden="true">⧉</span> Copy number
</button>
<button class="quick-btn" id="revealBtn" type="button" aria-pressed="false">
<span aria-hidden="true">👁</span> Reveal CVV
</button>
<button class="quick-btn quick-virtual" id="virtualBtn" type="button">
<span aria-hidden="true">+</span> New virtual card
</button>
</div>
</div>
<div class="freeze-panel" id="freezePanel">
<div class="freeze-text">
<h2 id="freezeTitle">Card is active</h2>
<p id="freezeDesc">Payments, ATM and online use are enabled.</p>
</div>
<button class="toggle" id="freezeToggle" role="switch" aria-checked="false" aria-label="Freeze card">
<span class="toggle-knob"></span>
</button>
</div>
<div class="limit-panel">
<div class="limit-head">
<h2>Monthly spending limit</h2>
<span class="limit-val" id="limitVal">$3,500</span>
</div>
<input type="range" id="limitSlider" class="slider" min="500" max="10000" step="250" value="3500"
aria-label="Monthly spending limit" />
<div class="limit-meta">
<span>Spent this month <strong id="limitSpent">$1,842</strong></span>
<span id="limitPct" class="limit-pct">53% used</span>
</div>
<div class="limit-bar"><span id="limitBarFill" style="width:53%"></span></div>
</div>
</section>
<!-- RIGHT: settings + transactions -->
<section class="col-detail">
<div class="panel settings-panel">
<h2 class="panel-title">Card controls</h2>
<ul class="settings-list" id="settingsList">
<li class="setting" data-key="online">
<div class="setting-icon" aria-hidden="true">🌐</div>
<div class="setting-text">
<span class="s-name">Online payments</span>
<span class="s-desc">E-commerce & subscriptions</span>
</div>
<button class="toggle toggle-sm on" role="switch" aria-checked="true" aria-label="Toggle online payments">
<span class="toggle-knob"></span>
</button>
</li>
<li class="setting" data-key="contactless">
<div class="setting-icon" aria-hidden="true">📶</div>
<div class="setting-text">
<span class="s-name">Contactless</span>
<span class="s-desc">Tap to pay in stores</span>
</div>
<button class="toggle toggle-sm on" role="switch" aria-checked="true" aria-label="Toggle contactless">
<span class="toggle-knob"></span>
</button>
</li>
<li class="setting" data-key="atm">
<div class="setting-icon" aria-hidden="true">🏧</div>
<div class="setting-text">
<span class="s-name">ATM withdrawals</span>
<span class="s-desc">Cash at any network ATM</span>
</div>
<button class="toggle toggle-sm" role="switch" aria-checked="false" aria-label="Toggle ATM withdrawals">
<span class="toggle-knob"></span>
</button>
</li>
<li class="setting" data-key="intl">
<div class="setting-icon" aria-hidden="true">✈</div>
<div class="setting-text">
<span class="s-name">International use</span>
<span class="s-desc">Payments outside your region</span>
</div>
<button class="toggle toggle-sm on" role="switch" aria-checked="true" aria-label="Toggle international use">
<span class="toggle-knob"></span>
</button>
</li>
</ul>
</div>
<div class="panel tx-panel">
<div class="tx-head">
<h2 class="panel-title">Card transactions</h2>
<span class="tx-count" id="txCount">6 this week</span>
</div>
<ul class="tx-list" id="txList">
<li class="tx">
<span class="tx-logo" data-c="teal" aria-hidden="true">SP</span>
<div class="tx-main">
<span class="tx-name">Spotify Premium</span>
<span class="tx-meta">Subscription · Today, 09:12</span>
</div>
<div class="tx-right">
<span class="amt debit">−$11.99</span>
<span class="status cleared">Cleared</span>
</div>
</li>
<li class="tx">
<span class="tx-logo" data-c="violet" aria-hidden="true">UB</span>
<div class="tx-main">
<span class="tx-name">Uber · Trip to Midtown</span>
<span class="tx-meta">Transport · Today, 08:04</span>
</div>
<div class="tx-right">
<span class="amt debit">−$18.40</span>
<span class="status pending">Pending</span>
</div>
</li>
<li class="tx">
<span class="tx-logo" data-c="ok" aria-hidden="true">↺</span>
<div class="tx-main">
<span class="tx-name">Refund · Nordwind Apparel</span>
<span class="tx-meta">Refund · Yesterday, 16:48</span>
</div>
<div class="tx-right">
<span class="amt credit">+$64.00</span>
<span class="status cleared">Cleared</span>
</div>
</li>
<li class="tx">
<span class="tx-logo" data-c="accent" aria-hidden="true">WF</span>
<div class="tx-main">
<span class="tx-name">Whole Foods Market</span>
<span class="tx-meta">Groceries · Yesterday, 13:21</span>
</div>
<div class="tx-right">
<span class="amt debit">−$73.58</span>
<span class="status cleared">Cleared</span>
</div>
</li>
<li class="tx">
<span class="tx-logo" data-c="danger" aria-hidden="true">!</span>
<div class="tx-main">
<span class="tx-name">Aurora Cloud Hosting</span>
<span class="tx-meta">Software · Mon, 11:02</span>
</div>
<div class="tx-right">
<span class="amt debit">−$29.00</span>
<span class="status failed">Failed</span>
</div>
</li>
<li class="tx">
<span class="tx-logo" data-c="teal" aria-hidden="true">BL</span>
<div class="tx-main">
<span class="tx-name">Blue Bottle Coffee</span>
<span class="tx-meta">Dining · Mon, 08:37</span>
</div>
<div class="tx-right">
<span class="amt debit">−$6.25</span>
<span class="status cleared">Cleared</span>
</div>
</li>
</ul>
</div>
</section>
</div>
</main>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Card Detail
A complete card management screen built in the trust-first fintech style: calm navy gradients, Inter typography and tabular figures for every amount. The hero is an animated payment card with a masked PAN (5412 •••• •••• 4242) that flips in 3D to reveal its CVV, a metallic chip, and a frosted “Frozen” badge that fades in when the card is paused.
Controls sit directly below the card. A freeze toggle dims and desaturates the card while blocking payments, a spending-limit slider updates the live amount, usage percentage and progress bar in real time (turning red as you approach the cap), and quick actions let you copy the full card number or spin up a new virtual card. On the right, a settings panel governs online payments, contactless, ATM withdrawals and international use, followed by a transaction feed with merchant avatars, color-coded credit/debit amounts and cleared, pending and failed status pills.
Everything is vanilla JavaScript with a small toast() helper for feedback — no frameworks, no build step. Toggles use real role="switch" semantics, the slider and buttons are keyboard-usable, and the layout collapses to a single column down to 360px for a mobile-first customer feel.
Illustrative UI only — not real banking software or financial advice.