/*
Theme Name: Proscenium
Theme URI: http://107.150.41.186:8133/
Author: Studio build
Description: A season book for a lyric theatre. Built around the printed playbill rather than the landing page: a velvet curtain that actually rises, a repertoire rail you scrub through, a programme spread with a real cast list, a seat map you can hover, and 128 years of archive as a ledger. For opera houses, ballet companies, symphony halls and festival venues.
Version: 1.0
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: proscenium
Tags: opera, theatre, performing-arts, events, custom-colors, custom-menu, featured-images
*/

/* =====================================================================
   PROSCENIUM
   ---------------------------------------------------------------------
   The visual language is a printed playbill from a house that has been
   open since 1897: Didone display type with the extreme thick/thin
   contrast of a 19th-century theatre bill, condensed caps for the cast
   list, oxblood velvet and tarnished gilt, ivory paper stock.

   Two rules keep it from drifting into the generic dark-hero template:
   the page is a *book* (recto/verso spreads, a ledger index, a rail of
   posters) and gold is the only accent — everything else is velvet,
   ink, or paper.
   ===================================================================== */

/* ---------- Tokens ---------- */
:root {
	/* Surfaces: the auditorium in darkness, lifting toward the stage */
	--night:    #140a0b;
	--velvet:   #2b0d13;
	--velvet-2: #3a1119;
	--velvet-3: #4a1720;

	/* Paper: the playbill itself */
	--paper:    #f2ead9;
	--paper-2:  #e4d6ba;
	--paper-3:  #d3c09c;

	/* The one accent. Tarnished leaf, not chrome yellow. */
	--gilt:     #c9a227;
	--gilt-2:   #e8c86a;
	--gilt-dim: #8c6f1a;

	/* Ink hierarchy on dark, then on paper */
	--on-dark:    #f4ecdc;
	--on-dark-2:  rgba(244,236,220,0.66);
	--on-dark-3:  rgba(244,236,220,0.40);
	--ink:        #191410;
	--ink-2:      rgba(25,20,16,0.70);
	--ink-3:      rgba(25,20,16,0.46);

	/* Hairlines are always translucent over the ground, never flat grey */
	--line:        rgba(244,236,220,0.14);
	--line-strong: rgba(244,236,220,0.28);
	--line-ink:    rgba(25,20,16,0.18);
	--line-gilt:   rgba(201,162,39,0.42);

	/* Type */
	--ff-disp: "Bodoni Moda", "Didot", "Bodoni MT", Georgia, serif;
	--ff-body: "Spectral", Georgia, "Times New Roman", serif;
	--ff-bill: "Barlow Condensed", "Oswald", "Arial Narrow", sans-serif;

	/* A Didone needs room; the scale is wide and the steps are large. */
	--t-xs:  0.72rem;
	--t-sm:  0.84rem;
	--t-md:  1.0rem;
	--t-lg:  clamp(1.18rem, 1.6vw, 1.45rem);
	--t-xl:  clamp(1.7rem, 3vw, 2.6rem);
	--t-2xl: clamp(2.6rem, 6vw, 5.2rem);
	--t-3xl: clamp(3.4rem, 10vw, 9rem);

	--gap:   clamp(20px, 3.2vw, 46px);
	--wrap:  1380px;
	--wrap-narrow: 820px;

	--ease:  cubic-bezier(0.32, 0.08, 0.24, 1);
	--slow:  cubic-bezier(0.19, 1, 0.22, 1);
	--fast:  260ms;
	--dur:   760ms;
}

/* ---------- Reset-ish ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Lenis drives scrolling; native smooth scroll fights it and shows as jitter. */
html.lenis { scroll-behavior: auto; }

body {
	margin: 0;
	background: var(--night);
	color: var(--on-dark);
	font-family: var(--ff-body);
	font-size: 1.02rem;
	line-height: 1.68;
	font-weight: 300;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

img, svg, video, canvas { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

h1, h2, h3, h4 {
	font-family: var(--ff-disp);
	font-weight: 500;
	line-height: 1.02;
	margin: 0;
	letter-spacing: -0.012em;
	text-wrap: balance;
}
h1 { font-size: var(--t-3xl); }
h2 { font-size: var(--t-2xl); }
h3 { font-size: var(--t-xl); }
p  { margin: 0 0 1.15em; }

::selection { background: var(--gilt); color: var(--night); }

:focus-visible {
	outline: 2px solid var(--gilt-2);
	outline-offset: 3px;
}

/* ---------- Layout primitives ---------- */
.wrap { width: min(100% - var(--gap) * 2, var(--wrap)); margin-inline: auto; }
.wrap--narrow { width: min(100% - var(--gap) * 2, var(--wrap-narrow)); margin-inline: auto; }

/* Sections deliberately do NOT paint an opaque background — body carries
   the ground, so the fixed ambient layer reads through the whole scroll.
   (Slipstream shipped with every band opaque and the ambient layer was
   invisible for it; not repeating that.) */
.act { padding-block: clamp(84px, 11vw, 168px); position: relative; }
.act--paper { background: var(--paper); color: var(--ink); }
.act--tight { padding-block: clamp(52px, 6vw, 88px); }

/* ---------- Playbill typographic devices ---------- */

/* The rule-and-caps label that heads every section of a printed bill. */
.bill {
	font-family: var(--ff-bill);
	font-size: var(--t-sm);
	font-weight: 500;
	letter-spacing: 0.34em;
	text-transform: uppercase;
	color: var(--gilt);
	display: inline-flex;
	align-items: center;
	gap: 14px;
}
.bill::before {
	content: "";
	width: clamp(28px, 5vw, 68px);
	height: 1px;
	background: var(--line-gilt);
}
.act--paper .bill { color: var(--gilt-dim); }
.act--paper .bill::before { background: rgba(140,111,26,0.5); }

/* Small-caps data pairs — running time, language, act count. */
.datum {
	font-family: var(--ff-bill);
	text-transform: uppercase;
	letter-spacing: 0.16em;
	font-size: var(--t-xs);
	color: var(--on-dark-3);
	display: flex;
	gap: 8px;
	align-items: baseline;
}
.datum b { font-weight: 600; color: var(--on-dark); letter-spacing: 0.1em; }
.act--paper .datum { color: var(--ink-3); }
.act--paper .datum b { color: var(--ink); }

/* An ornament rule — the printer's flourish between sections. */
.ornament {
	display: flex; align-items: center; gap: 18px;
	color: var(--gilt);
	margin-block: clamp(30px, 4vw, 54px);
}
.ornament::before, .ornament::after {
	content: ""; height: 1px; flex: 1; background: var(--line-gilt);
}
.ornament span { font-family: var(--ff-disp); font-size: 1.1rem; letter-spacing: 0.4em; }

/* Drop-cap opening, straight off a programme note. */
.lede-drop::first-letter {
	font-family: var(--ff-disp);
	font-size: 4.1em;
	float: left;
	line-height: 0.82;
	padding: 0.06em 0.12em 0 0;
	color: var(--gilt);
	font-weight: 500;
}

/* ---------- Buttons ---------- */
.btn {
	display: inline-flex; align-items: center; gap: 12px;
	font-family: var(--ff-bill);
	font-size: var(--t-sm);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	font-weight: 500;
	padding: 1.05em 2.2em;
	border: 1px solid var(--line-gilt);
	color: var(--gilt-2);
	position: relative;
	overflow: hidden;
	transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.btn::after {
	content: "";
	position: absolute; inset: 0;
	background: var(--gilt);
	transform: translateY(101%);
	transition: transform 440ms var(--slow);
	z-index: -1;
}
.btn:hover { color: var(--night); border-color: var(--gilt); }
.btn:hover::after { transform: translateY(0); }
.btn--solid { background: var(--gilt); color: var(--night); border-color: var(--gilt); }
.btn--solid::after { background: var(--gilt-2); }
.btn--solid:hover { color: var(--night); }
.act--paper .btn { color: var(--gilt-dim); border-color: rgba(140,111,26,0.5); }
.act--paper .btn:hover { color: var(--paper); }
.act--paper .btn::after { background: var(--ink); }

/* ---------- Reveal system ----------
   Only .rv is ever handed to IntersectionObserver. .rvi is a clip-path
   curtain that collapses to zero intersectable area, so it can never
   trigger its own reveal — it rides on its .rv ancestor's callback.
   This cost the project a debugging session twice; it stays documented. */
.js .rv {
	opacity: 0;
	transform: translateY(26px);
	transition: opacity var(--dur) var(--slow), transform var(--dur) var(--slow);
}
.js .rv.in { opacity: 1; transform: none; }
.js .rvi { clip-path: inset(0 0 100% 0); transition: clip-path 980ms var(--slow); }
.js .rvi.in { clip-path: inset(0 0 0 0); }
.js .rv[data-d="1"] { transition-delay: 90ms; }
.js .rv[data-d="2"] { transition-delay: 180ms; }
.js .rv[data-d="3"] { transition-delay: 270ms; }
.js .rv[data-d="4"] { transition-delay: 360ms; }

/* ---------- Ambient plate ----------
   Gilt dust drifting in a dark house. Fixed, behind everything. */
.dust { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; contain: strict; }
.dust__gl { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 1600ms var(--slow); }
.dust__gl.on { opacity: 0.62; }
.dust__gl.is-off { opacity: 0; }
/* No WebGL: two slow warm pools. Cheap, reads as the same idea. */
.dust__wash {
	position: absolute; inset: -25%;
	background:
		radial-gradient(46% 38% at 22% 28%, rgba(201,162,39,0.11), transparent 66%),
		radial-gradient(40% 44% at 78% 66%, rgba(160,40,52,0.13), transparent 68%);
	filter: blur(26px);
}
@media (prefers-reduced-motion: no-preference) {
	.dust__wash { animation: dust-drift 34s ease-in-out infinite alternate; }
	@keyframes dust-drift {
		from { transform: translate3d(-2.5%, 1.5%, 0) scale(1.02); }
		to   { transform: translate3d(2.5%, -1.5%, 0) scale(1.08); }
	}
}
/* Only elements already in normal flow get raised. Never give .drawer
   position:relative — it is fixed with its own z-index and would drop
   into the flow and punch a hole through the page. */
main, .site-foot { position: relative; z-index: 1; }

/* ---------- Header ---------- */
.site-head {
	position: fixed; top: 0; left: 0; right: 0; z-index: 60;
	display: flex; align-items: center; justify-content: space-between;
	gap: 24px;
	padding: 20px var(--gap);
	transition: background 520ms var(--ease), border-color 520ms var(--ease), padding 520ms var(--ease);
	border-bottom: 1px solid transparent;
}
.site-head.solid {
	background: rgba(20,10,11,0.86);
	backdrop-filter: blur(14px) saturate(1.3);
	border-bottom-color: var(--line);
	padding-block: 13px;
}
.mark { display: flex; flex-direction: column; line-height: 1; gap: 5px; }
.mark__name {
	font-family: var(--ff-disp);
	font-size: 1.5rem;
	letter-spacing: 0.02em;
	font-weight: 500;
}
.mark__sub {
	font-family: var(--ff-bill);
	font-size: 0.62rem;
	letter-spacing: 0.42em;
	text-transform: uppercase;
	color: var(--gilt);
}
.nav { display: flex; gap: clamp(18px, 2.4vw, 38px); align-items: center; }
.nav a {
	font-family: var(--ff-bill);
	font-size: var(--t-sm);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--on-dark-2);
	position: relative;
	padding-block: 4px;
	transition: color var(--fast) var(--ease);
}
.nav a::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: 0;
	height: 1px; background: var(--gilt);
	transform: scaleX(0); transform-origin: right;
	transition: transform 400ms var(--slow);
}
.nav a:hover { color: var(--on-dark); }
.nav a:hover::after { transform: scaleX(1); transform-origin: left; }
.nav .current-menu-item > a { color: var(--gilt-2); }
@media (max-width: 900px) { .nav { display: none; } }

.burger {
	display: none; width: 42px; height: 42px;
	align-items: center; justify-content: center;
	border: 1px solid var(--line-strong);
}
.burger span { display: block; width: 17px; height: 1px; background: var(--on-dark); position: relative; }
.burger span::before, .burger span::after {
	content: ""; position: absolute; left: 0; width: 17px; height: 1px; background: var(--on-dark);
}
.burger span::before { top: -5px; }
.burger span::after  { top: 5px; }
@media (max-width: 900px) { .burger { display: flex; } }

.drawer {
	position: fixed; inset: 0; z-index: 70;
	background: var(--velvet);
	display: grid; place-content: center; gap: 22px;
	text-align: center;
	transform: translateY(-100%);
	transition: transform 640ms var(--slow);
}
.drawer.open { transform: none; }
.drawer a {
	font-family: var(--ff-disp);
	font-size: clamp(1.9rem, 7vw, 3.4rem);
	color: var(--on-dark);
}
.drawer a:hover { color: var(--gilt-2); }
.drawer__close {
	position: absolute; top: 22px; right: var(--gap);
	font-family: var(--ff-bill); letter-spacing: 0.24em; text-transform: uppercase;
	font-size: var(--t-sm); color: var(--gilt);
}

/* =====================================================================
   ACT I — THE CURTAIN
   A real cloth simulation hangs over the stage photograph and rises.
   ===================================================================== */
.stage {
	position: relative;
	min-height: 100svh;
	display: grid;
	align-items: end;
	overflow: hidden;
	isolation: isolate;
}
.stage__plate { position: absolute; inset: 0; z-index: 0; }
.stage__plate img { width: 100%; height: 100%; object-fit: cover; }
/* The house lights: a warm pool centred on the stage, dark at the edges. */
.stage__plate::after {
	content: ""; position: absolute; inset: 0;
	background:
		radial-gradient(64% 56% at 50% 42%, rgba(20,10,11,0.05), rgba(20,10,11,0.62) 76%, rgba(20,10,11,0.9) 100%),
		linear-gradient(180deg, rgba(20,10,11,0.72) 0%, transparent 26%, transparent 52%, rgba(20,10,11,0.92) 100%);
}
.stage__gl {
	position: absolute; inset: 0; z-index: 2;
	width: 100%; height: 100%;
	pointer-events: none;
}
/* No WebGL / reduced motion: a CSS curtain that still parts, so the
   opening gesture survives without the simulation. */
.stage__fallback { position: absolute; inset: 0; z-index: 2; pointer-events: none; display: none; }
.stage.no-gl .stage__fallback { display: block; }
.stage__fallback i {
	position: absolute; top: 0; bottom: 0; width: 52%;
	background:
		repeating-linear-gradient(90deg, rgba(0,0,0,0.30) 0 8px, rgba(0,0,0,0) 8px 26px),
		linear-gradient(180deg, var(--velvet-3), var(--velvet) 42%, #1e080d);
	transition: transform 2200ms var(--slow);
}
.stage__fallback i:first-child { left: 0; transform: translateX(0); }
.stage__fallback i:last-child  { right: 0; transform: translateX(0); }
.stage.open .stage__fallback i:first-child { transform: translateX(-101%); }
.stage.open .stage__fallback i:last-child  { transform: translateX(101%); }

.stage__inner { position: relative; z-index: 3; padding-bottom: clamp(56px, 9vh, 120px); width: 100%; }
.stage__season {
	font-family: var(--ff-bill);
	font-size: var(--t-sm);
	letter-spacing: 0.44em;
	text-transform: uppercase;
	color: var(--gilt);
	margin-bottom: 22px;
	display: block;
}
.stage h1 {
	margin-bottom: 0.22em;
	/* Didone at display size wants slightly tighter tracking, not looser */
	letter-spacing: -0.022em;
}
.stage h1 em {
	font-style: italic;
	color: var(--gilt-2);
}
.stage__sub {
	font-size: var(--t-lg);
	color: var(--on-dark-2);
	max-width: 46ch;
	font-weight: 300;
	margin-bottom: 32px;
}
.stage__cta { display: flex; gap: 14px; flex-wrap: wrap; align-items: center; }

/* Line-mask reveal for the display heading. */
.mask { display: block; overflow: hidden; }
.mask > span { display: block; }
.js .mask > span { transform: translateY(104%); transition: transform 1180ms var(--slow); }
.js .mask.in > span { transform: none; }
.js .mask[data-d="1"] > span { transition-delay: 110ms; }
.js .mask[data-d="2"] > span { transition-delay: 220ms; }

/* =====================================================================
   ACT II — TONIGHT
   A real strip driven by the actual performance calendar.
   ===================================================================== */
.tonight {
	border-block: 1px solid var(--line);
	background: rgba(43,13,19,0.42);
	backdrop-filter: blur(6px);
}
.tonight__row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	gap: clamp(20px, 4vw, 60px);
	align-items: center;
	padding-block: clamp(20px, 2.6vw, 34px);
}
@media (max-width: 860px) {
	.tonight__row { grid-template-columns: 1fr; gap: 18px; text-align: left; }
}
.tonight__flag {
	font-family: var(--ff-bill);
	font-size: var(--t-sm);
	letter-spacing: 0.3em;
	text-transform: uppercase;
	color: var(--gilt);
	display: flex; align-items: center; gap: 11px;
	white-space: nowrap;
}
/* The lamp: on when there is a performance tonight. */
.lamp {
	width: 7px; height: 7px; border-radius: 50%;
	background: var(--gilt);
	box-shadow: 0 0 0 0 rgba(201,162,39,0.55);
}
@media (prefers-reduced-motion: no-preference) {
	.lamp { animation: lamp 2.6s var(--ease) infinite; }
	@keyframes lamp {
		0%   { box-shadow: 0 0 0 0 rgba(201,162,39,0.5); }
		70%  { box-shadow: 0 0 0 11px rgba(201,162,39,0); }
		100% { box-shadow: 0 0 0 0 rgba(201,162,39,0); }
	}
}
.lamp--dark { background: var(--on-dark-3); animation: none; box-shadow: none; }
.tonight__title { font-family: var(--ff-disp); font-size: var(--t-xl); line-height: 1.1; }
.tonight__title a:hover { color: var(--gilt-2); }
.tonight__meta { display: flex; gap: clamp(14px, 2vw, 30px); flex-wrap: wrap; margin-top: 8px; }
.tonight__when {
	font-family: var(--ff-bill);
	text-transform: uppercase;
	letter-spacing: 0.14em;
	font-size: var(--t-sm);
	color: var(--on-dark-2);
	text-align: right;
	white-space: nowrap;
}
@media (max-width: 860px) { .tonight__when { text-align: left; } }
.tonight__when b { display: block; font-size: var(--t-lg); color: var(--gilt-2); letter-spacing: 0.06em; font-weight: 500; }

/* =====================================================================
   ACT III — THE REPERTOIRE RAIL
   Horizontal, poster-format, scrubbed by vertical scroll. Explicitly
   not a card grid.
   ===================================================================== */
.rail-act { overflow: hidden; }
.rail-head {
	display: flex; align-items: flex-end; justify-content: space-between;
	gap: 26px; flex-wrap: wrap;
	margin-bottom: clamp(34px, 4.5vw, 62px);
}
.rail-head h2 { max-width: 16ch; }
.rail-viewport { position: relative; }
.rail {
	display: flex;
	gap: clamp(18px, 2.4vw, 38px);
	will-change: transform;
	padding-left: max(var(--gap), calc((100vw - var(--wrap)) / 2));
	padding-right: max(var(--gap), calc((100vw - var(--wrap)) / 2));
}
/* Touch/narrow: fall back to a real horizontal swipe, no scrub. */
@media (max-width: 900px), (hover: none) {
	.rail { overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
	.rail::-webkit-scrollbar { display: none; }
	.poster { scroll-snap-align: center; }
}

.poster {
	flex: 0 0 clamp(250px, 26vw, 372px);
	position: relative;
}
.poster__plate {
	position: relative;
	aspect-ratio: 2 / 3;
	overflow: hidden;
	background: var(--velvet-2);
	border: 1px solid var(--line);
}
.poster__plate img {
	width: 100%; height: 100%; object-fit: cover;
	filter: saturate(0.72) contrast(1.06);
	transition: transform 1300ms var(--slow), filter 700ms var(--ease);
}
.poster:hover .poster__plate img { transform: scale(1.055); filter: saturate(1) contrast(1.02); }
/* A gilt frame that draws itself on hover — the house style for a
   "selected" poster in a display case. */
.poster__frame {
	position: absolute; inset: 11px; z-index: 2; pointer-events: none;
	border: 1px solid var(--gilt);
	opacity: 0;
	transform: scale(1.03);
	transition: opacity 460ms var(--ease), transform 620ms var(--slow);
}
.poster:hover .poster__frame { opacity: 0.85; transform: none; }
.poster__no {
	position: absolute; top: 12px; left: 14px; z-index: 3;
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.2em; color: var(--on-dark-2);
}
.poster__genre {
	position: absolute; bottom: 12px; left: 14px; right: 14px; z-index: 3;
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.22em; text-transform: uppercase; color: var(--gilt-2);
}
.poster__body { padding-top: 17px; }
.poster__body h3 { font-size: var(--t-lg); line-height: 1.14; }
.poster__body h3 a:hover { color: var(--gilt-2); }
.poster__composer {
	font-family: var(--ff-bill); text-transform: uppercase;
	letter-spacing: 0.18em; font-size: var(--t-xs);
	color: var(--on-dark-3); margin-top: 7px;
}
.poster__dates {
	margin-top: 11px; padding-top: 11px;
	border-top: 1px solid var(--line);
	font-family: var(--ff-bill); font-size: var(--t-sm);
	letter-spacing: 0.08em; color: var(--on-dark-2);
}

.rail-progress { height: 1px; background: var(--line); margin-top: clamp(30px, 4vw, 52px); position: relative; }
.rail-progress i { position: absolute; inset: 0 auto 0 0; background: var(--gilt); width: 12%; transform-origin: left; }

/* =====================================================================
   ACT IV — THE PROGRAMME SPREAD
   Recto/verso. Asymmetric on purpose: the plate bleeds off one edge,
   the cast list sits in a narrow measure like real programme copy.
   ===================================================================== */
.spread { position: relative; }
.spread__grid {
	display: grid;
	grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
	gap: clamp(28px, 5vw, 86px);
	align-items: start;
}
@media (max-width: 980px) { .spread__grid { grid-template-columns: 1fr; } }

.spread__plate { position: relative; }
.spread__plate .shot {
	aspect-ratio: 4 / 5;
	overflow: hidden;
	background: var(--velvet-2);
	border: 1px solid var(--line);
}
.spread__plate .shot img { width: 100%; height: 100%; object-fit: cover; }
/* The floating gilt data badge on the plate — a cheap, effective tell. */
.spread__badge {
	position: absolute; right: clamp(-12px, -1vw, 0px); bottom: 26px; z-index: 3;
	background: var(--night);
	border: 1px solid var(--line-gilt);
	padding: 16px 22px;
	display: grid; gap: 3px;
	min-width: 168px;
}
.spread__badge .k {
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.24em; text-transform: uppercase; color: var(--gilt);
}
.spread__badge .v { font-family: var(--ff-disp); font-size: 1.7rem; line-height: 1; }

.spread__body { padding-top: clamp(0px, 2vw, 26px); }
.spread__body h2 { margin-block: 16px 20px; }
.spread__body .lede { font-size: var(--t-lg); color: var(--on-dark-2); font-weight: 300; }

/* The cast list — the single most "opera" piece of typography there is.
   Dotted leaders between role and artist, like a printed programme. */
.cast { margin-top: clamp(26px, 3.4vw, 42px); }
.cast__head {
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.3em; text-transform: uppercase; color: var(--gilt);
	padding-bottom: 11px; border-bottom: 1px solid var(--line-gilt);
	margin-bottom: 6px;
}
.cast__row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	gap: 10px;
	align-items: baseline;
	padding-block: 9px;
	border-bottom: 1px solid var(--line);
}
.cast__role { font-family: var(--ff-body); font-style: italic; color: var(--on-dark-2); font-size: var(--t-md); }
.cast__lead { border-bottom: 1px dotted var(--line-strong); transform: translateY(-4px); }
.cast__name {
	font-family: var(--ff-bill); text-transform: uppercase;
	letter-spacing: 0.13em; font-size: var(--t-sm); color: var(--on-dark);
	text-align: right;
}
.act--paper .cast__row { border-bottom-color: var(--line-ink); }
.act--paper .cast__role { color: var(--ink-2); }
.act--paper .cast__name { color: var(--ink); }
.act--paper .cast__lead { border-bottom-color: var(--line-ink); }

/* =====================================================================
   ACT V — THE HOUSE (seat map + chandelier)
   ===================================================================== */
.house { position: relative; overflow: hidden; }
.house__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 320px;
	gap: clamp(26px, 4vw, 62px);
	align-items: start;
}
@media (max-width: 1020px) { .house__grid { grid-template-columns: 1fr; } }

.seatmap {
	position: relative;
	aspect-ratio: 16 / 11;
	background: linear-gradient(180deg, #1b0c0f, #12080a);
	border: 1px solid var(--line);
	overflow: hidden;
	cursor: crosshair;
}
/* Selected on the element, not on a class the markup has to remember to
   carry. Sizing the canvas by class alone is how it silently fell back
   to the intrinsic 300x150 default and drew the whole auditorium into
   the top-left corner of the panel. */
.seatmap > canvas, .seatmap__gl { position: absolute; inset: 0; width: 100%; height: 100%; }
.seatmap__stage {
	position: absolute; left: 50%; top: 5.5%; transform: translateX(-50%);
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.42em; text-transform: uppercase; color: var(--gilt);
	pointer-events: none; z-index: 2;
}
/* Hover readout, positioned by JS. */
.seatmap__tip {
	position: absolute; z-index: 4; pointer-events: none;
	background: var(--night);
	border: 1px solid var(--line-gilt);
	padding: 9px 13px;
	font-family: var(--ff-bill);
	font-size: var(--t-xs);
	letter-spacing: 0.13em;
	text-transform: uppercase;
	white-space: nowrap;
	opacity: 0;
	transform: translate(-50%, -132%);
	transition: opacity 170ms var(--ease);
}
.seatmap__tip.on { opacity: 1; }
.seatmap__tip b { color: var(--gilt-2); }
.seatmap__hint {
	position: absolute; left: 14px; bottom: 12px; z-index: 2;
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--on-dark-3);
	pointer-events: none;
}
.seatmap.no-gl .seatmap__gl { display: none; }
.seatmap__fallback { display: none; position: absolute; inset: 0; place-content: center; text-align: center; padding: 30px; }
.seatmap.no-gl .seatmap__fallback { display: grid; }

/* Price tier key — doubles as the seat-map legend and a real price list. */
.tiers { display: grid; gap: 2px; }
.tier {
	display: grid; grid-template-columns: 12px 1fr auto;
	gap: 14px; align-items: center;
	padding: 14px 16px;
	border: 1px solid var(--line);
	background: rgba(43,13,19,0.34);
	transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
	cursor: pointer;
}
.tier:hover, .tier.on { border-color: var(--line-gilt); background: rgba(58,17,25,0.6); }
.tier__swatch { width: 12px; height: 12px; border-radius: 2px; }
.tier__name { font-family: var(--ff-bill); text-transform: uppercase; letter-spacing: 0.16em; font-size: var(--t-sm); }
.tier__name small { display: block; letter-spacing: 0.1em; color: var(--on-dark-3); font-size: var(--t-xs); text-transform: none; }
.tier__price { font-family: var(--ff-disp); font-size: 1.32rem; color: var(--gilt-2); }

/* The chandelier sits under the price key, as an object in the room
   rather than a banner: it is atmosphere, not a headline. */
.lamp-stage {
	position: relative;
	margin-top: clamp(28px, 4vw, 52px);
	aspect-ratio: 1 / 1;
	max-height: 340px;
}
.lamp-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.lamp-stage.no-gl { display: none; }

.seatmap__chosen {
	font-family: var(--ff-bill);
	text-transform: uppercase;
	letter-spacing: 0.2em;
	font-size: var(--t-sm);
	color: var(--gilt-2);
	margin: 18px 0 0;
	padding-top: 16px;
	border-top: 1px solid var(--line);
}

/* =====================================================================
   ACT VI — THE LEDGER (128 years of archive)
   A dense index, not cards. Rows are the design.
   ===================================================================== */
.ledger { border-top: 1px solid var(--line-ink); }
.ledger__row {
	display: grid;
	grid-template-columns: 92px minmax(0, 1fr) minmax(0, 0.8fr) auto;
	gap: clamp(12px, 2vw, 34px);
	align-items: baseline;
	padding-block: clamp(13px, 1.5vw, 20px);
	border-bottom: 1px solid var(--line-ink);
	position: relative;
	transition: background 300ms var(--ease);
}
.ledger__row:hover { background: rgba(25,20,16,0.045); }
@media (max-width: 820px) {
	.ledger__row { grid-template-columns: 62px 1fr; row-gap: 5px; }
	.ledger__co, .ledger__note { grid-column: 2; }
}
.ledger__yr {
	font-family: var(--ff-disp);
	font-size: 1.28rem;
	color: var(--gilt-dim);
	font-variant-numeric: tabular-nums;
}
.ledger__work { font-family: var(--ff-disp); font-size: 1.24rem; line-height: 1.16; }
.ledger__work em { font-style: italic; }
.ledger__co, .ledger__note {
	font-family: var(--ff-bill);
	text-transform: uppercase;
	letter-spacing: 0.15em;
	font-size: var(--t-xs);
	color: var(--ink-3);
}
.ledger__note { text-align: right; white-space: nowrap; }
@media (max-width: 820px) { .ledger__note { text-align: left; } }

/* =====================================================================
   ACT VII — PATRONS
   A real tier table. This is the component that makes the theme
   sellable to an actual institution.
   ===================================================================== */
.patrons { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (max-width: 1000px) { .patrons { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .patrons { grid-template-columns: 1fr; } }
.patron {
	background: var(--night);
	padding: clamp(24px, 3vw, 38px) clamp(20px, 2.4vw, 30px);
	display: flex; flex-direction: column; gap: 14px;
	position: relative;
	transition: background 420ms var(--ease);
}
.patron:hover { background: var(--velvet); }
.patron--feature { background: var(--velvet); }
.patron--feature::before {
	content: "";
	position: absolute; left: 0; right: 0; top: 0; height: 2px;
	background: linear-gradient(90deg, transparent, var(--gilt), transparent);
}
.patron__tier { font-family: var(--ff-bill); text-transform: uppercase; letter-spacing: 0.26em; font-size: var(--t-xs); color: var(--gilt); }
.patron__amt { font-family: var(--ff-disp); font-size: clamp(1.9rem, 3vw, 2.7rem); line-height: 1; }
.patron__amt small { font-family: var(--ff-bill); font-size: var(--t-xs); letter-spacing: 0.2em; text-transform: uppercase; color: var(--on-dark-3); display: block; margin-top: 8px; }
.patron__list { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 9px; }
.patron__list li {
	font-size: var(--t-sm); color: var(--on-dark-2);
	padding-left: 19px; position: relative; line-height: 1.5;
}
.patron__list li::before {
	content: ""; position: absolute; left: 0; top: 0.62em;
	width: 7px; height: 1px; background: var(--gilt);
}

/* =====================================================================
   Interior pages
   ===================================================================== */
.phead { padding-block: clamp(140px, 17vw, 220px) clamp(34px, 5vw, 62px); }
.phead .bill { margin-bottom: 20px; }
.phead h1 { max-width: 18ch; }
.phead .lede { margin-top: 20px; max-width: 58ch; color: var(--on-dark-2); font-size: var(--t-lg); font-weight: 300; }

.pplate { position: relative; aspect-ratio: 21 / 9; overflow: hidden; background: var(--velvet-2); }
.pplate img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 760px) { .pplate { aspect-ratio: 3 / 2; } }

/* Production single: the performance schedule table. */
.perfs { border-top: 1px solid var(--line); }
.perf {
	display: grid; grid-template-columns: auto 1fr auto auto;
	gap: clamp(12px, 2vw, 28px);
	align-items: center;
	padding-block: 15px;
	border-bottom: 1px solid var(--line);
}
@media (max-width: 720px) { .perf { grid-template-columns: 1fr auto; row-gap: 5px; } }
.perf__date { font-family: var(--ff-disp); font-size: 1.22rem; font-variant-numeric: tabular-nums; min-width: 116px; }
.perf__day  { font-family: var(--ff-bill); text-transform: uppercase; letter-spacing: 0.18em; font-size: var(--t-xs); color: var(--on-dark-3); }
.perf__time { font-family: var(--ff-bill); letter-spacing: 0.14em; font-size: var(--t-sm); color: var(--on-dark-2); }
.perf__act  { justify-self: end; }
.perf.is-past { opacity: 0.42; }
.perf.is-past .perf__act { pointer-events: none; }
/* The schedule lives inside .act--paper on a production page, where the
   dark-ground text tokens are near-white and vanish completely. Every
   component that can appear on both grounds needs this pair. */
.act--paper .perfs, .act--paper .perf { border-color: var(--line-ink); }
.act--paper .perf__day { color: var(--ink-3); }
.act--paper .perf__time { color: var(--ink-2); }
.act--paper .cast__head { color: var(--gilt-dim); border-bottom-color: rgba(140,111,26,0.45); }
.act--paper .acts__no { color: var(--gilt-dim); border-top-color: rgba(140,111,26,0.45); }
.act--paper .ornament { color: var(--gilt-dim); }
.act--paper .ornament::before, .act--paper .ornament::after { background: rgba(140,111,26,0.4); }
.act--paper .spread__badge { border-color: rgba(140,111,26,0.5); color: var(--on-dark); }

/* Synopsis by act. */
.acts { display: grid; gap: clamp(22px, 3vw, 38px); }
.acts__item { display: grid; grid-template-columns: 116px 1fr; gap: clamp(16px, 2.4vw, 34px); align-items: start; }
@media (max-width: 700px) { .acts__item { grid-template-columns: 1fr; gap: 8px; } }
.acts__no {
	font-family: var(--ff-disp); font-size: 1.5rem; color: var(--gilt);
	border-top: 1px solid var(--line-gilt); padding-top: 12px;
}
.acts__body p:last-child { margin-bottom: 0; }

/* Long-form prose (pages, journal). */
.prose { max-width: 68ch; font-size: 1.06rem; }
.prose > * + * { margin-top: 1.1em; }
.prose h2 { font-size: var(--t-xl); margin-top: 1.7em; }
.prose h3 { font-size: var(--t-lg); margin-top: 1.5em; }
.prose a { color: var(--gilt-2); border-bottom: 1px solid var(--line-gilt); }
.prose a:hover { color: var(--gilt); }
.prose blockquote {
	margin: 1.7em 0; padding-left: 26px;
	border-left: 1px solid var(--line-gilt);
	font-family: var(--ff-disp); font-size: 1.3rem; font-style: italic;
	color: var(--on-dark);
}
.prose ul, .prose ol { padding-left: 1.2em; }
.prose li { margin-bottom: 0.5em; }
.act--paper .prose a { color: var(--gilt-dim); }
.act--paper .prose blockquote { color: var(--ink); }

/* Archive/index grids used on non-front templates. */
.index-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 3vw, 44px); }
@media (max-width: 1000px) { .index-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .index-grid { grid-template-columns: 1fr; } }

/* Journal entry cards. */
.entry__plate { aspect-ratio: 3 / 2; overflow: hidden; background: var(--velvet-2); border: 1px solid var(--line); }
.entry__plate img { width: 100%; height: 100%; object-fit: cover; transition: transform 1100ms var(--slow); }
.entry:hover .entry__plate img { transform: scale(1.05); }
.entry__body { padding-top: 15px; }
.entry__body h3 { font-size: var(--t-lg); line-height: 1.16; }
.entry__body h3 a:hover { color: var(--gilt-2); }
.entry__date { font-family: var(--ff-bill); text-transform: uppercase; letter-spacing: 0.18em; font-size: var(--t-xs); color: var(--on-dark-3); margin-top: 9px; }

/* Filter chips (season / genre archives). */
.chips { display: flex; flex-wrap: wrap; gap: 9px; }
.chip {
	font-family: var(--ff-bill); text-transform: uppercase;
	letter-spacing: 0.17em; font-size: var(--t-xs);
	padding: 8px 15px; border: 1px solid var(--line);
	color: var(--on-dark-2);
	transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.chip:hover, .chip.on { color: var(--gilt-2); border-color: var(--line-gilt); }

/* Pagination. */
.nav-links { display: flex; gap: 9px; flex-wrap: wrap; margin-top: clamp(30px, 4vw, 54px); }
.nav-links .page-numbers {
	font-family: var(--ff-bill); letter-spacing: 0.14em; font-size: var(--t-sm);
	padding: 9px 15px; border: 1px solid var(--line); color: var(--on-dark-2);
}
.nav-links .page-numbers.current { color: var(--night); background: var(--gilt); border-color: var(--gilt); }
.nav-links a.page-numbers:hover { color: var(--gilt-2); border-color: var(--line-gilt); }

/* Next-production footer link on singles. */
.next-up { border-top: 1px solid var(--line); }
.next-up a { display: grid; gap: 12px; padding-block: clamp(38px, 5vw, 72px); }
.next-up h3 { font-size: var(--t-2xl); transition: color var(--fast) var(--ease); }
.next-up a:hover h3 { color: var(--gilt-2); }

/* ---------- Footer ---------- */
.site-foot {
	border-top: 1px solid var(--line);
	padding-block: clamp(56px, 7vw, 92px) 30px;
	color: var(--on-dark-2);
}
.foot-grid {
	display: grid;
	grid-template-columns: 1.4fr repeat(3, 1fr);
	gap: clamp(24px, 3.4vw, 54px);
	margin-bottom: clamp(38px, 5vw, 64px);
}
@media (max-width: 900px) { .foot-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .foot-grid { grid-template-columns: 1fr; } }
.foot-col h4 {
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.28em; text-transform: uppercase; color: var(--gilt);
	margin-bottom: 16px;
}
.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.foot-col a { font-size: var(--t-sm); transition: color var(--fast) var(--ease); }
.foot-col a:hover { color: var(--gilt-2); }
.foot-col address { font-style: normal; font-size: var(--t-sm); line-height: 1.8; }
.foot-bottom {
	display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
	padding-top: 24px; border-top: 1px solid var(--line);
	font-family: var(--ff-bill); font-size: var(--t-xs);
	letter-spacing: 0.14em; color: var(--on-dark-3);
}
.foot-fiction { max-width: 66ch; line-height: 1.75; letter-spacing: 0.06em; }

.skip { position: absolute; left: -9999px; top: 0; z-index: 100; background: var(--gilt); color: var(--night); padding: 12px 18px; font-family: var(--ff-bill); }
.skip:focus { left: var(--gap); top: var(--gap); }

/* ---------- Reduced motion ----------
   transition:none, not a 1ms duration — setting a duration on * actually
   switches transitions ON everywhere and can pin elements at stale
   values. Learned the hard way; don't "optimise" this back. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation: none !important;
		transition: none !important;
		scroll-behavior: auto !important;
	}
	.js .rv { opacity: 1; transform: none; }
	.js .rvi { clip-path: none; }
	.js .mask > span { transform: none; }
}
