Web3 — Wallet App Landing
A warm, consumer-grade landing page for Lumen Wallet, a fictional self-custody crypto wallet. Features an animated phone mockup that cycles between home balance, swap, and buy-with-card screens, app-store download CTAs, a count-up downloads stat, a feature trio with soft-glow cards, a non-custodial trust band, a supported-chains chip row, a three-step onboarding flow, and an auto-advancing testimonial slider. Dark, rounded, friendly, and accessible — built with vanilla HTML, CSS, and JavaScript.
MCP
Code
/* ============================================================
Lumen Wallet — consumer wallet-app landing
Palette override: clean dark + friendly single accent.
UI-only simulation. Fictional tokens & chains.
============================================================ */
:root {
--bg: #0c0e14;
--surface: #141722;
--surface-2: #1b1f2c;
--elevated: #232838;
--text: #eef0f6;
--muted: #9298ac;
--line: rgba(255, 255, 255, 0.08);
--line-2: rgba(255, 255, 255, 0.16);
--accent: #6c5ce7;
--accent-2: #2bd9a8;
--accent-soft: rgba(108, 92, 231, 0.16);
--accent-glow: rgba(108, 92, 231, 0.45);
--pos: #26d07c;
--neg: #ff4d6d;
--warn: #ffb347;
--r-sm: 10px;
--r-md: 16px;
--r-lg: 24px;
--r-pill: 999px;
--maxw: 1140px;
--shadow-soft: 0 18px 50px -18px rgba(0, 0, 0, 0.7);
--shadow-glow: 0 14px 40px -10px var(--accent-glow);
--font-ui: "Space Grotesk", system-ui, -apple-system, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--font-ui);
background: var(--bg);
color: var(--text);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
background-image:
radial-gradient(900px 600px at 80% -8%, rgba(108, 92, 231, 0.14), transparent 60%),
radial-gradient(700px 500px at 0% 12%, rgba(43, 217, 168, 0.08), transparent 55%);
}
.mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1; }
.pos { color: var(--pos); }
.neg { color: var(--neg); }
.muted { color: var(--muted); }
.grad-text {
background: linear-gradient(100deg, var(--accent) 10%, var(--accent-2) 95%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
a { color: inherit; text-decoration: none; }
button {
font: inherit;
cursor: pointer;
color: inherit;
border: none;
background: none;
}
:focus-visible {
outline: 2px solid var(--accent-2);
outline-offset: 2px;
border-radius: 6px;
}
/* ---------- buttons ---------- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 11px 18px;
border-radius: var(--r-pill);
font-weight: 600;
font-size: 0.92rem;
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(0.99); }
.btn--primary {
background: linear-gradient(100deg, var(--accent), #8b7bff);
color: #fff;
box-shadow: var(--shadow-glow);
}
.btn--primary:hover { box-shadow: 0 18px 50px -8px var(--accent-glow); transform: translateY(-1px); }
.btn--ghost {
background: var(--surface-2);
border: 1px solid var(--line);
color: var(--text);
}
.btn--ghost:hover { background: var(--elevated); border-color: var(--line-2); }
.btn--lg { padding: 15px 26px; font-size: 1rem; }
/* ---------- nav ---------- */
.nav {
position: sticky;
top: 0;
z-index: 40;
display: flex;
align-items: center;
gap: 22px;
max-width: var(--maxw);
margin: 0 auto;
padding: 14px 22px;
background: rgba(12, 14, 20, 0.72);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-bottom: 1px solid var(--line);
}
.nav__brand {
display: inline-flex;
align-items: center;
gap: 9px;
font-weight: 700;
font-size: 1.12rem;
letter-spacing: -0.01em;
}
.nav__brand em { font-style: normal; color: var(--accent-2); }
.nav__logo {
display: grid;
place-items: center;
width: 32px;
height: 32px;
border-radius: 9px;
color: #fff;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
box-shadow: 0 6px 16px -4px var(--accent-glow);
}
.nav__links {
display: flex;
gap: 20px;
margin-left: auto;
font-size: 0.92rem;
color: var(--muted);
}
.nav__links a { transition: color 0.15s ease; }
.nav__links a:hover { color: var(--text); }
.nav__cta { display: flex; gap: 10px; }
/* ---------- hero ---------- */
.hero {
position: relative;
max-width: var(--maxw);
margin: 0 auto;
padding: 64px 22px 56px;
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 48px;
align-items: center;
}
.hero__glow {
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(420px 360px at 78% 42%, var(--accent-soft), transparent 70%);
filter: blur(8px);
}
.hero__copy { position: relative; z-index: 2; }
.pill {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 13px;
border-radius: var(--r-pill);
font-size: 0.8rem;
font-weight: 500;
background: var(--surface-2);
border: 1px solid var(--line);
color: var(--muted);
}
.pill--accent { color: var(--accent-2); border-color: rgba(43, 217, 168, 0.3); background: rgba(43, 217, 168, 0.08); }
.pill__dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--accent-2);
box-shadow: 0 0 0 4px rgba(43, 217, 168, 0.18);
animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
.hero__title {
font-size: clamp(2.2rem, 5.2vw, 3.5rem);
line-height: 1.06;
letter-spacing: -0.025em;
font-weight: 700;
margin: 18px 0 14px;
}
.hero__sub {
color: var(--muted);
font-size: 1.08rem;
max-width: 30rem;
margin: 0 0 26px;
}
.hero__stores { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 30px; }
.store-btn {
display: inline-flex;
align-items: center;
gap: 11px;
padding: 9px 18px;
border-radius: 14px;
background: var(--surface-2);
border: 1px solid var(--line);
color: var(--text);
transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
}
.store-btn:hover { transform: translateY(-2px); border-color: var(--line-2); background: var(--elevated); }
.store-btn__text { display: flex; flex-direction: column; line-height: 1.1; text-align: left; }
.store-btn__text small { font-size: 0.62rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.store-btn__text strong { font-size: 1rem; font-weight: 600; }
.hero__stats {
display: flex;
gap: 30px;
flex-wrap: wrap;
padding-top: 22px;
border-top: 1px solid var(--line);
}
.stat { display: flex; flex-direction: column; }
.stat__num { font-size: 1.7rem; font-weight: 700; letter-spacing: -0.02em; }
.stat__label { font-size: 0.8rem; color: var(--muted); }
/* ---------- phone mockup ---------- */
.hero__phone {
position: relative;
display: grid;
place-items: center;
z-index: 2;
}
.phone {
position: relative;
width: 300px;
height: 600px;
border-radius: 44px;
padding: 14px;
background: linear-gradient(160deg, #2a3047, #14171f);
border: 1px solid var(--line-2);
box-shadow: var(--shadow-soft), 0 0 0 1px rgba(108, 92, 231, 0.18), 0 40px 80px -30px var(--accent-glow);
overflow: hidden;
animation: floaty 7s ease-in-out infinite;
}
@keyframes floaty {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.phone__notch {
position: absolute;
top: 16px; left: 50%;
transform: translateX(-50%);
width: 120px; height: 24px;
background: #0a0c11;
border-radius: var(--r-pill);
z-index: 5;
}
.phone__screens {
position: relative;
width: 100%;
height: calc(100% - 40px);
border-radius: 32px;
background: radial-gradient(120% 60% at 50% 0%, #1a1f30, var(--surface));
overflow: hidden;
}
.screen {
position: absolute;
inset: 0;
padding: 44px 18px 18px;
display: flex;
flex-direction: column;
opacity: 0;
transform: translateY(14px) scale(0.98);
transition: opacity 0.5s ease, transform 0.5s ease;
pointer-events: none;
}
.screen.is-active { opacity: 1; transform: none; pointer-events: auto; }
.screen__top {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 14px;
}
.screen__title { font-weight: 600; font-size: 1.05rem; }
.avatar {
width: 30px; height: 30px;
border-radius: 50%;
display: grid; place-items: center;
font-weight: 700; font-size: 0.85rem; color: #fff;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
}
.addr {
font-size: 0.8rem;
color: var(--muted);
background: var(--surface-2);
padding: 3px 9px;
border-radius: var(--r-pill);
}
.icon-btn {
display: inline-grid;
place-items: center;
width: 28px; height: 28px;
border-radius: 8px;
color: var(--muted);
background: var(--surface-2);
border: 1px solid var(--line);
transition: color 0.15s, background 0.15s;
}
.icon-btn:hover { color: var(--text); background: var(--elevated); }
.icon-btn--lg { width: 40px; height: 40px; border-radius: 12px; font-size: 1.1rem; }
.screen__top .icon-btn { margin-left: auto; }
.screen__top .chip-sm { margin-left: auto; }
.screen__label { font-size: 0.78rem; color: var(--muted); margin: 2px 0 2px; }
.screen__balance { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; margin: 0; }
.screen__delta { font-size: 0.78rem; margin: 4px 0 14px; }
.screen__sub { font-size: 0.8rem; color: var(--muted); margin: 4px 0 12px; }
.screen__actions {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 6px;
margin-bottom: 16px;
}
.mini-action {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
font-size: 0.68rem;
color: var(--muted);
}
.mini-action i {
display: grid;
place-items: center;
width: 38px; height: 38px;
border-radius: 12px;
font-style: normal;
font-size: 1rem;
color: var(--accent-2);
background: var(--surface-2);
border: 1px solid var(--line);
}
.token-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; overflow: hidden; }
.token-row {
display: flex;
align-items: center;
gap: 10px;
padding: 9px 11px;
border-radius: 14px;
background: var(--surface-2);
border: 1px solid var(--line);
}
.token-ico {
flex: none;
width: 32px; height: 32px;
border-radius: 50%;
display: grid; place-items: center;
font-weight: 700; font-size: 0.82rem; color: #0c0e14;
}
.tok-nova { background: linear-gradient(135deg, #7c5cff, #b3a4ff); }
.tok-aur { background: linear-gradient(135deg, #ffc15c, #ff9d47); }
.tok-zph { background: linear-gradient(135deg, #2bd9a8, #45f0c4); }
.tok-usd { background: linear-gradient(135deg, #4fa9ff, #7ec6ff); }
.token-meta { display: flex; flex-direction: column; line-height: 1.2; }
.token-meta strong { font-size: 0.88rem; }
.token-meta small { font-size: 0.7rem; color: var(--muted); }
.token-val { margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; line-height: 1.2; }
.token-val strong { font-size: 0.88rem; }
.token-val small { font-size: 0.72rem; }
.chip-sm {
font-size: 0.72rem;
color: var(--muted);
background: var(--surface-2);
border: 1px solid var(--line);
padding: 4px 9px;
border-radius: var(--r-pill);
}
/* swap screen */
.swap-card {
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: 16px;
padding: 12px 13px;
}
.swap-card__label { font-size: 0.72rem; color: var(--muted); margin: 0 0 6px; }
.swap-card__row { display: flex; align-items: center; justify-content: space-between; }
.swap-card__amt { font-size: 1.3rem; font-weight: 700; }
.token-pick {
display: inline-flex;
align-items: center;
gap: 6px;
font-weight: 600;
font-size: 0.85rem;
background: var(--elevated);
padding: 5px 10px 5px 5px;
border-radius: var(--r-pill);
}
.token-pick .token-ico { width: 22px; height: 22px; font-size: 0.65rem; }
.swap-card__sub { font-size: 0.7rem; color: var(--muted); margin: 6px 0 0; }
.swap-flip {
width: 34px; height: 34px;
margin: -10px auto;
position: relative; z-index: 2;
display: grid; place-items: center;
border-radius: 50%;
background: var(--elevated);
border: 3px solid var(--surface);
color: var(--accent-2);
font-size: 1rem;
}
.swap-meta {
display: grid;
grid-template-columns: 1fr auto;
gap: 5px 10px;
margin: 16px 0 14px;
font-size: 0.72rem;
}
.swap-meta span:nth-child(odd) { color: var(--muted); }
.swap-meta span:nth-child(even) { text-align: right; }
.screen-cta {
margin-top: auto;
text-align: center;
padding: 13px;
border-radius: 14px;
font-weight: 600;
font-size: 0.92rem;
color: #fff;
background: linear-gradient(100deg, var(--accent), #8b7bff);
box-shadow: 0 10px 26px -8px var(--accent-glow);
}
.screen-cta--mint {
background: linear-gradient(100deg, var(--accent-2), #43f0c4);
color: #06140f;
box-shadow: 0 10px 26px -8px rgba(43, 217, 168, 0.5);
}
/* buy keypad */
.keypad {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
margin: 8px 0 16px;
}
.keypad span {
display: grid;
place-items: center;
padding: 12px 0;
border-radius: 12px;
font-family: var(--font-mono);
font-size: 1.1rem;
background: var(--surface-2);
border: 1px solid var(--line);
}
/* phone dots */
.phone__dots {
position: absolute;
bottom: 22px; left: 50%;
transform: translateX(-50%);
display: flex;
gap: 7px;
z-index: 6;
}
.dot {
width: 8px; height: 8px;
border-radius: 50%;
background: var(--line-2);
transition: width 0.3s ease, background 0.3s ease;
}
.dot.is-active { width: 22px; border-radius: var(--r-pill); background: var(--accent); }
/* floating cards */
.float-card {
position: absolute;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 13px;
border-radius: 14px;
font-size: 0.78rem;
background: rgba(20, 23, 34, 0.82);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid var(--line-2);
box-shadow: var(--shadow-soft);
animation: floaty 6s ease-in-out infinite;
}
.float-card .token-ico { width: 22px; height: 22px; font-size: 0.6rem; }
.float-card--a { top: 14%; left: -18px; animation-delay: 0.6s; }
.float-card--b { bottom: 16%; right: -26px; animation-delay: 1.4s; }
.shield-ico { font-size: 1rem; }
/* ---------- generic sections ---------- */
.section {
max-width: var(--maxw);
margin: 0 auto;
padding: 70px 22px;
}
.section--tight { padding-top: 40px; padding-bottom: 40px; }
.kicker {
text-transform: uppercase;
letter-spacing: 0.14em;
font-size: 0.74rem;
font-weight: 600;
color: var(--accent-2);
margin: 0 0 8px;
}
.section__title {
font-size: clamp(1.6rem, 3.6vw, 2.3rem);
letter-spacing: -0.02em;
font-weight: 700;
margin: 0 0 8px;
}
.section__sub { color: var(--muted); margin: 0 0 30px; font-size: 1.02rem; }
/* feature trio */
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
}
.feature-card {
position: relative;
padding: 26px 24px;
border-radius: var(--r-lg);
background: var(--surface);
border: 1px solid var(--line);
overflow: hidden;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.25s ease;
}
.feature-card::before {
content: "";
position: absolute;
inset: -40% 40% auto -40%;
height: 160px;
background: radial-gradient(circle, var(--accent-soft), transparent 70%);
opacity: 0;
transition: opacity 0.3s ease;
}
.feature-card:hover, .feature-card:focus-visible {
transform: translateY(-4px);
border-color: var(--line-2);
box-shadow: var(--shadow-soft);
}
.feature-card:hover::before, .feature-card:focus-visible::before { opacity: 1; }
.feature-card__icon {
position: relative;
display: grid;
place-items: center;
width: 52px; height: 52px;
border-radius: 16px;
margin-bottom: 16px;
color: #fff;
}
.ic-key { background: linear-gradient(135deg, var(--accent), #8b7bff); box-shadow: 0 10px 26px -10px var(--accent-glow); }
.ic-swap { background: linear-gradient(135deg, var(--accent-2), #43f0c4); color: #06140f; box-shadow: 0 10px 26px -10px rgba(43, 217, 168, 0.5); }
.ic-card { background: linear-gradient(135deg, #4fa9ff, #7ec6ff); color: #04121f; box-shadow: 0 10px 26px -10px rgba(79, 169, 255, 0.5); }
.feature-card h3 { position: relative; font-size: 1.22rem; margin: 0 0 8px; }
.feature-card p { position: relative; color: var(--muted); margin: 0 0 16px; font-size: 0.95rem; }
.feature-card__tag {
position: relative;
display: inline-block;
font-size: 0.74rem;
color: var(--accent-2);
background: rgba(43, 217, 168, 0.09);
border: 1px solid rgba(43, 217, 168, 0.22);
padding: 4px 10px;
border-radius: var(--r-pill);
}
/* trust band */
.trust {
max-width: var(--maxw);
margin: 12px auto;
padding: 0 22px;
}
.trust__inner {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 26px;
align-items: center;
padding: 34px 34px;
border-radius: var(--r-lg);
background:
linear-gradient(var(--surface), var(--surface)) padding-box,
linear-gradient(120deg, var(--accent), var(--accent-2)) border-box;
border: 1.5px solid transparent;
box-shadow: var(--shadow-soft);
}
.trust__badge {
display: grid;
place-items: center;
width: 68px; height: 68px;
border-radius: 20px;
color: var(--accent-2);
background: rgba(43, 217, 168, 0.1);
border: 1px solid rgba(43, 217, 168, 0.25);
}
.trust__copy h2 { margin: 0 0 8px; font-size: 1.5rem; letter-spacing: -0.02em; }
.trust__copy p { margin: 0; color: var(--muted); font-size: 0.96rem; }
.trust__points { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 0.88rem; }
.trust__points li { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.check {
display: inline-grid;
place-items: center;
width: 18px; height: 18px;
border-radius: 50%;
font-size: 0.7rem;
color: #06140f;
background: var(--accent-2);
}
/* chains */
.chains { display: flex; flex-wrap: wrap; gap: 10px; }
.chain-chip {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 16px;
border-radius: var(--r-pill);
font-size: 0.9rem;
font-weight: 500;
background: var(--surface);
border: 1px solid var(--line);
transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
}
.chain-chip:hover { transform: translateY(-2px); border-color: var(--accent); background: var(--surface-2); }
.chain-chip--more { color: var(--accent-2); border-style: dashed; }
.chain-dot { width: 10px; height: 10px; border-radius: 50%; }
.d1 { background: #7c5cff; } .d2 { background: #ff9d47; } .d3 { background: #2bd9a8; }
.d4 { background: #4fa9ff; } .d5 { background: #ff4d6d; } .d6 { background: #45f0c4; }
.d7 { background: #ffc15c; }
/* steps */
.steps {
list-style: none;
margin: 0; padding: 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
counter-reset: step;
}
.step {
position: relative;
padding: 26px 22px;
border-radius: var(--r-lg);
background: var(--surface);
border: 1px solid var(--line);
}
.step__num {
font-size: 1.4rem;
font-weight: 700;
color: var(--accent);
display: block;
margin-bottom: 10px;
}
.step h3 { margin: 0 0 6px; font-size: 1.12rem; }
.step p { margin: 0; color: var(--muted); font-size: 0.92rem; }
/* reviews */
.reviews { position: relative; }
.reviews__track {
position: relative;
min-height: 200px;
}
.review {
position: absolute;
inset: 0;
margin: 0;
padding: 30px 32px;
border-radius: var(--r-lg);
background: var(--surface);
border: 1px solid var(--line);
opacity: 0;
transform: translateX(24px);
transition: opacity 0.45s ease, transform 0.45s ease;
pointer-events: none;
}
.review.is-active { opacity: 1; transform: none; position: relative; pointer-events: auto; }
.review__stars { color: var(--warn); letter-spacing: 2px; margin-bottom: 12px; }
.review blockquote {
margin: 0 0 18px;
font-size: 1.2rem;
line-height: 1.45;
letter-spacing: -0.01em;
}
.review figcaption { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 0.9rem; }
.review__avatar {
width: 38px; height: 38px;
border-radius: 50%;
display: grid; place-items: center;
font-weight: 700; font-size: 0.82rem; color: #fff;
}
.av1 { background: linear-gradient(135deg, #7c5cff, #b3a4ff); }
.av2 { background: linear-gradient(135deg, #2bd9a8, #45f0c4); }
.av3 { background: linear-gradient(135deg, #ff9d47, #ffc15c); }
.review figcaption .mono { width: 100%; font-size: 0.78rem; margin-top: -2px; }
.reviews__nav { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 22px; }
.reviews__dots { display: flex; gap: 7px; }
.reviews__dots .dot { background: var(--line-2); }
.reviews__dots .dot.is-active { background: var(--accent); }
/* final cta */
.final-cta {
max-width: var(--maxw);
margin: 30px auto 0;
padding: 60px 22px 70px;
text-align: center;
}
.final-cta h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); letter-spacing: -0.02em; margin: 0 0 10px; }
.final-cta p { color: var(--muted); margin: 0 0 26px; font-size: 1.05rem; }
.final-cta strong { color: var(--accent-2); }
.final-cta__btns { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
/* footer */
.footer {
border-top: 1px solid var(--line);
background: var(--surface);
}
.footer__grid {
max-width: var(--maxw);
margin: 0 auto;
padding: 48px 22px 30px;
display: grid;
grid-template-columns: 1.6fr 1fr 1fr 1fr;
gap: 30px;
}
.footer__brand strong { display: block; margin: 10px 0 6px; font-size: 1.05rem; }
.footer__brand p { color: var(--muted); font-size: 0.9rem; margin: 0; max-width: 22rem; }
.footer nav { display: flex; flex-direction: column; gap: 8px; }
.footer nav h4 { margin: 0 0 4px; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.footer nav a { color: var(--text); font-size: 0.9rem; opacity: 0.82; transition: opacity 0.15s; }
.footer nav a:hover { opacity: 1; color: var(--accent-2); }
.footer__legal {
max-width: var(--maxw);
margin: 0 auto;
padding: 16px 22px 26px;
font-size: 0.76rem;
color: var(--muted);
border-top: 1px solid var(--line);
}
/* toast */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 24px);
z-index: 80;
padding: 12px 18px;
border-radius: var(--r-pill);
background: var(--elevated);
border: 1px solid var(--line-2);
box-shadow: var(--shadow-soft);
font-size: 0.9rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
max-width: 90vw;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }
/* count-up shimmer */
.stat__num.is-counting { color: var(--accent-2); }
/* ---------- responsive ---------- */
@media (max-width: 900px) {
.hero { grid-template-columns: 1fr; gap: 36px; }
.hero__phone { order: -1; }
.features, .steps { grid-template-columns: 1fr; }
.trust__inner { grid-template-columns: 1fr; text-align: center; }
.trust__badge { margin: 0 auto; }
.trust__points { justify-items: center; }
.footer__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.nav { gap: 12px; padding: 12px 16px; }
.nav__links { display: none; }
.nav__cta .btn--ghost { display: none; }
.hero { padding: 36px 16px 40px; }
.hero__stats { gap: 20px; }
.section { padding: 48px 16px; }
.phone { width: 270px; height: 540px; }
.float-card--a { left: -6px; }
.float-card--b { right: -8px; }
.review blockquote { font-size: 1.05rem; }
.footer__grid { grid-template-columns: 1fr; gap: 22px; }
.trust__inner { padding: 26px 20px; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; scroll-behavior: auto; }
}/* ============================================================
Lumen Wallet — landing interactions (vanilla JS, no libs)
UI-only simulation: nothing here touches a real wallet,
network, RPC, or chain. All data is mock/fictional.
============================================================ */
(function () {
"use strict";
var reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2400);
}
// any element with data-toast fires the toast on click
document.addEventListener("click", function (e) {
var t = e.target.closest("[data-toast]");
if (t) toast(t.getAttribute("data-toast"));
});
/* ---------- count-up stats (animate on first view) ---------- */
function formatNum(value, decimals) {
if (decimals) return value.toFixed(decimals);
if (value >= 1e6) return (value / 1e6).toFixed(value % 1e6 === 0 ? 0 : 1) + "M";
if (value >= 1e3) return Math.round(value).toLocaleString("en-US");
return Math.round(value).toString();
}
function countUp(el) {
var target = parseFloat(el.getAttribute("data-countup")) || 0;
var decimals = parseInt(el.getAttribute("data-decimals") || "0", 10);
var suffix = el.getAttribute("data-suffix") || "";
if (reduceMotion) {
el.textContent = formatNum(target, decimals) + suffix;
return;
}
el.classList.add("is-counting");
var dur = 1500;
var start = performance.now();
function tick(now) {
var p = Math.min((now - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
el.textContent = formatNum(target * eased, decimals) + suffix;
if (p < 1) {
requestAnimationFrame(tick);
} else {
el.textContent = formatNum(target, decimals) + suffix;
el.classList.remove("is-counting");
}
}
requestAnimationFrame(tick);
}
var stats = [].slice.call(document.querySelectorAll("[data-countup]"));
if ("IntersectionObserver" in window && stats.length) {
var io = new IntersectionObserver(function (entries, obs) {
entries.forEach(function (en) {
if (en.isIntersecting) {
countUp(en.target);
obs.unobserve(en.target);
}
});
}, { threshold: 0.5 });
stats.forEach(function (s) { io.observe(s); });
} else {
stats.forEach(countUp);
}
/* ---------- phone screen carousel ---------- */
var phone = document.getElementById("phone");
if (phone) {
var screens = [].slice.call(phone.querySelectorAll(".screen"));
var dots = [].slice.call(phone.querySelectorAll(".dot[data-go]"));
var current = 0;
var autoTimer;
function showScreen(i, userInitiated) {
current = (i + screens.length) % screens.length;
screens.forEach(function (s, idx) {
s.classList.toggle("is-active", idx === current);
});
dots.forEach(function (d, idx) {
var on = idx === current;
d.classList.toggle("is-active", on);
d.setAttribute("aria-selected", on ? "true" : "false");
});
if (userInitiated) restartAuto();
}
function nextScreen() { showScreen(current + 1); }
function startAuto() {
if (reduceMotion) return;
autoTimer = setInterval(nextScreen, 3600);
}
function restartAuto() {
clearInterval(autoTimer);
startAuto();
}
dots.forEach(function (d) {
d.addEventListener("click", function () {
showScreen(parseInt(d.getAttribute("data-go"), 10), true);
});
});
// pause cycling while hovering / focusing the phone
phone.addEventListener("mouseenter", function () { clearInterval(autoTimer); });
phone.addEventListener("mouseleave", startAuto);
phone.addEventListener("focusin", function () { clearInterval(autoTimer); });
phone.addEventListener("focusout", startAuto);
// simulated CTA confirmations inside the phone
phone.addEventListener("click", function (e) {
var cta = e.target.closest(".screen-cta");
if (cta) toast("Review screen (demo) — you'd confirm & sign locally. Nothing is broadcast.");
});
showScreen(0);
startAuto();
}
/* ---------- testimonial slider ---------- */
var track = document.getElementById("reviewsTrack");
if (track) {
var reviews = [].slice.call(track.querySelectorAll(".review"));
var dotsWrap = document.getElementById("reviewsDots");
var prevBtn = document.getElementById("revPrev");
var nextBtn = document.getElementById("revNext");
var rIndex = 0;
var rTimer;
// build dots
reviews.forEach(function (_, i) {
var b = document.createElement("button");
b.type = "button";
b.className = "dot" + (i === 0 ? " is-active" : "");
b.setAttribute("role", "tab");
b.setAttribute("aria-label", "Testimonial " + (i + 1));
b.setAttribute("aria-selected", i === 0 ? "true" : "false");
b.addEventListener("click", function () { showReview(i, true); });
dotsWrap.appendChild(b);
});
var rDots = [].slice.call(dotsWrap.querySelectorAll(".dot"));
function showReview(i, userInitiated) {
rIndex = (i + reviews.length) % reviews.length;
reviews.forEach(function (r, idx) { r.classList.toggle("is-active", idx === rIndex); });
rDots.forEach(function (d, idx) {
var on = idx === rIndex;
d.classList.toggle("is-active", on);
d.setAttribute("aria-selected", on ? "true" : "false");
});
if (userInitiated) restartReviews();
}
function startReviews() {
if (reduceMotion) return;
rTimer = setInterval(function () { showReview(rIndex + 1); }, 5200);
}
function restartReviews() { clearInterval(rTimer); startReviews(); }
if (prevBtn) prevBtn.addEventListener("click", function () { showReview(rIndex - 1, true); });
if (nextBtn) nextBtn.addEventListener("click", function () { showReview(rIndex + 1, true); });
track.parentElement.addEventListener("mouseenter", function () { clearInterval(rTimer); });
track.parentElement.addEventListener("mouseleave", startReviews);
startReviews();
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Lumen Wallet — Your keys, your crypto, made simple</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=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ====== NAV ====== -->
<header class="nav">
<a class="nav__brand" href="#top" aria-label="Lumen Wallet home">
<span class="nav__logo" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none">
<path d="M12 2 3 7v10l9 5 9-5V7l-9-5Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
<circle cx="12" cy="12" r="3.2" fill="currentColor"/>
</svg>
</span>
Lumen<em>Wallet</em>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#features">Features</a>
<a href="#security">Security</a>
<a href="#chains">Chains</a>
<a href="#steps">Get started</a>
<a href="#reviews">Reviews</a>
</nav>
<div class="nav__cta">
<button class="btn btn--ghost" type="button" data-toast="Opening web app (demo) — nothing actually launches">Web app</button>
<button class="btn btn--primary" type="button" data-toast="Download started (demo)">Get the app</button>
</div>
</header>
<main id="top">
<!-- ====== HERO ====== -->
<section class="hero">
<div class="hero__glow" aria-hidden="true"></div>
<div class="hero__copy">
<span class="pill pill--accent">
<span class="pill__dot" aria-hidden="true"></span>
Self-custodial · Non-custodial by design
</span>
<h1 class="hero__title">Your keys, your crypto, <span class="grad-text">made simple</span></h1>
<p class="hero__sub">
Lumen Wallet keeps your assets in your hands — buy, swap, and bridge across
chains with a wallet that feels like your favorite app, not a spreadsheet.
</p>
<div class="hero__stores">
<button class="store-btn" type="button" data-toast="Redirecting to App Store (demo)">
<svg viewBox="0 0 24 24" width="26" height="26" fill="currentColor" aria-hidden="true">
<path d="M16.7 12.9c0-2.5 2-3.7 2.1-3.7-1.1-1.7-2.9-1.9-3.6-1.9-1.5-.2-3 .9-3.7.9-.8 0-2-.9-3.3-.9-1.7 0-3.2 1-4.1 2.5-1.7 3-0.4 7.5 1.3 10 .8 1.2 1.8 2.6 3.1 2.5 1.2-.1 1.7-.8 3.2-.8s1.9.8 3.3.8c1.4 0 2.2-1.2 3-2.4.9-1.4 1.3-2.8 1.3-2.8s-2.6-1-2.6-4.2ZM14.2 5.2c.7-.8 1.1-2 1-3.2-1 0-2.2.7-2.9 1.5-.6.7-1.2 1.9-1 3 1.1.1 2.2-.5 2.9-1.3Z"/>
</svg>
<span class="store-btn__text"><small>Download on the</small><strong>App Store</strong></span>
</button>
<button class="store-btn" type="button" data-toast="Redirecting to Play Store (demo)">
<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" aria-hidden="true">
<path d="M3.6 2.3c-.3.3-.5.8-.5 1.4v16.6c0 .6.2 1.1.5 1.4l.1.1 9.3-9.3v-1L3.7 2.2l-.1.1Zm12.5 12.6L13 11.8v-.2l3.1-3.1 4.4 2.5c1.3.7 1.3 1.9 0 2.6l-4.4 2.5v-.2ZM4.8 22.4l8.7-8.7 2.6 2.6-9.8 5.6c-.6.3-1.1.4-1.5.5Zm0-20.8c.4 0 .9.2 1.5.5l9.8 5.6-2.6 2.6-8.7-8.7Z"/>
</svg>
<span class="store-btn__text"><small>Get it on</small><strong>Google Play</strong></span>
</button>
</div>
<div class="hero__stats" role="list" aria-label="Adoption stats">
<div class="stat" role="listitem">
<strong class="stat__num mono" data-countup="2400000" data-suffix="+">0</strong>
<span class="stat__label">Downloads</span>
</div>
<div class="stat" role="listitem">
<strong class="stat__num mono" data-countup="14" data-suffix="">0</strong>
<span class="stat__label">Chains supported</span>
</div>
<div class="stat" role="listitem">
<strong class="stat__num mono" data-countup="4.9" data-decimals="1" data-suffix="★">0</strong>
<span class="stat__label">Avg. store rating</span>
</div>
</div>
</div>
<!-- Phone mockup -->
<div class="hero__phone">
<div class="phone" id="phone">
<div class="phone__notch" aria-hidden="true"></div>
<div class="phone__screens" aria-live="polite">
<!-- Screen 1: Home / balance -->
<div class="screen is-active" data-screen="home" aria-label="Wallet home preview">
<div class="screen__top">
<div class="avatar" aria-hidden="true">L</div>
<span class="addr mono" title="Demo address">0x7a3f…c41d</span>
<button class="icon-btn" type="button" data-toast="Address copied (demo)" aria-label="Copy address">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg>
</button>
</div>
<p class="screen__label">Total balance</p>
<p class="screen__balance mono">$12,408.52</p>
<p class="screen__delta mono pos">▲ +$324.18 (2.68%) today</p>
<div class="screen__actions">
<span class="mini-action"><i aria-hidden="true">↑</i>Send</span>
<span class="mini-action"><i aria-hidden="true">↓</i>Receive</span>
<span class="mini-action"><i aria-hidden="true">⇄</i>Swap</span>
<span class="mini-action"><i aria-hidden="true">+</i>Buy</span>
</div>
<ul class="token-list">
<li class="token-row">
<span class="token-ico tok-nova" aria-hidden="true">N</span>
<span class="token-meta"><strong>NOVA</strong><small>Lumen Chain</small></span>
<span class="token-val mono"><strong>$6,210.40</strong><small class="pos">+4.2%</small></span>
</li>
<li class="token-row">
<span class="token-ico tok-aur" aria-hidden="true">A</span>
<span class="token-meta"><strong>AURUM</strong><small>Helios Network</small></span>
<span class="token-val mono"><strong>$3,154.07</strong><small class="pos">+1.1%</small></span>
</li>
<li class="token-row">
<span class="token-ico tok-zph" aria-hidden="true">Z</span>
<span class="token-meta"><strong>ZEPHYR</strong><small>Mistral L2</small></span>
<span class="token-val mono"><strong>$2,044.05</strong><small class="neg">−0.8%</small></span>
</li>
<li class="token-row">
<span class="token-ico tok-usd" aria-hidden="true">$</span>
<span class="token-meta"><strong>USDx</strong><small>Stable · multichain</small></span>
<span class="token-val mono"><strong>$1,000.00</strong><small class="muted">0.0%</small></span>
</li>
</ul>
</div>
<!-- Screen 2: Swap -->
<div class="screen" data-screen="swap" aria-label="Swap preview">
<div class="screen__top">
<span class="screen__title">Swap</span>
<span class="chip-sm mono">Fee 0.25%</span>
</div>
<div class="swap-card">
<p class="swap-card__label">You pay</p>
<div class="swap-card__row">
<span class="mono swap-card__amt">1,250.00</span>
<span class="token-pick"><span class="token-ico tok-nova" aria-hidden="true">N</span>NOVA</span>
</div>
<p class="swap-card__sub mono">≈ $1,562.50 · Bal 4,968.2</p>
</div>
<div class="swap-flip" aria-hidden="true">⇅</div>
<div class="swap-card">
<p class="swap-card__label">You receive</p>
<div class="swap-card__row">
<span class="mono swap-card__amt">1,557.84</span>
<span class="token-pick"><span class="token-ico tok-usd" aria-hidden="true">$</span>USDx</span>
</div>
<p class="swap-card__sub mono">1 NOVA = 1.2463 USDx</p>
</div>
<div class="swap-meta">
<span>Route</span><span class="mono">Lumen → Helios bridge</span>
<span>Network fee</span><span class="mono">~0.0021 NOVA ($0.26)</span>
<span>Slippage</span><span class="mono">0.5%</span>
</div>
<div class="screen-cta">Review swap</div>
</div>
<!-- Screen 3: Buy with card -->
<div class="screen" data-screen="buy" aria-label="Buy with card preview">
<div class="screen__top">
<span class="screen__title">Buy crypto</span>
<span class="chip-sm mono">Visa ··4821</span>
</div>
<p class="screen__label">Amount</p>
<p class="screen__balance mono">$250.00</p>
<p class="screen__sub mono">≈ 200.12 NOVA</p>
<div class="keypad" aria-hidden="true">
<span>1</span><span>2</span><span>3</span>
<span>4</span><span>5</span><span>6</span>
<span>7</span><span>8</span><span>9</span>
<span>.</span><span>0</span><span>⌫</span>
</div>
<div class="screen-cta screen-cta--mint">Continue · instant delivery</div>
</div>
</div>
<div class="phone__dots" role="tablist" aria-label="Phone screen preview selector">
<button class="dot is-active" type="button" role="tab" aria-selected="true" data-go="0" aria-label="Home screen"></button>
<button class="dot" type="button" role="tab" aria-selected="false" data-go="1" aria-label="Swap screen"></button>
<button class="dot" type="button" role="tab" aria-selected="false" data-go="2" aria-label="Buy screen"></button>
</div>
</div>
<div class="float-card float-card--a" aria-hidden="true">
<span class="token-ico tok-nova">N</span>
<span class="mono">+482.6 NOVA received</span>
</div>
<div class="float-card float-card--b" aria-hidden="true">
<span class="shield-ico">🛡</span>
<span>Keys never leave device</span>
</div>
</div>
</section>
<!-- ====== FEATURE TRIO ====== -->
<section class="section" id="features" aria-labelledby="features-title">
<p class="kicker">Why Lumen</p>
<h2 class="section__title" id="features-title">Everything a wallet should be</h2>
<p class="section__sub">Powerful when you need it, invisible when you don't.</p>
<div class="features">
<article class="feature-card" tabindex="0">
<span class="feature-card__icon ic-key" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="14" r="4.5"/><path d="M11.5 10.5 20 2m-4 4 3 3m-6-0 2.2 2.2"/></svg>
</span>
<h3>Self-custody</h3>
<p>Your seed phrase is generated and stored only on your device, protected by a secure enclave. We can't touch your funds — and neither can anyone else.</p>
<span class="feature-card__tag mono">12 / 24-word recovery</span>
</article>
<article class="feature-card" tabindex="0">
<span class="feature-card__icon ic-swap" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h13m0 0-3.5-3.5M17 7l-3.5 3.5M20 17H7m0 0 3.5-3.5M7 17l3.5 3.5"/></svg>
</span>
<h3>Swap & bridge</h3>
<p>One tap to swap or move assets across 14 chains. Lumen finds the best simulated route, shows the fee up-front, and asks before anything is signed.</p>
<span class="feature-card__tag mono">Best-route aggregation</span>
</article>
<article class="feature-card" tabindex="0">
<span class="feature-card__icon ic-card" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="2.5" y="5" width="19" height="14" rx="3"/><path d="M2.5 10h19M6.5 15h4"/></svg>
</span>
<h3>Buy with card</h3>
<p>Top up with a debit or credit card in under a minute. Transparent pricing, no surprise spreads — what you see at checkout is what arrives.</p>
<span class="feature-card__tag mono">Apple Pay · Visa · MC</span>
</article>
</div>
</section>
<!-- ====== SECURITY TRUST BAND ====== -->
<section class="trust" id="security" aria-labelledby="trust-title">
<div class="trust__inner">
<div class="trust__badge" aria-hidden="true">
<svg viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.5 4.5 5.5v6c0 4.7 3.2 8.3 7.5 10 4.3-1.7 7.5-5.3 7.5-10v-6L12 2.5Z"/><path d="m8.8 12 2.3 2.3 4.3-4.5"/></svg>
</div>
<div class="trust__copy">
<h2 id="trust-title">Non-custodial. Audited. Open.</h2>
<p>
Lumen never holds your assets or your keys. Signing happens locally, every
transaction shows a plain-language preview before you approve, and the wallet
core is open source and independently audited (fictional audits for this demo).
</p>
</div>
<ul class="trust__points">
<li><span class="check" aria-hidden="true">✓</span> Keys encrypted on-device only</li>
<li><span class="check" aria-hidden="true">✓</span> Human-readable transaction previews</li>
<li><span class="check" aria-hidden="true">✓</span> Scam & approval-drainer warnings</li>
<li><span class="check" aria-hidden="true">✓</span> Biometric + passcode lock</li>
</ul>
</div>
</section>
<!-- ====== SUPPORTED CHAINS ====== -->
<section class="section section--tight" id="chains" aria-labelledby="chains-title">
<p class="kicker">Multichain</p>
<h2 class="section__title" id="chains-title">14 chains, one balance</h2>
<div class="chains" role="list">
<button class="chain-chip" type="button" role="listitem" data-toast="Lumen Chain — 1.2s finality (demo)"><span class="chain-dot d1" aria-hidden="true"></span>Lumen Chain</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Helios Network — EVM compatible (demo)"><span class="chain-dot d2" aria-hidden="true"></span>Helios Network</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Mistral L2 — rollup, ~$0.002 fees (demo)"><span class="chain-dot d3" aria-hidden="true"></span>Mistral L2</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Borealis — proof-of-stake (demo)"><span class="chain-dot d4" aria-hidden="true"></span>Borealis</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Quasar — high-throughput chain (demo)"><span class="chain-dot d5" aria-hidden="true"></span>Quasar</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Tidal — appchain network (demo)"><span class="chain-dot d6" aria-hidden="true"></span>Tidal</button>
<button class="chain-chip" type="button" role="listitem" data-toast="Ember — gaming-focused L2 (demo)"><span class="chain-dot d7" aria-hidden="true"></span>Ember</button>
<button class="chain-chip chain-chip--more" type="button" role="listitem" data-toast="…and 7 more fictional chains (demo)">+7 more</button>
</div>
</section>
<!-- ====== 3 STEPS ====== -->
<section class="section" id="steps" aria-labelledby="steps-title">
<p class="kicker">Onboarding</p>
<h2 class="section__title" id="steps-title">Get started in 3 steps</h2>
<ol class="steps">
<li class="step">
<span class="step__num mono" aria-hidden="true">01</span>
<h3>Download & create</h3>
<p>Install Lumen and create a wallet in seconds. Your recovery phrase is shown once — write it down, it's the only backup.</p>
</li>
<li class="step">
<span class="step__num mono" aria-hidden="true">02</span>
<h3>Fund your wallet</h3>
<p>Buy with a card, receive from a friend, or import an existing wallet. Funds appear under one unified multichain balance.</p>
</li>
<li class="step">
<span class="step__num mono" aria-hidden="true">03</span>
<h3>Explore safely</h3>
<p>Swap, bridge, and connect to apps. Every signature gets a plain-language preview and a risk check before you approve.</p>
</li>
</ol>
</section>
<!-- ====== REVIEWS ====== -->
<section class="section" id="reviews" aria-labelledby="reviews-title">
<p class="kicker">Loved by humans</p>
<h2 class="section__title" id="reviews-title">What people say</h2>
<div class="reviews" aria-roledescription="carousel" aria-label="User testimonials">
<div class="reviews__track" id="reviewsTrack">
<figure class="review is-active">
<div class="review__stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>“First wallet my mom could actually use. The transaction previews in plain English are a game changer — she knows exactly what she's approving.”</blockquote>
<figcaption><span class="review__avatar av1" aria-hidden="true">MR</span><strong>Marta R.</strong><span class="mono muted">App Store · 0x91ce…04ab</span></figcaption>
</figure>
<figure class="review">
<div class="review__stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>“Bridged NOVA from Lumen to Mistral L2 in one tap. No tab juggling, no sketchy bridge sites, fee shown before I signed. Exactly how it should work.”</blockquote>
<figcaption><span class="review__avatar av2" aria-hidden="true">DK</span><strong>Dev K.</strong><span class="mono muted">Google Play · 0x4be2…77f0</span></figcaption>
</figure>
<figure class="review">
<div class="review__stars" aria-label="4 out of 5 stars">★★★★☆</div>
<blockquote>“The drainer warning literally saved my NFTs. Tried to sign a bad approval on a phishing site and Lumen flagged it in red before I confirmed.”</blockquote>
<figcaption><span class="review__avatar av3" aria-hidden="true">SO</span><strong>Sana O.</strong><span class="mono muted">App Store · 0xa11c…9d3e</span></figcaption>
</figure>
</div>
<div class="reviews__nav">
<button class="icon-btn icon-btn--lg" type="button" id="revPrev" aria-label="Previous testimonial">←</button>
<div class="reviews__dots" id="reviewsDots" role="tablist" aria-label="Choose testimonial"></div>
<button class="icon-btn icon-btn--lg" type="button" id="revNext" aria-label="Next testimonial">→</button>
</div>
</div>
</section>
<!-- ====== FINAL CTA ====== -->
<section class="final-cta">
<h2>Ready to hold your own keys?</h2>
<p>Join <strong class="mono">2.4M+</strong> people using Lumen Wallet. Free, open, yours.</p>
<div class="final-cta__btns">
<button class="btn btn--primary btn--lg" type="button" data-toast="Download started (demo)">Download Lumen Wallet</button>
<button class="btn btn--ghost btn--lg" type="button" data-toast="Docs are fictional in this demo">Read the docs</button>
</div>
</section>
</main>
<!-- ====== FOOTER ====== -->
<footer class="footer">
<div class="footer__grid">
<div class="footer__brand">
<span class="nav__logo" aria-hidden="true">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none"><path d="M12 2 3 7v10l9 5 9-5V7l-9-5Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><circle cx="12" cy="12" r="3.2" fill="currentColor"/></svg>
</span>
<strong>Lumen Wallet</strong>
<p>A fictional self-custody wallet for a fictional multichain world.</p>
</div>
<nav aria-label="Product"><h4>Product</h4><a href="#features">Features</a><a href="#chains">Chains</a><a href="#steps">Get started</a></nav>
<nav aria-label="Security"><h4>Security</h4><a href="#security">Audits</a><a href="#security">Bug bounty</a><a href="#security">Recovery guide</a></nav>
<nav aria-label="Company"><h4>Company</h4><a href="#top">About</a><a href="#reviews">Reviews</a><a href="#top">Press kit</a></nav>
</div>
<p class="footer__legal mono">© 2026 Lumen Labs (fictional) · UI demo — no real wallet, RPC, or on-chain calls.</p>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Wallet App Landing
A consumer-facing marketing page for Lumen Wallet, a fictional non-custodial crypto wallet. The hero pairs the headline “Your keys, your crypto, made simple” with App Store and Google Play CTAs, a row of count-up adoption stats, and a floating phone mockup. The phone screen auto-cycles between three live previews — a home balance view with a multichain token list (NOVA, AURUM, ZEPHYR, USDx), a swap card showing route, fee, and slippage, and a buy-with-card keypad — and you can jump between them with the dots beneath the device.
Below the hero, a soft-glow feature trio covers self-custody, swap & bridge, and buy with card; a gradient-bordered trust band reinforces the non-custodial, audited, plain-language-preview story; a hoverable chip row lists the supported fictional chains; and a three-step onboarding section walks through download, fund, and explore. An auto-advancing testimonial slider with prev/next controls and tab dots rounds out the social proof before the final download CTA and footer.
All interactions are pure vanilla JS: an IntersectionObserver-driven count-up for the stats, an auto-playing phone-screen carousel that pauses on hover/focus, a testimonial slider, hover lifts on chips and cards, and a small toast() helper that surfaces clearly-labelled demo confirmations for any download, swap, or signing action. Monospace type is used throughout for addresses, amounts, fees, and hashes, and the layout stays usable down to ~360px.
UI-only simulation — no real wallet, RPC, or on-chain calls. Mock data, fictional tokens.