Museum — Membership / Patron Tiers
A refined membership and patronage page for a fictional art museum, presenting four levels of support — Individual, Dual, Patron, and Benefactor — as gallery-cool cards over generous wall space. Each tier carries a price, a curated benefits list, and its own join button, with the Patron level marked as the most chosen. A monthly/annual toggle smoothly re-prices every card and updates the billing line, selecting a tier marks the card and raises a toast, and a quiet statistics band grounds the philanthropic tone.
MCP
Code
:root {
--paper: #f6f4ef;
--wall: #ffffff;
--charcoal: #1c1b19;
--ink: #2a2825;
--ink-2: #4a4640;
--muted: #8c857a;
--gold: #a98140;
--gold-d: #876631;
--gold-50: #f3ecdd;
--line: rgba(28, 27, 25, 0.12);
--line-2: rgba(28, 27, 25, 0.2);
--ok: #3f7d56;
--warn: #b8842c;
--danger: #b4493a;
--r-sm: 6px;
--r-md: 12px;
--r-lg: 18px;
--shadow-sm: 0 1px 2px rgba(28, 27, 25, 0.05);
--shadow-md: 0 10px 30px -12px rgba(28, 27, 25, 0.18);
--shadow-lg: 0 24px 60px -24px rgba(28, 27, 25, 0.28);
--serif: "Cormorant Garamond", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
* {
box-sizing: border-box;
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
margin: 0;
background: var(--paper);
color: var(--ink);
font-family: var(--sans);
line-height: 1.55;
font-size: 16px;
}
.wrap {
width: min(1140px, 100% - 48px);
margin-inline: auto;
}
a {
color: inherit;
}
.skip-link {
position: absolute;
left: -999px;
top: 0;
background: var(--charcoal);
color: var(--wall);
padding: 10px 16px;
border-radius: 0 0 var(--r-sm) 0;
z-index: 50;
}
.skip-link:focus {
left: 0;
}
:focus-visible {
outline: 2px solid var(--gold);
outline-offset: 2px;
}
/* Masthead */
.masthead {
background: var(--wall);
border-bottom: 1px solid var(--line);
}
.masthead-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 18px 0;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand-mark {
color: var(--gold-d);
display: inline-flex;
}
.brand-text {
display: flex;
flex-direction: column;
line-height: 1.05;
}
.brand-name {
font-family: var(--serif);
font-weight: 700;
font-size: 1.5rem;
letter-spacing: 0.01em;
}
.brand-sub {
font-size: 0.66rem;
text-transform: uppercase;
letter-spacing: 0.22em;
color: var(--muted);
}
.masthead-nav {
display: flex;
gap: 28px;
}
.masthead-nav a {
text-decoration: none;
font-size: 0.82rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ink-2);
padding-bottom: 2px;
border-bottom: 1px solid transparent;
transition: color 0.18s ease, border-color 0.18s ease;
}
.masthead-nav a:hover,
.masthead-nav a[aria-current="page"] {
color: var(--charcoal);
border-color: var(--gold);
}
/* Hero */
.hero {
padding: 72px 0 40px;
text-align: center;
}
.eyebrow {
margin: 0 0 14px;
text-transform: uppercase;
letter-spacing: 0.28em;
font-size: 0.72rem;
color: var(--gold-d);
font-weight: 600;
}
.hero-title {
font-family: var(--serif);
font-weight: 600;
font-size: clamp(2.5rem, 6vw, 4rem);
line-height: 1.05;
margin: 0 0 22px;
color: var(--charcoal);
}
.hero-lede {
max-width: 56ch;
margin: 0 auto 34px;
color: var(--ink-2);
font-size: 1.05rem;
}
.hero-lede em {
font-family: var(--serif);
font-style: italic;
font-size: 1.1em;
color: var(--ink);
}
/* Billing cycle toggle */
.cycle {
display: inline-flex;
background: var(--wall);
border: 1px solid var(--line-2);
border-radius: 999px;
padding: 5px;
box-shadow: var(--shadow-sm);
}
.cycle-btn {
font-family: var(--sans);
font-size: 0.86rem;
font-weight: 500;
letter-spacing: 0.02em;
color: var(--ink-2);
background: transparent;
border: 0;
border-radius: 999px;
padding: 9px 22px;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 8px;
transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}
.cycle-btn:hover {
color: var(--charcoal);
}
.cycle-btn.is-active {
background: var(--charcoal);
color: var(--wall);
box-shadow: var(--shadow-sm);
}
.cycle-save {
font-size: 0.64rem;
text-transform: uppercase;
letter-spacing: 0.1em;
background: var(--gold-50);
color: var(--gold-d);
padding: 2px 8px;
border-radius: 999px;
font-weight: 600;
}
.cycle-btn.is-active .cycle-save {
background: var(--gold);
color: #fff;
}
/* Tiers */
.tiers {
padding: 24px 0 64px;
}
.tier-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
align-items: stretch;
}
.tier {
position: relative;
background: var(--wall);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 30px 26px 28px;
display: flex;
flex-direction: column;
box-shadow: var(--shadow-sm);
transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}
.tier:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
border-color: var(--line-2);
}
.tier.is-popular {
border-color: var(--gold);
box-shadow: var(--shadow-md);
background:
linear-gradient(180deg, var(--gold-50) 0%, var(--wall) 120px);
}
.tier.is-popular:hover {
box-shadow: var(--shadow-lg);
}
.popular-badge {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: var(--gold);
color: #fff;
font-size: 0.64rem;
text-transform: uppercase;
letter-spacing: 0.16em;
font-weight: 600;
padding: 5px 14px;
border-radius: 999px;
white-space: nowrap;
box-shadow: var(--shadow-sm);
}
.tier-head {
border-bottom: 1px solid var(--line);
padding-bottom: 18px;
margin-bottom: 18px;
}
.tier-kicker {
margin: 0 0 8px;
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.18em;
color: var(--muted);
font-weight: 600;
}
.tier-name {
font-family: var(--serif);
font-weight: 700;
font-size: 2rem;
line-height: 1;
margin: 0 0 12px;
color: var(--charcoal);
}
.tier-blurb {
margin: 0;
font-size: 0.88rem;
color: var(--ink-2);
min-height: 2.6em;
}
.tier-price {
margin: 0 0 4px;
display: flex;
align-items: baseline;
gap: 8px;
}
.amount {
font-family: var(--serif);
font-weight: 700;
font-size: 2.75rem;
line-height: 1;
color: var(--charcoal);
transition: opacity 0.18s ease;
}
.amount.is-flip {
opacity: 0;
}
.per {
font-size: 0.85rem;
color: var(--muted);
}
.tier-billed {
margin: 0 0 22px;
font-size: 0.74rem;
color: var(--muted);
letter-spacing: 0.02em;
}
.benefits {
list-style: none;
margin: 0 0 26px;
padding: 0;
display: grid;
gap: 11px;
flex: 1;
}
.benefits li {
position: relative;
padding-left: 24px;
font-size: 0.875rem;
color: var(--ink-2);
}
.benefits li::before {
content: "";
position: absolute;
left: 0;
top: 0.45em;
width: 11px;
height: 11px;
border-radius: 50%;
border: 1.5px solid var(--gold);
background:
radial-gradient(circle at center, var(--gold) 0 2px, transparent 2.5px);
}
.benefits li em {
font-family: var(--serif);
font-style: italic;
font-size: 1.08em;
color: var(--ink);
}
.join {
font-family: var(--sans);
font-size: 0.9rem;
font-weight: 600;
letter-spacing: 0.02em;
width: 100%;
padding: 13px 18px;
border-radius: var(--r-md);
border: 1px solid var(--charcoal);
background: transparent;
color: var(--charcoal);
cursor: pointer;
transition: background 0.18s ease, color 0.18s ease, transform 0.12s ease;
}
.join:hover {
background: var(--charcoal);
color: var(--wall);
}
.join:active {
transform: translateY(1px);
}
.tier.is-popular .join {
background: var(--gold);
border-color: var(--gold);
color: #fff;
}
.tier.is-popular .join:hover {
background: var(--gold-d);
border-color: var(--gold-d);
}
.join.is-joined {
background: var(--ok);
border-color: var(--ok);
color: #fff;
}
.tiers-note {
text-align: center;
margin: 40px auto 0;
max-width: 60ch;
font-size: 0.78rem;
color: var(--muted);
}
/* Assurance band */
.assurance {
background: var(--charcoal);
color: var(--paper);
padding: 56px 0;
}
.assurance-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 32px;
text-align: center;
}
.assurance-item {
display: flex;
flex-direction: column;
gap: 10px;
}
.assurance-num {
font-family: var(--serif);
font-weight: 600;
font-size: clamp(2.2rem, 5vw, 3.2rem);
line-height: 1;
color: var(--gold);
}
.assurance-label {
font-size: 0.82rem;
letter-spacing: 0.04em;
color: rgba(246, 244, 239, 0.72);
text-transform: uppercase;
}
/* Footer */
.footer {
background: var(--wall);
border-top: 1px solid var(--line);
padding: 30px 0;
}
.footer-inner {
display: flex;
flex-direction: column;
gap: 6px;
text-align: center;
}
.footer-inner p {
margin: 0;
font-size: 0.8rem;
color: var(--ink-2);
}
.footer-fine {
color: var(--muted) !important;
font-style: italic;
}
/* Toast */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 18px);
background: var(--charcoal);
color: var(--wall);
padding: 13px 20px;
border-radius: var(--r-md);
font-size: 0.86rem;
letter-spacing: 0.01em;
box-shadow: var(--shadow-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.26s ease, transform 0.26s ease;
z-index: 60;
max-width: calc(100% - 40px);
}
.toast.is-show {
opacity: 1;
transform: translate(-50%, 0);
}
.toast::before {
content: "";
display: inline-block;
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--gold);
margin-right: 9px;
vertical-align: middle;
}
/* Responsive */
@media (max-width: 960px) {
.tier-grid {
grid-template-columns: repeat(2, 1fr);
}
.tier.is-popular {
grid-column: span 2;
}
}
@media (max-width: 520px) {
.wrap {
width: min(1140px, 100% - 32px);
}
.masthead-nav {
display: none;
}
.hero {
padding: 48px 0 28px;
}
.tier-grid {
grid-template-columns: 1fr;
gap: 28px;
}
.tier.is-popular {
grid-column: span 1;
order: -1;
}
.assurance-grid {
grid-template-columns: 1fr;
gap: 28px;
}
.cycle-btn {
padding: 9px 16px;
font-size: 0.8rem;
}
}(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);
}
var fmt = new Intl.NumberFormat("en-US");
/* ---- Billing cycle toggle ---- */
var cycleBtns = Array.prototype.slice.call(
document.querySelectorAll(".cycle-btn")
);
var amounts = Array.prototype.slice.call(document.querySelectorAll(".amount"));
var pers = Array.prototype.slice.call(document.querySelectorAll("[data-per]"));
var billeds = Array.prototype.slice.call(
document.querySelectorAll("[data-billed]")
);
var currentCycle = "monthly";
function renderPrices(cycle, animate) {
amounts.forEach(function (el) {
var monthly = Number(el.getAttribute("data-price-monthly"));
var annual = Number(el.getAttribute("data-price-annual"));
var value = cycle === "annual" ? annual : monthly;
var text = "$" + fmt.format(value);
if (animate) {
el.classList.add("is-flip");
window.setTimeout(function () {
el.textContent = text;
el.classList.remove("is-flip");
}, 160);
} else {
el.textContent = text;
}
});
pers.forEach(function (el) {
el.textContent = cycle === "annual" ? "/ year" : "/ month";
});
billeds.forEach(function (el) {
el.textContent =
cycle === "annual"
? "Billed annually — two months on us"
: "Billed monthly";
});
}
function setCycle(cycle) {
if (cycle === currentCycle) return;
currentCycle = cycle;
cycleBtns.forEach(function (btn) {
var active = btn.getAttribute("data-cycle") === cycle;
btn.classList.toggle("is-active", active);
btn.setAttribute("aria-pressed", active ? "true" : "false");
});
renderPrices(cycle, true);
toast(
cycle === "annual"
? "Showing annual pricing — two months free."
: "Showing monthly pricing."
);
}
cycleBtns.forEach(function (btn) {
btn.addEventListener("click", function () {
setCycle(btn.getAttribute("data-cycle"));
});
});
/* ---- Join CTAs ---- */
var joinBtns = Array.prototype.slice.call(
document.querySelectorAll(".join")
);
joinBtns.forEach(function (btn) {
btn.addEventListener("click", function () {
var tier = btn.getAttribute("data-join");
var card = btn.closest(".tier");
var priceEl = card ? card.querySelector(".amount") : null;
var price = priceEl ? priceEl.textContent : "";
var cadence = currentCycle === "annual" ? "year" : "month";
// Reset any previously selected card
joinBtns.forEach(function (other) {
if (other !== btn) {
other.classList.remove("is-joined");
other.textContent = other.getAttribute("data-label-default");
}
});
btn.classList.add("is-joined");
btn.textContent = "Selected ✓";
toast(
tier +
" membership selected — " +
price +
" / " +
cadence +
". Proceed to checkout."
);
});
});
// Cache default labels so we can restore them
joinBtns.forEach(function (btn) {
btn.setAttribute("data-label-default", btn.textContent);
});
/* ---- Init ---- */
renderPrices(currentCycle, false);
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Membership & Patron Tiers — Verrand Museum of Art</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=Cormorant+Garamond:wght@500;600;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#tiers">Skip to membership tiers</a>
<header class="masthead">
<div class="wrap masthead-inner">
<div class="brand">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 40 40" width="40" height="40" role="img" aria-label="Verrand Museum monogram">
<rect x="1" y="1" width="38" height="38" rx="3" fill="none" stroke="currentColor" stroke-width="1.4"/>
<path d="M11 12 L20 28 L29 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="20" cy="9" r="1.6" fill="currentColor"/>
</svg>
</span>
<span class="brand-text">
<span class="brand-name">Verrand</span>
<span class="brand-sub">Museum of Art</span>
</span>
</div>
<nav class="masthead-nav" aria-label="Primary">
<a href="#collection">Collection</a>
<a href="#exhibitions">Exhibitions</a>
<a href="#tiers" aria-current="page">Membership</a>
<a href="#visit">Visit</a>
</nav>
</div>
</header>
<main>
<section class="hero">
<div class="wrap hero-inner">
<p class="eyebrow">Join the Museum</p>
<h1 class="hero-title">Membership & Patron Tiers</h1>
<p class="hero-lede">
Your membership sustains the care of more than 41,000 works in the
Verrand collection — from the <em>Lenten Triptych</em> (c. 1480)
to the contemporary commissions in the West Atrium. Choose a level of
support and step behind the velvet rope.
</p>
<div class="cycle" role="group" aria-label="Billing cycle">
<button type="button" class="cycle-btn is-active" data-cycle="monthly" aria-pressed="true">Monthly</button>
<button type="button" class="cycle-btn" data-cycle="annual" aria-pressed="false">
Annual <span class="cycle-save">Save 2 months</span>
</button>
</div>
</div>
</section>
<section id="tiers" class="tiers" aria-label="Membership levels">
<div class="wrap tier-grid">
<article class="tier" data-tier="individual">
<header class="tier-head">
<p class="tier-kicker">For one</p>
<h2 class="tier-name">Individual</h2>
<p class="tier-blurb">A standing welcome at the door, and the galleries whenever the mood arrives.</p>
</header>
<p class="tier-price">
<span class="amount" data-price-monthly="9" data-price-annual="90">$9</span>
<span class="per" data-per>/ month</span>
</p>
<p class="tier-billed" data-billed>Billed monthly</p>
<ul class="benefits">
<li>Unlimited free admission for one</li>
<li>Members-only morning hours, Saturdays</li>
<li>10% off the Museum Shop & Café</li>
<li>Quarterly print of <em>The Verrand Review</em></li>
</ul>
<button type="button" class="join" data-join="Individual">Become a Member</button>
</article>
<article class="tier" data-tier="dual">
<header class="tier-head">
<p class="tier-kicker">For two</p>
<h2 class="tier-name">Dual</h2>
<p class="tier-blurb">Two names on the card, plus guest passes for the friends you keep meaning to bring.</p>
</header>
<p class="tier-price">
<span class="amount" data-price-monthly="15" data-price-annual="150">$15</span>
<span class="per" data-per>/ month</span>
</p>
<p class="tier-billed" data-billed>Billed monthly</p>
<ul class="benefits">
<li>Admission for two named members</li>
<li>Four single-use guest passes annually</li>
<li>Members-only morning hours, Saturdays</li>
<li>15% off the Museum Shop & Café</li>
<li>Priority booking for ticketed exhibitions</li>
</ul>
<button type="button" class="join" data-join="Dual">Become a Member</button>
</article>
<article class="tier is-popular" data-tier="patron">
<span class="popular-badge">Most chosen</span>
<header class="tier-head">
<p class="tier-kicker">For the devoted</p>
<h2 class="tier-name">Patron</h2>
<p class="tier-blurb">A deeper standing — curator talks, the Patron Lounge, and your name in the annual report.</p>
</header>
<p class="tier-price">
<span class="amount" data-price-monthly="45" data-price-annual="450">$45</span>
<span class="per" data-per>/ month</span>
</p>
<p class="tier-billed" data-billed>Billed monthly</p>
<ul class="benefits">
<li>Admission for two, plus dependent children</li>
<li>Access to the Patron Lounge & private cloakroom</li>
<li>Invitations to curator-led previews</li>
<li>Two exhibition catalogues each year</li>
<li>Recognition in the Annual Report of Patrons</li>
<li>20% off the Museum Shop & Café</li>
</ul>
<button type="button" class="join" data-join="Patron">Become a Patron</button>
</article>
<article class="tier" data-tier="benefactor">
<header class="tier-head">
<p class="tier-kicker">For the visionary</p>
<h2 class="tier-name">Benefactor</h2>
<p class="tier-blurb">A philanthropic partnership — behind-the-scenes access and a hand in what the Museum acquires next.</p>
</header>
<p class="tier-price">
<span class="amount" data-price-monthly="200" data-price-annual="2000">$200</span>
<span class="per" data-per>/ month</span>
</p>
<p class="tier-billed" data-billed>Billed monthly</p>
<ul class="benefits">
<li>All Patron benefits, fully transferable</li>
<li>Private after-hours tours for up to eight</li>
<li>Conservation-studio & archive visits</li>
<li>Seat on the Acquisitions Circle</li>
<li>Dedicated patron liaison</li>
<li>Reserved seating at the Spring Benefit Gala</li>
</ul>
<button type="button" class="join" data-join="Benefactor">Become a Benefactor</button>
</article>
</div>
<p class="tiers-note">
Memberships are tax-deductible to the extent allowed by law. The Verrand Museum
of Art is a registered nonprofit cultural institution, EIN 47-0913224.
</p>
</section>
<section class="assurance" aria-label="Why members give">
<div class="wrap assurance-grid">
<div class="assurance-item">
<span class="assurance-num">41,200</span>
<span class="assurance-label">works in the permanent collection</span>
</div>
<div class="assurance-item">
<span class="assurance-num">1907</span>
<span class="assurance-label">year the Museum opened its doors</span>
</div>
<div class="assurance-item">
<span class="assurance-num">12,800</span>
<span class="assurance-label">members & patrons sustaining us today</span>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap footer-inner">
<p>Verrand Museum of Art · 88 Cloister Lane · Open Tuesday–Sunday, 10–5</p>
<p class="footer-fine">Illustrative UI only — demo data; not a real museum system.</p>
</div>
</footer>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Membership / Patron Tiers
A membership page for the fictional Verrand Museum of Art, framed in the calm, curatorial register of a cultural institution. A serif display masthead and a generous hero set the philanthropic tone — your support sustains the care of more than 41,000 works, from the Lenten Triptych (c. 1480) to the West Atrium commissions. Four tier cards follow: Individual, Dual, Patron, and Benefactor, each with a kicker, a price, a curated benefits list with gold ring markers, and its own join button. The Patron card is lifted as the Most chosen level with a gold ribbon and a warm gradient wash.
The page is genuinely interactive. A pill-shaped monthly/annual toggle re-prices
every card at once — amounts flip with a brief fade, the / month cadence becomes
/ year, and the billing line updates to note the two free months. Choosing a level
marks that card’s button as selected, restores any previously chosen card, and raises
a small toast summarizing the tier, price, and cadence. A charcoal statistics band and
a tax-deductibility note round out the layout.
Everything is vanilla HTML, CSS, and JavaScript with no dependencies. The grid reflows
from four columns to two and then to a single stack with the popular tier floated to the
top, navigation collapses, and focus styles, a skip link, and aria-pressed toggles keep
it keyboard- and screen-reader-friendly down to 360px.
Illustrative UI only — demo data; not a real museum system.