Web Pages Hard
Dark SaaS Dashboard Preview
A dark SaaS dashboard preview landing page — the app UI IS the hero. Includes a sidebar, metric cards, a revenue chart (CSS-drawn), a data table, and an activity feed.
Open in Lab
MCP
gsap scrolltrigger lenis css vanilla-js
Targets: JS HTML
Code
/* ── Reset & Base ──────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #080c14;
--bg2: #0d1117;
--bg3: #161b22;
--bg4: #1e2530;
--accent: #6366f1;
--green: #10b981;
--red: #ef4444;
--amber: #f59e0b;
--text: #e2e8f0;
--muted: #64748b;
--border: rgba(255, 255, 255, 0.07);
--surface: rgba(255, 255, 255, 0.04);
--radius: 8px;
}
html {
scroll-behavior: smooth;
}
body {
background: var(--bg);
color: var(--text);
font-family: "Inter", system-ui, -apple-system, sans-serif;
font-size: 14px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* ── Landing Nav ───────────────────────────────────────────────────────────── */
.landing-nav {
position: sticky;
top: 0;
z-index: 200;
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 48px;
background: rgba(8, 12, 20, 0.9);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
}
.landing-logo {
display: flex;
align-items: center;
gap: 8px;
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--text);
text-decoration: none;
}
.landing-nav-links {
display: flex;
align-items: center;
gap: 32px;
list-style: none;
}
.landing-nav-links a {
font-size: 0.85rem;
color: var(--muted);
text-decoration: none;
transition: color 0.2s;
}
.landing-nav-links a:hover {
color: var(--text);
}
.landing-nav-actions {
display: flex;
align-items: center;
gap: 12px;
}
.nav-signin {
font-size: 0.85rem;
color: var(--muted);
text-decoration: none;
transition: color 0.2s;
}
.nav-signin:hover {
color: var(--text);
}
.btn-signup {
padding: 8px 18px;
border-radius: var(--radius);
background: var(--accent);
border: none;
color: #fff;
font-size: 0.82rem;
font-weight: 600;
cursor: pointer;
font-family: inherit;
transition: opacity 0.2s;
}
.btn-signup:hover {
opacity: 0.85;
}
/* ── Hero Text Section ─────────────────────────────────────────────────────── */
.hero-text-section {
padding: 80px 48px 56px;
text-align: center;
background: radial-gradient(
ellipse 70% 50% at 50% 0%,
rgba(99, 102, 241, 0.07) 0%,
transparent 60%
);
}
.hero-text-inner {
max-width: 700px;
margin: 0 auto;
}
.hero-badge {
display: inline-flex;
align-items: center;
padding: 5px 14px;
border-radius: 50px;
border: 1px solid rgba(99, 102, 241, 0.3);
background: rgba(99, 102, 241, 0.07);
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.06em;
color: #818cf8;
margin-bottom: 24px;
}
.hero-headline {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 1.05;
margin-bottom: 16px;
}
.headline-gradient {
background: linear-gradient(90deg, #818cf8, #38bdf8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-sub {
font-size: 1rem;
color: var(--muted);
max-width: 540px;
margin: 0 auto;
line-height: 1.7;
}
/* ── Dashboard Preview Section ─────────────────────────────────────────────── */
.dashboard-preview-section {
margin: 0 48px 80px;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 32px 80px rgba(0, 0, 0, 0.65);
}
.dashboard-chrome {
display: flex;
flex-direction: column;
}
.chrome-bar {
display: flex;
align-items: center;
gap: 12px;
padding: 11px 16px;
background: var(--bg3);
border-bottom: 1px solid var(--border);
}
.chrome-dots {
display: flex;
gap: 6px;
}
.chrome-dots span {
width: 10px;
height: 10px;
border-radius: 50%;
}
.chrome-url {
flex: 1;
background: var(--surface);
border-radius: 6px;
padding: 5px 12px;
font-family: "JetBrains Mono", "Courier New", monospace;
font-size: 0.7rem;
color: var(--muted);
}
/* ── Dashboard UI ──────────────────────────────────────────────────────────── */
.dashboard-ui {
display: flex;
height: 620px;
background: var(--bg2);
overflow: hidden;
}
/* Sidebar */
.sidebar {
width: 192px;
flex-shrink: 0;
background: var(--bg3);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 16px 0;
overflow: hidden;
}
.sidebar-logo {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
margin-bottom: 20px;
font-size: 0.85rem;
font-weight: 700;
color: var(--text);
white-space: nowrap;
}
.sidebar-nav {
display: flex;
flex-direction: column;
flex: 1;
gap: 2px;
padding: 0 8px;
}
.sidebar-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
border-radius: 6px;
font-size: 0.8rem;
color: var(--muted);
text-decoration: none;
cursor: pointer;
transition: background 0.15s, color 0.15s;
white-space: nowrap;
}
.sidebar-item:hover {
background: var(--surface);
color: var(--text);
}
.sidebar-item.active {
background: rgba(99, 102, 241, 0.1);
color: #818cf8;
}
.sidebar-user {
margin-top: auto;
padding: 12px 16px;
display: flex;
align-items: center;
gap: 10px;
border-top: 1px solid var(--border);
}
.sidebar-avatar {
width: 30px;
height: 30px;
border-radius: 50%;
flex-shrink: 0;
background: linear-gradient(135deg, var(--accent), #38bdf8);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.68rem;
font-weight: 700;
color: #fff;
}
.sidebar-user-info {
display: flex;
flex-direction: column;
gap: 1px;
min-width: 0;
}
.sidebar-user-name {
font-size: 0.78rem;
font-weight: 600;
color: var(--text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sidebar-user-role {
font-size: 0.68rem;
color: var(--muted);
}
/* Main content */
.dash-main {
flex: 1;
overflow-y: auto;
padding: 20px 24px;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.dash-main::-webkit-scrollbar {
width: 5px;
}
.dash-main::-webkit-scrollbar-thumb {
background: var(--bg4);
border-radius: 3px;
}
/* Top bar */
.dash-topbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.dash-greeting {
font-size: 0.92rem;
font-weight: 700;
color: var(--text);
}
.dash-date {
font-size: 0.72rem;
color: var(--muted);
margin-top: 2px;
}
.topbar-actions {
display: flex;
align-items: center;
gap: 10px;
}
.btn-dash-action {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 12px;
border-radius: var(--radius);
background: var(--accent);
border: none;
color: #fff;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
font-family: inherit;
transition: opacity 0.2s;
}
.btn-dash-action:hover {
opacity: 0.85;
}
.topbar-notif {
position: relative;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius);
background: var(--surface);
border: 1px solid var(--border);
cursor: pointer;
color: var(--muted);
}
.notif-badge {
position: absolute;
top: -4px;
right: -4px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--red);
color: #fff;
font-size: 0.6rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
}
/* Metric cards */
.metric-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.metric-card {
background: var(--bg4);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 14px;
}
.metric-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}
.metric-label {
font-size: 0.7rem;
color: var(--muted);
}
.metric-badge {
display: inline-flex;
align-items: center;
padding: 2px 7px;
border-radius: 50px;
font-size: 0.66rem;
font-weight: 600;
}
.metric-badge.up {
background: rgba(16, 185, 129, 0.12);
color: var(--green);
}
.metric-badge.down {
background: rgba(239, 68, 68, 0.12);
color: var(--red);
}
.metric-value {
font-size: 1.4rem;
font-weight: 800;
letter-spacing: -0.02em;
color: var(--text);
margin-bottom: 8px;
font-variant-numeric: tabular-nums;
}
.metric-sparkline {
margin-bottom: 6px;
}
.spark-bars {
display: flex;
align-items: flex-end;
gap: 2px;
height: 32px;
}
.spark-bars span {
flex: 1;
height: var(--h, 50%);
background: rgba(99, 102, 241, 0.3);
border-radius: 2px 2px 0 0;
}
.spark-bars span.spark-active {
background: var(--accent);
}
.spark-bars.churn span {
background: rgba(239, 68, 68, 0.2);
}
.spark-bars.churn span.spark-active {
background: var(--red);
}
.metric-sub {
font-size: 0.65rem;
color: var(--muted);
}
/* Chart card */
.chart-card {
background: var(--bg4);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px;
margin-bottom: 16px;
}
.chart-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
}
.chart-title {
font-size: 0.82rem;
font-weight: 600;
}
.chart-sub {
font-size: 0.68rem;
color: var(--muted);
margin-top: 2px;
}
.chart-tabs {
display: flex;
gap: 4px;
}
.chart-tab {
padding: 4px 10px;
border-radius: 5px;
background: none;
border: 1px solid var(--border);
color: var(--muted);
font-size: 0.72rem;
font-weight: 500;
cursor: pointer;
font-family: inherit;
transition: all 0.15s;
}
.chart-tab:hover {
color: var(--text);
border-color: rgba(255, 255, 255, 0.15);
}
.chart-tab.active {
background: var(--accent);
border-color: var(--accent);
color: #fff;
font-weight: 600;
}
.chart-wrap {
position: relative;
}
.revenue-chart {
width: 100%;
height: 140px;
overflow: visible;
display: block;
}
/* Chart draw animation — JS sets strokeDasharray/Offset, then adds .drawn */
.revenue-chart path[stroke-linecap] {
transition: stroke-dashoffset 1.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.revenue-chart path[stroke-linecap].drawn {
stroke-dashoffset: 0;
}
.chart-x-labels {
display: flex;
justify-content: space-between;
padding-top: 6px;
font-size: 0.62rem;
color: var(--muted);
}
/* Bottom row: transactions + activity */
.dash-bottom-row {
display: grid;
grid-template-columns: 1fr 320px;
gap: 16px;
}
.transactions-card,
.activity-card {
background: var(--bg4);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 14px;
border-bottom: 1px solid var(--border);
}
.card-title {
font-size: 0.82rem;
font-weight: 600;
}
.card-link {
font-size: 0.72rem;
color: var(--accent);
text-decoration: none;
transition: opacity 0.2s;
}
.card-link:hover {
opacity: 0.75;
}
/* Transactions table */
.tx-table {
width: 100%;
border-collapse: collapse;
font-size: 0.76rem;
}
.tx-table th {
text-align: left;
padding: 8px 14px;
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
border-bottom: 1px solid var(--border);
}
.tx-table td {
padding: 9px 14px;
border-bottom: 1px solid var(--border);
}
.tx-table tr:last-child td {
border-bottom: none;
}
.tx-table tr:hover td {
background: var(--surface);
}
.tx-user {
display: flex;
align-items: center;
gap: 8px;
}
.tx-avatar {
width: 26px;
height: 26px;
border-radius: 50%;
flex-shrink: 0;
background: var(--bg, #6366f1);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.62rem;
font-weight: 700;
color: #fff;
}
.tx-plan {
color: var(--muted);
font-size: 0.74rem;
}
.tx-amount {
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: 50px;
font-size: 0.66rem;
font-weight: 600;
}
.status-badge::before {
content: "";
width: 5px;
height: 5px;
border-radius: 50%;
background: currentColor;
}
.status-badge.paid {
background: rgba(16, 185, 129, 0.1);
color: var(--green);
}
.status-badge.pending {
background: rgba(245, 158, 11, 0.1);
color: var(--amber);
}
.status-badge.failed {
background: rgba(239, 68, 68, 0.1);
color: var(--red);
}
/* Activity feed */
.activity-card .card-header {
border-bottom: 1px solid var(--border);
}
.activity-list {
display: flex;
flex-direction: column;
padding: 4px 0;
}
.activity-item {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 10px 14px;
border-bottom: 1px solid var(--border);
}
.activity-item:last-child {
border-bottom: none;
}
.activity-dot {
width: 7px;
height: 7px;
border-radius: 50%;
flex-shrink: 0;
background: var(--c, var(--accent));
margin-top: 4px;
}
.activity-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.activity-text {
font-size: 0.76rem;
line-height: 1.45;
color: var(--text);
}
.activity-text strong {
color: var(--text);
}
.activity-time {
font-size: 0.68rem;
color: var(--muted);
}
/* ── Features Section ──────────────────────────────────────────────────────── */
.features-section {
padding: 80px 48px;
}
.features-header {
text-align: center;
margin-bottom: 48px;
}
.features-eyebrow {
display: block;
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #818cf8;
margin-bottom: 12px;
}
.features-title {
font-size: clamp(1.5rem, 3vw, 2.2rem);
font-weight: 800;
letter-spacing: -0.025em;
}
.features-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.feature-card {
background: var(--bg3);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
transition: border-color 0.25s, box-shadow 0.25s;
}
.feature-card:hover {
border-color: rgba(99, 102, 241, 0.25);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.feature-icon {
width: 40px;
height: 40px;
border-radius: var(--radius);
background: rgba(99, 102, 241, 0.1);
border: 1px solid rgba(99, 102, 241, 0.15);
display: flex;
align-items: center;
justify-content: center;
color: var(--c, var(--accent));
margin-bottom: 16px;
}
.feature-title {
font-size: 0.92rem;
font-weight: 700;
margin-bottom: 8px;
}
.feature-desc {
font-size: 0.8rem;
color: var(--muted);
line-height: 1.65;
}
/* ── Pricing Section ───────────────────────────────────────────────────────── */
.pricing-section {
padding: 80px 48px;
border-top: 1px solid var(--border);
}
.pricing-header {
text-align: center;
margin-bottom: 48px;
}
.pricing-title {
font-size: clamp(1.5rem, 3vw, 2.2rem);
font-weight: 800;
letter-spacing: -0.025em;
margin-bottom: 8px;
}
.pricing-sub {
font-size: 0.95rem;
color: var(--muted);
}
.pricing-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
max-width: 700px;
margin: 0 auto;
}
.plan-card {
background: var(--bg3);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 28px;
position: relative;
}
.plan-card.featured {
border-color: rgba(99, 102, 241, 0.4);
background: rgba(99, 102, 241, 0.04);
}
.plan-badge {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
background: var(--accent);
color: #fff;
font-size: 0.68rem;
font-weight: 700;
padding: 3px 12px;
border-radius: 50px;
white-space: nowrap;
}
.plan-header {
margin-bottom: 16px;
}
.plan-name {
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 8px;
}
.plan-price {
display: flex;
align-items: baseline;
gap: 2px;
margin-bottom: 4px;
}
.plan-price-val {
font-size: 2.2rem;
font-weight: 900;
letter-spacing: -0.03em;
font-variant-numeric: tabular-nums;
}
.plan-price-period {
font-size: 0.82rem;
color: var(--muted);
}
.plan-features {
list-style: none;
margin-bottom: 24px;
display: flex;
flex-direction: column;
gap: 6px;
}
.plan-features li {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.82rem;
color: var(--muted);
}
.plan-features li::before {
content: "✓";
color: var(--green);
font-weight: 700;
font-size: 0.72rem;
flex-shrink: 0;
}
.btn-plan {
width: 100%;
padding: 11px;
border-radius: var(--radius);
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
font-family: inherit;
transition: opacity 0.2s;
}
.btn-plan.outline {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
.btn-plan.outline:hover {
border-color: rgba(255, 255, 255, 0.2);
}
.btn-plan.primary {
background: var(--accent);
color: #fff;
border: none;
}
.btn-plan.primary:hover {
opacity: 0.85;
}
/* ── Footer ────────────────────────────────────────────────────────────────── */
.footer {
border-top: 1px solid var(--border);
padding: 48px 48px 24px;
}
.footer-inner {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 48px;
margin-bottom: 40px;
flex-wrap: wrap;
}
.footer-brand {
max-width: 240px;
}
.footer-logo {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.95rem;
font-weight: 700;
color: var(--text);
margin-bottom: 10px;
}
.footer-brand p {
font-size: 0.82rem;
color: var(--muted);
line-height: 1.6;
}
.footer-cols {
display: flex;
gap: 48px;
}
.footer-col {
display: flex;
flex-direction: column;
gap: 10px;
min-width: 100px;
}
.footer-col-title {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text);
}
.footer-col a {
font-size: 0.8rem;
color: var(--muted);
text-decoration: none;
transition: color 0.2s;
}
.footer-col a:hover {
color: var(--text);
}
.footer-bottom {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 20px;
border-top: 1px solid var(--border);
font-size: 0.75rem;
color: var(--muted);
flex-wrap: wrap;
gap: 12px;
}
.footer-bottom-links {
display: flex;
gap: 20px;
}
.footer-bottom-links a {
color: var(--muted);
text-decoration: none;
transition: color 0.2s;
}
.footer-bottom-links a:hover {
color: var(--text);
}
/* ── Responsive ────────────────────────────────────────────────────────────── */
@media (max-width: 1200px) {
.metric-cards {
grid-template-columns: repeat(2, 1fr);
}
.dash-bottom-row {
grid-template-columns: 1fr;
}
}
@media (max-width: 900px) {
.landing-nav {
padding: 14px 20px;
}
.landing-nav-links {
display: none;
}
.hero-text-section {
padding: 60px 20px 40px;
}
.dashboard-preview-section {
margin: 0 16px 48px;
}
.features-section,
.pricing-section {
padding: 60px 20px;
}
.features-grid {
grid-template-columns: 1fr;
}
.pricing-grid {
grid-template-columns: 1fr;
max-width: 400px;
}
.footer {
padding: 40px 20px 20px;
}
.footer-inner {
flex-direction: column;
}
.footer-cols {
flex-wrap: wrap;
gap: 28px;
}
}/* ── lgc-68-dark-saas-dashboard · script.js ───────────────────────────────── */
/* ── Metric Counter Animation ──────────────────────────────────────────────── */
(function initMetricCounters() {
var dashboard = document.querySelector(".dashboard-preview-section");
if (!dashboard) return;
var cards = dashboard.querySelectorAll(".metric-value");
var started = false;
function easeOut(t) {
return 1 - Math.pow(1 - t, 3);
}
function animateValue(el) {
var target = parseFloat(el.dataset.target) || 0;
var prefix = el.dataset.prefix || "";
var suffix = el.dataset.suffix || "";
var decimals = el.dataset.decimals ? parseInt(el.dataset.decimals, 10) : 0;
var duration = 1400;
var start = null;
function tick(ts) {
if (!start) start = ts;
var progress = Math.min((ts - start) / duration, 1);
var value = easeOut(progress) * target;
var formatted = decimals > 0 ? value.toFixed(decimals) : Math.round(value).toLocaleString();
el.textContent = prefix + formatted + suffix;
if (progress < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
// Snapshot text as targets before animating
cards.forEach(function (el) {
var raw = el.textContent.replace(/[^0-9.]/g, "");
el.dataset.target = raw || "0";
el.dataset.prefix = el.textContent.match(/^[^0-9]*/)[0] || "";
el.dataset.suffix = el.textContent.match(/[^0-9]*$/)[0] || "";
el.textContent = el.dataset.prefix + "0" + el.dataset.suffix;
});
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting && !started) {
started = true;
cards.forEach(function (el) {
animateValue(el);
});
observer.disconnect();
}
});
},
{ threshold: 0.2 }
);
observer.observe(dashboard);
})();
/* ── SVG Revenue Chart Draw Animation ──────────────────────────────────────── */
(function initChartAnimation() {
// Target the stroke line path (has stroke-linecap="round" in HTML)
var line = document.querySelector(".revenue-chart path[stroke-linecap]");
if (!line) return;
var animated = false;
function getTotalLength() {
try {
return line.getTotalLength();
} catch (e) {
return 800;
}
}
function draw() {
if (animated) return;
animated = true;
var len = getTotalLength();
line.style.strokeDasharray = len;
line.style.strokeDashoffset = len;
// Force reflow then trigger CSS transition
line.getBoundingClientRect();
line.classList.add("drawn");
}
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
draw();
observer.disconnect();
}
});
},
{ threshold: 0.3 }
);
observer.observe(line.closest(".chart-card") || line);
})();
/* ── Chart Tab Switcher ─────────────────────────────────────────────────────── */
(function initChartTabs() {
var tabs = document.querySelectorAll(".chart-tab");
if (!tabs.length) return;
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("active");
});
tab.classList.add("active");
});
});
})();
/* ── Sidebar item active state ─────────────────────────────────────────────── */
(function initSidebarNav() {
var items = document.querySelectorAll(".sidebar-item");
if (!items.length) return;
items.forEach(function (item) {
item.addEventListener("click", function (e) {
e.preventDefault();
items.forEach(function (i) {
i.classList.remove("active");
});
item.classList.add("active");
});
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Orbit — Analytics Dashboard</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
<script type="importmap">{"imports":{"gsap":"https://esm.sh/gsap@3.13.0","gsap/ScrollTrigger":"https://esm.sh/gsap@3.13.0/ScrollTrigger","lenis":"https://esm.sh/lenis@1.1.13/dist/lenis.mjs"}}</script>
</head>
<body>
<!-- LANDING NAV -->
<nav class="landing-nav">
<a href="#" class="landing-logo">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<circle cx="10" cy="10" r="4" fill="#6366f1"/>
<circle cx="10" cy="10" r="8.5" stroke="#6366f1" stroke-width="1" opacity="0.4"/>
<circle cx="10" cy="10" r="14" stroke="#6366f1" stroke-width="0.5" opacity="0.2"/>
</svg>
Orbit
</a>
<ul class="landing-nav-links">
<li><a href="#">Features</a></li>
<li><a href="#">Pricing</a></li>
<li><a href="#">Docs</a></li>
<li><a href="#">Blog</a></li>
</ul>
<div class="landing-nav-actions">
<a href="#" class="nav-signin">Sign in</a>
<button class="btn-signup">Sign up free</button>
</div>
</nav>
<!-- HERO HEADLINE -->
<section class="hero-text-section">
<div class="hero-text-inner">
<div class="hero-badge">New — Orbit AI Insights →</div>
<h1 class="hero-headline">Analytics that<br /><span class="headline-gradient">actually make sense.</span></h1>
<p class="hero-sub">Orbit turns raw product data into decisions. Real-time dashboards, cohort analysis, and AI-powered recommendations — all in one beautiful interface.</p>
</div>
</section>
<!-- DASHBOARD PREVIEW -->
<section class="dashboard-preview-section">
<div class="dashboard-chrome">
<div class="chrome-bar">
<div class="chrome-dots">
<span style="background:#ff5f57"></span>
<span style="background:#ffbd2e"></span>
<span style="background:#28c840"></span>
</div>
<div class="chrome-url">app.orbitanalytics.io/dashboard</div>
</div>
<div class="dashboard-ui">
<!-- SIDEBAR -->
<aside class="sidebar">
<div class="sidebar-logo">
<svg width="18" height="18" viewBox="0 0 20 20" fill="none">
<circle cx="10" cy="10" r="4" fill="#6366f1"/>
<circle cx="10" cy="10" r="8.5" stroke="#6366f1" stroke-width="1" opacity="0.4"/>
</svg>
<span>Orbit</span>
</div>
<nav class="sidebar-nav">
<a href="#" class="sidebar-item active">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
Dashboard
</a>
<a href="#" class="sidebar-item">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
Analytics
</a>
<a href="#" class="sidebar-item">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
Users
</a>
<a href="#" class="sidebar-item">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
Reports
</a>
<a href="#" class="sidebar-item">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93l-1.41 1.41M6.34 17.66l-1.41 1.41M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M12 2v2M12 20v2"/></svg>
Settings
</a>
</nav>
<div class="sidebar-user">
<div class="sidebar-avatar">SL</div>
<div class="sidebar-user-info">
<span class="sidebar-user-name">Sarah Lee</span>
<span class="sidebar-user-role">Admin</span>
</div>
</div>
</aside>
<!-- MAIN CONTENT -->
<main class="dash-main">
<!-- TOP BAR -->
<div class="dash-topbar">
<div>
<h2 class="dash-greeting">Good morning, Sarah</h2>
<p class="dash-date">Saturday, March 1, 2026</p>
</div>
<div class="topbar-actions">
<button class="btn-dash-action">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
New Report
</button>
<div class="topbar-notif">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
<span class="notif-badge">3</span>
</div>
</div>
</div>
<!-- METRIC CARDS -->
<div class="metric-cards">
<div class="metric-card">
<div class="metric-header">
<span class="metric-label">Monthly Recurring Revenue</span>
<span class="metric-badge up">+12%</span>
</div>
<div class="metric-value">$48,200</div>
<div class="metric-sparkline">
<div class="spark-bars">
<span style="--h:50%"></span><span style="--h:62%"></span><span style="--h:55%"></span>
<span style="--h:70%"></span><span style="--h:65%"></span><span style="--h:78%"></span>
<span style="--h:72%"></span><span style="--h:85%"></span><span style="--h:80%"></span>
<span style="--h:100%" class="spark-active"></span>
</div>
</div>
<span class="metric-sub">vs $43,020 last month</span>
</div>
<div class="metric-card">
<div class="metric-header">
<span class="metric-label">Active Users</span>
<span class="metric-badge up">+8%</span>
</div>
<div class="metric-value">12,840</div>
<div class="metric-sparkline">
<div class="spark-bars">
<span style="--h:60%"></span><span style="--h:58%"></span><span style="--h:65%"></span>
<span style="--h:70%"></span><span style="--h:68%"></span><span style="--h:75%"></span>
<span style="--h:80%"></span><span style="--h:78%"></span><span style="--h:88%"></span>
<span style="--h:100%" class="spark-active"></span>
</div>
</div>
<span class="metric-sub">vs 11,887 last month</span>
</div>
<div class="metric-card">
<div class="metric-header">
<span class="metric-label">Churn Rate</span>
<span class="metric-badge down">-0.4%</span>
</div>
<div class="metric-value">2.1%</div>
<div class="metric-sparkline">
<div class="spark-bars churn">
<span style="--h:80%"></span><span style="--h:72%"></span><span style="--h:78%"></span>
<span style="--h:65%"></span><span style="--h:70%"></span><span style="--h:60%"></span>
<span style="--h:55%"></span><span style="--h:50%"></span><span style="--h:45%"></span>
<span style="--h:38%" class="spark-active"></span>
</div>
</div>
<span class="metric-sub">vs 2.5% last month</span>
</div>
<div class="metric-card">
<div class="metric-header">
<span class="metric-label">Net Promoter Score</span>
<span class="metric-badge up">+5 pts</span>
</div>
<div class="metric-value">72</div>
<div class="metric-sparkline">
<div class="spark-bars">
<span style="--h:55%"></span><span style="--h:52%"></span><span style="--h:60%"></span>
<span style="--h:58%"></span><span style="--h:65%"></span><span style="--h:70%"></span>
<span style="--h:68%"></span><span style="--h:80%"></span><span style="--h:85%"></span>
<span style="--h:100%" class="spark-active"></span>
</div>
</div>
<span class="metric-sub">vs 67 last month</span>
</div>
</div>
<!-- REVENUE CHART -->
<div class="chart-card">
<div class="chart-header">
<div>
<h3 class="chart-title">Revenue Overview</h3>
<span class="chart-sub">12-month trend</span>
</div>
<div class="chart-tabs">
<button class="chart-tab active">MRR</button>
<button class="chart-tab">ARR</button>
<button class="chart-tab">New</button>
</div>
</div>
<div class="chart-wrap">
<svg class="revenue-chart" viewBox="0 0 760 140" preserveAspectRatio="none" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="chartFill" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#6366f1" stop-opacity="0.3"/>
<stop offset="100%" stop-color="#6366f1" stop-opacity="0"/>
</linearGradient>
</defs>
<!-- Grid lines -->
<line x1="0" y1="140" x2="760" y2="140" stroke="#1e293b" stroke-width="1"/>
<line x1="0" y1="105" x2="760" y2="105" stroke="#1e293b" stroke-width="1" stroke-dasharray="4,4"/>
<line x1="0" y1="70" x2="760" y2="70" stroke="#1e293b" stroke-width="1" stroke-dasharray="4,4"/>
<line x1="0" y1="35" x2="760" y2="35" stroke="#1e293b" stroke-width="1" stroke-dasharray="4,4"/>
<line x1="0" y1="5" x2="760" y2="5" stroke="#1e293b" stroke-width="1" stroke-dasharray="4,4"/>
<!-- Fill area -->
<path d="M0,120 C40,118 80,115 120,108 C160,101 200,95 240,88 C280,81 320,82 360,74 C400,66 440,65 480,55 C520,45 560,42 600,35 C640,28 680,22 760,18 L760,140 L0,140 Z" fill="url(#chartFill)"/>
<!-- Line -->
<path d="M0,120 C40,118 80,115 120,108 C160,101 200,95 240,88 C280,81 320,82 360,74 C400,66 440,65 480,55 C520,45 560,42 600,35 C640,28 680,22 760,18" stroke="#6366f1" stroke-width="2" stroke-linecap="round"/>
<!-- Dots -->
<circle cx="0" cy="120" r="3" fill="#6366f1"/>
<circle cx="120" cy="108" r="3" fill="#6366f1"/>
<circle cx="240" cy="88" r="3" fill="#6366f1"/>
<circle cx="360" cy="74" r="3" fill="#6366f1"/>
<circle cx="480" cy="55" r="3" fill="#6366f1"/>
<circle cx="600" cy="35" r="3" fill="#6366f1"/>
<circle cx="760" cy="18" r="4" fill="#6366f1" stroke="#fff" stroke-width="1.5"/>
</svg>
<div class="chart-x-labels">
<span>Mar</span><span>Apr</span><span>May</span><span>Jun</span>
<span>Jul</span><span>Aug</span><span>Sep</span><span>Oct</span>
<span>Nov</span><span>Dec</span><span>Jan</span><span>Feb</span>
</div>
</div>
</div>
<!-- BOTTOM ROW -->
<div class="dash-bottom-row">
<!-- TRANSACTIONS TABLE -->
<div class="transactions-card">
<div class="card-header">
<h3 class="card-title">Recent Transactions</h3>
<a href="#" class="card-link">View all</a>
</div>
<table class="tx-table">
<thead>
<tr>
<th>Customer</th>
<th>Plan</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tx-user">
<div class="tx-avatar" style="--bg:#6366f1">JD</div>
<span>James Dorsey</span>
</td>
<td class="tx-plan">Pro</td>
<td class="tx-amount">$149</td>
<td><span class="status-badge paid">Paid</span></td>
</tr>
<tr>
<td class="tx-user">
<div class="tx-avatar" style="--bg:#0891b2">AK</div>
<span>Anna Kowalski</span>
</td>
<td class="tx-plan">Team</td>
<td class="tx-amount">$499</td>
<td><span class="status-badge paid">Paid</span></td>
</tr>
<tr>
<td class="tx-user">
<div class="tx-avatar" style="--bg:#d97706">RM</div>
<span>Raj Mehta</span>
</td>
<td class="tx-plan">Starter</td>
<td class="tx-amount">$49</td>
<td><span class="status-badge pending">Pending</span></td>
</tr>
<tr>
<td class="tx-user">
<div class="tx-avatar" style="--bg:#059669">LC</div>
<span>Lucie Chen</span>
</td>
<td class="tx-plan">Pro</td>
<td class="tx-amount">$149</td>
<td><span class="status-badge paid">Paid</span></td>
</tr>
<tr>
<td class="tx-user">
<div class="tx-avatar" style="--bg:#db2777">MP</div>
<span>Marco Petit</span>
</td>
<td class="tx-plan">Team</td>
<td class="tx-amount">$499</td>
<td><span class="status-badge failed">Failed</span></td>
</tr>
</tbody>
</table>
</div>
<!-- ACTIVITY FEED -->
<div class="activity-card">
<div class="card-header">
<h3 class="card-title">Activity Feed</h3>
<a href="#" class="card-link">See all</a>
</div>
<div class="activity-list">
<div class="activity-item">
<div class="activity-dot" style="--c:#6366f1"></div>
<div class="activity-content">
<span class="activity-text"><strong>New signup</strong> — james@example.com joined on Pro plan</span>
<span class="activity-time">2 min ago</span>
</div>
</div>
<div class="activity-item">
<div class="activity-dot" style="--c:#f59e0b"></div>
<div class="activity-content">
<span class="activity-text"><strong>Upgrade</strong> — Acme Corp moved from Starter → Team</span>
<span class="activity-time">14 min ago</span>
</div>
</div>
<div class="activity-item">
<div class="activity-dot" style="--c:#10b981"></div>
<div class="activity-content">
<span class="activity-text"><strong>Payment received</strong> — $499 from DataStream Inc.</span>
<span class="activity-time">38 min ago</span>
</div>
</div>
<div class="activity-item">
<div class="activity-dot" style="--c:#ef4444"></div>
<div class="activity-content">
<span class="activity-text"><strong>Churn alert</strong> — marco@petit.io cancelled subscription</span>
<span class="activity-time">1h 12m ago</span>
</div>
</div>
<div class="activity-item">
<div class="activity-dot" style="--c:#6366f1"></div>
<div class="activity-content">
<span class="activity-text"><strong>Report generated</strong> — Q1 Executive Summary ready</span>
<span class="activity-time">2h 05m ago</span>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</section>
<!-- FEATURES -->
<section class="features-section">
<div class="features-header">
<span class="features-eyebrow">Why Orbit</span>
<h2 class="features-title">Everything you need to understand your product</h2>
</div>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon" style="--c:#6366f1">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
</div>
<h3 class="feature-title">Real-Time Analytics</h3>
<p class="feature-desc">Data streams at sub-second latency. Watch your metrics update as events happen, not hours later.</p>
</div>
<div class="feature-card">
<div class="feature-icon" style="--c:#0ea5e9">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/></svg>
</div>
<h3 class="feature-title">Cohort Analysis</h3>
<p class="feature-desc">Understand retention and behavior by user segment. Build cohorts from any event or property combination.</p>
</div>
<div class="feature-card">
<div class="feature-icon" style="--c:#a78bfa">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a10 10 0 1 0 10 10H12V2z"/><path d="M20 2a10 10 0 0 0-8 8h8V2z"/></svg>
</div>
<h3 class="feature-title">AI Insights</h3>
<p class="feature-desc">Our ML engine surfaces anomalies, predicts churn risk, and writes plain-English summaries of your data.</p>
</div>
</div>
</section>
<!-- PRICING -->
<section class="pricing-section">
<div class="pricing-header">
<h2 class="pricing-title">Simple, transparent pricing</h2>
<p class="pricing-sub">Start free. Upgrade when you need more.</p>
</div>
<div class="pricing-grid">
<div class="plan-card">
<div class="plan-header">
<h3 class="plan-name">Starter</h3>
<div class="plan-price"><span class="plan-price-val">$49</span><span class="plan-price-period">/mo</span></div>
</div>
<ul class="plan-features">
<li>Up to 10,000 monthly users</li>
<li>30 days data retention</li>
<li>Core dashboards</li>
<li>Email reports</li>
<li>2 team members</li>
</ul>
<button class="btn-plan outline">Get started</button>
</div>
<div class="plan-card featured">
<div class="plan-badge">Most popular</div>
<div class="plan-header">
<h3 class="plan-name">Pro</h3>
<div class="plan-price"><span class="plan-price-val">$149</span><span class="plan-price-period">/mo</span></div>
</div>
<ul class="plan-features">
<li>Up to 100,000 monthly users</li>
<li>1 year data retention</li>
<li>All dashboards + custom</li>
<li>Cohort & funnel analysis</li>
<li>AI Insights (beta)</li>
<li>Unlimited team members</li>
</ul>
<button class="btn-plan primary">Start free trial</button>
</div>
</div>
</section>
<!-- FOOTER -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-brand">
<span class="footer-logo">
<svg width="18" height="18" viewBox="0 0 20 20" fill="none">
<circle cx="10" cy="10" r="4" fill="#6366f1"/>
<circle cx="10" cy="10" r="8.5" stroke="#6366f1" stroke-width="1" opacity="0.4"/>
</svg>
Orbit
</span>
<p>Built for modern product teams.</p>
</div>
<div class="footer-cols">
<div class="footer-col">
<span class="footer-col-title">Product</span>
<a href="#">Features</a>
<a href="#">Changelog</a>
<a href="#">Roadmap</a>
<a href="#">Status</a>
</div>
<div class="footer-col">
<span class="footer-col-title">Company</span>
<a href="#">About</a>
<a href="#">Blog</a>
<a href="#">Careers</a>
<a href="#">Press</a>
</div>
<div class="footer-col">
<span class="footer-col-title">Support</span>
<a href="#">Docs</a>
<a href="#">Guides</a>
<a href="#">API Reference</a>
<a href="#">Contact</a>
</div>
</div>
</div>
<div class="footer-bottom">
<span>© 2026 Orbit Analytics Inc.</span>
<div class="footer-bottom-links">
<a href="#">Privacy Policy</a>
<a href="#">Terms of Service</a>
<a href="#">Security</a>
</div>
</div>
</footer>
<script type="module" src="script.js"></script>
</body>
</html>Dark SaaS Dashboard Preview
The product IS the hero. A full-screen dark dashboard UI embedded in the landing page — showing real-looking data to instantly communicate product value.
Layout
┌─────────────────────────────────────────────────┐
│ Nav (landing) │
├──────┬──────────────────────────────────────────┤
│ Side │ Metric cards (4) │
│ bar │ Revenue chart (CSS/SVG sparklines) │
│ │ Recent transactions table │
│ │ Activity feed + User summary │
└──────┴──────────────────────────────────────────┘
│ Features section (below the fold) │
│ Pricing table │
│ CTA + Footer │
Dashboard components
- Sidebar — nav items with icons, active state, collapse toggle
- Metric cards — MRR, Users, Churn, NPS with trend arrow + sparkline
- Revenue chart — SVG polyline drawn with GSAP
strokeDashoffset - Transactions table — avatar, name, amount, status badge, date
- Activity feed — timestamped events with type icons
Animations
- Chart line draws in on scroll enter
- Metric numbers count up (GSAP)
- Table rows stagger in
- Sidebar collapse animation