Web3 — DeFi Protocol Landing
A futuristic DeFi protocol landing page for the fictional Luminal liquidity layer. Features a glowing animated mesh-gradient hero, count-up protocol stats revealed on scroll, a live token-price ticker, and an interactive markets table with drifting supply and borrow APRs. Includes a how-it-works flow with glowing connectors, an audited security band, an ecosystem grid, a governance teaser, and a risk-gated launch confirmation modal. Glassy surfaces, neon accents, monospace numerics throughout.
MCP
Code
:root {
--bg: #08080f;
--surface: #11121c;
--surface-2: #181a27;
--elevated: #20222f;
--text: #e9ecf2;
--muted: #8a90a2;
--line: rgba(255, 255, 255, 0.08);
--line-2: rgba(255, 255, 255, 0.16);
--accent: #7c5cff;
--accent-2: #00e0c6;
--accent-grad: linear-gradient(120deg, #7c5cff, #00e0c6);
--accent-glow: rgba(124, 92, 255, 0.45);
--teal-glow: rgba(0, 224, 198, 0.35);
--pos: #26d07c;
--neg: #ff4d6d;
--warn: #ffb347;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--r-pill: 999px;
--font-ui: "Space Grotesk", system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--font-ui);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.mono { font-family: var(--font-mono); }
.pos { color: var(--pos); }
.neg { color: var(--neg); }
.muted { color: var(--muted); }
.sr-only {
position: absolute;
width: 1px; height: 1px;
margin: -1px; padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap; border: 0;
}
.grad-text {
background: var(--accent-grad);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.glass {
background: rgba(19, 21, 32, 0.55);
border: 1px solid var(--line);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-radius: var(--r-lg);
}
/* ---------- Buttons ---------- */
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--font-ui);
font-weight: 600;
font-size: 0.92rem;
border-radius: var(--r-pill);
border: 1px solid transparent;
padding: 10px 20px;
cursor: pointer;
transition: transform 0.18s ease, box-shadow 0.25s ease, background 0.2s ease, border-color 0.2s ease;
}
.btn:focus-visible {
outline: 2px solid var(--accent-2);
outline-offset: 3px;
}
.btn-primary {
background: var(--accent-grad);
color: #06060c;
box-shadow: 0 0 22px var(--accent-glow), 0 4px 14px rgba(0, 0, 0, 0.4);
}
.btn-primary:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 0 34px var(--accent-glow), 0 0 18px var(--teal-glow), 0 6px 18px rgba(0, 0, 0, 0.5);
}
.btn-primary:active:not(:disabled) { transform: translateY(0); }
.btn-primary:disabled {
opacity: 0.45;
cursor: not-allowed;
box-shadow: none;
}
.btn-ghost {
background: rgba(255, 255, 255, 0.04);
color: var(--text);
border-color: var(--line-2);
}
.btn-ghost:hover {
border-color: var(--accent);
box-shadow: 0 0 16px rgba(124, 92, 255, 0.25);
}
.btn-lg { padding: 14px 28px; font-size: 1rem; }
/* ---------- Ticker ---------- */
.ticker {
overflow: hidden;
border-bottom: 1px solid var(--line);
background: rgba(13, 14, 22, 0.9);
font-family: var(--font-mono);
font-size: 0.76rem;
}
.ticker-track {
display: flex;
gap: 36px;
width: max-content;
padding: 8px 0;
animation: ticker-scroll 32s linear infinite;
will-change: transform;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
.ticker-item { display: inline-flex; gap: 8px; white-space: nowrap; }
.ticker-sym { color: var(--text); font-weight: 700; }
.ticker-price { color: var(--muted); }
@keyframes ticker-scroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* ---------- Nav ---------- */
.nav {
position: sticky;
top: 0;
z-index: 50;
display: flex;
align-items: center;
gap: 28px;
padding: 14px clamp(16px, 4vw, 48px);
background: rgba(8, 8, 15, 0.75);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-bottom: 1px solid var(--line);
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
text-decoration: none;
color: var(--text);
}
.brand-mark {
display: grid;
place-items: center;
width: 36px; height: 36px;
border-radius: var(--r-sm);
background: rgba(124, 92, 255, 0.12);
border: 1px solid rgba(124, 92, 255, 0.35);
box-shadow: 0 0 14px rgba(124, 92, 255, 0.25);
}
.brand-name { font-weight: 700; font-size: 1.12rem; letter-spacing: 0.02em; }
.nav-links {
display: flex;
gap: 22px;
margin-left: 8px;
}
.nav-links a {
color: var(--muted);
text-decoration: none;
font-size: 0.92rem;
font-weight: 500;
transition: color 0.18s ease;
}
.nav-links a:hover, .nav-links a:focus-visible { color: var(--text); }
.nav-actions {
margin-left: auto;
display: flex;
align-items: center;
gap: 14px;
}
.net-pill {
display: inline-flex;
align-items: center;
gap: 7px;
font-size: 0.8rem;
color: var(--muted);
border: 1px solid var(--line);
border-radius: var(--r-pill);
padding: 6px 13px;
background: rgba(255, 255, 255, 0.03);
}
.net-dot {
width: 7px; height: 7px;
border-radius: 50%;
background: var(--accent-2);
box-shadow: 0 0 8px var(--accent-2);
animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.45; }
}
/* ---------- Hero ---------- */
.hero {
position: relative;
overflow: hidden;
padding: clamp(72px, 11vw, 140px) clamp(16px, 4vw, 48px) clamp(56px, 7vw, 96px);
text-align: center;
}
.hero-mesh {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
filter: blur(70px) saturate(1.25);
opacity: 0.85;
}
.hero-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
background-size: 56px 56px;
mask-image: radial-gradient(ellipse 75% 65% at 50% 35%, black 30%, transparent 75%);
-webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 35%, black 30%, transparent 75%);
}
.hero-inner {
position: relative;
max-width: 980px;
margin: 0 auto;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 9px;
font-size: 0.82rem;
font-weight: 500;
color: var(--accent-2);
border: 1px solid rgba(0, 224, 198, 0.35);
background: rgba(0, 224, 198, 0.07);
border-radius: var(--r-pill);
padding: 7px 16px;
box-shadow: 0 0 18px rgba(0, 224, 198, 0.15);
}
.badge-pulse {
width: 8px; height: 8px;
border-radius: 50%;
background: var(--accent-2);
box-shadow: 0 0 10px var(--accent-2);
animation: pulse 1.8s ease-in-out infinite;
}
.hero h1 {
margin: 26px 0 0;
font-size: clamp(2.4rem, 6.4vw, 4.6rem);
line-height: 1.05;
font-weight: 700;
letter-spacing: -0.02em;
}
.hero-sub {
max-width: 580px;
margin: 22px auto 0;
color: var(--muted);
font-size: clamp(1rem, 1.6vw, 1.14rem);
}
.hero-ctas {
display: flex;
justify-content: center;
gap: 14px;
margin-top: 34px;
flex-wrap: wrap;
}
.hero-contract {
margin: 22px 0 0;
font-size: 0.82rem;
color: var(--muted);
}
.addr {
display: inline-flex;
align-items: center;
gap: 6px;
font-family: var(--font-mono);
font-size: 0.82rem;
color: var(--accent-2);
background: rgba(0, 224, 198, 0.06);
border: 1px solid rgba(0, 224, 198, 0.25);
border-radius: var(--r-sm);
padding: 4px 10px;
cursor: pointer;
transition: background 0.18s ease, box-shadow 0.18s ease;
}
.addr:hover { background: rgba(0, 224, 198, 0.13); box-shadow: 0 0 12px rgba(0, 224, 198, 0.2); }
.addr:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
/* Stats */
.stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
margin: clamp(48px, 6vw, 72px) 0 0;
padding: 0;
}
.stat {
position: relative;
padding: 22px 18px 20px;
border-radius: var(--r-md);
background: rgba(19, 21, 32, 0.6);
border: 1px solid var(--line);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
text-align: left;
overflow: hidden;
}
.stat::before {
content: "";
position: absolute;
inset: 0 0 auto;
height: 2px;
background: var(--accent-grad);
opacity: 0.85;
}
.stat dt {
margin: 0;
font-size: 0.76rem;
text-transform: uppercase;
letter-spacing: 0.09em;
color: var(--muted);
}
.stat dd { margin: 8px 0 4px; }
.stat-num {
font-size: clamp(1.3rem, 2.4vw, 1.7rem);
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.stat-delta { font-size: 0.76rem; }
/* ---------- Sections ---------- */
.section {
position: relative;
padding: clamp(56px, 8vw, 110px) clamp(16px, 4vw, 48px);
max-width: 1160px;
margin: 0 auto;
}
.section-head { max-width: 620px; margin-bottom: clamp(32px, 4vw, 52px); }
.kicker {
display: inline-block;
font-family: var(--font-mono);
font-size: 0.74rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--accent-2);
margin-bottom: 12px;
}
.section-head h2, .security h2, .gov h2 {
margin: 0 0 12px;
font-size: clamp(1.6rem, 3.4vw, 2.3rem);
font-weight: 700;
letter-spacing: -0.015em;
}
.section-head p { margin: 0; color: var(--muted); }
/* Reveal-on-scroll */
.reveal {
opacity: 0;
transform: translateY(22px);
transition: opacity 0.7s ease var(--d, 0s), transform 0.7s ease var(--d, 0s);
}
.reveal.in { opacity: 1; transform: none; }
/* ---------- Steps ---------- */
.steps {
list-style: none;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
margin: 0;
padding: 0;
position: relative;
}
.step {
position: relative;
padding: 28px 24px;
transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease, opacity 0.7s ease var(--d, 0s);
}
.step.in { transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease; }
.step:hover {
border-color: rgba(124, 92, 255, 0.5);
box-shadow: 0 0 28px rgba(124, 92, 255, 0.18);
transform: translateY(-4px);
}
/* glowing connector lines between steps */
.step:not(:last-child)::after {
content: "";
position: absolute;
top: 50%;
right: -19px;
width: 20px;
height: 2px;
background: var(--accent-grad);
box-shadow: 0 0 10px var(--accent-glow);
opacity: 0.8;
}
.step-num {
font-size: 0.84rem;
font-weight: 700;
letter-spacing: 0.1em;
}
.step-icon {
display: grid;
place-items: center;
width: 52px; height: 52px;
margin: 16px 0 4px;
border-radius: var(--r-md);
color: var(--accent-2);
background: rgba(0, 224, 198, 0.07);
border: 1px solid rgba(0, 224, 198, 0.25);
box-shadow: 0 0 16px rgba(0, 224, 198, 0.12);
}
.step h3 { margin: 14px 0 8px; font-size: 1.12rem; }
.step p { margin: 0; color: var(--muted); font-size: 0.92rem; }
/* ---------- Markets table ---------- */
.table-card {
padding: 8px 8px 4px;
overflow-x: auto;
}
.markets {
width: 100%;
border-collapse: collapse;
min-width: 640px;
}
.markets th, .markets td {
text-align: left;
padding: 14px 16px;
font-size: 0.9rem;
border-bottom: 1px solid var(--line);
}
.markets th {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted);
font-weight: 600;
}
.markets .num { text-align: right; }
.markets td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.markets tbody tr {
transition: background 0.15s ease;
}
.markets tbody tr:hover { background: rgba(124, 92, 255, 0.07); }
.markets tbody tr:last-child td { border-bottom: 0; }
.asset-cell { display: flex; align-items: center; gap: 12px; }
.asset-icon {
width: 34px; height: 34px;
border-radius: 50%;
display: grid;
place-items: center;
font-weight: 700;
font-size: 0.78rem;
color: #06060c;
flex: none;
}
.asset-name { font-weight: 600; }
.asset-chain {
display: block;
font-size: 0.74rem;
color: var(--muted);
font-family: var(--font-mono);
}
.apr-flash { animation: apr-flash 0.7s ease; }
@keyframes apr-flash {
0% { background: rgba(0, 224, 198, 0.22); border-radius: 4px; }
100% { background: transparent; }
}
.util-wrap { display: inline-flex; align-items: center; gap: 8px; }
.util-bar {
width: 64px; height: 5px;
border-radius: var(--r-pill);
background: rgba(255, 255, 255, 0.08);
overflow: hidden;
}
.util-fill {
display: block;
height: 100%;
border-radius: inherit;
background: var(--accent-grad);
}
.util-fill.hot { background: linear-gradient(90deg, var(--warn), var(--neg)); }
.row-action {
font-family: var(--font-ui);
font-size: 0.78rem;
font-weight: 600;
color: var(--accent-2);
background: transparent;
border: 1px solid rgba(0, 224, 198, 0.35);
border-radius: var(--r-pill);
padding: 6px 14px;
cursor: pointer;
opacity: 0;
transform: translateX(6px);
transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease;
}
.markets tbody tr:hover .row-action,
.row-action:focus-visible {
opacity: 1;
transform: none;
}
.row-action:hover { background: rgba(0, 224, 198, 0.12); }
.row-action:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.table-note {
margin: 10px 16px 12px;
font-size: 0.78rem;
color: var(--muted);
}
/* ---------- Security band ---------- */
.security {
padding: 0 clamp(16px, 4vw, 48px);
max-width: 1160px;
margin: 0 auto;
}
.security-inner {
display: grid;
grid-template-columns: 1.1fr 1fr;
gap: clamp(24px, 4vw, 56px);
align-items: center;
padding: clamp(28px, 4vw, 48px);
position: relative;
overflow: hidden;
}
.security-inner::before {
content: "";
position: absolute;
inset: -1px;
border-radius: inherit;
padding: 1px;
background: var(--accent-grad);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0.5;
pointer-events: none;
}
.security-copy p { color: var(--muted); margin: 0; }
.audit-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 12px;
}
.audit-list li {
display: flex;
align-items: center;
gap: 12px;
font-size: 0.94rem;
padding: 12px 16px;
border-radius: var(--r-md);
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--line);
}
.audit-check {
display: grid;
place-items: center;
width: 24px; height: 24px;
flex: none;
border-radius: 50%;
font-size: 0.78rem;
color: #06060c;
background: var(--accent-grad);
box-shadow: 0 0 12px var(--accent-glow);
}
/* ---------- Ecosystem ---------- */
.eco-grid {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
}
.eco-cell {
display: grid;
place-items: center;
padding: 26px 12px;
font-weight: 600;
font-size: 0.96rem;
color: var(--muted);
border-radius: var(--r-md);
transition: color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease, opacity 0.7s ease var(--d, 0s);
cursor: default;
}
.eco-cell:hover {
color: var(--text);
border-color: rgba(0, 224, 198, 0.4);
box-shadow: 0 0 22px rgba(0, 224, 198, 0.14);
transform: translateY(-3px);
}
/* ---------- Governance ---------- */
.gov-card {
display: grid;
grid-template-columns: 1.15fr 1fr;
gap: clamp(24px, 4vw, 56px);
align-items: center;
padding: clamp(28px, 4vw, 48px);
}
.gov-copy p { color: var(--muted); }
.gov-copy .btn { margin-top: 8px; }
.gov-proposal {
padding: 24px;
border-radius: var(--r-md);
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--line-2);
}
.prop-tag {
font-size: 0.72rem;
font-weight: 700;
color: var(--accent-2);
letter-spacing: 0.08em;
text-transform: uppercase;
}
.gov-proposal h3 { margin: 10px 0 18px; font-size: 1.1rem; }
.prop-bar {
height: 8px;
border-radius: var(--r-pill);
background: rgba(255, 77, 109, 0.3);
overflow: hidden;
}
.prop-for {
display: block;
height: 100%;
background: linear-gradient(90deg, var(--pos), var(--accent-2));
box-shadow: 0 0 10px rgba(38, 208, 124, 0.5);
border-radius: inherit;
}
.prop-meta {
display: flex;
gap: 16px;
flex-wrap: wrap;
margin-top: 12px;
font-size: 0.78rem;
}
/* ---------- Footer ---------- */
.footer {
border-top: 1px solid var(--line);
background: rgba(13, 14, 22, 0.7);
padding: clamp(40px, 5vw, 64px) clamp(16px, 4vw, 48px) 28px;
}
.footer-inner {
max-width: 1160px;
margin: 0 auto;
display: grid;
grid-template-columns: 1.2fr 2fr;
gap: clamp(28px, 5vw, 72px);
}
.footer-brand p { color: var(--muted); font-size: 0.9rem; margin: 10px 0 0; max-width: 280px; }
.footer-addr { font-size: 0.78rem; }
.footer-cols {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.footer-cols h4 {
margin: 0 0 14px;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted);
}
.footer-cols a {
display: block;
color: var(--text);
opacity: 0.8;
text-decoration: none;
font-size: 0.92rem;
padding: 4px 0;
transition: color 0.18s ease, opacity 0.18s ease;
}
.footer-cols a:hover { color: var(--accent-2); opacity: 1; }
.footer-legal {
max-width: 1160px;
margin: 36px auto 0;
padding-top: 20px;
border-top: 1px solid var(--line);
font-size: 0.78rem;
color: var(--muted);
}
/* ---------- Modal ---------- */
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 100;
display: grid;
place-items: center;
padding: 20px;
background: rgba(4, 4, 10, 0.7);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
animation: fade-in 0.2s ease;
}
.modal-backdrop[hidden] { display: none; }
.modal {
width: min(480px, 100%);
padding: 30px 28px;
border-radius: var(--r-lg);
background: rgba(24, 26, 39, 0.92);
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6), 0 0 40px rgba(124, 92, 255, 0.18);
animation: modal-pop 0.25s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.modal h3 { margin: 0 0 6px; font-size: 1.3rem; }
.modal-sub { margin: 0 0 18px; color: var(--muted); font-size: 0.92rem; }
.risk-list {
list-style: none;
margin: 0 0 18px;
padding: 16px;
display: grid;
gap: 12px;
border-radius: var(--r-md);
background: rgba(255, 179, 71, 0.06);
border: 1px solid rgba(255, 179, 71, 0.25);
font-size: 0.87rem;
}
.risk-list li { display: flex; gap: 10px; align-items: flex-start; }
.warn-dot {
flex: none;
width: 8px; height: 8px;
margin-top: 6px;
border-radius: 50%;
background: var(--warn);
box-shadow: 0 0 8px rgba(255, 179, 71, 0.7);
}
.risk-accept {
display: flex;
gap: 10px;
align-items: flex-start;
font-size: 0.88rem;
cursor: pointer;
margin-bottom: 22px;
}
.risk-accept input {
width: 17px; height: 17px;
margin-top: 2px;
accent-color: var(--accent);
cursor: pointer;
}
.risk-accept input:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.risk-accept a { color: var(--accent-2); }
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
}
@keyframes fade-in { from { opacity: 0; } }
@keyframes modal-pop {
from { opacity: 0; transform: translateY(14px) scale(0.97); }
}
/* ---------- Toast ---------- */
.toast-stack {
position: fixed;
bottom: 22px;
left: 50%;
transform: translateX(-50%);
z-index: 200;
display: grid;
gap: 10px;
justify-items: center;
pointer-events: none;
}
.toast {
font-size: 0.88rem;
font-weight: 500;
color: var(--text);
background: rgba(32, 34, 47, 0.95);
border: 1px solid var(--line-2);
border-radius: var(--r-pill);
padding: 11px 22px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5), 0 0 18px rgba(124, 92, 255, 0.2);
backdrop-filter: blur(10px);
animation: toast-in 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.toast.out { animation: toast-out 0.3s ease forwards; }
@keyframes toast-in {
from { opacity: 0; transform: translateY(14px); }
}
@keyframes toast-out {
to { opacity: 0; transform: translateY(10px); }
}
/* ---------- Motion preference ---------- */
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.ticker-track { animation: none; }
.reveal { transition: none; opacity: 1; transform: none; }
.net-dot, .badge-pulse { animation: none; }
}
/* ---------- Responsive ---------- */
@media (max-width: 900px) {
.nav-links { display: none; }
.stats { grid-template-columns: repeat(2, 1fr); }
.steps { grid-template-columns: 1fr; }
.step:not(:last-child)::after {
top: auto;
bottom: -19px;
right: auto;
left: 50%;
width: 2px;
height: 20px;
}
.security-inner, .gov-card { grid-template-columns: 1fr; }
.eco-grid { grid-template-columns: repeat(2, 1fr); }
.footer-inner { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
.net-pill { display: none; }
.nav { gap: 14px; padding-top: 10px; padding-bottom: 10px; }
.btn-launch { padding: 9px 16px; font-size: 0.85rem; }
.hero h1 { font-size: 2.1rem; }
.hero-ctas .btn-lg { width: 100%; justify-content: center; }
.stats { grid-template-columns: 1fr; }
.hide-sm { display: none; }
.markets { min-width: 460px; }
.footer-cols { grid-template-columns: 1fr 1fr; }
.modal { padding: 24px 18px; }
.modal-actions { flex-direction: column-reverse; }
.modal-actions .btn { width: 100%; justify-content: center; }
}// Luminal — DeFi protocol landing (UI-only simulation).
// No wallet, RPC or on-chain calls. All data is mock/fictional.
(function () {
"use strict";
var reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- Toast helper ---------- */
var toastStack = document.getElementById("toastStack");
function toast(msg, ms) {
if (!toastStack) return;
var el = document.createElement("div");
el.className = "toast";
el.textContent = msg;
toastStack.appendChild(el);
setTimeout(function () {
el.classList.add("out");
setTimeout(function () { el.remove(); }, 320);
}, ms || 2600);
}
/* ---------- Number formatting ---------- */
function fmtUsd(n) {
if (n >= 1e9) return "$" + (n / 1e9).toFixed(2) + "B";
if (n >= 1e6) return "$" + (n / 1e6).toFixed(2) + "M";
if (n >= 1e3) return "$" + (n / 1e3).toFixed(1) + "K";
return "$" + n.toFixed(2);
}
function fmtInt(n) {
return Math.round(n).toLocaleString("en-US");
}
/* ---------- Count-up stats on scroll ---------- */
function countUp(el) {
var target = parseFloat(el.getAttribute("data-count")) || 0;
var fmt = el.getAttribute("data-format");
var dur = 1600;
var start = performance.now();
function ease(t) { return 1 - Math.pow(1 - t, 3); }
function tick(now) {
var p = Math.min((now - start) / dur, 1);
var v = target * ease(p);
el.textContent = fmt === "usd" ? fmtUsd(v) : fmtInt(v);
if (p < 1) requestAnimationFrame(tick);
}
if (reduceMotion) {
el.textContent = fmt === "usd" ? fmtUsd(target) : fmtInt(target);
} else {
requestAnimationFrame(tick);
}
}
var statsRow = document.getElementById("statsRow");
var statsDone = false;
if (statsRow) {
var statObs = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting && !statsDone) {
statsDone = true;
statsRow.querySelectorAll(".stat-num").forEach(countUp);
statObs.disconnect();
}
});
}, { threshold: 0.4 });
statObs.observe(statsRow);
}
/* ---------- Generic reveal-on-scroll ---------- */
var revealObs = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) {
e.target.classList.add("in");
revealObs.unobserve(e.target);
}
});
}, { threshold: 0.15 });
document.querySelectorAll(".reveal").forEach(function (el) { revealObs.observe(el); });
/* ---------- Markets table ---------- */
var markets = [
{ sym: "NOVA", name: "Nova Token", chain: "Lumen Chain", color: "#7c5cff", price: 4.182, supply: 3.5, borrow: 6.1, tvl: 842.1e6, util: 71 },
{ sym: "lmETH", name: "Lumen ETH", chain: "Lumen Chain", color: "#00e0c6", price: 3128.40, supply: 2.7, borrow: 4.4, tvl: 1240.6e6, util: 64 },
{ sym: "USDx", name: "USD Stable", chain: "Driftlane", color: "#26d07c", price: 1.0001, supply: 8.9, borrow: 11.2, tvl: 612.3e6, util: 88 },
{ sym: "wBTL", name: "Wrapped Bitlume", chain: "ZenithBridge", color: "#ffb347", price: 61840.0, supply: 1.4, borrow: 2.9, tvl: 498.7e6, util: 42 },
{ sym: "stNOVA", name: "Staked NOVA", chain: "Lumen Chain", color: "#b48cff", price: 4.510, supply: 5.2, borrow: 7.8, tvl: 327.9e6, util: 79 }
];
function shortPrice(p) {
if (p >= 1000) return "$" + p.toLocaleString("en-US", { maximumFractionDigits: 0 });
if (p >= 1) return "$" + p.toFixed(2);
return "$" + p.toFixed(4);
}
var marketsBody = document.getElementById("marketsBody");
function renderMarkets() {
if (!marketsBody) return;
marketsBody.innerHTML = "";
markets.forEach(function (m) {
var tr = document.createElement("tr");
var hot = m.util >= 85 ? " hot" : "";
tr.innerHTML =
'<td><div class="asset-cell">' +
'<span class="asset-icon" style="background:' + m.color + '">' + m.sym.slice(0, 2) + '</span>' +
'<span><span class="asset-name">' + m.sym + '</span>' +
'<span class="asset-chain">' + m.chain + '</span></span>' +
'</div></td>' +
'<td class="num">' + shortPrice(m.price) + '</td>' +
'<td class="num pos" data-apr="supply">' + m.supply.toFixed(2) + '%</td>' +
'<td class="num" data-apr="borrow">' + m.borrow.toFixed(2) + '%</td>' +
'<td class="num hide-sm">' + fmtUsd(m.tvl) + '</td>' +
'<td class="num hide-sm"><span class="util-wrap">' +
'<span class="util-bar"><span class="util-fill' + hot + '" style="width:' + m.util + '%"></span></span>' +
m.util + '%</span></td>' +
'<td class="action-col"><button class="row-action" type="button" data-sym="' + m.sym + '">Supply</button></td>';
marketsBody.appendChild(tr);
});
}
renderMarkets();
// Live-ish APR drift every few seconds with a flash.
if (!reduceMotion) {
setInterval(function () {
var i = Math.floor(Math.random() * markets.length);
var m = markets[i];
m.supply = Math.max(0.3, +(m.supply + (Math.random() - 0.5) * 0.4).toFixed(2));
m.borrow = Math.max(m.supply + 0.5, +(m.borrow + (Math.random() - 0.5) * 0.4).toFixed(2));
var row = marketsBody.children[i];
if (!row) return;
var sCell = row.querySelector('[data-apr="supply"]');
var bCell = row.querySelector('[data-apr="borrow"]');
sCell.textContent = m.supply.toFixed(2) + "%";
bCell.textContent = m.borrow.toFixed(2) + "%";
[sCell, bCell].forEach(function (c) {
c.classList.remove("apr-flash");
void c.offsetWidth;
c.classList.add("apr-flash");
});
}, 3200);
}
if (marketsBody) {
marketsBody.addEventListener("click", function (e) {
var btn = e.target.closest(".row-action");
if (!btn) return;
toast("Connect a wallet to supply " + btn.getAttribute("data-sym") + " — demo only.");
});
}
/* ---------- Price ticker ---------- */
var tickerTrack = document.getElementById("tickerTrack");
var tickerTokens = [
{ sym: "NOVA", price: 4.18, chg: 4.2 },
{ sym: "lmETH", price: 3128.40, chg: 1.8 },
{ sym: "USDx", price: 1.00, chg: 0.01 },
{ sym: "wBTL", price: 61840, chg: -0.9 },
{ sym: "stNOVA", price: 4.51, chg: 2.6 },
{ sym: "LUMI", price: 0.842, chg: 9.4 },
{ sym: "ZEN", price: 12.07, chg: -2.1 },
{ sym: "DRFT", price: 0.318, chg: 5.7 }
];
function tickerItem(t) {
var cls = t.chg >= 0 ? "pos" : "neg";
var arrow = t.chg >= 0 ? "▲" : "▼";
var price = t.price >= 1000 ? t.price.toLocaleString("en-US") : t.price.toFixed(t.price < 1 ? 3 : 2);
return '<span class="ticker-item">' +
'<span class="ticker-sym">' + t.sym + '</span>' +
'<span class="ticker-price">$' + price + '</span>' +
'<span class="' + cls + '">' + arrow + " " + Math.abs(t.chg).toFixed(1) + '%</span>' +
'</span>';
}
function renderTicker() {
if (!tickerTrack) return;
var html = tickerTokens.map(tickerItem).join("");
tickerTrack.innerHTML = html + html; // duplicate for seamless loop
}
renderTicker();
if (!reduceMotion) {
setInterval(function () {
tickerTokens.forEach(function (t) {
var drift = (Math.random() - 0.5) * 0.012;
t.price = +(t.price * (1 + drift)).toFixed(t.price < 1 ? 4 : 2);
t.chg = +(t.chg + (Math.random() - 0.5) * 0.6).toFixed(1);
});
renderTicker();
}, 4000);
}
/* ---------- Copy contract address ---------- */
var copyAddr = document.getElementById("copyAddr");
if (copyAddr) {
copyAddr.addEventListener("click", function () {
var full = "0x7a3f9c2e4b8d1a06f5e3c2b7a9d8e1f40c41d";
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(full).then(
function () { toast("Contract address copied"); },
function () { toast("Copy failed — select manually"); }
);
} else {
toast("Clipboard unavailable in this context");
}
});
}
/* ---------- Launch-app confirm modal (risk gate) ---------- */
var modal = document.getElementById("launchModal");
var riskCheck = document.getElementById("riskCheck");
var modalConfirm = document.getElementById("modalConfirm");
var modalCancel = document.getElementById("modalCancel");
var lastFocus = null;
function openModal(trigger) {
if (!modal) return;
lastFocus = trigger || document.activeElement;
modal.hidden = false;
if (riskCheck) riskCheck.checked = false;
if (modalConfirm) modalConfirm.disabled = true;
document.body.style.overflow = "hidden";
(modalCancel || modal).focus();
}
function closeModal() {
if (!modal) return;
modal.hidden = true;
document.body.style.overflow = "";
if (lastFocus && lastFocus.focus) lastFocus.focus();
}
document.querySelectorAll("[data-launch]").forEach(function (b) {
b.addEventListener("click", function () { openModal(b); });
});
if (riskCheck) {
riskCheck.addEventListener("change", function () {
if (modalConfirm) modalConfirm.disabled = !riskCheck.checked;
});
}
if (modalCancel) modalCancel.addEventListener("click", closeModal);
if (modalConfirm) {
modalConfirm.addEventListener("click", function () {
closeModal();
toast("Entering Luminal app… (demo — no real app to open)");
});
}
if (modal) {
modal.addEventListener("click", function (e) {
if (e.target === modal) closeModal();
});
}
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && modal && !modal.hidden) closeModal();
});
/* ---------- Misc buttons ---------- */
var docsBtn = document.getElementById("docsBtn");
if (docsBtn) docsBtn.addEventListener("click", function () { toast("Docs are part of the demo — nothing to open."); });
var govBtn = document.getElementById("govBtn");
if (govBtn) govBtn.addEventListener("click", function () { toast("Proposal LIP-042 is a simulated example."); });
/* ---------- Animated mesh / gradient hero ---------- */
var canvas = document.getElementById("mesh");
if (canvas && !reduceMotion) {
var ctx = canvas.getContext("2d");
var blobs = [
{ x: 0.25, y: 0.30, r: 0.42, c: [124, 92, 255], vx: 0.00010, vy: 0.00014 },
{ x: 0.72, y: 0.40, r: 0.40, c: [0, 224, 198], vx: -0.00013, vy: 0.00009 },
{ x: 0.50, y: 0.70, r: 0.36, c: [180, 120, 255], vx: 0.00008, vy: -0.00012 }
];
var W = 0, H = 0;
function resize() {
var rect = canvas.getBoundingClientRect();
var dpr = Math.min(window.devicePixelRatio || 1, 2);
W = canvas.width = Math.max(1, rect.width * dpr);
H = canvas.height = Math.max(1, rect.height * dpr);
}
resize();
window.addEventListener("resize", resize);
var t = 0;
function draw() {
ctx.clearRect(0, 0, W, H);
ctx.globalCompositeOperation = "lighter";
blobs.forEach(function (b, i) {
b.x += b.vx; b.y += b.vy;
if (b.x < 0.1 || b.x > 0.9) b.vx *= -1;
if (b.y < 0.1 || b.y > 0.9) b.vy *= -1;
var wob = Math.sin(t / 60 + i) * 0.04;
var cx = b.x * W, cy = b.y * H, rad = (b.r + wob) * Math.max(W, H);
var g = ctx.createRadialGradient(cx, cy, 0, cx, cy, rad);
g.addColorStop(0, "rgba(" + b.c[0] + "," + b.c[1] + "," + b.c[2] + ",0.55)");
g.addColorStop(1, "rgba(" + b.c[0] + "," + b.c[1] + "," + b.c[2] + ",0)");
ctx.fillStyle = g;
ctx.beginPath();
ctx.arc(cx, cy, rad, 0, Math.PI * 2);
ctx.fill();
});
ctx.globalCompositeOperation = "source-over";
t++;
requestAnimationFrame(draw);
}
draw();
} else if (canvas) {
// Static fallback gradient for reduced motion.
canvas.style.background =
"radial-gradient(40% 50% at 30% 35%, rgba(124,92,255,.4), transparent), " +
"radial-gradient(40% 50% at 72% 45%, rgba(0,224,198,.35), transparent)";
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Luminal — The liquidity layer for everything</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>
<!-- Token price ticker -->
<div class="ticker" aria-label="Live token prices (simulated)">
<div class="ticker-track" id="tickerTrack"></div>
</div>
<!-- Nav -->
<header class="nav">
<a class="brand" href="#top" aria-label="Luminal Protocol home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none">
<path d="M12 2 21 7v10l-9 5-9-5V7l9-5Z" stroke="url(#lg)" stroke-width="1.6"/>
<path d="M12 7v10M7.5 9.5l9 5M16.5 9.5l-9 5" stroke="url(#lg)" stroke-width="1.2" opacity=".7"/>
<defs><linearGradient id="lg" x1="0" y1="0" x2="24" y2="24"><stop stop-color="#7c5cff"/><stop offset="1" stop-color="#00e0c6"/></linearGradient></defs>
</svg>
</span>
<span class="brand-name">Luminal</span>
</a>
<nav class="nav-links" aria-label="Primary">
<a href="#markets">Markets</a>
<a href="#how">How it works</a>
<a href="#security">Security</a>
<a href="#governance">Governance</a>
</nav>
<div class="nav-actions">
<span class="net-pill" title="Connected network (simulated)">
<span class="net-dot" aria-hidden="true"></span> Lumen Chain
</span>
<button class="btn btn-primary btn-launch" type="button" data-launch>Launch App</button>
</div>
</header>
<main id="top">
<!-- Hero -->
<section class="hero" aria-labelledby="hero-title">
<canvas id="mesh" class="hero-mesh" aria-hidden="true"></canvas>
<div class="hero-grid" aria-hidden="true"></div>
<div class="hero-inner">
<span class="hero-badge">
<span class="badge-pulse" aria-hidden="true"></span>
Luminal v3 is live on Lumen Chain
</span>
<h1 id="hero-title">The liquidity layer<br /><span class="grad-text">for everything.</span></h1>
<p class="hero-sub">
Supply, borrow and route liquidity across 14 fictional chains through one unified,
audited protocol. Non-custodial. Composable. Always on.
</p>
<div class="hero-ctas">
<button class="btn btn-primary btn-lg" type="button" data-launch>
Launch App
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3 8h10m0 0L9 4m4 4-4 4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<button class="btn btn-ghost btn-lg" type="button" id="docsBtn">Read the docs</button>
</div>
<p class="hero-contract">
Core contract:
<button class="addr" type="button" id="copyAddr" title="Copy contract address">
0x7a3f…c41d
<svg width="13" height="13" viewBox="0 0 16 16" fill="none" aria-hidden="true"><rect x="5" y="5" width="8" height="8" rx="1.5" stroke="currentColor" stroke-width="1.3"/><path d="M11 5V4a1.5 1.5 0 0 0-1.5-1.5h-5A1.5 1.5 0 0 0 3 4v5A1.5 1.5 0 0 0 4.5 10.5H5" stroke="currentColor" stroke-width="1.3"/></svg>
</button>
</p>
<!-- Protocol stats -->
<dl class="stats" id="statsRow">
<div class="stat">
<dt>Total value locked</dt>
<dd><span class="stat-num mono" data-count="2841350922" data-prefix="$" data-format="usd">$0</span></dd>
<span class="stat-delta pos mono">▲ 4.2% / 24h</span>
</div>
<div class="stat">
<dt>Total volume</dt>
<dd><span class="stat-num mono" data-count="97200000000" data-prefix="$" data-format="usd">$0</span></dd>
<span class="stat-delta pos mono">▲ 1.8% / 24h</span>
</div>
<div class="stat">
<dt>Active users</dt>
<dd><span class="stat-num mono" data-count="412806" data-format="int">0</span></dd>
<span class="stat-delta pos mono">▲ 12,114 this week</span>
</div>
<div class="stat">
<dt>Chains routed</dt>
<dd><span class="stat-num mono" data-count="14" data-format="int">0</span></dd>
<span class="stat-delta mono muted">+2 in audit</span>
</div>
</dl>
</div>
</section>
<!-- How it works -->
<section class="section" id="how" aria-labelledby="how-title">
<div class="section-head">
<span class="kicker">How it works</span>
<h2 id="how-title">Three steps to deep liquidity</h2>
<p>One deposit unlocks yield, borrowing power and cross-chain routing — no bridges to babysit.</p>
</div>
<ol class="steps">
<li class="step glass reveal">
<span class="step-num grad-text mono">01</span>
<span class="step-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none"><path d="M12 3v12m0 0 4-4m-4 4-4-4" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h3>Deposit any asset</h3>
<p>Supply NOVA, lmETH, USDx or 40+ listed assets into isolated, risk-scored pools. Receive yield-bearing <span class="mono">lTokens</span> instantly.</p>
</li>
<li class="step glass reveal" style="--d:.12s">
<span class="step-num grad-text mono">02</span>
<span class="step-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none"><circle cx="7" cy="7" r="3.2" stroke="currentColor" stroke-width="1.6"/><circle cx="17" cy="17" r="3.2" stroke="currentColor" stroke-width="1.6"/><path d="M9.5 9.5 14.5 14.5M17 7h-3M7 17v-3" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h3>Route & borrow</h3>
<p>The Luminal router finds the best rate across every connected market and lets you borrow against your whole portfolio, cross-chain.</p>
</li>
<li class="step glass reveal" style="--d:.24s">
<span class="step-num grad-text mono">03</span>
<span class="step-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none"><path d="M4 16.5 9 11l3.5 3.5L20 7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/><path d="M15 7h5v5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<h3>Compound on autopilot</h3>
<p>Strategies rebalance every block. Rewards stream to your wallet in real time — claim once, or let them auto-compound forever.</p>
</li>
</ol>
</section>
<!-- Markets -->
<section class="section" id="markets" aria-labelledby="markets-title">
<div class="section-head">
<span class="kicker">Markets</span>
<h2 id="markets-title">Live yields, updated every block</h2>
<p>Rates shown are simulated and refresh in place. Hover a row to preview the market action.</p>
</div>
<div class="table-card glass reveal">
<table class="markets" aria-describedby="markets-note">
<thead>
<tr>
<th scope="col">Asset</th>
<th scope="col" class="num">Price</th>
<th scope="col" class="num">Supply APR</th>
<th scope="col" class="num">Borrow APR</th>
<th scope="col" class="num hide-sm">Total supplied</th>
<th scope="col" class="num hide-sm">Utilization</th>
<th scope="col" class="action-col"><span class="sr-only">Action</span></th>
</tr>
</thead>
<tbody id="marketsBody"><!-- rows injected by script.js --></tbody>
</table>
<p class="table-note" id="markets-note">All markets settle on Lumen Chain. Rates are illustrative — this is a UI demo.</p>
</div>
</section>
<!-- Security band -->
<section class="security" id="security" aria-labelledby="security-title">
<div class="security-inner glass reveal">
<div class="security-copy">
<span class="kicker">Security</span>
<h2 id="security-title">Audited. Verified. Over-collateralized.</h2>
<p>Every Luminal contract ships with formal verification and an on-chain safety module backstopping <span class="mono">$84.2M</span> of cover.</p>
</div>
<ul class="audit-list">
<li><span class="audit-check" aria-hidden="true">✓</span> 6 audits · Halberd Labs & Cryptid Security</li>
<li><span class="audit-check" aria-hidden="true">✓</span> $2.5M bug bounty on Hivemind</li>
<li><span class="audit-check" aria-hidden="true">✓</span> 48h timelock on every parameter change</li>
<li><span class="audit-check" aria-hidden="true">✓</span> Open source · <span class="mono">v3.4.1</span> · MIT</li>
</ul>
</div>
</section>
<!-- Ecosystem -->
<section class="section" id="ecosystem" aria-labelledby="eco-title">
<div class="section-head">
<span class="kicker">Ecosystem</span>
<h2 id="eco-title">Plugged into everything</h2>
<p>Wallets, aggregators and L2s already routing through Luminal liquidity.</p>
</div>
<ul class="eco-grid">
<li class="eco-cell glass reveal">◆ Lumen Chain</li>
<li class="eco-cell glass reveal" style="--d:.05s">⬡ NovaSwap</li>
<li class="eco-cell glass reveal" style="--d:.1s">◎ OrbitWallet</li>
<li class="eco-cell glass reveal" style="--d:.15s">⟁ ZenithBridge</li>
<li class="eco-cell glass reveal" style="--d:.2s">✶ StarkPulse</li>
<li class="eco-cell glass reveal" style="--d:.25s">◇ Driftlane</li>
<li class="eco-cell glass reveal" style="--d:.3s">⬢ HexaYield</li>
<li class="eco-cell glass reveal" style="--d:.35s">○ Moonbeam X</li>
</ul>
</section>
<!-- Governance teaser -->
<section class="section gov" id="governance" aria-labelledby="gov-title">
<div class="gov-card glass reveal">
<div class="gov-copy">
<span class="kicker">Governance</span>
<h2 id="gov-title">Owned by <span class="grad-text">LUMI</span> holders</h2>
<p>Every listing, rate curve and treasury move is decided on-chain. Stake LUMI to vote, delegate, and earn a share of protocol revenue.</p>
<button class="btn btn-ghost" type="button" id="govBtn">View active proposals</button>
</div>
<div class="gov-proposal" role="group" aria-label="Latest proposal (simulated)">
<span class="prop-tag mono">LIP-042 · Active</span>
<h3>Onboard stNOVA as collateral</h3>
<div class="prop-bar" aria-hidden="true">
<span class="prop-for" style="width:78%"></span>
</div>
<div class="prop-meta mono">
<span class="pos">For 78%</span>
<span class="neg">Against 22%</span>
<span class="muted">ends in 2d 14h</span>
</div>
</div>
</div>
</section>
</main>
<!-- Footer -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-brand">
<span class="brand-name">Luminal</span>
<p>The liquidity layer for everything. Built on Lumen Chain.</p>
<p class="mono footer-addr">treasury: 0x9b21…e07a</p>
</div>
<nav class="footer-cols" aria-label="Footer">
<div>
<h4>Protocol</h4>
<a href="#markets">Markets</a>
<a href="#how">How it works</a>
<a href="#security">Audits</a>
</div>
<div>
<h4>Community</h4>
<a href="#governance">Governance</a>
<a href="#ecosystem">Ecosystem</a>
<a href="#top">Forum</a>
</div>
<div>
<h4>Developers</h4>
<a href="#top">Docs</a>
<a href="#top">SDK</a>
<a href="#top">Bug bounty</a>
</div>
</nav>
</div>
<p class="footer-legal">© 2026 Luminal Protocol — fictional demo. Nothing here is financial advice; no real assets exist.</p>
</footer>
<!-- Launch confirm modal -->
<div class="modal-backdrop" id="launchModal" hidden>
<div class="modal glass" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<h3 id="modal-title">Before you enter the app</h3>
<p class="modal-sub">Luminal is a non-custodial protocol. You — and only you — control your funds and signatures.</p>
<ul class="risk-list">
<li><span class="warn-dot" aria-hidden="true"></span> Smart contracts can fail. Never supply more than you can afford to lose.</li>
<li><span class="warn-dot" aria-hidden="true"></span> Borrow positions can be liquidated if your health factor drops below <span class="mono">1.00</span>.</li>
<li><span class="warn-dot" aria-hidden="true"></span> Always verify the contract <span class="mono">0x7a3f…c41d</span> before signing anything.</li>
</ul>
<label class="risk-accept">
<input type="checkbox" id="riskCheck" />
<span>I understand the risks and accept the <a href="#top">Terms of Use</a>.</span>
</label>
<div class="modal-actions">
<button class="btn btn-ghost" type="button" id="modalCancel">Cancel</button>
<button class="btn btn-primary" type="button" id="modalConfirm" disabled>Enter Luminal App</button>
</div>
</div>
</div>
<div class="toast-stack" id="toastStack" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>DeFi Protocol Landing
A complete marketing landing for Luminal, a fictional cross-chain liquidity protocol. The hero pairs a headline — “The liquidity layer for everything” — with a canvas-rendered animated mesh of drifting neon blobs, a masked grid overlay, and big protocol stats (TVL, lifetime volume, active users, chains) that count up the first time they scroll into view. A copyable mock contract address and a sticky network pill reinforce the on-chain feel.
Below the fold: a three-step how it works flow joined by glowing gradient connector lines, a live markets table where supply and borrow APRs drift in real time with a flash highlight and utilization bars, an audited security band with a gradient border, an ecosystem grid of fictional integrations, and a governance teaser showing a simulated proposal tally. A monospace price ticker scrolls fictional tokens across the top, repricing every few seconds.
Every action is gated for safety: the Launch App buttons open a confirmation modal that lists protocol risks (smart-contract failure, liquidation, address verification) and disables the confirm button until the user accepts the terms. All interactions emit a small toast(), respect prefers-reduced-motion (static gradient fallback, no count-up or ticker animation), and are keyboard-accessible with focus-visible rings. No frameworks or web3 libraries — vanilla JS only.
UI-only simulation — no real wallet, RPC, or on-chain calls. Mock data, fictional tokens.