SaaS — AI Product Landing
A sleek, futuristic landing page for a fictional AI workspace product on a black canvas with an iridescent purple-teal-pink gradient. Features a glowing aurora hero, a live prompt-to-result demo that streams a canned answer token by token with a blinking cursor, capability tiles, a model-quality comparison band, animated stat counters, customer social proof, a working theme toggle, and an email try-it CTA. Respects reduced-motion.
MCP
Code
:root {
--bg: #07070d;
--bg-2: #0c0c17;
--surface: rgba(255, 255, 255, .04);
--surface-2: rgba(255, 255, 255, .06);
--ink: #f4f5fb;
--muted: #a3a7c2;
--line: rgba(255, 255, 255, .12);
--brand: #7c5cff;
--brand-2: #26d0ce;
--brand-3: #ff5db1;
--ok: #34d399;
--warn: #fbbf24;
--danger: #fb7185;
--grad: linear-gradient(110deg, #7c5cff 0%, #26d0ce 48%, #ff5db1 100%);
--grad-soft: linear-gradient(110deg, rgba(124, 92, 255, .9), rgba(38, 208, 206, .85), rgba(255, 93, 177, .9));
--shadow: 0 24px 70px -28px rgba(0, 0, 0, .8);
--radius: 18px;
--maxw: 1140px;
--sans: "Inter", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
--display: "Space Grotesk", var(--sans);
}
[data-theme="light"] {
--bg: #f5f6fc;
--bg-2: #eef0fa;
--surface: rgba(15, 18, 34, .03);
--surface-2: rgba(15, 18, 34, .05);
--ink: #0f1222;
--muted: #5b6079;
--line: rgba(15, 18, 34, .12);
--shadow: 0 24px 60px -30px rgba(40, 30, 90, .35);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--sans);
background: var(--bg);
color: var(--ink);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
transition: background .4s ease, color .4s ease;
}
h1, h2, h3 { font-family: var(--display); line-height: 1.12; letter-spacing: -.02em; margin: 0; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
.sr-only {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
:focus-visible {
outline: 2px solid var(--brand-2);
outline-offset: 3px;
border-radius: 8px;
}
/* ---------- aurora background ---------- */
.aurora {
position: fixed; inset: 0; z-index: -1; overflow: hidden;
background: radial-gradient(1200px 700px at 80% -10%, rgba(124, 92, 255, .18), transparent 60%),
radial-gradient(900px 600px at 5% 10%, rgba(38, 208, 206, .14), transparent 55%),
var(--bg);
}
.blob {
position: absolute; border-radius: 50%; filter: blur(70px); opacity: .55;
animation: drift 22s ease-in-out infinite;
}
.b1 { width: 460px; height: 460px; left: -120px; top: -80px; background: radial-gradient(circle, #7c5cff, transparent 70%); }
.b2 { width: 520px; height: 520px; right: -160px; top: 8%; background: radial-gradient(circle, #26d0ce, transparent 70%); animation-delay: -7s; }
.b3 { width: 420px; height: 420px; left: 30%; bottom: -180px; background: radial-gradient(circle, #ff5db1, transparent 70%); animation-delay: -13s; }
@keyframes drift {
0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
33% { transform: translate3d(40px, 30px, 0) scale(1.08); }
66% { transform: translate3d(-30px, 20px, 0) scale(.95); }
}
/* ---------- nav ---------- */
.nav {
max-width: var(--maxw); margin: 0 auto;
display: flex; align-items: center; gap: 18px;
padding: 20px 22px;
position: sticky; top: 0; z-index: 30;
backdrop-filter: blur(14px);
}
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--display); font-weight: 700; font-size: 1.15rem; }
.mark { display: grid; place-items: center; }
.nav-links { display: flex; gap: 22px; margin-left: auto; font-size: .95rem; color: var(--muted); font-weight: 500; }
.nav-links a:hover { color: var(--ink); }
.nav-cta { display: flex; gap: 10px; align-items: center; }
.nav .nav-cta { margin-left: 8px; }
.nav-links + .nav-cta { margin-left: 0; }
/* ---------- buttons ---------- */
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
font: inherit; font-weight: 600; cursor: pointer;
border-radius: 12px; padding: 10px 18px; border: 1px solid transparent;
transition: transform .15s ease, box-shadow .2s ease, background .2s ease, border-color .2s ease;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn.primary {
color: #fff; background: var(--grad); background-size: 180% 180%;
box-shadow: 0 10px 26px -10px rgba(124, 92, 255, .7);
}
.btn.primary:hover { box-shadow: 0 14px 34px -10px rgba(124, 92, 255, .85); animation: shift 4s ease infinite; }
@keyframes shift { 0%, 100% { background-position: 0 50%; } 50% { background-position: 100% 50%; } }
.btn.ghost {
background: var(--surface); border-color: var(--line); color: var(--ink);
}
.btn.ghost:hover { background: var(--surface-2); border-color: var(--brand-2); }
.btn.lg { padding: 14px 24px; font-size: 1.02rem; border-radius: 14px; }
.btn.xs { padding: 6px 12px; font-size: .82rem; border-radius: 9px; }
.theme-ico { font-size: 1rem; }
/* ---------- hero ---------- */
.hero {
max-width: var(--maxw); margin: 0 auto; padding: 48px 22px 70px;
display: grid; grid-template-columns: 1.05fr 1fr; gap: 48px; align-items: center;
}
.pill {
display: inline-flex; align-items: center; gap: 8px;
font-size: .82rem; font-weight: 600; color: var(--ink);
padding: 7px 14px; border-radius: 999px;
background: var(--surface); border: 1px solid var(--line);
}
.pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brand-2); box-shadow: 0 0 0 0 rgba(38, 208, 206, .6); animation: pulse 2.2s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(38, 208, 206, .55); } 70% { box-shadow: 0 0 0 9px rgba(38, 208, 206, 0); } 100% { box-shadow: 0 0 0 0 rgba(38, 208, 206, 0); } }
.hero h1 { font-size: clamp(2.3rem, 5vw, 3.6rem); font-weight: 700; margin: 20px 0 16px; }
.grad {
background: var(--grad); background-size: 200% auto;
-webkit-background-clip: text; background-clip: text; color: transparent;
animation: shift 6s ease infinite;
}
.lede { color: var(--muted); font-size: 1.1rem; max-width: 48ch; }
.hero-actions { display: flex; gap: 12px; margin: 28px 0 22px; flex-wrap: wrap; }
.trust-row { list-style: none; margin: 0; padding: 0; display: flex; gap: 22px; flex-wrap: wrap; color: var(--muted); font-size: .9rem; }
.trust-row strong { color: var(--ink); }
/* ---------- glass ---------- */
.glass {
background: linear-gradient(160deg, var(--surface-2), var(--surface));
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
backdrop-filter: blur(12px);
}
/* ---------- demo card ---------- */
.hero-demo { position: relative; }
.demo-card { padding: 18px; position: relative; overflow: hidden; }
.demo-card::before {
content: ""; position: absolute; inset: -1px; border-radius: var(--radius); padding: 1px;
background: var(--grad-soft); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor; mask-composite: exclude; opacity: .5; pointer-events: none;
}
.demo-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.demo-head h2 { font-size: 1rem; font-family: var(--sans); font-weight: 600; }
.dots { display: inline-flex; gap: 6px; }
.dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--line); }
.dots i:nth-child(1) { background: #ff5f57; } .dots i:nth-child(2) { background: #febc2e; } .dots i:nth-child(3) { background: #28c840; }
.badge {
margin-left: auto; font-size: .72rem; font-weight: 600; padding: 4px 10px;
border-radius: 999px; background: var(--surface); border: 1px solid var(--line); color: var(--muted);
text-transform: uppercase; letter-spacing: .05em;
}
.badge.live[data-state="streaming"] { color: var(--brand-2); border-color: rgba(38, 208, 206, .5); }
.badge.live[data-state="done"] { color: var(--ok); border-color: rgba(52, 211, 153, .5); }
.prompt-bar { display: flex; gap: 8px; align-items: flex-end; }
#promptInput {
flex: 1; resize: none; font: inherit; color: var(--ink);
background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
padding: 12px 14px; line-height: 1.45; max-height: 120px; min-height: 46px;
}
#promptInput::placeholder { color: var(--muted); }
#promptInput:focus { border-color: var(--brand); outline: none; }
.send { align-self: stretch; }
.suggests { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0 4px; }
.chip {
font: inherit; font-size: .82rem; font-weight: 500; cursor: pointer;
padding: 6px 12px; border-radius: 999px; color: var(--muted);
background: var(--surface); border: 1px solid var(--line); transition: .15s;
}
.chip:hover { color: var(--ink); border-color: var(--brand-2); background: var(--surface-2); }
.result { margin-top: 14px; min-height: 150px; }
.result-empty {
min-height: 150px; display: flex; align-items: center; justify-content: center; gap: 10px;
color: var(--muted); font-size: .92rem; text-align: center;
border: 1px dashed var(--line); border-radius: 12px; padding: 16px;
}
.spark { font-size: 1.2rem; background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; animation: spin 6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.result-body {
background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px;
}
.rb-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.model-tag {
font-size: .74rem; font-weight: 700; padding: 3px 9px; border-radius: 7px; color: #fff;
background: var(--grad);
}
.rb-meta { font-size: .78rem; color: var(--muted); }
.rb-text { font-size: .95rem; white-space: pre-wrap; min-height: 1.5em; }
.rb-text .cursor { display: inline-block; width: 7px; height: 1.05em; vertical-align: text-bottom; margin-left: 1px; background: var(--brand-2); animation: blink 1s step-end infinite; border-radius: 1px; }
@keyframes blink { 50% { opacity: 0; } }
.rb-foot { display: flex; align-items: center; gap: 8px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.tok { margin-left: auto; font-size: .76rem; color: var(--muted); }
/* ---------- sections ---------- */
.sec-head { max-width: 620px; margin: 0 auto 36px; text-align: center; }
.sec-head h2 { font-size: clamp(1.7rem, 3.5vw, 2.4rem); }
.sec-head p { color: var(--muted); margin-top: 10px; font-size: 1.05rem; }
.capabilities, .models, .proof, .cta { max-width: var(--maxw); margin: 0 auto; padding: 70px 22px; }
.cap-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.tile {
padding: 22px; border-radius: var(--radius);
background: linear-gradient(160deg, var(--surface-2), var(--surface));
border: 1px solid var(--line); transition: transform .2s ease, border-color .2s ease;
}
.tile:hover { transform: translateY(-4px); border-color: var(--brand); }
.tile-ico { font-size: 1.6rem; display: block; margin-bottom: 10px; }
.tile h3 { font-size: 1.1rem; margin-bottom: 6px; }
.tile p { color: var(--muted); font-size: .94rem; }
/* ---------- models band ---------- */
.model-band { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch; }
.model-card {
position: relative; padding: 24px; border-radius: var(--radius);
background: linear-gradient(160deg, var(--surface-2), var(--surface));
border: 1px solid var(--line); display: flex; flex-direction: column;
}
.model-card.featured { border-color: transparent; box-shadow: 0 20px 50px -24px rgba(124, 92, 255, .6); }
.model-card.featured::before {
content: ""; position: absolute; inset: -1px; border-radius: var(--radius); padding: 1.5px;
background: var(--grad); -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none;
}
.ribbon {
position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
font-size: .72rem; font-weight: 700; color: #fff; padding: 4px 12px; border-radius: 999px;
background: var(--grad);
}
.model-card h3 { font-size: 1.25rem; }
.m-sub { color: var(--muted); font-size: .9rem; margin: 6px 0 16px; }
.meter { margin: 0 0 18px; display: grid; gap: 10px; }
.meter div { display: grid; grid-template-columns: 56px 1fr; align-items: center; gap: 10px; }
.meter dt { font-size: .8rem; color: var(--muted); }
.meter dd { margin: 0; height: 8px; border-radius: 999px; background: var(--surface); overflow: hidden; }
.bar { display: block; height: 100%; width: var(--v); border-radius: 999px; background: var(--grad); transform-origin: left; animation: grow 1s ease both; }
.bar.ok { background: linear-gradient(90deg, #34d399, #26d0ce); }
.bar.warn { background: linear-gradient(90deg, #fbbf24, #ff5db1); }
@keyframes grow { from { transform: scaleX(0); } }
.m-price { margin-top: auto; font-family: var(--display); font-size: 1.5rem; font-weight: 700; }
.m-price span { font-size: .82rem; font-weight: 500; color: var(--muted); font-family: var(--sans); }
/* ---------- proof ---------- */
.proof { text-align: center; }
.proof-eyebrow { color: var(--muted); font-size: .9rem; text-transform: uppercase; letter-spacing: .12em; }
.logos {
list-style: none; margin: 22px 0 44px; padding: 0;
display: flex; flex-wrap: wrap; gap: 14px 34px; justify-content: center;
font-family: var(--display); font-weight: 600; font-size: 1.15rem; color: var(--muted);
}
.logos li { opacity: .65; transition: opacity .2s, color .2s; }
.logos li:hover { opacity: 1; color: var(--ink); }
.quote { max-width: 720px; margin: 0 auto 44px; padding: 30px; text-align: left; }
.quote blockquote { margin: 0; font-family: var(--display); font-size: 1.3rem; font-weight: 500; line-height: 1.45; }
.quote figcaption { display: flex; align-items: center; gap: 12px; margin-top: 18px; color: var(--muted); font-size: .92rem; }
.quote strong { color: var(--ink); }
.avatar {
width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
font-weight: 700; color: #fff; background: var(--grad); font-family: var(--sans); flex: 0 0 auto;
}
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.stats div {
padding: 22px 14px; border-radius: var(--radius);
background: linear-gradient(160deg, var(--surface-2), var(--surface)); border: 1px solid var(--line);
}
.stats strong {
display: block; font-family: var(--display); font-size: 2rem; font-weight: 700;
background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.stats span { color: var(--muted); font-size: .88rem; }
/* ---------- cta ---------- */
.cta-card { max-width: 720px; margin: 0 auto; padding: 44px 34px; text-align: center; }
.cta-card h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); }
.cta-card > p { color: var(--muted); margin: 12px 0 26px; font-size: 1.05rem; }
.cta-form { display: flex; gap: 10px; max-width: 460px; margin: 0 auto; }
.cta-form input {
flex: 1; font: inherit; padding: 14px 16px; border-radius: 14px; color: var(--ink);
background: var(--surface); border: 1px solid var(--line);
}
.cta-form input:focus { border-color: var(--brand); outline: none; }
.cta-fine { margin-top: 16px; font-size: .85rem; color: var(--muted); }
.cta-fine.ok { color: var(--ok); }
.cta-fine.err { color: var(--danger); }
/* ---------- footer ---------- */
.footer {
max-width: var(--maxw); margin: 0 auto; padding: 30px 22px 50px;
display: flex; align-items: center; justify-content: space-between; gap: 16px;
border-top: 1px solid var(--line); color: var(--muted); font-size: .9rem; flex-wrap: wrap;
}
.footer nav { display: flex; gap: 20px; }
.footer a:hover { color: var(--ink); }
/* ---------- toast ---------- */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 24px);
background: var(--ink); color: var(--bg); padding: 12px 20px; border-radius: 12px;
font-size: .9rem; font-weight: 600; box-shadow: var(--shadow);
opacity: 0; pointer-events: none; transition: .3s ease; z-index: 50;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- responsive ---------- */
@media (max-width: 920px) {
.hero { grid-template-columns: 1fr; gap: 36px; }
.nav-links { display: none; }
.cap-grid { grid-template-columns: repeat(2, 1fr); }
.model-band { grid-template-columns: 1fr; }
.model-card.featured { order: -1; }
.stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
.cap-grid { grid-template-columns: 1fr; }
.cta-form { flex-direction: column; }
.footer { flex-direction: column; text-align: center; }
.hero-actions .btn { flex: 1; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
.rb-text .cursor { animation: none; }
}(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("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () { toastEl.classList.remove("show"); }, 2400);
}
/* ---------- theme toggle ---------- */
var themeToggle = document.getElementById("themeToggle");
if (themeToggle) {
themeToggle.addEventListener("click", function () {
var light = document.documentElement.getAttribute("data-theme") === "light";
var next = light ? null : "light";
if (next) document.documentElement.setAttribute("data-theme", next);
else document.documentElement.removeAttribute("data-theme");
var nowLight = !light;
themeToggle.setAttribute("aria-pressed", String(nowLight));
themeToggle.querySelector(".theme-label").textContent = nowLight ? "Light" : "Dark";
themeToggle.querySelector(".theme-ico").textContent = nowLight ? "◑" : "◐";
});
}
/* ---------- prompt → streaming demo ---------- */
var promptInput = document.getElementById("promptInput");
var runBtn = document.getElementById("runBtn");
var resultEmpty = document.getElementById("resultEmpty");
var resultBody = document.getElementById("resultBody");
var rbText = document.getElementById("rbText");
var rbMeta = document.getElementById("rbMeta");
var rbFoot = document.getElementById("rbFoot");
var tokCount = document.getElementById("tokCount");
var streamState = document.getElementById("streamState");
var copyBtn = document.getElementById("copyBtn");
var regenBtn = document.getElementById("regenBtn");
// auto-grow textarea
function autoGrow() {
promptInput.style.height = "auto";
promptInput.style.height = Math.min(promptInput.scrollHeight, 120) + "px";
}
if (promptInput) {
autoGrow();
promptInput.addEventListener("input", autoGrow);
promptInput.addEventListener("keydown", function (e) {
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); run(); }
});
}
// canned responses keyed by intent — picked by simple keyword match
var CANNED = [
{
match: ["summar", "q3", "launch", "bullet"],
text: "Here's a tight summary of the Q3 launch:\n\n• Shipped Lumina 3.5 with a 280K-token context — 2.3× longer documents in one pass.\n• Cut median response latency 41% while holding answer quality steady on internal evals.\n• Opened the streaming SDK to 65+ integrations, with day-one connectors for Slack and Notion.\n\nTagline: “Think bigger. Ship faster. Lumina 3.5.”"
},
{
match: ["cold email", "cto", "infra", "cost"],
text: "Subject: Trim 30% off your infra bill this quarter\n\nHi {Name},\n\nMost platform teams overspend on idle compute they can't see. Lumina maps your workloads, flags waste, and drafts the migration plan — usually surfacing a 25–35% reduction in the first week.\n\nWorth a 15-minute look? I'll bring a sample teardown of a stack like yours.\n\n— The Lumina team"
},
{
match: ["vector", "database", "pm", "product manager"],
text: "Vector databases, for a PM:\n\n1. They store meaning as coordinates, not exact text — “dog” and “puppy” land close together.\n2. A search finds nearest neighbors, so you match by intent instead of keywords.\n3. That powers semantic search, recommendations, and RAG for AI features.\n4. The win: relevance without brittle keyword rules."
},
{
match: ["checklist", "5-step", "5 step", "launch plan", "mobile app"],
text: "5-step mobile app launch checklist:\n\n1. Lock scope — freeze the v1 feature list and write the one-line value prop.\n2. Polish — run a device matrix pass and fix the top 10 friction points.\n3. Stage — ship a TestFlight/closed beta to ~100 users, watch crash-free rate.\n4. Prep store — screenshots, keywords, and a 30-second preview video.\n5. Launch — submit for review, schedule announcements, and stand up day-one support."
}
];
var FALLBACK = "Got it. Here's a first pass:\n\n• I broke your request into clear, actionable steps.\n• Each point is concrete enough to act on today.\n• Ask a follow-up and I'll refine the tone, length, or depth.\n\nThis is a canned demo response — in the real product, Lumina streams a live answer here.";
function pickResponse(prompt) {
var p = prompt.toLowerCase();
var best = null, bestScore = 0;
CANNED.forEach(function (c) {
var score = c.match.reduce(function (s, k) { return s + (p.indexOf(k) > -1 ? 1 : 0); }, 0);
if (score > bestScore) { bestScore = score; best = c; }
});
return best && bestScore > 0 ? best.text : FALLBACK;
}
var streaming = false;
var streamTimer = null;
var lastPrompt = "";
function setState(state) {
streamState.textContent = state;
streamState.setAttribute("data-state", state);
}
function tokenize(text) {
// split into word-ish tokens, keeping whitespace/newlines attached
return text.match(/\s*\S+|\s+/g) || [text];
}
function run() {
if (streaming) return;
var prompt = (promptInput.value || "").trim();
if (!prompt) { toast("Type a prompt first"); promptInput.focus(); return; }
lastPrompt = prompt;
startStream(pickResponse(prompt));
}
function startStream(fullText) {
streaming = true;
runBtn.disabled = true;
regenBtn && (regenBtn.disabled = true);
resultEmpty.hidden = true;
resultBody.hidden = false;
rbFoot.hidden = true;
setState("streaming");
var t0 = performance.now();
var tokens = tokenize(fullText);
var i = 0;
rbText.innerHTML = "";
var span = document.createElement("span");
rbText.appendChild(span);
var cursor = document.createElement("span");
cursor.className = "cursor";
rbText.appendChild(cursor);
function finish() {
streaming = false;
runBtn.disabled = false;
regenBtn && (regenBtn.disabled = false);
if (cursor.parentNode) cursor.parentNode.removeChild(cursor);
var ms = Math.round(performance.now() - t0);
var words = fullText.trim().split(/\s+/).length;
rbMeta.textContent = "responded in " + (ms / 1000).toFixed(1) + "s";
tokCount.textContent = "~" + Math.round(words * 1.3) + " tokens";
rbFoot.hidden = false;
setState("done");
}
if (reduceMotion) {
span.textContent = fullText;
finish();
return;
}
function step() {
if (i >= tokens.length) { finish(); return; }
span.textContent += tokens[i];
i++;
var delay = 14 + Math.random() * 36;
if (/[.\n!?]/.test(tokens[i - 1] || "")) delay += 90;
streamTimer = setTimeout(step, delay);
}
step();
}
if (runBtn) runBtn.addEventListener("click", run);
if (regenBtn) regenBtn.addEventListener("click", function () {
if (!lastPrompt) return;
startStream(pickResponse(lastPrompt));
});
if (copyBtn) copyBtn.addEventListener("click", function () {
var text = rbText.textContent || "";
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () { toast("Copied to clipboard"); },
function () { toast("Copy failed"); });
} else {
var ta = document.createElement("textarea");
ta.value = text; document.body.appendChild(ta); ta.select();
try { document.execCommand("copy"); toast("Copied to clipboard"); }
catch (e) { toast("Copy failed"); }
document.body.removeChild(ta);
}
});
// example chips
document.querySelectorAll(".chip").forEach(function (chip) {
chip.addEventListener("click", function () {
if (streaming) { clearTimeout(streamTimer); streaming = false; runBtn.disabled = false; }
promptInput.value = chip.getAttribute("data-prompt");
autoGrow();
run();
});
});
/* ---------- animated stat counters ---------- */
var counters = document.querySelectorAll(".stats strong[data-count]");
if ("IntersectionObserver" in window && counters.length) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
animateCount(entry.target);
io.unobserve(entry.target);
});
}, { threshold: 0.5 });
counters.forEach(function (c) { io.observe(c); });
} else {
counters.forEach(function (c) { c.textContent = c.getAttribute("data-count"); });
}
function animateCount(el) {
var target = parseInt(el.getAttribute("data-count"), 10);
if (reduceMotion) { el.textContent = target; return; }
var start = performance.now(), dur = 1100;
function tick(now) {
var p = Math.min((now - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = Math.round(target * eased);
if (p < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
/* ---------- CTA form ---------- */
var ctaForm = document.getElementById("ctaForm");
var ctaMsg = document.getElementById("ctaMsg");
if (ctaForm) {
ctaForm.addEventListener("submit", function (e) {
e.preventDefault();
var email = document.getElementById("email").value.trim();
var valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
if (!valid) {
ctaMsg.textContent = "Please enter a valid work email.";
ctaMsg.className = "cta-fine err";
document.getElementById("email").focus();
return;
}
ctaMsg.textContent = "You're in — check " + email + " for your trial link.";
ctaMsg.className = "cta-fine ok";
ctaForm.reset();
toast("Welcome to Lumina ✦");
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Lumina — AI that writes, reasons, and ships with you</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=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="aurora" aria-hidden="true">
<span class="blob b1"></span>
<span class="blob b2"></span>
<span class="blob b3"></span>
</div>
<header class="nav" role="banner">
<a class="brand" href="#top" aria-label="Lumina home">
<span class="mark" aria-hidden="true">
<svg viewBox="0 0 32 32" width="28" height="28" role="img" aria-hidden="true">
<defs>
<linearGradient id="g1" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#7c5cff"/>
<stop offset=".5" stop-color="#26d0ce"/>
<stop offset="1" stop-color="#ff5db1"/>
</linearGradient>
</defs>
<path d="M16 2 L20 12 L30 16 L20 20 L16 30 L12 20 L2 16 L12 12 Z" fill="url(#g1)"/>
</svg>
</span>
<span class="brand-name">Lumina</span>
</a>
<nav class="nav-links" aria-label="Primary">
<a href="#capabilities">Capabilities</a>
<a href="#models">Models</a>
<a href="#proof">Customers</a>
<a href="#try">Pricing</a>
</nav>
<div class="nav-cta">
<button class="btn ghost" id="themeToggle" aria-pressed="false" aria-label="Toggle dark mode">
<span class="theme-ico" aria-hidden="true">◐</span>
<span class="theme-label">Dark</span>
</button>
<a class="btn primary" href="#try">Start free</a>
</div>
</header>
<main id="top">
<section class="hero" aria-labelledby="hero-title">
<div class="hero-copy">
<span class="pill"><span class="dot" aria-hidden="true"></span> Lumina 3.5 is live — 280K context</span>
<h1 id="hero-title">The AI workspace that <span class="grad">thinks alongside you</span></h1>
<p class="lede">
Draft, reason, and ship faster with a model tuned for real work. Ask in plain language —
Lumina streams structured answers, cites its steps, and plugs into your stack.
</p>
<div class="hero-actions">
<a class="btn primary lg" href="#try">Start free — no card</a>
<a class="btn ghost lg" href="#demo">See it stream ↓</a>
</div>
<ul class="trust-row" aria-label="At a glance">
<li><strong>4.9★</strong> on 12k reviews</li>
<li><strong>SOC 2</strong> Type II</li>
<li><strong>99.98%</strong> uptime</li>
</ul>
</div>
<div class="hero-demo" id="demo" aria-labelledby="demo-title">
<div class="demo-card glass">
<div class="demo-head">
<span class="dots" aria-hidden="true"><i></i><i></i><i></i></span>
<h2 id="demo-title">Try a prompt</h2>
<span class="badge live" id="streamState">idle</span>
</div>
<div class="prompt-bar">
<label class="sr-only" for="promptInput">Your prompt</label>
<textarea id="promptInput" rows="1" placeholder="Ask Lumina anything…"
autocomplete="off">Summarize our Q3 launch in 3 crisp bullets and a tagline.</textarea>
<button class="btn primary send" id="runBtn" aria-label="Run prompt">
<span class="send-label">Generate</span>
</button>
</div>
<div class="suggests" role="group" aria-label="Example prompts">
<button class="chip" data-prompt="Write a cold email to a CTO about cutting infra costs 30%.">Cold email</button>
<button class="chip" data-prompt="Explain vector databases to a product manager in 4 lines.">Explain simply</button>
<button class="chip" data-prompt="Refactor this idea into a 5-step launch checklist for a mobile app.">Launch plan</button>
</div>
<div class="result" id="result" aria-live="polite" aria-atomic="false">
<div class="result-empty" id="resultEmpty">
<span class="spark" aria-hidden="true">✦</span>
Output streams here, token by token.
</div>
<article class="result-body" id="resultBody" hidden>
<header class="rb-head">
<span class="model-tag">Lumina 3.5</span>
<span class="rb-meta" id="rbMeta"></span>
</header>
<div class="rb-text" id="rbText"></div>
<footer class="rb-foot" id="rbFoot" hidden>
<button class="btn ghost xs" id="copyBtn">Copy</button>
<button class="btn ghost xs" id="regenBtn">Regenerate</button>
<span class="tok" id="tokCount"></span>
</footer>
</article>
</div>
</div>
</div>
</section>
<section class="capabilities" id="capabilities" aria-labelledby="cap-title">
<div class="sec-head">
<h2 id="cap-title">One model, the whole workflow</h2>
<p>From a blank cursor to shipped — Lumina covers the messy middle.</p>
</div>
<div class="cap-grid">
<article class="tile">
<span class="tile-ico" aria-hidden="true">✍️</span>
<h3>Write & rewrite</h3>
<p>Long-form drafts, emails, docs — in your voice, on the first pass.</p>
</article>
<article class="tile">
<span class="tile-ico" aria-hidden="true">🧠</span>
<h3>Reason & plan</h3>
<p>Step-by-step problem solving with visible, auditable thinking.</p>
</article>
<article class="tile">
<span class="tile-ico" aria-hidden="true">🔌</span>
<h3>Connect tools</h3>
<p>Call your APIs, search the web, and run code in a sandbox.</p>
</article>
<article class="tile">
<span class="tile-ico" aria-hidden="true">📊</span>
<h3>Analyze data</h3>
<p>Turn spreadsheets and logs into charts, summaries, and decisions.</p>
</article>
<article class="tile">
<span class="tile-ico" aria-hidden="true">🛡️</span>
<h3>Stay private</h3>
<p>Your data is never used for training. Encrypted at rest and in flight.</p>
</article>
<article class="tile">
<span class="tile-ico" aria-hidden="true">⚡</span>
<h3>Ship to prod</h3>
<p>SDKs, streaming, and 99.98% uptime backed by an SLA.</p>
</article>
</div>
</section>
<section class="models" id="models" aria-labelledby="mdl-title">
<div class="sec-head">
<h2 id="mdl-title">Pick the right intelligence</h2>
<p>Speed when you need it, depth when it counts.</p>
</div>
<div class="model-band" role="list">
<article class="model-card" role="listitem">
<h3>Lumina Flash</h3>
<p class="m-sub">Instant answers, drafts, classification.</p>
<dl class="meter">
<div><dt>Speed</dt><dd><span class="bar" style="--v:96%"></span></dd></div>
<div><dt>Depth</dt><dd><span class="bar" style="--v:58%"></span></dd></div>
<div><dt>Cost</dt><dd><span class="bar ok" style="--v:22%"></span></dd></div>
</dl>
<p class="m-price">$0.20 <span>/ 1M tokens</span></p>
</article>
<article class="model-card featured" role="listitem">
<span class="ribbon">Most picked</span>
<h3>Lumina 3.5</h3>
<p class="m-sub">The balanced workhorse for daily work.</p>
<dl class="meter">
<div><dt>Speed</dt><dd><span class="bar" style="--v:78%"></span></dd></div>
<div><dt>Depth</dt><dd><span class="bar" style="--v:88%"></span></dd></div>
<div><dt>Cost</dt><dd><span class="bar ok" style="--v:48%"></span></dd></div>
</dl>
<p class="m-price">$3.00 <span>/ 1M tokens</span></p>
</article>
<article class="model-card" role="listitem">
<h3>Lumina Reason</h3>
<p class="m-sub">Hard problems, math, multi-step agents.</p>
<dl class="meter">
<div><dt>Speed</dt><dd><span class="bar" style="--v:46%"></span></dd></div>
<div><dt>Depth</dt><dd><span class="bar" style="--v:99%"></span></dd></div>
<div><dt>Cost</dt><dd><span class="bar warn" style="--v:74%"></span></dd></div>
</dl>
<p class="m-price">$9.00 <span>/ 1M tokens</span></p>
</article>
</div>
</section>
<section class="proof" id="proof" aria-labelledby="proof-title">
<h2 id="proof-title" class="sr-only">Customer proof</h2>
<p class="proof-eyebrow">Trusted by teams shipping at speed</p>
<ul class="logos" aria-label="Customer logos">
<li>Northwind</li>
<li>Vertex Labs</li>
<li>Halcyon</li>
<li>Pinemark</li>
<li>Driftwave</li>
<li>Quanta</li>
</ul>
<figure class="quote glass">
<blockquote>
“Lumina replaced four tools and a backlog of prompts. Our team ships
weekly content in an afternoon — and the reasoning trace makes it auditable.”
</blockquote>
<figcaption>
<span class="avatar" aria-hidden="true">RA</span>
<span><strong>Rania Adler</strong><br />VP Product, Vertex Labs</span>
</figcaption>
</figure>
<div class="stats" role="list">
<div role="listitem"><strong data-count="280">0</strong><span>K context window</span></div>
<div role="listitem"><strong data-count="42">0</strong><span>M prompts / day</span></div>
<div role="listitem"><strong data-count="99">0</strong><span>.98% uptime</span></div>
<div role="listitem"><strong data-count="65">0</strong><span>+ integrations</span></div>
</div>
</section>
<section class="cta" id="try" aria-labelledby="cta-title">
<div class="cta-card glass">
<h2 id="cta-title">Put Lumina to work today</h2>
<p>Free for 14 days. No credit card. Cancel anytime.</p>
<form class="cta-form" id="ctaForm" novalidate>
<label class="sr-only" for="email">Work email</label>
<input type="email" id="email" name="email" placeholder="[email protected]"
autocomplete="email" required />
<button class="btn primary lg" type="submit">Start free</button>
</form>
<p class="cta-fine" id="ctaMsg">Join 12,000+ teams. SOC 2 Type II · GDPR ready.</p>
</div>
</section>
</main>
<footer class="footer" role="contentinfo">
<p>© 2026 Lumina AI — a fictional product for demonstration.</p>
<nav aria-label="Footer">
<a href="#capabilities">Product</a>
<a href="#models">Pricing</a>
<a href="#proof">Customers</a>
</nav>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>AI Product Landing
A cutting-edge marketing landing for Lumina, a fictional AI workspace. The page opens on a black canvas with slowly drifting iridescent aurora blobs and a gradient headline. The centerpiece is an interactive demo card: type a prompt (or tap an example chip) and Lumina streams a canned, intent-matched response token by token, complete with a blinking cursor, a “streaming → done” status badge, response time, and a rough token count.
Below the fold, capability tiles outline the product’s range, a three-card model band compares Flash / 3.5 / Reason on animated speed-depth-cost meters, and a social-proof section animates stat counters into view alongside a customer quote and logo wall. A glassy CTA validates an email inline before confirming sign-up.
Everything runs on vanilla JS with no dependencies: the streaming demo, Cmd/Ctrl-Enter to send, copy and regenerate actions, a light/dark theme toggle, IntersectionObserver count-up stats, and a toast helper. All motion is gated behind prefers-reduced-motion, and controls are keyboard-usable with visible focus rings.
Illustrative SaaS UI only — fictional product, metrics, and billing. No real backend.