Pricing — Single-plan / one-price layout
A centered single-plan pricing hero for a fictional SaaS, Northwind. One bold seat price with a monthly/yearly toggle that animates the figure and reveals the annual total, an Everything included ribbon, two columns of feature checkmarks, a 30-day money-back guarantee line, and one prominent gradient call-to-action. A four-item FAQ accordion sits below with keyboard and Escape support. Pure HTML, CSS, and vanilla JS, responsive to 360px.
MCP
Code
:root {
--brand: #5b5bf0;
--brand-d: #4646d6;
--brand-700: #3a3ab8;
--brand-50: #eef0ff;
--accent: #00b4a6;
--accent-soft: #d8f5f2;
--ink: #101322;
--ink-2: #3a4060;
--muted: #6c7393;
--bg: #f6f7fb;
--white: #ffffff;
--surface: #ffffff;
--line: rgba(16, 19, 34, 0.1);
--line-2: rgba(16, 19, 34, 0.16);
--ok: #2f9e6f;
--warn: #d98a2b;
--danger: #d4503e;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-1: 0 1px 2px rgba(16, 19, 34, 0.08);
--sh-2: 0 8px 24px rgba(16, 19, 34, 0.08);
--sh-3: 0 24px 60px rgba(16, 19, 34, 0.14);
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(1200px 420px at 50% -120px, var(--brand-50), transparent 70%),
var(--bg);
min-height: 100vh;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.page {
max-width: 720px;
margin: 0 auto;
padding: 56px 20px 80px;
}
/* ---------- Header ---------- */
.page__head {
text-align: center;
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
margin-bottom: 28px;
}
.brand__mark {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 11px;
color: var(--brand);
background: var(--white);
box-shadow: var(--sh-1);
}
.brand__name {
font-weight: 800;
font-size: 1.15rem;
letter-spacing: -0.01em;
}
.page__eyebrow {
margin: 0 0 10px;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--brand);
}
.page__title {
margin: 0 0 12px;
font-size: clamp(1.7rem, 5vw, 2.5rem);
font-weight: 800;
letter-spacing: -0.025em;
line-height: 1.1;
}
.page__sub {
margin: 0 auto;
max-width: 460px;
color: var(--muted);
font-size: 1.02rem;
}
/* ---------- Plan card ---------- */
.plan {
position: relative;
margin: 40px auto 0;
max-width: 560px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 40px 36px 32px;
box-shadow: var(--sh-3);
text-align: center;
}
.plan__ribbon {
position: absolute;
top: -14px;
left: 50%;
transform: translateX(-50%);
padding: 7px 16px;
border-radius: 999px;
font-size: 0.74rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--white);
background: linear-gradient(135deg, var(--brand), var(--brand-d));
box-shadow: var(--sh-2);
white-space: nowrap;
}
.plan__name {
margin: 6px 0 6px;
font-size: 1.4rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.plan__tag {
margin: 0;
color: var(--muted);
font-size: 0.95rem;
}
.plan__pricing {
margin: 26px 0 22px;
}
.price {
display: inline-flex;
align-items: flex-start;
justify-content: center;
gap: 2px;
color: var(--ink);
}
.price__currency {
margin-top: 8px;
font-size: 1.6rem;
font-weight: 700;
color: var(--ink-2);
}
.price__amount {
font-size: clamp(3rem, 11vw, 4.2rem);
font-weight: 800;
letter-spacing: -0.04em;
line-height: 1;
transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.28s;
}
.price__amount.is-flipping {
transform: translateY(-8px);
opacity: 0;
}
.price__per {
align-self: flex-end;
margin-bottom: 9px;
margin-left: 6px;
font-size: 0.92rem;
font-weight: 500;
color: var(--muted);
}
.billing {
display: inline-flex;
margin-top: 20px;
padding: 4px;
border-radius: 999px;
background: var(--brand-50);
border: 1px solid var(--line);
gap: 2px;
}
.billing__btn {
display: inline-flex;
align-items: center;
gap: 8px;
border: 0;
cursor: pointer;
padding: 8px 16px;
border-radius: 999px;
font: inherit;
font-size: 0.88rem;
font-weight: 600;
color: var(--ink-2);
background: transparent;
transition: background 0.2s, color 0.2s, box-shadow 0.2s;
}
.billing__btn.is-active {
background: var(--white);
color: var(--ink);
box-shadow: var(--sh-1);
}
.billing__save {
font-size: 0.7rem;
font-weight: 700;
padding: 2px 7px;
border-radius: 999px;
color: var(--accent);
background: var(--accent-soft);
}
.plan__yearnote {
margin: 14px 0 0;
font-size: 0.85rem;
color: var(--accent);
font-weight: 600;
}
.plan__lead {
margin: 6px 0 18px;
font-size: 0.95rem;
font-weight: 600;
color: var(--ink-2);
}
/* ---------- Features ---------- */
.features {
list-style: none;
margin: 0 0 28px;
padding: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px 22px;
text-align: left;
}
.feature {
display: flex;
align-items: flex-start;
gap: 10px;
font-size: 0.93rem;
color: var(--ink-2);
}
.feature__check {
flex: none;
display: grid;
place-items: center;
width: 22px;
height: 22px;
border-radius: 50%;
color: var(--accent);
background: var(--accent-soft);
}
/* ---------- CTA ---------- */
.cta {
width: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
border: 0;
cursor: pointer;
padding: 16px 24px;
border-radius: var(--r-md);
font: inherit;
font-size: 1.02rem;
font-weight: 700;
color: var(--white);
background: linear-gradient(135deg, var(--brand), var(--brand-d));
box-shadow: 0 10px 24px rgba(91, 91, 240, 0.32);
transition: transform 0.16s, box-shadow 0.2s, filter 0.2s;
}
.cta svg {
transition: transform 0.2s;
}
.cta:hover {
filter: brightness(1.04);
box-shadow: 0 14px 30px rgba(91, 91, 240, 0.42);
}
.cta:hover svg {
transform: translateX(3px);
}
.cta:active {
transform: translateY(1px) scale(0.995);
box-shadow: 0 6px 16px rgba(91, 91, 240, 0.32);
}
.plan__guarantee {
display: inline-flex;
align-items: center;
gap: 8px;
margin: 18px 0 0;
font-size: 0.86rem;
font-weight: 500;
color: var(--muted);
}
.plan__shield {
display: grid;
place-items: center;
color: var(--ok);
}
/* ---------- FAQ ---------- */
.faq {
margin: 64px auto 0;
max-width: 560px;
}
.faq__title {
margin: 0 0 18px;
text-align: center;
font-size: 1.3rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.accordion {
display: flex;
flex-direction: column;
gap: 10px;
}
.acc {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
box-shadow: var(--sh-1);
overflow: hidden;
transition: border-color 0.2s, box-shadow 0.2s;
}
.acc:hover {
border-color: var(--line-2);
}
.acc__h {
margin: 0;
}
.acc__trigger {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
border: 0;
cursor: pointer;
padding: 17px 20px;
font: inherit;
font-size: 0.98rem;
font-weight: 600;
text-align: left;
color: var(--ink);
background: transparent;
}
.acc__icon {
flex: none;
position: relative;
width: 18px;
height: 18px;
}
.acc__icon::before,
.acc__icon::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 12px;
height: 2px;
border-radius: 2px;
background: var(--brand);
transform: translate(-50%, -50%);
transition: transform 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.acc__icon::after {
transform: translate(-50%, -50%) rotate(90deg);
}
.acc__trigger[aria-expanded="true"] .acc__icon::after {
transform: translate(-50%, -50%) rotate(0deg);
}
.acc__panel {
padding: 0 20px 18px;
color: var(--muted);
font-size: 0.93rem;
}
.acc__panel p {
margin: 0;
}
.acc__panel[hidden] {
display: none;
}
/* ---------- Focus ---------- */
.cta:focus-visible,
.billing__btn:focus-visible,
.acc__trigger:focus-visible {
outline: 3px solid rgba(91, 91, 240, 0.45);
outline-offset: 2px;
}
.acc__trigger:focus-visible {
outline-offset: -3px;
border-radius: var(--r-md);
}
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 24px);
max-width: calc(100% - 32px);
padding: 13px 20px;
border-radius: var(--r-md);
background: var(--ink);
color: var(--white);
font-size: 0.9rem;
font-weight: 600;
box-shadow: var(--sh-3);
opacity: 0;
pointer-events: none;
transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.3s;
z-index: 60;
}
.toast.is-show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ---------- Responsive ---------- */
@media (max-width: 520px) {
.page {
padding: 36px 16px 56px;
}
.plan {
padding: 36px 22px 26px;
}
.features {
grid-template-columns: 1fr;
gap: 11px;
}
.plan__guarantee {
font-size: 0.82rem;
}
.billing__btn {
padding: 8px 13px;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms !important;
}
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
window.clearTimeout(toastTimer);
toastTimer = window.setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2600);
}
/* ---------- Billing toggle ---------- */
var amountEl = document.getElementById("price-amount");
var periodEl = document.getElementById("price-period");
var yearNote = document.getElementById("year-note");
var billingBtns = Array.prototype.slice.call(
document.querySelectorAll(".billing__btn")
);
function setBilling(mode) {
var monthly = amountEl.getAttribute("data-monthly");
var yearly = amountEl.getAttribute("data-yearly");
var next = mode === "yearly" ? yearly : monthly;
// animate the price swap
amountEl.classList.add("is-flipping");
window.setTimeout(function () {
amountEl.textContent = next;
periodEl.textContent = mode === "yearly" ? "per month, billed yearly" : "per month";
amountEl.classList.remove("is-flipping");
}, 180);
if (yearNote) yearNote.hidden = mode !== "yearly";
billingBtns.forEach(function (btn) {
var active = btn.getAttribute("data-billing") === mode;
btn.classList.toggle("is-active", active);
btn.setAttribute("aria-pressed", active ? "true" : "false");
});
}
billingBtns.forEach(function (btn) {
btn.addEventListener("click", function () {
var mode = btn.getAttribute("data-billing");
setBilling(mode);
toast(
mode === "yearly"
? "Yearly billing — you save 20%."
: "Switched to monthly billing."
);
});
});
/* ---------- CTA ---------- */
var cta = document.getElementById("cta-btn");
if (cta) {
cta.addEventListener("click", function () {
toast("Trial started — check your inbox to confirm.");
});
}
/* ---------- FAQ accordion ---------- */
var triggers = Array.prototype.slice.call(
document.querySelectorAll(".acc__trigger")
);
function closeAll(except) {
triggers.forEach(function (trg) {
if (trg === except) return;
var panel = document.getElementById(trg.getAttribute("aria-controls"));
trg.setAttribute("aria-expanded", "false");
if (panel) panel.hidden = true;
});
}
triggers.forEach(function (trigger) {
var panel = document.getElementById(trigger.getAttribute("aria-controls"));
trigger.addEventListener("click", function () {
var open = trigger.getAttribute("aria-expanded") === "true";
if (open) {
trigger.setAttribute("aria-expanded", "false");
if (panel) panel.hidden = true;
} else {
closeAll(trigger);
trigger.setAttribute("aria-expanded", "true");
if (panel) panel.hidden = false;
}
});
});
/* ---------- Esc closes any open FAQ panel ---------- */
document.addEventListener("keydown", function (e) {
if (e.key !== "Escape") return;
var anyOpen = triggers.some(function (t) {
return t.getAttribute("aria-expanded") === "true";
});
if (anyOpen) closeAll(null);
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Northwind — One simple price</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>
<main class="page" role="main">
<header class="page__head">
<div class="brand">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none">
<path
d="M4 14.5 12 4l8 10.5-8 5.5-8-5.5Z"
fill="currentColor"
opacity=".9"
/>
<path d="m4 14.5 8 5.5 8-5.5" stroke="#fff" stroke-width="1.4" />
</svg>
</span>
<span class="brand__name">Northwind</span>
</div>
<p class="page__eyebrow">Pricing</p>
<h1 class="page__title">One plan. Everything included.</h1>
<p class="page__sub">
No tiers to compare, no feature gates, no surprise add-ons. Pay once
per seat and unlock the entire platform.
</p>
</header>
<section class="plan" aria-labelledby="plan-title">
<span class="plan__ribbon" aria-hidden="true">Everything included</span>
<div class="plan__top">
<h2 class="plan__name" id="plan-title">Northwind Complete</h2>
<p class="plan__tag">For teams who hate spreadsheets of features.</p>
</div>
<div class="plan__pricing">
<div class="price" aria-live="polite">
<span class="price__currency">$</span>
<span class="price__amount" id="price-amount" data-monthly="29" data-yearly="23">29</span>
<span class="price__per">/ seat <span id="price-period">per month</span></span>
</div>
<div
class="billing"
role="group"
aria-label="Choose billing period"
>
<button
type="button"
class="billing__btn is-active"
data-billing="monthly"
aria-pressed="true"
>
Monthly
</button>
<button
type="button"
class="billing__btn"
data-billing="yearly"
aria-pressed="false"
>
Yearly
<span class="billing__save">Save 20%</span>
</button>
</div>
<p class="plan__yearnote" id="year-note" hidden>
Billed as $276 / seat once a year.
</p>
</div>
<p class="plan__lead">Everything in Northwind, for every member of your team:</p>
<ul class="features" aria-label="Included features">
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Unlimited projects & boards
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Unlimited guests & viewers
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Advanced automations
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
100 GB storage per seat
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
SSO & SCIM provisioning
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Audit log & data residency
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Full REST & webhooks API
</li>
<li class="feature">
<span class="feature__check" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="m5 10.5 3.2 3.2L15 7" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
Priority support, 4h response
</li>
</ul>
<button type="button" class="cta" id="cta-btn">
Start free 14-day trial
<svg viewBox="0 0 20 20" width="18" height="18" aria-hidden="true"><path d="M4 10h11m-4-4 4 4-4 4" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</button>
<p class="plan__guarantee">
<span class="plan__shield" aria-hidden="true">
<svg viewBox="0 0 20 20" width="16" height="16"><path d="M10 2.5 4 5v4.5C4 13.5 6.6 16.4 10 17.5 13.4 16.4 16 13.5 16 9.5V5l-6-2.5Z" fill="none" stroke="currentColor" stroke-width="1.4"/><path d="m7.4 9.8 1.8 1.8 3.4-3.6" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
30-day money-back guarantee. No card required to start.
</p>
</section>
<section class="faq" aria-labelledby="faq-title">
<h2 class="faq__title" id="faq-title">Frequently asked questions</h2>
<div class="accordion">
<div class="acc">
<h3 class="acc__h">
<button
type="button"
class="acc__trigger"
id="acc-1"
aria-expanded="false"
aria-controls="acc-1-panel"
>
<span>Is it really one price for everything?</span>
<span class="acc__icon" aria-hidden="true"></span>
</button>
</h3>
<div
class="acc__panel"
id="acc-1-panel"
role="region"
aria-labelledby="acc-1"
hidden
>
<p>
Yes. Every Northwind feature — automations, SSO, the API, audit
logs — is on every seat. We never split features across plans, so
you never have to "upgrade to unlock."
</p>
</div>
</div>
<div class="acc">
<h3 class="acc__h">
<button
type="button"
class="acc__trigger"
id="acc-2"
aria-expanded="false"
aria-controls="acc-2-panel"
>
<span>How does seat-based billing work?</span>
<span class="acc__icon" aria-hidden="true"></span>
</button>
</h3>
<div
class="acc__panel"
id="acc-2-panel"
role="region"
aria-labelledby="acc-2"
hidden
>
<p>
You're billed only for active members. Add a teammate and we
prorate the cost; remove one and the credit rolls to your next
invoice automatically.
</p>
</div>
</div>
<div class="acc">
<h3 class="acc__h">
<button
type="button"
class="acc__trigger"
id="acc-3"
aria-expanded="false"
aria-controls="acc-3-panel"
>
<span>Can I switch between monthly and yearly?</span>
<span class="acc__icon" aria-hidden="true"></span>
</button>
</h3>
<div
class="acc__panel"
id="acc-3-panel"
role="region"
aria-labelledby="acc-3"
hidden
>
<p>
Anytime, from Billing settings. Switching to yearly applies the
20% discount immediately and credits any unused monthly time.
</p>
</div>
</div>
<div class="acc">
<h3 class="acc__h">
<button
type="button"
class="acc__trigger"
id="acc-4"
aria-expanded="false"
aria-controls="acc-4-panel"
>
<span>What happens after the trial ends?</span>
<span class="acc__icon" aria-hidden="true"></span>
</button>
</h3>
<div
class="acc__panel"
id="acc-4-panel"
role="region"
aria-labelledby="acc-4"
hidden
>
<p>
Nothing automatic. We'll email you before day 14 — if you don't
add a card, your workspace simply pauses in read-only mode until
you decide.
</p>
</div>
</div>
</div>
</section>
</main>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Single-plan / one-price layout
A focused, no-comparison pricing page for the fictional SaaS Northwind. Instead of three columns of tiers, it presents a single hero card — an “Everything included” ribbon, a large seat price, two columns of feature checkmarks, a money-back guarantee line, and one prominent call-to-action. The design uses the neutral product-UI palette with a soft brand radial glow and Inter throughout.
A pill toggle switches between Monthly ($29) and Yearly ($23/mo, save 20%) billing. The
price figure animates a quick vertical flip on change, the per-period label updates, and a small
note revealing the annual total ($276/seat) fades in for yearly. The primary CTA and each billing
switch fire a small toast() confirmation.
Below the card sits a four-item FAQ accordion. Each trigger toggles aria-expanded and the hidden
state of its associated region (a one-open-at-a-time pattern), the plus/minus icon animates, and
Esc collapses any open panel. Everything is keyboard-usable with visible focus rings, contrast
meets WCAG AA, and the layout collapses the feature grid to a single column under 520px.