Files
zeekay 7c5d9aa269 the face is Zen, and it ships from @hanzo/font
One family. Font stacks name Zen and fall back to the native faces, tokens
name the role rather than a face, and the packages that used to supply a
face now point at @hanzo/font.

Self-hosted @font-face blocks are removed rather than renamed: rewriting the
family in one would leave a src pointing at a file this repo no longer ships.
@hanzo/font carries the binaries and declares the faces, so the local copies
go with the declaration that used them.

Comments naming a face we no longer use are deleted, not reworded.
2026-09-01 08:16:50 -07:00

129 lines
8.0 KiB
HTML

<!doctype html>
<html><head><meta charset="utf-8"><link rel="stylesheet" href="lib.css">
<style>
.pay-grid { display: grid; grid-template-columns: 400px 1fr; gap: 20px; flex: 1; min-height: 0; }
.form-card { display: flex; flex-direction: column; gap: 14px; }
.field label { font-size: 11px; font-weight: 650; color: var(--ink3); text-transform: uppercase; letter-spacing: 0.07em; }
.field .input {
margin-top: 6px; padding: 12px 14px; border-radius: 10px;
background: var(--panel2); border: 1px solid var(--line2);
font-size: 15px; font-weight: 600; display: flex; justify-content: space-between; align-items: center;
}
.field .input .cur { color: var(--ink2); font-size: 12px; font-weight: 700; }
.send-btn {
margin-top: 4px; padding: 13px; border-radius: 10px; border: none;
background: linear-gradient(135deg, #ffffff, #d8c37a); color: #000;
font-size: 14px; font-weight: 700; font-family: Zen, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.3s ease;
}
.send-btn.pressed { transform: scale(0.97); box-shadow: 0 0 26px rgba(212, 175, 55, 0.45); }
.steps { display: flex; flex-direction: column; gap: 0; margin-top: 6px; }
.step { display: flex; align-items: center; gap: 12px; padding: 9px 2px; color: var(--ink3); font-size: 13px; font-weight: 550; transition: color 0.4s ease; }
.step .dot {
width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid var(--line2);
display: flex; align-items: center; justify-content: center; font-size: 11px;
transition: all 0.4s ease; flex-shrink: 0; color: transparent;
}
.step.done { color: var(--ink); }
.step.done .dot { background: rgba(52, 211, 153, 0.15); border-color: var(--green); color: var(--green); }
.step.live .dot { border-color: var(--gold); animation: pulse-glow 1s ease infinite; }
.rate { font-size: 12px; color: var(--ink3); display: flex; justify-content: space-between; }
.rate b { color: var(--ink2); font-variant-numeric: tabular-nums; }
.right-col { display: flex; flex-direction: column; gap: 20px; min-height: 0; }
.row { grid-template-columns: 2fr 1.4fr 1fr 1fr 1fr; }
.thead { grid-template-columns: 2fr 1.4fr 1fr 1fr 1fr; }
</style></head>
<body><div class="app">
<aside class="side">
<div class="brand"><div class="brand-mark">▼</div><div class="brand-name">Lux</div></div>
<div class="nav-item"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>Dashboard</div>
<div class="nav-item active"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3.5 3 14 0 18M12 3c-3 3.5-3 14 0 18"/></svg>Payments</div>
<div class="nav-item"><svg viewBox="0 0 24 24"><rect x="2" y="6" width="20" height="13" rx="2"/><path d="M2 10h20"/></svg>Cards</div>
<div class="nav-item"><svg viewBox="0 0 24 24"><path d="M21 8v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8m18 0V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v2m18 0H3"/></svg>Wallets</div>
<div class="nav-item"><svg viewBox="0 0 24 24"><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>Exchange</div>
<div class="foot"><span class="env-dot"></span>Sandbox · demo tenant</div>
</aside>
<main class="main">
<div class="topbar fx">
<h1>Cross-border payment</h1>
<div class="who"><span class="pill"><span class="env-dot"></span>Live rails</span><div class="avatar">LX</div>Lux Demo</div>
</div>
<div class="pay-grid">
<div class="card form-card fx">
<div class="field"><label>You send</label><div class="input"><span id="amt">$10,000.00</span><span class="cur">USDC · Polygon</span></div></div>
<div class="field"><label>Recipient gets</label><div class="input"><span id="recv">₦15,482,000</span><span class="cur">NGN · Lagos</span></div></div>
<div class="rate"><span>Rate</span><b>1 USDC = ₦1,548.20</b></div>
<div class="rate"><span>Arrives</span><b>in seconds</b></div>
<button class="send-btn" id="send">Send payment</button>
<div class="steps">
<div class="step" id="s1"><span class="dot">✓</span>Compliance check — sanctions, travel rule</div>
<div class="step" id="s2"><span class="dot">✓</span>MPC signing ceremony — 2 of 3 shares</div>
<div class="step" id="s3"><span class="dot">✓</span>Teleport — Polygon → settlement</div>
<div class="step" id="s4"><span class="dot">✓</span>Paid out — NGN local rails</div>
</div>
</div>
<div class="right-col">
<div class="stats" style="grid-template-columns: repeat(3, 1fr);">
<div class="card fx"><div class="label">Balance</div><div class="value" id="bal">$2,847,293</div><div class="delta">USDC · multi-chain</div></div>
<div class="card fx"><div class="label">Today</div><div class="value" id="cnt">1,247</div><div class="delta">payments sent</div></div>
<div class="card fx"><div class="label">Corridors</div><div class="value">40+</div><div class="delta">countries live</div></div>
</div>
<div class="table fx">
<div class="thead"><span>Recipient</span><span>Corridor</span><span>Amount</span><span>Rail</span><span>Status</span></div>
<div id="feed"></div>
</div>
</div>
</div>
</main>
</div>
<script>
const $ = (id) => document.getElementById(id);
const rows = [
['Adaeze O.', 'US → Nigeria', '$10,000.00', 'Teleport', 'ok', 'Settled'],
['Marisol G.', 'US → Mexico', '$3,420.00', 'SPEI', 'ok', 'Settled'],
['Rafael S.', 'US → Brazil', '$8,150.00', 'PIX', 'ok', 'Settled'],
['Priya N.', 'UK → India', '£2,600.00', 'UPI', 'ok', 'Settled'],
['Kwame A.', 'EU → Ghana', '€1,975.00', 'MoMo', 'ok', 'Settled'],
['Northwind Ltd', 'US → UK', '$42,000.00', 'SWIFT', 'ok', 'Settled'],
['Sandbox Realty', 'US → US', '$12,500.00', 'ACH', 'ok', 'Settled'],
['Linh T.', 'SG → Vietnam', 'S$4,800.00', 'Teleport', 'ok', 'Settled'],
['Acme Corp', 'EU → US', '€28,300.00', 'Fedwire', 'ok', 'Settled'],
['Fatima B.', 'UK → Pakistan', '£950.00', 'Teleport', 'ok', 'Settled'],
];
function addRow([name, corr, amt, rail, cls, st], flash) {
const d = document.createElement('div');
d.className = 'row' + (flash ? ' flash' : '');
d.style.gridTemplateColumns = '2fr 1.4fr 1fr 1fr 1fr';
d.innerHTML = `<span>${name}</span><span class="mono" style="color:var(--ink2)">${corr}</span><span>${amt}</span><span class="mono" style="color:var(--ink2)">${rail}</span><span class="tag ${cls}">${st}</span>`;
$('feed').prepend(d);
while ($('feed').children.length > 11) $('feed').lastChild.remove();
}
function count(el, from, to, ms, fmt) {
const t0 = performance.now();
(function tick(t) {
const k = Math.min(1, (t - t0) / ms), v = from + (to - from) * (1 - Math.pow(1 - k, 3));
el.textContent = fmt(v);
if (k < 1) requestAnimationFrame(tick);
})(t0);
}
const usd = (v) => '$' + Math.round(v).toLocaleString('en-US');
function cycle() {
document.querySelectorAll('.fx').forEach((el, i) => { el.classList.remove('in'); setTimeout(() => el.classList.add('in'), 80 + i * 90); });
['s1','s2','s3','s4'].forEach(id => $(id).className = 'step');
$('feed').innerHTML = '';
rows.slice(1).reverse().forEach(r => addRow(r, false));
count($('bal'), 2214000, 2847293, 1400, usd);
count($('cnt'), 1195, 1246, 1400, v => Math.round(v).toLocaleString());
setTimeout(() => { $('send').classList.add('pressed'); setTimeout(() => $('send').classList.remove('pressed'), 250); }, 1600);
const steps = ['s1','s2','s3','s4'];
steps.forEach((id, i) => {
setTimeout(() => {
if (i > 0) $(steps[i-1]).className = 'step done';
$(id).className = 'step live';
}, 2000 + i * 900);
});
setTimeout(() => { $(steps[3]).className = 'step done'; addRow(rows[0], true); count($('cnt'), 1246, 1247, 400, v => Math.round(v).toLocaleString()); }, 2000 + 4 * 900);
}
cycle(); setInterval(cycle, 8000);
</script></body></html>