SaaS — Pricing Page
A conversion-ready SaaS pricing page with a monthly to annual billing toggle that reveals a 20 percent savings, four plan cards including a highlighted most-popular tier, and a per-seat slider that recalculates the Team price live. Includes a scrollable feature-comparison table, an expandable FAQ accordion, a contact-sales band, and a working light and dark theme toggle. Built with semantic, accessible, responsive vanilla HTML, CSS, and JavaScript.
MCP
Code
:root {
--bg: #f7f8fb;
--surface: #ffffff;
--surface-2: #fbfbfe;
--ink: #0f1222;
--muted: #646b85;
--brand: #6366f1;
--brand-d: #4f46e5;
--brand-soft: rgba(99, 102, 241, .1);
--ok: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--line: rgba(15, 18, 34, .1);
--line-strong: rgba(15, 18, 34, .16);
--shadow: 0 1px 2px rgba(15, 18, 34, .06), 0 8px 24px rgba(15, 18, 34, .06);
--shadow-pop: 0 8px 18px rgba(99, 102, 241, .16), 0 24px 48px rgba(99, 102, 241, .14);
--radius: 16px;
--wrap: 1120px;
}
[data-theme="dark"] {
--bg: #0b0d18;
--surface: #14172a;
--surface-2: #181c33;
--ink: #eef0fb;
--muted: #9aa1c0;
--brand: #818cf8;
--brand-d: #6366f1;
--brand-soft: rgba(129, 140, 248, .16);
--line: rgba(255, 255, 255, .1);
--line-strong: rgba(255, 255, 255, .18);
--shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .4);
--shadow-pop: 0 8px 18px rgba(99, 102, 241, .3), 0 24px 48px rgba(0, 0, 0, .5);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
transition: background .25s ease, color .25s ease;
}
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 20px; }
a { color: inherit; }
:focus-visible {
outline: 2px solid var(--brand);
outline-offset: 2px;
border-radius: 6px;
}
/* ---------- Header ---------- */
.site {
position: sticky;
top: 0;
z-index: 20;
background: color-mix(in srgb, var(--bg) 82%, transparent);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--line);
}
.nav { display: flex; align-items: center; gap: 18px; height: 62px; }
.brand {
display: inline-flex; align-items: center; gap: 9px;
font-weight: 800; font-size: 1.05rem; text-decoration: none; letter-spacing: -.02em;
}
.logo {
display: grid; place-items: center;
width: 30px; height: 30px; border-radius: 9px;
background: linear-gradient(135deg, var(--brand), var(--brand-d));
color: #fff;
}
.links { margin-left: auto; display: flex; gap: 22px; }
.links a { text-decoration: none; color: var(--muted); font-weight: 500; font-size: .92rem; }
.links a:hover { color: var(--ink); }
.theme-btn {
width: 38px; height: 38px; border-radius: 10px;
border: 1px solid var(--line); background: var(--surface); color: var(--ink);
cursor: pointer; font-size: 1.05rem; display: grid; place-items: center;
transition: border-color .2s, transform .2s;
}
.theme-btn:hover { border-color: var(--brand); transform: translateY(-1px); }
/* ---------- Hero ---------- */
.hero { text-align: center; padding: 56px 0 8px; }
.eyebrow {
margin: 0 0 8px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
font-size: .72rem; color: var(--brand);
}
.hero h1 {
margin: 0 0 12px; font-size: clamp(1.9rem, 5vw, 2.9rem);
letter-spacing: -.03em; line-height: 1.1;
}
.lede { margin: 0 auto; max-width: 540px; color: var(--muted); font-size: 1.05rem; }
.billing {
margin-top: 26px; display: inline-flex; align-items: center; gap: 12px;
flex-wrap: wrap; justify-content: center;
}
.bill-label { font-weight: 600; color: var(--muted); transition: color .2s; }
.bill-label.active { color: var(--ink); }
.switch {
position: relative; width: 52px; height: 30px; border-radius: 999px;
border: 1px solid var(--line-strong); background: var(--surface);
cursor: pointer; padding: 0; transition: background .2s, border-color .2s;
}
.switch[aria-checked="true"] { background: var(--brand); border-color: var(--brand); }
.knob {
position: absolute; top: 3px; left: 3px; width: 22px; height: 22px;
border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .25);
transition: transform .22s cubic-bezier(.4, 0, .2, 1);
}
.switch[aria-checked="true"] .knob { transform: translateX(22px); }
.save-badge {
font-size: .76rem; font-weight: 700; color: var(--ok);
background: color-mix(in srgb, var(--ok) 14%, transparent);
padding: 4px 9px; border-radius: 999px;
opacity: 0; transform: scale(.9); transition: opacity .2s, transform .2s;
}
.save-badge.show { opacity: 1; transform: scale(1); }
/* ---------- Plans ---------- */
.plans {
display: grid; gap: 18px; margin: 40px 0 64px;
grid-template-columns: repeat(4, 1fr);
align-items: start;
}
.plan {
position: relative; background: var(--surface);
border: 1px solid var(--line); border-radius: var(--radius);
padding: 24px 22px; box-shadow: var(--shadow);
transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.plan:hover, .plan:focus-within { transform: translateY(-5px); border-color: var(--line-strong); box-shadow: var(--shadow-pop); }
.plan.popular {
border-color: var(--brand);
box-shadow: var(--shadow-pop);
background: linear-gradient(180deg, var(--brand-soft), var(--surface) 90px);
}
.plan.popular:hover, .plan.popular:focus-within { transform: translateY(-7px); }
.tag {
position: absolute; top: -11px; left: 50%; transform: translateX(-50%);
background: var(--brand); color: #fff; font-size: .72rem; font-weight: 700;
padding: 4px 12px; border-radius: 999px; letter-spacing: .02em; white-space: nowrap;
}
.plan-head h2 { margin: 0 0 4px; font-size: 1.2rem; letter-spacing: -.01em; }
.plan-sub { margin: 0 0 16px; color: var(--muted); font-size: .86rem; min-height: 2.4em; }
.price { margin: 0; display: flex; align-items: baseline; gap: 1px; }
.cur { font-size: 1.2rem; font-weight: 600; color: var(--muted); }
.amount { font-size: 2.4rem; font-weight: 800; letter-spacing: -.03em; }
.amount.custom { font-size: 1.9rem; }
.per { font-size: .9rem; color: var(--muted); margin-left: 4px; }
.price-note { margin: 4px 0 16px; font-size: .8rem; color: var(--muted); min-height: 1.2em; }
.seats {
background: var(--surface-2); border: 1px solid var(--line);
border-radius: 11px; padding: 11px 12px; margin-bottom: 16px;
}
.seats label { font-size: .82rem; color: var(--muted); display: block; margin-bottom: 7px; }
.seats strong { color: var(--ink); }
input[type="range"] {
-webkit-appearance: none; appearance: none; width: 100%; height: 6px;
border-radius: 999px; background: var(--line-strong); cursor: pointer; margin: 0;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none; appearance: none; width: 18px; height: 18px;
border-radius: 50%; background: var(--brand); border: 3px solid var(--surface);
box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
input[type="range"]::-moz-range-thumb {
width: 18px; height: 18px; border-radius: 50%; background: var(--brand);
border: 3px solid var(--surface); box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
.cta {
width: 100%; padding: 11px 14px; border-radius: 10px; font-weight: 700;
font-size: .92rem; cursor: pointer; font-family: inherit;
transition: transform .15s, box-shadow .2s, background .2s, border-color .2s;
}
.cta:active { transform: scale(.98); }
.cta.solid { background: var(--brand); color: #fff; border: 1px solid var(--brand); }
.cta.solid:hover { background: var(--brand-d); box-shadow: 0 6px 16px var(--brand-soft); }
.cta.ghost { background: transparent; color: var(--brand); border: 1px solid var(--line-strong); }
.cta.ghost:hover { border-color: var(--brand); background: var(--brand-soft); }
.cta.lg { width: auto; padding: 13px 26px; font-size: 1rem; }
.features { list-style: none; margin: 18px 0 0; padding: 16px 0 0; border-top: 1px solid var(--line); display: grid; gap: 10px; }
.features li { position: relative; padding-left: 24px; font-size: .9rem; color: var(--ink); }
.features li::before {
content: "✓"; position: absolute; left: 0; top: 0;
color: var(--ok); font-weight: 800; font-size: .9rem;
}
/* ---------- Compare ---------- */
.compare { margin: 0 0 64px; }
.compare h2, .faq h2, .sales h2 { font-size: clamp(1.4rem, 3vw, 1.8rem); letter-spacing: -.02em; margin: 0 0 22px; }
.table-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
table { width: 100%; border-collapse: collapse; min-width: 640px; }
thead th { background: var(--surface-2); font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
th, td { padding: 14px 16px; text-align: center; border-bottom: 1px solid var(--line); font-size: .92rem; }
tbody th[scope="row"], thead th:first-child { text-align: left; font-weight: 600; }
th.hl, td.hl { background: var(--brand-soft); }
tbody tr:last-child th, tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td, tbody tr:hover th { background: color-mix(in srgb, var(--brand) 5%, transparent); }
.yes { color: var(--ok); font-weight: 800; }
.no { color: var(--muted); }
/* ---------- FAQ ---------- */
.faq { margin: 0 0 64px; max-width: 760px; }
.accordion { display: grid; gap: 12px; }
.qa { border: 1px solid var(--line); border-radius: 13px; background: var(--surface); overflow: hidden; transition: border-color .2s; }
.qa:hover { border-color: var(--line-strong); }
.q {
width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 14px;
padding: 16px 18px; background: transparent; border: 0; cursor: pointer;
font-family: inherit; font-weight: 600; font-size: 1rem; color: var(--ink); text-align: left;
}
.chev { transition: transform .25s ease; color: var(--muted); font-size: 1.2rem; }
.q[aria-expanded="true"] .chev { transform: rotate(180deg); color: var(--brand); }
.a { padding: 0 18px 16px; }
.a p { margin: 0; color: var(--muted); font-size: .94rem; }
/* ---------- Sales band ---------- */
.sales { margin: 0 0 70px; }
.sales-inner {
display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
padding: 34px 36px; border-radius: 20px;
background: linear-gradient(120deg, var(--brand-d), var(--brand));
color: #fff; box-shadow: var(--shadow-pop);
}
.sales-inner h2 { color: #fff; margin: 0 0 6px; }
.sales-inner p { margin: 0; color: rgba(255, 255, 255, .88); }
.sales-inner .cta.solid { background: #fff; color: var(--brand-d); border-color: #fff; }
.sales-inner .cta.solid:hover { background: rgba(255, 255, 255, .9); }
/* ---------- Footer ---------- */
.site-foot { border-top: 1px solid var(--line); padding: 24px 0; }
.site-foot p { margin: 0; color: var(--muted); font-size: .85rem; text-align: center; }
/* ---------- Toast ---------- */
.toast {
position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 20px);
background: var(--ink); color: var(--bg);
padding: 12px 18px; border-radius: 11px; font-weight: 600; font-size: .9rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, .25); opacity: 0; pointer-events: none;
transition: opacity .25s, transform .25s; z-index: 50; max-width: 90vw;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Responsive ---------- */
@media (max-width: 980px) {
.plans { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
.links { display: none; }
.plans { grid-template-columns: 1fr; }
.hero { padding-top: 40px; }
.sales-inner { padding: 26px 22px; }
}
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; scroll-behavior: auto; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------- Billing toggle ---------- */
var billToggle = document.getElementById("billToggle");
var saveBadge = document.getElementById("saveBadge");
var labMonthly = document.getElementById("billMonthly");
var labAnnual = document.getElementById("billAnnual");
var isAnnual = false;
function applyBilling() {
billToggle.setAttribute("aria-checked", String(isAnnual));
labMonthly.classList.toggle("active", !isAnnual);
labAnnual.classList.toggle("active", isAnnual);
saveBadge.classList.toggle("show", isAnnual);
// Fixed-price plans (Starter, Business)
document.querySelectorAll(".amount[data-monthly]").forEach(function (el) {
el.textContent = isAnnual ? el.dataset.annual : el.dataset.monthly;
});
renderTeam();
}
billToggle.addEventListener("click", function () {
isAnnual = !isAnnual;
applyBilling();
toast(isAnnual ? "Annual billing — you save 20%" : "Switched to monthly billing");
});
/* ---------- Team seat slider ---------- */
var seatRange = document.getElementById("seatRange");
var seatCount = document.getElementById("seatCount");
var teamPrice = document.getElementById("teamPrice");
var teamNote = document.getElementById("teamSeatNote");
function renderTeam() {
var seats = parseInt(seatRange.value, 10);
var perSeat = isAnnual
? parseInt(teamPrice.dataset.baseAnnual, 10)
: parseInt(teamPrice.dataset.baseMonthly, 10);
var total = seats * perSeat;
seatCount.textContent = seats;
teamPrice.textContent = total;
teamNote.textContent = seats + " seats × $" + perSeat + "/seat" + (isAnnual ? " (annual)" : "");
}
seatRange.addEventListener("input", renderTeam);
/* ---------- Plan CTAs ---------- */
document.querySelectorAll(".cta[data-plan]").forEach(function (btn) {
btn.addEventListener("click", function () {
var plan = btn.dataset.plan;
if (btn.dataset.sales) {
toast("Opening contact form for " + plan + " — our team will reach out.");
document.getElementById("faq").scrollIntoView({ block: "start" });
} else if (plan === "Starter") {
toast("Welcome aboard! Creating your free Starter workspace…");
} else {
var detail = plan === "Team" ? " (" + seatRange.value + " seats)" : "";
toast("Starting your 14-day " + plan + " trial" + detail + " — no card required.");
}
});
});
/* ---------- FAQ accordion ---------- */
document.querySelectorAll(".accordion .q").forEach(function (q) {
q.addEventListener("click", function () {
var panel = document.getElementById(q.getAttribute("aria-controls"));
var open = q.getAttribute("aria-expanded") === "true";
// close all others
document.querySelectorAll(".accordion .q").forEach(function (other) {
if (other !== q) {
other.setAttribute("aria-expanded", "false");
document.getElementById(other.getAttribute("aria-controls")).hidden = true;
}
});
q.setAttribute("aria-expanded", String(!open));
panel.hidden = open;
});
});
/* ---------- Theme toggle ---------- */
var themeToggle = document.getElementById("themeToggle");
function setTheme(dark) {
document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
themeToggle.setAttribute("aria-pressed", String(dark));
themeToggle.querySelector(".theme-ico").textContent = dark ? "☀" : "◐";
}
var prefersDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
setTheme(prefersDark);
themeToggle.addEventListener("click", function () {
setTheme(document.documentElement.getAttribute("data-theme") !== "dark");
});
/* ---------- Init ---------- */
applyBilling();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Northwind — Pricing</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@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header class="site" role="banner">
<div class="wrap nav">
<a class="brand" href="#" aria-label="Northwind home">
<span class="logo" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22"><path d="M4 14 L10 4 L13 10 L20 4 L20 20 L4 20 Z" fill="currentColor"/></svg>
</span>
Northwind
</a>
<nav class="links" aria-label="Primary">
<a href="#plans">Plans</a>
<a href="#compare">Compare</a>
<a href="#faq">FAQ</a>
</nav>
<button id="themeToggle" class="theme-btn" type="button" aria-pressed="false" aria-label="Toggle dark mode">
<span class="theme-ico" aria-hidden="true">◐</span>
</button>
</div>
</header>
<main class="wrap" role="main">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">Pricing</p>
<h1 id="hero-title">Plans that scale with your team</h1>
<p class="lede">Start free, upgrade when you grow. No hidden fees, cancel anytime. Every plan includes our core analytics engine.</p>
<div class="billing" role="group" aria-label="Billing period">
<span class="bill-label" id="billMonthly">Monthly</span>
<button id="billToggle" class="switch" type="button" role="switch" aria-checked="false" aria-labelledby="billMonthly billAnnual">
<span class="knob" aria-hidden="true"></span>
</button>
<span class="bill-label" id="billAnnual">Annual</span>
<span class="save-badge" id="saveBadge">Save 20%</span>
</div>
</section>
<section id="plans" class="plans" aria-label="Pricing plans">
<!-- Starter -->
<article class="plan" tabindex="0">
<header class="plan-head">
<h2>Starter</h2>
<p class="plan-sub">For solo builders and side projects.</p>
</header>
<p class="price">
<span class="cur">$</span><span class="amount" data-monthly="0" data-annual="0">0</span><span class="per">/mo</span>
</p>
<p class="price-note">Free forever</p>
<button class="cta ghost" type="button" data-plan="Starter">Get started</button>
<ul class="features">
<li>1 project</li>
<li>Up to 3 seats</li>
<li>7-day data retention</li>
<li>Community support</li>
</ul>
</article>
<!-- Team (popular) -->
<article class="plan popular" tabindex="0" aria-label="Team plan, most popular">
<span class="tag">Most popular</span>
<header class="plan-head">
<h2>Team</h2>
<p class="plan-sub">For growing teams that ship fast.</p>
</header>
<p class="price">
<span class="cur">$</span><span class="amount" id="teamPrice" data-base-monthly="12" data-base-annual="10">96</span><span class="per">/mo</span>
</p>
<p class="price-note" id="teamSeatNote">8 seats × $12/seat</p>
<div class="seats">
<label for="seatRange">Seats: <strong id="seatCount">8</strong></label>
<input id="seatRange" type="range" min="3" max="50" value="8" step="1" aria-describedby="teamSeatNote" />
</div>
<button class="cta solid" type="button" data-plan="Team">Start free trial</button>
<ul class="features">
<li>Unlimited projects</li>
<li>Per-seat pricing</li>
<li>90-day data retention</li>
<li>Custom dashboards</li>
<li>Priority email support</li>
</ul>
</article>
<!-- Business -->
<article class="plan" tabindex="0">
<header class="plan-head">
<h2>Business</h2>
<p class="plan-sub">Advanced controls and SSO.</p>
</header>
<p class="price">
<span class="cur">$</span><span class="amount" data-monthly="49" data-annual="39">49</span><span class="per">/mo</span>
</p>
<p class="price-note">per seat, billed per workspace</p>
<button class="cta ghost" type="button" data-plan="Business">Start free trial</button>
<ul class="features">
<li>Everything in Team</li>
<li>SSO & SAML</li>
<li>1-year data retention</li>
<li>Audit logs</li>
<li>Role-based access</li>
</ul>
</article>
<!-- Enterprise -->
<article class="plan" tabindex="0">
<header class="plan-head">
<h2>Enterprise</h2>
<p class="plan-sub">For org-wide deployments.</p>
</header>
<p class="price">
<span class="amount custom">Custom</span>
</p>
<p class="price-note">Volume & compliance</p>
<button class="cta ghost" type="button" data-plan="Enterprise" data-sales="true">Contact sales</button>
<ul class="features">
<li>Everything in Business</li>
<li>Dedicated manager</li>
<li>Unlimited retention</li>
<li>99.99% uptime SLA</li>
<li>On-prem option</li>
</ul>
</article>
</section>
<section id="compare" class="compare" aria-labelledby="compare-title">
<h2 id="compare-title">Compare all features</h2>
<div class="table-scroll" tabindex="0" role="region" aria-label="Feature comparison table, scrollable">
<table>
<thead>
<tr>
<th scope="col">Feature</th>
<th scope="col">Starter</th>
<th scope="col" class="hl">Team</th>
<th scope="col">Business</th>
<th scope="col">Enterprise</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">Projects</th><td>1</td><td class="hl">Unlimited</td><td>Unlimited</td><td>Unlimited</td></tr>
<tr><th scope="row">Seats included</th><td>3</td><td class="hl">Per-seat</td><td>Per-seat</td><td>Unlimited</td></tr>
<tr><th scope="row">Data retention</th><td>7 days</td><td class="hl">90 days</td><td>1 year</td><td>Unlimited</td></tr>
<tr><th scope="row">Custom dashboards</th><td><span class="no" aria-label="No">–</span></td><td class="hl"><span class="yes" aria-label="Yes">✓</span></td><td><span class="yes" aria-label="Yes">✓</span></td><td><span class="yes" aria-label="Yes">✓</span></td></tr>
<tr><th scope="row">SSO & SAML</th><td><span class="no" aria-label="No">–</span></td><td class="hl"><span class="no" aria-label="No">–</span></td><td><span class="yes" aria-label="Yes">✓</span></td><td><span class="yes" aria-label="Yes">✓</span></td></tr>
<tr><th scope="row">Audit logs</th><td><span class="no" aria-label="No">–</span></td><td class="hl"><span class="no" aria-label="No">–</span></td><td><span class="yes" aria-label="Yes">✓</span></td><td><span class="yes" aria-label="Yes">✓</span></td></tr>
<tr><th scope="row">Uptime SLA</th><td><span class="no" aria-label="No">–</span></td><td class="hl">99.9%</td><td>99.95%</td><td>99.99%</td></tr>
<tr><th scope="row">Support</th><td>Community</td><td class="hl">Priority email</td><td>Email + chat</td><td>Dedicated</td></tr>
</tbody>
</table>
</div>
</section>
<section id="faq" class="faq" aria-labelledby="faq-title">
<h2 id="faq-title">Frequently asked questions</h2>
<div class="accordion">
<div class="qa">
<button class="q" type="button" aria-expanded="false" aria-controls="a1" id="q1">
Can I change plans later?<span class="chev" aria-hidden="true">⌄</span>
</button>
<div class="a" id="a1" role="region" aria-labelledby="q1" hidden>
<p>Yes. Upgrade or downgrade anytime from your workspace settings. Changes are prorated to the day, so you only pay for what you use.</p>
</div>
</div>
<div class="qa">
<button class="q" type="button" aria-expanded="false" aria-controls="a2" id="q2">
How does annual billing work?<span class="chev" aria-hidden="true">⌄</span>
</button>
<div class="a" id="a2" role="region" aria-labelledby="q2" hidden>
<p>Annual plans are billed once per year and save you 20% versus paying monthly. Prices shown are the equivalent monthly rate.</p>
</div>
</div>
<div class="qa">
<button class="q" type="button" aria-expanded="false" aria-controls="a3" id="q3">
Is there a free trial?<span class="chev" aria-hidden="true">⌄</span>
</button>
<div class="a" id="a3" role="region" aria-labelledby="q3" hidden>
<p>Every paid plan starts with a 14-day free trial — no credit card required. The Starter plan is free forever.</p>
</div>
</div>
<div class="qa">
<button class="q" type="button" aria-expanded="false" aria-controls="a4" id="q4">
What payment methods do you accept?<span class="chev" aria-hidden="true">⌄</span>
</button>
<div class="a" id="a4" role="region" aria-labelledby="q4" hidden>
<p>All major credit cards and, on annual Business and Enterprise plans, invoicing with net-30 terms.</p>
</div>
</div>
</div>
</section>
<section class="sales" aria-labelledby="sales-title">
<div class="sales-inner">
<div>
<h2 id="sales-title">Need a custom plan?</h2>
<p>Talk to our team about volume discounts, security reviews, and procurement.</p>
</div>
<button class="cta solid lg" type="button" data-plan="Enterprise" data-sales="true">Contact sales</button>
</div>
</section>
</main>
<footer class="site-foot" role="contentinfo">
<div class="wrap">
<p>© 2026 Northwind Analytics — illustrative demo. Fictional product & pricing.</p>
</div>
</footer>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Pricing Page
A clean, trustworthy pricing page for a fictional analytics product. Four plan cards — Starter, Team, Business, and Enterprise — sit on neutral surfaces with a single indigo accent, and the Team plan is highlighted as the most popular tier with a soft gradient and badge. A hero billing switch flips every price between monthly and annual rates and reveals a “Save 20%” badge when annual is active.
The Team card embeds a seat slider: dragging it from 3 to 50 seats recalculates the displayed price live and updates the per-seat note. Below the cards, a horizontally scrollable feature-comparison table contrasts all four plans with checkmarks and per-tier values, and the popular column stays visually emphasized. An FAQ accordion expands one answer at a time, and a gradient contact-sales band closes the page.
Every interaction is wired in vanilla JavaScript: the billing toggle, seat slider, plan CTAs (each fires a contextual toast), the accordion, and a light/dark theme toggle that respects the system preference. Controls are keyboard-usable with visible focus rings and proper ARIA roles, and the layout collapses from four columns to two to one down to roughly 360px.
Illustrative SaaS UI only — fictional product, metrics, and billing. No real backend.