Ticketing — Theater Landing
An elegant theater and arts ticketing landing page for a fictional stage production, built in burgundy, gold, and cream with a refined serif headline treatment. It pairs a cinematic gradient hero and live opening-night countdown with a synopsis, a cast and creative grid, an interactive month-by-month performance calendar showing seat availability, seating tiers with sold-out and low-stock badges, critic quotes, and a booking form that tallies a live total.
MCP
Code
:root {
--burgundy: #6b1f2e;
--burgundy-d: #511620;
--burgundy-l: #8a3344;
--gold: #c8a24b;
--gold-d: #a8842f;
--cream: #f7f1e6;
--cream-2: #efe5d4;
--ink: #211317;
--ink-2: #4a3a3e;
--muted: #8a7a76;
--surface: #ffffff;
--line: rgba(33, 19, 23, 0.12);
--ok: #2f7d4f;
--low: #c08a2a;
--out: #b03a4a;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-sm: 0 2px 8px rgba(33, 19, 23, 0.08);
--sh-md: 0 14px 40px rgba(33, 19, 23, 0.16);
--sh-lg: 0 30px 70px rgba(33, 19, 23, 0.28);
--serif: "Cormorant Garamond", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--sans);
color: var(--ink);
background: var(--cream);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
.wrap { width: min(1140px, 92vw); margin-inline: auto; }
.skip {
position: absolute; left: -999px; top: 0; z-index: 200;
background: var(--burgundy); color: var(--cream);
padding: 10px 16px; border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; }
/* Buttons */
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: 8px; font-family: var(--sans); font-weight: 700;
font-size: 0.94rem; letter-spacing: 0.01em;
padding: 12px 22px; border-radius: var(--r-sm);
border: 1.5px solid transparent; cursor: pointer;
transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.btn--lg { padding: 15px 30px; font-size: 1rem; }
.btn--full { width: 100%; }
.btn--gold { background: var(--gold); color: var(--burgundy-d); box-shadow: var(--sh-sm); }
.btn--gold:hover { background: #d6b25c; transform: translateY(-2px); box-shadow: var(--sh-md); }
.btn--gold:active { transform: translateY(0); }
.btn--ghost { background: transparent; border-color: currentColor; color: var(--cream); }
.btn--ghost:hover { background: rgba(255, 255, 255, 0.1); transform: translateY(-2px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
.kicker {
font-family: var(--sans); text-transform: uppercase;
letter-spacing: 0.18em; font-size: 0.74rem; font-weight: 700;
color: var(--gold-d); margin: 0 0 10px;
}
.kicker--light { color: var(--gold); }
/* Nav */
.nav {
position: sticky; top: 0; z-index: 100;
background: rgba(247, 241, 230, 0.86);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--line);
}
.nav__inner { display: flex; align-items: center; gap: 18px; height: 70px; }
.brand { display: inline-flex; align-items: center; gap: 10px; }
.brand__mark {
width: 38px; height: 38px; display: grid; place-items: center;
background: var(--burgundy); color: var(--gold);
font-family: var(--serif); font-weight: 700; font-size: 1.3rem;
border-radius: var(--r-sm); box-shadow: inset 0 0 0 1px var(--gold);
}
.brand__name {
font-family: var(--serif); font-weight: 700; font-size: 1.32rem;
letter-spacing: 0.01em; color: var(--burgundy);
}
.brand__name span { color: var(--ink-2); font-weight: 500; }
.nav__links { display: flex; gap: 26px; margin-left: auto; }
.nav__links a {
font-size: 0.9rem; font-weight: 500; color: var(--ink-2);
position: relative; padding: 4px 0;
}
.nav__links a::after {
content: ""; position: absolute; left: 0; bottom: -2px;
width: 0; height: 2px; background: var(--gold); transition: width 0.22s ease;
}
.nav__links a:hover { color: var(--burgundy); }
.nav__links a:hover::after { width: 100%; }
.nav__cta { margin-left: 4px; }
.nav__burger {
display: none; flex-direction: column; gap: 5px; margin-left: auto;
background: none; border: 0; cursor: pointer; padding: 8px;
}
.nav__burger span { width: 24px; height: 2px; background: var(--burgundy); transition: 0.25s; }
.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.mobile-nav {
display: none; flex-direction: column; gap: 4px;
padding: 10px 4vw 20px; background: var(--cream);
border-bottom: 1px solid var(--line);
}
.mobile-nav a { padding: 12px 6px; font-weight: 600; color: var(--ink-2); border-bottom: 1px solid var(--line); }
.mobile-nav .btn { margin-top: 10px; }
.mobile-nav.open { display: flex; }
/* Hero */
.hero { position: relative; overflow: hidden; color: var(--cream); isolation: isolate; }
.hero__bg {
position: absolute; inset: 0; z-index: -2;
background:
radial-gradient(120% 90% at 80% 10%, rgba(200, 162, 75, 0.34), transparent 55%),
linear-gradient(160deg, #2a0e16 0%, var(--burgundy-d) 40%, var(--burgundy) 100%);
}
.hero__veil {
position: absolute; inset: 0; z-index: -1;
background:
repeating-linear-gradient(115deg, rgba(255, 255, 255, 0.04) 0 2px, transparent 2px 26px),
radial-gradient(60% 60% at 20% 90%, rgba(0, 0, 0, 0.4), transparent 60%);
}
.hero__inner { padding: 96px 0 88px; max-width: 760px; }
.hero__eyebrow {
text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.76rem;
font-weight: 700; color: var(--gold); margin: 0 0 18px;
}
.hero__title {
font-family: var(--serif); font-weight: 700;
font-size: clamp(3.2rem, 9vw, 6.2rem); line-height: 0.98;
margin: 0 0 18px; letter-spacing: 0.005em;
text-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
}
.hero__sub {
font-size: clamp(1.05rem, 2.4vw, 1.3rem); color: rgba(247, 241, 230, 0.88);
max-width: 560px; margin: 0 0 28px;
}
.hero__meta {
display: flex; flex-wrap: wrap; gap: 14px 30px;
list-style: none; padding: 0; margin: 0 0 32px;
}
.hero__meta li { font-size: 1rem; font-weight: 600; }
.hero__meta span {
display: block; text-transform: uppercase; letter-spacing: 0.14em;
font-size: 0.66rem; font-weight: 700; color: var(--gold); margin-bottom: 4px;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 40px; }
.hero__countdown { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.hero__countdown-label {
text-transform: uppercase; letter-spacing: 0.16em; font-size: 0.72rem;
font-weight: 700; color: var(--gold);
}
.count { display: flex; gap: 10px; }
.count__cell {
background: rgba(0, 0, 0, 0.28); border: 1px solid rgba(200, 162, 75, 0.4);
border-radius: var(--r-sm); padding: 8px 12px; min-width: 60px; text-align: center;
}
.count__num { font-family: var(--serif); font-size: 1.7rem; font-weight: 700; line-height: 1; }
.count__lab { display: block; font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.12em; color: rgba(247,241,230,0.7); margin-top: 4px; }
/* Sections */
.section { padding: 84px 0; }
.section__head { max-width: 640px; margin: 0 0 44px; }
.section__head h2, .synopsis__lead h2 {
font-family: var(--serif); font-weight: 700; color: var(--burgundy);
font-size: clamp(2rem, 4.4vw, 3rem); line-height: 1.05; margin: 0;
}
/* Synopsis */
.synopsis { background: var(--cream-2); }
.synopsis__grid { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 50px; align-items: start; }
.synopsis__lead h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); }
.synopsis__body p { font-size: 1.08rem; color: var(--ink-2); margin: 0 0 18px; }
.synopsis__body em { color: var(--burgundy); font-style: italic; }
.tags { display: flex; flex-wrap: wrap; gap: 10px; list-style: none; padding: 0; margin: 22px 0 0; }
.tags li {
font-size: 0.8rem; font-weight: 600; color: var(--burgundy);
background: var(--surface); border: 1px solid var(--line);
padding: 6px 14px; border-radius: 999px;
}
/* Cast */
.cast__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.person {
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-md); padding: 22px; text-align: center;
box-shadow: var(--sh-sm); transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.person:hover { transform: translateY(-6px); box-shadow: var(--sh-md); }
.person__photo {
width: 96px; height: 96px; margin: 0 auto 16px; border-radius: 50%;
display: grid; place-items: center;
background: linear-gradient(150deg, var(--burgundy-l), var(--burgundy-d));
color: var(--gold); font-family: var(--serif); font-weight: 700; font-size: 1.8rem;
box-shadow: inset 0 0 0 2px var(--gold);
}
.person__photo::after { content: attr(data-initials); }
.person h3 { font-family: var(--serif); font-size: 1.4rem; color: var(--burgundy); margin: 0 0 4px; }
.person p { color: var(--muted); margin: 0; font-size: 0.92rem; }
/* Calendar */
.calendar { background: var(--cream-2); }
.cal {
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-lg); padding: 26px; box-shadow: var(--sh-md);
max-width: 720px;
}
.cal__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
.cal__month { font-family: var(--serif); color: var(--burgundy); font-size: 1.6rem; margin: 0; }
.cal__nav {
width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line);
background: var(--cream); color: var(--burgundy); font-size: 1.1rem; cursor: pointer;
transition: 0.18s;
}
.cal__nav:hover:not(:disabled) { background: var(--burgundy); color: var(--gold); }
.cal__nav:disabled { opacity: 0.35; cursor: not-allowed; }
.cal__dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.cal__dow span { text-align: center; font-size: 0.72rem; font-weight: 700; color: var(--muted); text-transform: uppercase; }
.cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal__cell {
aspect-ratio: 1; border: 1px solid var(--line); border-radius: var(--r-sm);
background: var(--cream); font-weight: 600; font-size: 0.95rem; color: var(--ink-2);
display: flex; flex-direction: column; align-items: center; justify-content: center;
gap: 4px; cursor: pointer; position: relative; transition: 0.16s;
}
.cal__cell.empty { background: transparent; border-color: transparent; cursor: default; }
.cal__cell.none { color: var(--muted); cursor: not-allowed; background: transparent; }
.cal__cell.has:hover { transform: translateY(-2px); border-color: var(--gold); box-shadow: var(--sh-sm); }
.cal__cell.out { cursor: not-allowed; opacity: 0.6; }
.cal__cell.selected { background: var(--burgundy); color: var(--cream); border-color: var(--burgundy); }
.cal__cell .dot { width: 7px; height: 7px; border-radius: 50%; }
.cal__cell.selected .dot { box-shadow: 0 0 0 1.5px var(--cream); }
.dot--ok { background: var(--ok); }
.dot--low { background: var(--low); }
.dot--out { background: var(--out); }
.dot--none { background: var(--muted); }
.cal__legend { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 18px 0 0; font-size: 0.8rem; color: var(--ink-2); }
.cal__legend span { display: inline-flex; align-items: center; gap: 7px; }
.cal__legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.cal__selection {
margin-top: 18px; padding: 16px; border-radius: var(--r-md);
background: var(--cream); border: 1px dashed var(--gold);
}
.cal__selection p { margin: 0; color: var(--ink-2); }
.cal__selection h4 { font-family: var(--serif); color: var(--burgundy); margin: 0 0 8px; font-size: 1.2rem; }
.cal__times { display: flex; flex-wrap: wrap; gap: 8px; }
.cal__time {
border: 1px solid var(--line); background: var(--surface); color: var(--burgundy);
font-weight: 600; padding: 8px 14px; border-radius: var(--r-sm); cursor: pointer; transition: 0.16s;
}
.cal__time:hover { background: var(--gold); color: var(--burgundy-d); border-color: var(--gold); }
/* Pricing */
.pricing__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; align-items: stretch; }
.tier {
position: relative; background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-md); padding: 28px 22px 24px; overflow: hidden;
display: flex; flex-direction: column; box-shadow: var(--sh-sm);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.tier:hover { transform: translateY(-6px); box-shadow: var(--sh-md); }
.tier__band { position: absolute; top: 0; left: 0; right: 0; height: 6px; background: var(--band); }
.tier--feature { border-color: var(--gold); box-shadow: 0 14px 40px rgba(107, 31, 46, 0.22); }
.tier__ribbon {
position: absolute; top: 16px; right: -34px; transform: rotate(45deg);
background: var(--gold); color: var(--burgundy-d); font-size: 0.66rem; font-weight: 800;
text-transform: uppercase; letter-spacing: 0.08em; padding: 5px 40px;
}
.tier h3 { font-family: var(--serif); color: var(--burgundy); font-size: 1.5rem; margin: 8px 0 4px; }
.tier__seats { color: var(--muted); font-size: 0.88rem; margin: 0 0 14px; }
.tier__price { font-family: var(--serif); font-size: 2.4rem; font-weight: 700; color: var(--ink); margin: 0 0 12px; }
.badge {
align-self: flex-start; font-size: 0.74rem; font-weight: 700;
padding: 4px 12px; border-radius: 999px; margin-bottom: 18px;
}
.badge--ok { background: rgba(47, 125, 79, 0.14); color: var(--ok); }
.badge--low { background: rgba(192, 138, 42, 0.16); color: var(--low); }
.badge--out { background: rgba(176, 58, 74, 0.14); color: var(--out); }
.tier button { margin-top: auto; }
/* Reviews */
.reviews { background: var(--burgundy-d); color: var(--cream); }
.reviews .section__head h2 { color: var(--cream); }
.reviews .kicker { color: var(--gold); }
.reviews__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.quote {
background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(200, 162, 75, 0.32);
border-radius: var(--r-md); padding: 28px; margin: 0; transition: 0.2s;
}
.quote:hover { transform: translateY(-5px); border-color: var(--gold); background: rgba(255, 255, 255, 0.08); }
.stars { color: var(--gold); font-size: 1.1rem; letter-spacing: 0.1em; margin-bottom: 14px; }
.quote blockquote { font-family: var(--serif); font-size: 1.4rem; line-height: 1.35; margin: 0 0 16px; }
.quote figcaption { color: var(--gold); font-weight: 600; font-size: 0.9rem; letter-spacing: 0.04em; }
/* Book */
.book { background: var(--cream-2); }
.book__card {
position: relative; background: var(--surface);
border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 48px clamp(24px, 5vw, 56px); box-shadow: var(--sh-md);
max-width: 860px; margin-inline: auto; overflow: hidden;
}
.book__perf { position: absolute; top: 0; left: 0; right: 0; display: flex; justify-content: space-between; padding: 0 24px; transform: translateY(-50%); }
.book__perf span { width: 22px; height: 22px; border-radius: 50%; background: var(--cream-2); }
.book__card .kicker { text-align: center; }
.book__card h2 { font-family: var(--serif); color: var(--burgundy); text-align: center; font-size: clamp(1.7rem, 4vw, 2.6rem); margin: 0 0 12px; }
.book__lead { text-align: center; color: var(--ink-2); margin: 0 auto 30px; max-width: 460px; }
.book__form { display: grid; grid-template-columns: 1.4fr 1fr 0.7fr; gap: 16px; align-items: end; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); }
.field input, .field select {
font-family: var(--sans); font-size: 0.98rem; padding: 12px 14px;
border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--cream);
color: var(--ink); transition: 0.16s;
}
.field input:focus, .field select:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 3px rgba(200, 162, 75, 0.25); }
.field input[readonly] { color: var(--burgundy); font-weight: 600; }
.field--total { grid-column: 1 / -1; flex-direction: row; align-items: baseline; justify-content: flex-end; gap: 12px; border-top: 1px dashed var(--line); padding-top: 18px; }
.field--total span { font-weight: 600; color: var(--muted); }
.field--total strong { font-family: var(--serif); font-size: 2rem; color: var(--burgundy); }
.book__form .btn--full { grid-column: 1 / -1; }
/* Footer */
.footer { background: var(--ink); color: var(--cream); padding: 56px 0 26px; }
.footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: 30px; }
.brand--footer .brand__name { color: var(--cream); }
.brand--footer .brand__name span { color: var(--gold); }
.footer__note { color: rgba(247, 241, 230, 0.6); margin: 14px 0 0; font-size: 0.9rem; }
.footer h4 { color: var(--gold); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.12em; margin: 0 0 14px; }
.footer nav a { display: block; color: rgba(247, 241, 230, 0.78); padding: 5px 0; font-size: 0.92rem; }
.footer nav a:hover { color: var(--gold); }
.footer__base { border-top: 1px solid rgba(255, 255, 255, 0.1); margin-top: 34px; padding-top: 20px; }
.footer__base p { color: rgba(247, 241, 230, 0.5); font-size: 0.84rem; margin: 0; }
/* Toast */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 30px);
background: var(--burgundy); color: var(--cream); font-weight: 600;
padding: 14px 22px; border-radius: var(--r-sm); box-shadow: var(--sh-lg);
border: 1px solid var(--gold); opacity: 0; pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease; z-index: 300; max-width: 90vw;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* Reveal */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.6s ease, transform 0.6s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.reveal { opacity: 1; transform: none; transition: none; }
html { scroll-behavior: auto; }
}
/* Responsive */
@media (max-width: 920px) {
.nav__links, .nav__cta { display: none; }
.nav__burger { display: flex; }
.synopsis__grid { grid-template-columns: 1fr; gap: 26px; }
.cast__grid { grid-template-columns: repeat(2, 1fr); }
.pricing__grid { grid-template-columns: repeat(2, 1fr); }
.reviews__grid { grid-template-columns: 1fr; }
.footer__grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.section { padding: 60px 0; }
.hero__inner { padding: 70px 0 64px; }
.hero__meta { gap: 12px 22px; }
.cast__grid { grid-template-columns: 1fr; }
.pricing__grid { grid-template-columns: 1fr; }
.book__form { grid-template-columns: 1fr; }
.book__card { padding: 36px 22px; }
.footer__grid { grid-template-columns: 1fr; }
.cal { padding: 18px; }
.cal__cell { font-size: 0.82rem; }
.count__cell { min-width: 52px; padding: 6px 9px; }
}(function () {
"use strict";
/* ---------- Toast ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () { toastEl.classList.remove("show"); }, 2600);
}
/* ---------- Mobile nav ---------- */
var burger = document.getElementById("burger");
var mobileNav = document.getElementById("mobileNav");
if (burger && mobileNav) {
burger.addEventListener("click", function () {
var open = mobileNav.classList.toggle("open");
burger.setAttribute("aria-expanded", String(open));
});
mobileNav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
mobileNav.classList.remove("open");
burger.setAttribute("aria-expanded", "false");
});
});
}
/* ---------- Scroll reveal ---------- */
var revealEls = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); }
});
}, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
revealEls.forEach(function (el) { io.observe(el); });
} else {
revealEls.forEach(function (el) { el.classList.add("in"); });
}
/* ---------- Countdown to opening night ---------- */
var openingNight = new Date("2026-09-14T19:30:00");
var countEl = document.getElementById("count");
function pad(n) { return String(n).padStart(2, "0"); }
function renderCountdown() {
if (!countEl) return;
var diff = openingNight - new Date();
if (diff <= 0) {
countEl.innerHTML = '<div class="count__cell"><span class="count__num">Now</span><span class="count__lab">Playing</span></div>';
return;
}
var d = Math.floor(diff / 86400000);
var h = Math.floor((diff % 86400000) / 3600000);
var m = Math.floor((diff % 3600000) / 60000);
var s = Math.floor((diff % 60000) / 1000);
var cells = [[d, "Days"], [pad(h), "Hrs"], [pad(m), "Min"], [pad(s), "Sec"]];
countEl.innerHTML = cells.map(function (c) {
return '<div class="count__cell"><span class="count__num">' + c[0] + '</span><span class="count__lab">' + c[1] + "</span></div>";
}).join("");
}
renderCountdown();
setInterval(renderCountdown, 1000);
/* ---------- Performance calendar ---------- */
// Performances run Sep–Dec 2026. Status keyed by ISO date.
// status: ok | low | out (absence = no performance)
var MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
var TIMES = ["19:30 Evening", "14:30 Matinée"];
// Build a schedule: Tue–Sun evenings, Sat/Sun also matinées, across the run.
var schedule = {};
function isoOf(y, m, d) { return y + "-" + pad(m + 1) + "-" + pad(d); }
(function buildSchedule() {
var start = new Date(2026, 8, 14); // 14 Sep
var end = new Date(2026, 11, 22); // 22 Dec
var seed = 7;
function rng() { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; }
for (var dt = new Date(start); dt <= end; dt.setDate(dt.getDate() + 1)) {
var dow = dt.getDay(); // 0 Sun .. 6 Sat
if (dow === 1) continue; // dark on Mondays
var iso = isoOf(dt.getFullYear(), dt.getMonth(), dt.getDate());
var times = (dow === 6 || dow === 0) ? TIMES.slice() : [TIMES[0]];
var r = rng();
var status = r < 0.16 ? "out" : (r < 0.42 ? "low" : "ok");
schedule[iso] = { status: status, times: times };
}
})();
var viewYear = 2026, viewMonth = 9; // October 2026
var minMonth = { y: 2026, m: 8 }; // September
var maxMonth = { y: 2026, m: 11 }; // December
var selectedIso = null;
var calGrid = document.getElementById("calGrid");
var calMonthEl = document.getElementById("calMonth");
var calPrev = document.getElementById("calPrev");
var calNext = document.getElementById("calNext");
var calSelection = document.getElementById("calSelection");
var bDate = document.getElementById("bDate");
function monthIndex(y, m) { return y * 12 + m; }
function clampNav() {
var cur = monthIndex(viewYear, viewMonth);
calPrev.disabled = cur <= monthIndex(minMonth.y, minMonth.m);
calNext.disabled = cur >= monthIndex(maxMonth.y, maxMonth.m);
}
function statusDot(status) {
var cls = status === "out" ? "dot--out" : status === "low" ? "dot--low" : "dot--ok";
return '<i class="dot ' + cls + '"></i>';
}
function renderCalendar() {
if (!calGrid) return;
calMonthEl.textContent = MONTHS[viewMonth] + " " + viewYear;
calGrid.innerHTML = "";
var first = new Date(viewYear, viewMonth, 1);
var lead = (first.getDay() + 6) % 7; // Monday-first offset
var days = new Date(viewYear, viewMonth + 1, 0).getDate();
for (var i = 0; i < lead; i++) {
var blank = document.createElement("div");
blank.className = "cal__cell empty";
calGrid.appendChild(blank);
}
for (var d = 1; d <= days; d++) {
var iso = isoOf(viewYear, viewMonth, d);
var perf = schedule[iso];
var cell = document.createElement("button");
cell.type = "button";
cell.setAttribute("role", "gridcell");
cell.dataset.iso = iso;
if (!perf) {
cell.className = "cal__cell none";
cell.disabled = true;
cell.innerHTML = "<span>" + d + "</span>";
cell.setAttribute("aria-label", iso + ", no performance");
} else {
cell.className = "cal__cell has " + (perf.status === "out" ? "out" : "");
if (iso === selectedIso) cell.classList.add("selected");
cell.innerHTML = "<span>" + d + "</span>" + statusDot(perf.status);
var label = perf.status === "out" ? "sold out" : perf.status === "low" ? "few seats" : "available";
cell.setAttribute("aria-label", iso + ", " + label);
}
calGrid.appendChild(cell);
}
clampNav();
}
function formatHuman(iso) {
var p = iso.split("-");
var dt = new Date(+p[0], +p[1] - 1, +p[2]);
var dow = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][dt.getDay()];
return dow + " " + (+p[2]) + " " + MONTHS[+p[1] - 1].slice(0, 3) + " " + p[0];
}
function selectDate(iso) {
var perf = schedule[iso];
if (!perf) return;
if (perf.status === "out") { toast("That performance is sold out — try another date."); return; }
selectedIso = iso;
renderCalendar();
var human = formatHuman(iso);
var timesHtml = perf.times.map(function (t) {
return '<button type="button" class="cal__time" data-time="' + t + '">' + t + "</button>";
}).join("");
calSelection.innerHTML =
"<h4>" + human + "</h4>" +
'<p style="margin-bottom:12px">Choose a performance time:</p>' +
'<div class="cal__times">' + timesHtml + "</div>";
calSelection.querySelectorAll(".cal__time").forEach(function (btn) {
btn.addEventListener("click", function () {
var picked = human + " · " + btn.dataset.time;
if (bDate) bDate.value = picked;
updateTotal();
toast("Performance selected: " + btn.dataset.time);
var book = document.getElementById("book");
if (book) book.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
}
if (calGrid) {
calGrid.addEventListener("click", function (e) {
var cell = e.target.closest(".cal__cell.has");
if (cell && cell.dataset.iso) selectDate(cell.dataset.iso);
});
calPrev.addEventListener("click", function () {
var idx = monthIndex(viewYear, viewMonth) - 1;
viewYear = Math.floor(idx / 12); viewMonth = idx % 12; renderCalendar();
});
calNext.addEventListener("click", function () {
var idx = monthIndex(viewYear, viewMonth) + 1;
viewYear = Math.floor(idx / 12); viewMonth = idx % 12; renderCalendar();
});
renderCalendar();
}
/* ---------- Pricing select buttons ---------- */
var bTier = document.getElementById("bTier");
document.querySelectorAll(".tier button[data-tier]").forEach(function (btn) {
if (btn.disabled) return;
btn.addEventListener("click", function () {
var val = btn.dataset.tier + "|" + btn.dataset.price;
if (bTier) {
bTier.value = val;
updateTotal();
}
toast(btn.dataset.tier + " selected — £" + btn.dataset.price + " per seat");
var book = document.getElementById("book");
if (book) book.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
/* ---------- Booking total ---------- */
var bQty = document.getElementById("bQty");
var bTotal = document.getElementById("bTotal");
function updateTotal() {
if (!bTotal) return;
var price = 0;
if (bTier && bTier.value) price = parseInt(bTier.value.split("|")[1], 10) || 0;
var qty = bQty ? Math.max(1, parseInt(bQty.value, 10) || 0) : 0;
bTotal.textContent = "£" + (price * qty).toLocaleString();
}
if (bTier) bTier.addEventListener("change", updateTotal);
if (bQty) bQty.addEventListener("input", updateTotal);
updateTotal();
/* ---------- Booking form ---------- */
var bookForm = document.getElementById("bookForm");
if (bookForm) {
bookForm.addEventListener("submit", function (e) {
e.preventDefault();
if (!bDate || !bDate.value) { toast("Pick a performance from the calendar first."); return; }
if (!bTier || !bTier.value) { toast("Choose a seating tier."); bTier && bTier.focus(); return; }
var qty = parseInt(bQty.value, 10) || 0;
if (qty < 1) { toast("Select at least one seat."); return; }
var tierName = bTier.value.split("|")[0];
toast("Booked " + qty + " × " + tierName + " — held for 15 minutes. Check your email!");
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>The Gilded Hour — Aldridge Theatre</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;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip" href="#book">Skip to booking</a>
<header class="nav" id="top">
<div class="wrap nav__inner">
<a class="brand" href="#top" aria-label="Aldridge Theatre home">
<span class="brand__mark" aria-hidden="true">A</span>
<span class="brand__name">Aldridge<span>Theatre</span></span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#synopsis">Synopsis</a>
<a href="#cast">Cast & Creative</a>
<a href="#calendar">Performances</a>
<a href="#pricing">Tickets</a>
<a href="#reviews">Reviews</a>
</nav>
<a class="btn btn--gold nav__cta" href="#book">Book Now</a>
<button class="nav__burger" id="burger" aria-label="Open menu" aria-expanded="false" aria-controls="mobileNav">
<span></span><span></span><span></span>
</button>
</div>
<nav class="mobile-nav" id="mobileNav" aria-label="Mobile">
<a href="#synopsis">Synopsis</a>
<a href="#cast">Cast & Creative</a>
<a href="#calendar">Performances</a>
<a href="#pricing">Tickets</a>
<a href="#reviews">Reviews</a>
<a class="btn btn--gold" href="#book">Book Now</a>
</nav>
</header>
<main>
<!-- HERO -->
<section class="hero" aria-labelledby="show-title">
<div class="hero__bg" aria-hidden="true"></div>
<div class="hero__veil" aria-hidden="true"></div>
<div class="wrap hero__inner reveal">
<p class="hero__eyebrow">A New Production · Limited Engagement</p>
<h1 class="hero__title" id="show-title">The Gilded Hour</h1>
<p class="hero__sub">A sweeping drama of fortune, betrayal, and the long shadow of a single evening — newly adapted for the Aldridge stage.</p>
<ul class="hero__meta">
<li><span>Run</span>14 Sep – 22 Dec 2026</li>
<li><span>Venue</span>Aldridge Main House</li>
<li><span>Running time</span>2h 40m · one interval</li>
</ul>
<div class="hero__actions">
<a class="btn btn--gold btn--lg" href="#book">Book Tickets</a>
<a class="btn btn--ghost btn--lg" href="#synopsis">Read Synopsis</a>
</div>
<div class="hero__countdown" id="countdown" aria-live="polite">
<span class="hero__countdown-label">Opening night in</span>
<div class="count" id="count"></div>
</div>
</div>
</section>
<!-- SYNOPSIS -->
<section class="section synopsis" id="synopsis" aria-labelledby="syn-h">
<div class="wrap synopsis__grid reveal">
<div class="synopsis__lead">
<p class="kicker">The Story</p>
<h2 id="syn-h">An inheritance that comes due at midnight.</h2>
</div>
<div class="synopsis__body">
<p>On the eve of her father's funeral, Eleanor Vance returns to the crumbling Vance estate to find the family fortune bound to a clause no one will explain. As guests arrive for the reading of the will, old loyalties fracture and a single hour decides three generations.</p>
<p>Adapted by award-winning playwright Mira Solano from the 1924 novel, <em>The Gilded Hour</em> moves with the precision of a clock and the heat of a confession — a production critics are calling the season's most assured revival.</p>
<ul class="tags">
<li>Period Drama</li><li>Ages 12+</li><li>English with surtitles</li>
</ul>
</div>
</div>
</section>
<!-- CAST & CREATIVE -->
<section class="section cast" id="cast" aria-labelledby="cast-h">
<div class="wrap">
<div class="section__head reveal">
<p class="kicker">On Stage & Behind It</p>
<h2 id="cast-h">Cast & Creative</h2>
</div>
<div class="cast__grid">
<article class="person reveal">
<div class="person__photo" data-initials="HC" aria-hidden="true"></div>
<h3>Helena Crane</h3>
<p>Eleanor Vance</p>
</article>
<article class="person reveal">
<div class="person__photo" data-initials="JO" aria-hidden="true"></div>
<h3>Julian Okafor</h3>
<p>Thomas Reed</p>
</article>
<article class="person reveal">
<div class="person__photo" data-initials="MR" aria-hidden="true"></div>
<h3>Margot Rivière</h3>
<p>The Dowager</p>
</article>
<article class="person reveal">
<div class="person__photo" data-initials="DA" aria-hidden="true"></div>
<h3>Desmond Ashe</h3>
<p>The Executor</p>
</article>
<article class="person reveal">
<div class="person__photo" data-initials="MS" aria-hidden="true"></div>
<h3>Mira Solano</h3>
<p>Playwright</p>
</article>
<article class="person reveal">
<div class="person__photo" data-initials="TF" aria-hidden="true"></div>
<h3>Theo Fennimore</h3>
<p>Director</p>
</article>
</div>
</div>
</section>
<!-- CALENDAR / PERFORMANCES -->
<section class="section calendar" id="calendar" aria-labelledby="cal-h">
<div class="wrap">
<div class="section__head reveal">
<p class="kicker">Choose Your Evening</p>
<h2 id="cal-h">Performance Calendar</h2>
</div>
<div class="cal reveal">
<div class="cal__top">
<button class="cal__nav" id="calPrev" aria-label="Previous month">←</button>
<h3 class="cal__month" id="calMonth">October 2026</h3>
<button class="cal__nav" id="calNext" aria-label="Next month">→</button>
</div>
<div class="cal__dow" aria-hidden="true">
<span>Mo</span><span>Tu</span><span>We</span><span>Th</span><span>Fr</span><span>Sa</span><span>Su</span>
</div>
<div class="cal__grid" id="calGrid" role="grid" aria-label="Performance dates"></div>
<div class="cal__legend">
<span><i class="dot dot--ok"></i> Available</span>
<span><i class="dot dot--low"></i> Few seats</span>
<span><i class="dot dot--out"></i> Sold out</span>
<span><i class="dot dot--none"></i> No performance</span>
</div>
<div class="cal__selection" id="calSelection" aria-live="polite">
<p>Select a date to see times.</p>
</div>
</div>
</div>
</section>
<!-- PRICING / SEATING -->
<section class="section pricing" id="pricing" aria-labelledby="price-h">
<div class="wrap">
<div class="section__head reveal">
<p class="kicker">Where You'll Sit</p>
<h2 id="price-h">Seating & Pricing</h2>
</div>
<div class="pricing__grid">
<article class="tier reveal">
<span class="tier__band" style="--band:var(--gold)"></span>
<h3>Premium Stalls</h3>
<p class="tier__seats">Rows A–F · centre</p>
<p class="tier__price">£94</p>
<span class="badge badge--low">Few seats</span>
<button class="btn btn--gold btn--full" data-tier="Premium Stalls" data-price="94">Select</button>
</article>
<article class="tier tier--feature reveal">
<span class="tier__band" style="--band:var(--burgundy)"></span>
<span class="tier__ribbon">Best value</span>
<h3>Dress Circle</h3>
<p class="tier__seats">Front balcony · full view</p>
<p class="tier__price">£68</p>
<span class="badge badge--ok">Available</span>
<button class="btn btn--gold btn--full" data-tier="Dress Circle" data-price="68">Select</button>
</article>
<article class="tier reveal">
<span class="tier__band" style="--band:#7a5d8a"></span>
<h3>Grand Circle</h3>
<p class="tier__seats">Upper tier · side</p>
<p class="tier__price">£42</p>
<span class="badge badge--ok">Available</span>
<button class="btn btn--gold btn--full" data-tier="Grand Circle" data-price="42">Select</button>
</article>
<article class="tier reveal">
<span class="tier__band" style="--band:#9a9a9a"></span>
<h3>Gallery</h3>
<p class="tier__seats">Rear balcony · restricted</p>
<p class="tier__price">£24</p>
<span class="badge badge--out">Sold out</span>
<button class="btn btn--ghost btn--full" data-tier="Gallery" data-price="24" disabled>Sold out</button>
</article>
</div>
</div>
</section>
<!-- REVIEWS -->
<section class="section reviews" id="reviews" aria-labelledby="rev-h">
<div class="wrap">
<div class="section__head reveal">
<p class="kicker">What the Critics Say</p>
<h2 id="rev-h">Reviews & Acclaim</h2>
</div>
<div class="reviews__grid">
<figure class="quote reveal">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>A revival of rare elegance — every silence lands like a verdict.</blockquote>
<figcaption>— The Evening Ledger</figcaption>
</figure>
<figure class="quote reveal">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>Helena Crane is magnetic; you cannot look away from her final hour.</blockquote>
<figcaption>— Stage & Curtain</figcaption>
</figure>
<figure class="quote reveal">
<div class="stars" aria-label="4 out of 5 stars">★★★★☆</div>
<blockquote>Solano's adaptation is taut and luminous — a clockwork of feeling.</blockquote>
<figcaption>— The Northgate Review</figcaption>
</figure>
</div>
</div>
</section>
<!-- BOOK CTA -->
<section class="section book" id="book" aria-labelledby="book-h">
<div class="wrap book__card reveal">
<div class="book__perf" aria-hidden="true">
<span></span><span></span><span></span><span></span><span></span><span></span>
</div>
<p class="kicker kicker--light">Reserve Your Seats</p>
<h2 id="book-h">Secure your evening at The Gilded Hour</h2>
<p class="book__lead">Choose a performance, pick your tier, and we'll hold your seats for 15 minutes.</p>
<form class="book__form" id="bookForm" novalidate>
<div class="field">
<label for="bDate">Performance</label>
<input id="bDate" name="date" placeholder="Select from the calendar" readonly />
</div>
<div class="field">
<label for="bTier">Tier</label>
<select id="bTier" name="tier">
<option value="">Choose a tier…</option>
<option value="Premium Stalls|94">Premium Stalls — £94</option>
<option value="Dress Circle|68">Dress Circle — £68</option>
<option value="Grand Circle|42">Grand Circle — £42</option>
</select>
</div>
<div class="field">
<label for="bQty">Seats</label>
<input id="bQty" name="qty" type="number" min="1" max="8" value="2" />
</div>
<div class="field field--total">
<span>Total</span>
<strong id="bTotal">£0</strong>
</div>
<button class="btn btn--gold btn--lg btn--full" type="submit">Confirm Booking</button>
</form>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap footer__grid">
<div>
<a class="brand brand--footer" href="#top">
<span class="brand__mark" aria-hidden="true">A</span>
<span class="brand__name">Aldridge<span>Theatre</span></span>
</a>
<p class="footer__note">17 Northgate Crescent · Old Town · Open Tue–Sun</p>
</div>
<nav aria-label="Footer">
<h4>Visit</h4>
<a href="#calendar">Performances</a>
<a href="#pricing">Tickets & Pricing</a>
<a href="#cast">Cast & Creative</a>
</nav>
<nav aria-label="More">
<h4>Theatre</h4>
<a href="#synopsis">About the Show</a>
<a href="#reviews">Press & Reviews</a>
<a href="#book">Box Office</a>
</nav>
</div>
<div class="wrap footer__base">
<p>© 2026 Aldridge Theatre. A fictional venue for demonstration.</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Theater Landing
A full marketing landing page for The Gilded Hour, a fictional limited-run stage production at the Aldridge Theatre. The design leans into a classic arts aesthetic — deep burgundy, antique gold, and warm cream, with a Cormorant Garamond serif for headlines against an Inter body. The hero opens on a layered gradient curtain with the show title, run dates, and a live countdown ticking down to opening night, followed by a synopsis, a cast and creative grid, seating tiers, critic quotes, and a closing box-office CTA shaped like a perforated ticket.
The page is genuinely interactive. The performance calendar is generated entirely in vanilla JS: it
spans the September–December run, marks each date as available, few-seats, or sold-out via a colored
dot legend, and lets you page between months. Selecting a date reveals its evening and matinée times;
choosing a time, or picking a seating tier, scrolls you to the booking form and pre-fills it. The
form then computes a live total from tier price and seat count, and a small toast() helper confirms
each action.
Everything is self-contained and responsive down to ~360px, with a hamburger mobile nav, scroll-reveal
animations (disabled under prefers-reduced-motion), semantic landmarks, and keyboard-usable controls.
Illustrative UI only — fictional events, not a real ticketing service.