/*
Theme Name: MSM Portfolio Arcade 20261002
Theme URI: https://mysteryschoolmedia.llc
Description: Select-screen portfolio for Mystery School Media LLC: every project on its own page, in the Cabinet palette with pixel / ASCII effects over real text and screenshots.
Version: 3.0.0
Author: Mystery School Media
Author URI: https://mysteryschoolmedia.llc
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: msm-portfolio-arcade-20261002
Requires at least: 6.3
Requires PHP: 7.4
*/

/* Metric-matched local fallbacks (P6, no downloads): while the Google fonts load (display=swap)
   the text is set in Arial / Courier New scaled to the web fonts' measured widths and line
   metrics, so the swap barely moves anything (CLS). Archivo gets one face per weight and width
   step it is used at (100% and 112.5%), since Arial cannot stretch. */
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial'), local('ArialMT');
	font-weight: 400;
	font-stretch: 50% 106%;
	size-adjust: 98.8%;
	ascent-override: 88.87%;
	descent-override: 21.26%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial'), local('ArialMT');
	font-weight: 500;
	font-stretch: 50% 106%;
	size-adjust: 100.4%;
	ascent-override: 87.45%;
	descent-override: 20.92%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial Bold'), local('Arial-BoldMT');
	font-weight: 600 900;
	font-stretch: 50% 106%;
	size-adjust: 98.3%;
	ascent-override: 89.32%;
	descent-override: 21.36%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial'), local('ArialMT');
	font-weight: 500;
	font-stretch: 106% 200%;
	size-adjust: 105.3%;
	ascent-override: 83.38%;
	descent-override: 19.94%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial Bold'), local('Arial-BoldMT');
	font-weight: 600;
	font-stretch: 106% 200%;
	size-adjust: 109.2%;
	ascent-override: 80.40%;
	descent-override: 19.23%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial Bold'), local('Arial-BoldMT');
	font-weight: 700;
	font-stretch: 106% 200%;
	size-adjust: 112.0%;
	ascent-override: 78.39%;
	descent-override: 18.75%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Archivo Fallback";
	src: local('Arial Bold'), local('Arial-BoldMT');
	font-weight: 800 900;
	font-stretch: 106% 200%;
	size-adjust: 116.6%;
	ascent-override: 75.30%;
	descent-override: 18.01%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "JetBrains Mono Fallback";
	src: local('Courier New'), local('CourierNewPSMT');
	font-weight: 100 900;
	size-adjust: 100.0%;
	ascent-override: 102.00%;
	descent-override: 30.00%;
	line-gap-override: 0%;
}
@font-face {
	font-family: "Silkscreen Fallback";
	src: local('Courier New'), local('CourierNewPSMT');
	size-adjust: 108.9%;
	ascent-override: 94.58%;
	descent-override: 22.96%;
	line-gap-override: 0%;
}

/* ==========================================================================
   0. DESIGN TOKENS
   ========================================================================== */

:root {
	--c-bezel: #0e1c19;
	--c-screen: #15302a;
	--c-ink: #f2e8d0;
	--c-amber: #ffb31a;
	--c-mint: #7ee2b8;
	--c-coral: #ff7b5c;
	--c-dim: #9fb3aa;
	--c-rule: #3a5a52;
	--c-glyph: #3f6a5f;
	--c-overlay: rgba(14, 28, 25, .72);

	--pfx-paper: var(--c-bezel);
	--pfx-ink: var(--c-ink);
	--pfx-accent: var(--c-amber);

	--font-display: "Archivo", "Archivo Fallback", "Helvetica Neue", Arial, sans-serif;
	--font-mono: "JetBrains Mono", "JetBrains Mono Fallback", ui-monospace, monospace;
	--font-pixel: "Silkscreen", "Silkscreen Fallback", "Courier New", monospace;

	--fs-h1: clamp(2.625rem, 1.6443rem + 4.423vw, 7.5rem);
	--fs-h2: clamp(1.75rem, 1rem + 2.2223vw, 3rem);
	--fs-h3: clamp(1.5rem, 0.75rem + 2.2223vw, 2.5rem);
	--fs-body: clamp(1rem, 0.9rem + 0.25vw, 1.125rem);
	--fs-row: clamp(1rem, 0.85rem + 0.445vw, 1.25rem);
	--fs-meta: clamp(0.8125rem, 0.75rem + 0.15vw, 0.875rem);
	--fs-mark: clamp(3.5rem, 12.6vw, 16rem);

	--space-1: 4px;
	--space-2: 8px;
	--space-4: 16px;
	--space-6: 24px;
	--space-12: 48px;
	--space-26: 104px;
	--space-30: 120px;
	--space-36: 144px;
	--space-60: 240px;

	--radius-bezel: 12px;
	--radius-pill: 16px;
	--shadow-bezel: inset 0 0 0 1px var(--c-rule), inset 0 0 48px rgba(0, 0, 0, .45);
	--shadow-tag: inset 0 0 0 1px var(--c-dim);
	--grad-scan: repeating-linear-gradient(rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, .18) 2px, rgba(0, 0, 0, .18) 3px);

	--t-roll: 160ms steps(4, end);
	--t-ui: 120ms steps(2, end);

	/* grid: 8 cols >= 992; --vw is set to the scrollbar-free width by site.js */
	--vw: 100vw;
	--cols: 8;
	--gutter: clamp(1rem, 1.111vw, 1.5rem);
	--pad: var(--gutter);
	--col: calc((var(--vw) - 2 * var(--pad) - (var(--cols) - 1) * var(--gutter)) / var(--cols));
	--rail-x: calc(var(--pad) + 3 * var(--col) + 2.5 * var(--gutter));
	--nav-h: 64px;
	/* first screen: the hero plus the strip's head and whole tile row fit the viewport */
	--tile-w: clamp(208px, calc(12vw + 58px), 340px);
	--strip-gap: 32px;

	--mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 16' shape-rendering='crispEdges'%3E%3Cpath d='M1 1h2v1h-2zM13 1h2v1h-2zM1 2h3v1h-3zM12 2h3v1h-3zM1 3h4v1h-4zM11 3h4v1h-4zM1 4h2v1h-2zM4 4h2v1h-2zM10 4h2v1h-2zM13 4h2v1h-2zM1 5h2v1h-2zM5 5h2v1h-2zM9 5h2v1h-2zM13 5h2v1h-2zM1 6h2v1h-2zM6 6h4v1h-4zM13 6h2v1h-2zM1 7h2v1h-2zM7 7h2v1h-2zM13 7h2v1h-2zM1 8h2v1h-2zM13 8h2v1h-2zM1 9h2v1h-2zM13 9h2v1h-2zM1 10h2v1h-2zM13 10h2v1h-2zM1 11h2v1h-2zM13 11h2v1h-2zM1 12h2v1h-2zM13 12h2v1h-2zM1 13h2v1h-2zM13 13h2v1h-2zM1 14h2v1h-2zM13 14h2v1h-2zM17 1h2v1h-2zM29 1h2v1h-2zM17 2h3v1h-3zM28 2h3v1h-3zM17 3h4v1h-4zM27 3h4v1h-4zM19 4h2v1h-2zM22 4h2v1h-2zM28 4h2v1h-2zM31 4h1v1h-1zM19 5h2v1h-2zM23 5h2v1h-2zM27 5h2v1h-2zM31 5h1v1h-1zM19 6h2v1h-2zM24 6h4v1h-4zM31 6h1v1h-1zM19 7h2v1h-2zM25 7h2v1h-2zM31 7h1v1h-1zM17 8h2v1h-2zM29 8h2v1h-2zM17 9h2v1h-2zM29 9h2v1h-2zM16 10h2v1h-2zM28 10h2v1h-2zM16 11h2v1h-2zM28 11h2v1h-2zM17 12h2v1h-2zM29 12h2v1h-2zM17 13h2v1h-2zM29 13h2v1h-2zM17 14h2v1h-2zM29 14h2v1h-2zM33 1h1v1h-1zM45 1h1v1h-1zM34 2h1v1h-1zM44 2h1v1h-1zM46 2h1v1h-1zM33 3h1v1h-1zM35 3h1v1h-1zM43 3h1v1h-1zM45 3h1v1h-1zM34 4h1v1h-1zM36 4h1v1h-1zM42 4h1v1h-1zM46 4h1v1h-1zM33 5h1v1h-1zM37 5h1v1h-1zM41 5h1v1h-1zM45 5h1v1h-1zM34 6h1v1h-1zM38 6h1v1h-1zM40 6h1v1h-1zM46 6h1v1h-1zM33 7h1v1h-1zM39 7h1v1h-1zM45 7h1v1h-1zM34 8h1v1h-1zM46 8h1v1h-1zM33 9h1v1h-1zM45 9h1v1h-1zM34 10h1v1h-1zM46 10h1v1h-1zM33 11h1v1h-1zM45 11h1v1h-1zM34 12h1v1h-1zM46 12h1v1h-1zM33 13h1v1h-1zM45 13h1v1h-1zM34 14h1v1h-1zM46 14h1v1h-1z'/%3E%3C/svg%3E");

	color-scheme: dark;
}

/* Wide canvases (R2): past 1600px the title keeps scaling (97px at 1600, ~170px at 2560, 176px cap)
   instead of stopping at 120px; continuous with the base clamp at 1600. */
@media (min-width: 1600px) {
	:root { --fs-h1: clamp(6rem, calc(7.6vw - 24.4px), 11rem); }
}
@media (min-width: 2200px) {
	:root { --nav-h: 80px; }
}

/* Manual mode: the light operator manual. */
html[data-mode="manual"] {
	--c-bezel: #ece3cb;
	--c-screen: #e0d4b6;
	--c-ink: #0e1c19;
	--c-amber: #7f4400;
	--c-mint: #1a6148;
	--c-coral: #9e3218;
	--c-dim: #4f5f58;
	--c-rule: #8f9a88;
	--c-glyph: #b9ad8e;
	--c-overlay: rgba(236, 227, 203, .78);
	--pfx-paper: var(--c-bezel);
	--pfx-ink: var(--c-ink);
	--pfx-accent: var(--c-amber);
	color-scheme: light;
}
/* On manual paper, badge text is paper-coloured (contrast 5.6-6.0:1). */

/* ==========================================================================
   1. RESET + BASE
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html {
	scroll-behavior: smooth;
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	scroll-padding-top: calc(var(--nav-h) + var(--wpab, 0px) + 16px);
}

/* WordPress admin bar (logged-in owner): fixed chrome sits below it. Core pins the bar at 32px,
   46px at <=782px and lets it scroll away at <=600px; here it stays pinned at every width so the
   nav is never covered. */
body.admin-bar { --wpab: 32px; }
:root:has(> body.admin-bar) { --wpab: 32px; } /* html's scroll-padding-top reads it too */
@media screen and (max-width: 782px) {
	body.admin-bar { --wpab: 46px; }
	:root:has(> body.admin-bar) { --wpab: 46px; }
}
@media screen and (max-width: 600px) {
	body.admin-bar #wpadminbar { position: fixed; }
}

body {
	margin: 0;
	min-height: 100vh;
	background-color: var(--c-bezel);
	color: var(--c-ink);
	font-family: var(--font-display);
	font-size: var(--fs-body);
	font-weight: 400;
	line-height: 1.5;
	font-optical-sizing: auto;
	font-synthesis: none;
	overflow-x: clip;
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ol, ul, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; }
canvas { display: block; }
[hidden] { display: none !important; }

::selection { background: var(--c-amber); color: var(--c-bezel); }

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

.visually-hidden {
	position: absolute !important;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* Status squares (live / in development / beta): decorative, the status word sits beside them.
   Used by the project strip, the select grid and the project pages. */
.status-sq { display: inline-flex; align-items: center; flex: none; }
.status-sq__box { display: inline-block; width: 8px; height: 8px; }
.status-sq--live .status-sq__box { background: var(--c-mint); }
.status-sq--rel .status-sq__box { box-shadow: inset 0 0 0 2px var(--c-mint); } /* Released: live, no current good check */
.status-sq--dev .status-sq__box { box-shadow: inset 0 0 0 2px var(--c-coral); }
.status-sq--beta .status-sq__box { background: linear-gradient(90deg, var(--c-amber) 50%, transparent 50%); box-shadow: inset 0 0 0 1px var(--c-amber); }

.skip-link {
	position: fixed;
	left: var(--gutter);
	top: -100px;
	z-index: 100;
	padding: var(--space-2) var(--space-4);
	background: var(--c-amber);
	color: var(--c-bezel);
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
}
.skip-link:focus { top: calc(var(--wpab, 0px) + var(--gutter)); }
main:focus { outline: none; }

/* ==========================================================================
   2. TYPE
   ========================================================================== */

.intro__title,
.intro__lede,
.contact__title,
.section-title,
.menu__label,
.wordmark__half,
.clock {
	font-family: var(--font-display);
	font-weight: 700;
	font-stretch: 112.5%;
	text-rendering: optimizeLegibility;
	text-transform: none;
}

.intro__title,
.intro__lede,
.contact__title {
	font-size: var(--fs-h1);
	line-height: .88;
	letter-spacing: -.05em;
	color: var(--c-ink);
}

.line { display: block; }

.section-title {
	font-size: var(--fs-h2);
	line-height: .9;
	letter-spacing: -.04em;
}

.meta {
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	font-weight: 400;
	line-height: 1.4;
	color: var(--c-dim);
}

.hud {
	font-family: var(--font-pixel);
	font-size: 1rem;
	font-weight: 400;
	line-height: 1;
	color: var(--c-dim);
}

.em { color: var(--c-amber); }

/* Block-assembly headings: hidden fill only while PixelFX is about to assemble them,
   with a 1.2 s failsafe. Without JS or with FX off nothing is hidden. */
.js[data-fx="on"] .pfx-pending {
	-webkit-text-fill-color: transparent;
	animation: cab-failsafe 0s 1.2s forwards;
}
@keyframes cab-failsafe { to { -webkit-text-fill-color: currentColor; } }

/* ==========================================================================
   3. GRID + RAIL
   ========================================================================== */

.grid {
	display: grid;
	grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
	column-gap: var(--gutter);
	padding-inline: var(--pad);
}

.rail {
	position: fixed;
	top: var(--wpab, 0px);
	bottom: var(--rail-end, 0px); /* site.js: the rail stops at the contact section's top edge */
	left: var(--rail-x);
	width: 1px;
	background-color: var(--c-rule);
	z-index: 30;
	pointer-events: none;
}
.rail__fill {
	position: absolute;
	top: 0;
	left: -1px;
	width: 3px;
	height: 0;
	background-color: var(--c-amber);
}
.rail__index {
	/* sits left of the rail, at the foot of the viewport (header.php prints it; site.js
	   updates it only on pages with cabinets) */
	position: absolute;
	right: 10px;
	bottom: var(--gutter);
	padding: 4px 6px;
	background: var(--c-bezel);
	color: var(--c-amber);
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	white-space: nowrap;
	visibility: hidden;
}
/* ==========================================================================
   4. NAV + MENU
   ========================================================================== */

.site-nav {
	position: fixed;
	top: var(--wpab, 0px);
	left: 0;
	right: 0;
	z-index: 50;
	height: var(--nav-h);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-4);
	padding: 0 var(--gutter);
	background: var(--c-bezel);
	box-shadow: 0 1px 0 var(--c-rule);
}

.brand {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	font-weight: 500;
	font-size: 1rem;
	line-height: 1.2;
	white-space: nowrap;
}
.brand .dot { color: var(--c-amber); }
.brand__short { display: none; }

.mark {
	display: inline-block;
	width: 16px;
	height: 16px;
	flex: none;
	background-color: var(--c-amber);
	-webkit-mask: var(--mark) 0 0 / 300% 100% no-repeat;
	mask: var(--mark) 0 0 / 300% 100% no-repeat;
	animation: cab-mark 1.2s steps(3, jump-none) infinite;
}
@keyframes cab-mark {
	from { -webkit-mask-position: 0 0; mask-position: 0 0; }
	to { -webkit-mask-position: 100% 0; mask-position: 100% 0; }
}

.nav-plain { display: none; }
.no-js .nav-plain {
	display: flex;
	gap: var(--space-4);
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
}
.no-js .nav-plain a { text-decoration: underline; text-underline-offset: 3px; }
.no-js .site-nav__tools,
.no-js .fx-toggle,
.no-js .menu-btn { display: none; }

.site-nav__tools {
	display: flex;
	align-items: center;
	gap: var(--space-2);
}

.fx-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	height: 32px;
	padding: 0 8px;
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	color: var(--c-ink);
	box-shadow: inset 0 0 0 1px var(--c-dim);
	cursor: pointer;
	transition: color var(--t-ui), box-shadow var(--t-ui);
}
.fx-toggle__sq {
	width: 12px;
	height: 12px;
	background: var(--c-amber);
	box-shadow: inset 0 0 0 1px var(--c-amber);
}
.fx-toggle[aria-pressed="false"] .fx-toggle__sq { background: transparent; box-shadow: inset 0 0 0 1px var(--c-dim); }
.fx-toggle[aria-pressed="false"] { color: var(--c-dim); }
.fx-toggle:hover { box-shadow: inset 0 0 0 1px var(--c-amber); }
.fx-toggle[aria-disabled="true"] { cursor: not-allowed; }

.menu-btn {
	display: inline-flex;
	align-items: center;
	min-height: 32px;
	padding: 4px 8px;
	border-radius: var(--radius-pill);
	background-color: var(--c-ink);
	color: var(--c-bezel);
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color var(--t-ui);
}
.menu-btn__label { padding-inline: 4px; }
.menu-btn[aria-expanded="true"] { background-color: var(--c-amber); }

.menu {
	position: fixed;
	top: calc(var(--nav-h) + var(--wpab, 0px) + var(--space-2));
	right: var(--gutter);
	z-index: 45;
}
/* Scrim: the page dims behind the open menu (a click on it closes the menu, site.js). */
.menu::before {
	content: "";
	position: fixed;
	inset: calc(var(--nav-h) + var(--wpab, 0px)) 0 0 0;
	z-index: -1;
	background: var(--c-overlay);
	background: color-mix(in srgb, var(--c-bezel) 90%, transparent);
	opacity: 0;
	transition: opacity 240ms steps(4, end);
}
.menu.is-open::before { opacity: 1; }
.menu__list {
	display: flex;
	align-items: flex-start;
	gap: var(--space-2);
}
.menu__panel {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	width: 240px;
	padding: var(--space-4);
	background: var(--c-screen);
	color: var(--c-ink);
	box-shadow: inset 0 0 0 1px var(--c-rule);
	clip-path: inset(0 0 100% 0);
	transition: clip-path 240ms steps(6, end), background-color var(--t-ui), color var(--t-ui);
}
/* Five panels step open within ~400ms (the last starts at 160ms). */
/* Steps 360 -> 208: the shortest still fits a 3-line label ("Law School AV") plus its index
   with a clear gap. */
.menu__list li:nth-child(1) .menu__panel { height: 360px; }
.menu__list li:nth-child(2) .menu__panel { height: 312px; transition-delay: 40ms, 0s, 0s; }
.menu__list li:nth-child(3) .menu__panel { height: 272px; transition-delay: 80ms, 0s, 0s; }
.menu__list li:nth-child(4) .menu__panel { height: 240px; transition-delay: 120ms, 0s, 0s; }
.menu__list li:nth-child(5) .menu__panel { height: 208px; transition-delay: 160ms, 0s, 0s; }
/* Five 240px panels need ~1240px; between 992 and 1300 they share the width. */
@media (min-width: 992px) and (max-width: 1299px) {
	.menu__panel { width: calc((100vw - 2 * var(--gutter) - 4 * var(--space-2)) / 5); }
	.menu__label { font-size: 2rem; }
}
.menu.is-open .menu__panel { clip-path: inset(0 0 0 0); }
.menu__panel .hud { color: var(--c-dim); }
.menu__label {
	position: relative;
	font-size: 2.5rem;
	line-height: .8;
	letter-spacing: -.036em;
	padding-block: 4px;
}
.menu__panel:hover,
.menu__panel:focus-visible { background: var(--c-amber); color: var(--c-bezel); }
.menu__panel:hover .hud,
.menu__panel:focus-visible .hud { color: var(--c-bezel); }

/* ==========================================================================
   5. ROLL LINKS
   ========================================================================== */

.roll { display: inline-flex; align-items: center; }
.roll__wrap {
	position: relative;
	display: inline-block;
	overflow: hidden;
	vertical-align: top;
}
.roll__a,
.roll__b {
	display: block;
	transition: transform var(--t-roll);
}
.roll__b {
	position: absolute;
	left: 0;
	top: 0;
	transform: translateY(100%);
	color: var(--c-amber);
}
@media (min-width: 992px) and (hover: hover) {
	.roll:hover .roll__a { transform: translateY(-100%); }
	.roll:hover .roll__b { transform: translateY(0); }
}

/* ==========================================================================
   6. INTRO
   ========================================================================== */

/* The first screen holds the hero AND the "Select a project" heading with its first row of tiles
   at 1440x900 and 1280x720 (the strip follows the selector; its height is still the reserve, which
   covers the selector head and first row with room to spare). Desktop: title with the lede right under it on the left, the attract
   screen on the right from the title's top edge, jump link + HUD count on one bottom row. The
   screen's width is capped by the height left over once the nav, paddings, bottom row and the
   strip (head + tile row) are reserved, so a short window shrinks the screen, never the strip. */
.intro {
	--hero-top: clamp(16px, 3vh, 48px);
	--hero-gap: var(--space-6);
	--hero-bottom: var(--space-6);
	--lede-fs: min(var(--fs-h2), calc(var(--fs-h1) * .56));
	--hero-reserve: calc(var(--nav-h) + var(--hero-top) + var(--hero-gap) + 24px + var(--hero-bottom) + var(--strip-gap) + var(--tile-w) * .625 + 136px);
	padding-top: calc(var(--nav-h) + var(--hero-top));
	padding-bottom: var(--hero-bottom);
	grid-template-rows: auto 1fr auto;
	row-gap: var(--hero-gap);
	align-items: start;
}
/* "Mystery School" is ~7.7em wide: the title never runs under the screen (4 columns). */
.intro__title {
	grid-column: 1 / 5;
	grid-row: 1;
	position: relative;
	font-size: min(var(--fs-h1), calc((4 * var(--col) + 3 * var(--gutter)) / 7.9));
}
/* Secondary to the H1: h2 scale (48px at 1440), one weight lighter, normal tracking; never more
   than 0.56x the title so the hierarchy holds on phones too. Sits directly under the title and
   stops short of the rail. */
.intro__lede {
	grid-column: 1 / 4;
	grid-row: 2;
	position: relative;
	max-width: 14em;
	font-size: var(--lede-fs);
	font-weight: 600;
	line-height: 1.05;
	letter-spacing: normal;
}
.caret {
	display: inline-block;
	width: .42em;
	height: .08em;
	margin-left: .06em;
	background: var(--c-amber);
	vertical-align: baseline;
	animation: cab-blink 1s steps(1) infinite;
}
@keyframes cab-blink {
	0%, 49% { opacity: 1; }
	50%, 100% { opacity: 0; }
}

.screen {
	grid-column: 5 / 9;
	grid-row: 1 / 3;
	justify-self: end;
	position: relative;
	width: min(100%, max(320px, calc((100vh - var(--wpab, 0px) - var(--hero-reserve)) * 16 / 9)));
	width: min(100%, max(320px, calc((100svh - var(--wpab, 0px) - var(--hero-reserve)) * 16 / 9)));
	aspect-ratio: 16 / 9;
	overflow: hidden;
	border-radius: var(--radius-bezel);
	background-color: var(--c-screen);
	background-image: var(--grad-scan);
	box-shadow: var(--shadow-bezel);
	isolation: isolate;
}
.screen__fallback {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	font-family: var(--font-pixel);
	font-size: clamp(2rem, 6vw, 6rem);
	color: var(--c-glyph);
}
/* Manual mode: a darker paper screen (ink at ~10% over the manual screen colour); site.js inks
   the ASCII picture in full-alpha dark amber (#7f4400, 4.3:1 here) with ink for the densest cells. */
html[data-mode="manual"] .screen { --c-screen: #cbc1a6; }
/* The ASCII picture (site.js) replaces the fallback mark; the caption names what it shows. */
.screen__art { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.screen.has-art .screen__fallback { visibility: hidden; }
.screen.is-link { cursor: pointer; }
.screen__cap {
	position: absolute;
	left: 12px;
	bottom: 10px;
	z-index: 6;
	max-width: calc(100% - 24px);
	padding: 4px 6px;
	overflow: hidden;
	background: var(--c-bezel);
	color: var(--c-amber);
	font-family: var(--font-pixel);
	font-size: .8125rem;
	line-height: 1;
	text-transform: uppercase;
	white-space: nowrap;
	text-overflow: ellipsis;
}
.screen__cap:empty,
.no-js .screen__cap { display: none; }
/* Bezel inset line stays on top of the canvas layers. */
.screen::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	box-shadow: var(--shadow-bezel);
	pointer-events: none;
	z-index: 5;
}

.intro__hud {
	grid-column: 5 / 9;
	grid-row: 3;
	justify-self: end;
	display: flex;
	gap: var(--space-4);
}
.intro__jump {
	grid-column: 1 / 4;
	grid-row: 3;
	justify-self: start;
	min-height: 24px;
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.4;
}
@media (min-width: 992px) and (max-height: 820px) {
	:root { --strip-gap: 16px; }
	.intro {
		--hero-gap: var(--space-4);
		--hero-bottom: var(--space-4);
		--lede-fs: min(var(--fs-h2), calc(var(--fs-h1) * .56), 5.2vh);
	}
}

/* Colour mode: two 32px dither swatches in the nav tools (>=600px) or the menu panel (<600px).
   The Cabinet / Manual label shows beside the squares on wide screens and in the menu; the
   "(dark)" / "(light)" hint is for screen readers. The swatch colours are the fixed previews of
   each mode, so they do not follow the active theme. */
.mode-switch {
	display: flex;
	align-items: center;
	gap: var(--space-2);
}
.mode-sq {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 32px;
	padding: 0;
	color: var(--c-dim);
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	cursor: pointer;
	transition: color var(--t-ui);
}
.mode-sq__box {
	position: relative;
	display: block;
	flex: none;
	width: 32px;
	height: 32px;
	overflow: hidden;
}
.mode-sq[data-mode-set="cabinet"] .mode-sq__box { background: #15302a; }
.mode-sq[data-mode-set="manual"] .mode-sq__box { background: #e0d4b6; }
.mode-sq__swatch { position: absolute; inset: 0; }
.mode-sq__box::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	box-shadow: inset 0 0 0 1px var(--c-rule);
	transition: box-shadow var(--t-ui);
}
.mode-sq:hover .mode-sq__box::after { box-shadow: inset 0 0 0 2px var(--c-dim); }
.mode-sq[aria-pressed="true"] { color: var(--c-ink); }
.mode-sq[aria-pressed="true"] .mode-sq__box::after { box-shadow: inset 0 0 0 2px var(--c-amber), inset 0 0 0 4px var(--c-bezel); }
.mode-switch--menu { display: none; }
.no-js .mode-switch { display: none; }

@media (min-width: 2200px) {
	.hud,
	.brand,
	.fx-toggle,
	.menu-btn,
	.mode-sq { font-size: 1.25rem; }
	.fx-toggle { height: 40px; }
	.menu-btn { min-height: 40px; }
	.mark { width: 20px; height: 20px; }
	.mode-sq__box { width: 40px; height: 40px; }
}
@media (max-width: 991px) {
	/* nav squares only; the label stays in the accessible name */
	.mode-switch--nav .mode-sq__label {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		padding: 0;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
	}
}
@media (max-width: 599px) {
	.site-nav .mode-switch--nav { display: none; }
	.js .mode-switch--menu {
		display: flex;
		gap: var(--space-6);
		margin-top: var(--space-2);
		padding: var(--space-4);
		background: var(--c-screen);
		box-shadow: inset 0 0 0 1px var(--c-rule);
		clip-path: inset(0 0 100% 0);
		transition: clip-path 360ms steps(9, end) 180ms;
	}
	.menu.is-open .mode-switch--menu { clip-path: inset(0 0 0 0); }
	.mode-switch--menu .mode-sq { min-height: 44px; gap: var(--space-2); }
	.mode-switch--menu .mode-sq__box { width: 44px; height: 44px; }
}

/* ==========================================================================
   6b. STRIP: every project in one reel under the hero
   Tiles rest as the real shot under a scanline tint, after a one-time pixel
   load-in; hover, keyboard focus and tap show the clean shot at once. A dot-leader ASCII
   ticker steps one character at a time underneath. Loop, drift, sharpen and
   ticker live in js/strip.js; without it this is a static scrollable row.
   The strip sits on an opaque band above the fixed rail line (z 30): the rule stops at its top
   edge and resumes under it. Nav (50) and menu (45) still cover it. Tile width (--tile-w on
   :root) grows with the viewport up to 340px at 2560.
   ========================================================================== */

.strip {
	--ramp: var(--c-screen) var(--c-glyph) var(--c-mint) var(--c-amber) var(--c-ink);
	position: relative;
	z-index: 31;
	margin-top: var(--strip-gap);
	background-color: var(--c-bezel);
}
html[data-mode="manual"] .strip { --ramp: var(--c-ink) var(--c-mint) var(--c-rule) var(--c-glyph) var(--c-screen); }

.strip__head {
	align-items: end;
	row-gap: var(--space-2);
	margin-bottom: var(--space-4);
}
.strip__label { grid-column: 1 / 4; margin: 0; }
.strip__readout {
	grid-column: 4 / 6;
	display: flex;
	align-items: baseline;
	gap: .35em;
	min-width: 0;
	margin: 0;
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	color: var(--c-dim);
	white-space: nowrap;
}
.strip__pos { flex: none; }
.strip__num { font-weight: 400; color: var(--c-amber); }
.strip__now {
	flex: 0 1 auto;
	min-width: 0;
	overflow: hidden;
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1;
	text-transform: uppercase;
	text-overflow: ellipsis;
	color: var(--c-ink);
}
.strip__ctl {
	grid-column: 6 / -1;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: var(--space-4);
	min-width: 0;
}
.strip__hint { flex: 0 1 auto; min-width: 0; margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
@media (max-width: 1199px) { .strip__hint { display: none; } }
html[data-fx="off"] .strip__hint { visibility: hidden; }
.strip__toggle {
	flex: none; /* never shrink under its white-space:pre label (page overflow at 992-1200) */
	min-width: 24px;
	min-height: 24px;
	margin-left: auto;
	padding: 4px 6px;
	color: var(--c-ink);
	cursor: pointer;
	box-shadow: inset 0 0 0 1px var(--c-rule);
	white-space: pre;
}
.strip__toggle:hover { color: var(--c-amber); box-shadow: inset 0 0 0 1px var(--c-amber); }
.strip__toggle[aria-pressed="true"] { color: var(--c-amber); }
.no-js .strip__toggle,
.strip.is-still .strip__toggle { display: none; }

/* Native horizontal scroller: swipe, trackpad and keyboard all work without JS. The amber notch
   over the centre is a background, so it stays put while the row scrolls under it. */
.strip__viewport {
	position: relative; /* containing block for the visually-hidden spans, so they clip too */
	overflow-x: auto;
	overflow-y: hidden;
	overscroll-behavior-x: contain;
	scrollbar-width: none;
	padding-inline: var(--pad);
	scroll-padding-inline: var(--pad);
	background: linear-gradient(var(--c-amber), var(--c-amber)) 50% 0 / 6px 6px no-repeat;
}
.strip__viewport::-webkit-scrollbar { display: none; }
.no-js .strip__viewport,
.strip.is-still .strip__viewport { background: none; }
/* Static row (no JS, reduced motion, FX off): thin scrollbar so the row reads as scrollable. */
.no-js .strip__viewport,
.strip.is-still .strip__viewport {
	scrollbar-width: thin;
	scrollbar-color: var(--c-rule) transparent;
	scroll-snap-type: x proximity;
}
.no-js .strip__item,
.strip.is-still .strip__item { scroll-snap-align: start; }
.strip.is-drag .strip__viewport { cursor: grabbing; }

.strip__list {
	display: flex;
	gap: var(--gutter);
	width: max-content;
	margin: 0;
	/* the 2px focus outline at 3px offset needs 5px: never clipped by the scroller */
	padding: 8px 0 var(--space-4);
	list-style: none;
}
.strip__item { position: relative; flex: none; width: var(--tile-w); }
.strip.is-still .strip__item--clone { display: none; }

.strip__cell {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	color: var(--c-ink);
	text-decoration: none;
	-webkit-user-select: none;
	user-select: none;
	-webkit-tap-highlight-color: transparent;
}
.strip__cell:focus-visible { outline: 2px solid var(--c-amber); outline-offset: 3px; }

.strip__media {
	position: relative;
	display: block;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	isolation: isolate;
	background-color: var(--c-screen);
}
html[data-mode="manual"] .strip__media { box-shadow: 3px 3px 0 var(--c-rule); }
.strip__img,
.strip__px {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0;
}
.strip__img.is-tall { object-position: 50% 35%; }
.strip__px {
	z-index: 1;
	image-rendering: pixelated;
	image-rendering: crisp-edges;
	pointer-events: none;
}
.strip__covers {
	position: absolute;
	inset: 0;
	display: flex;
	gap: 2px;
}
.strip__cover {
	flex: 1 1 0;
	min-width: 0;
	height: 100%;
	object-fit: cover;
	object-position: 50% 30%;
}
/* Until the first mosaic is painted the clean shot waits underneath (JS only). */
.strip__cell.is-wait .strip__img,
.strip__cell.is-wait .strip__covers { visibility: hidden; }
/* Scanlines ride on the mosaic (and the type card) only; the clean shot has none. */
.strip__media::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	background-image: var(--grad-scan);
	pointer-events: none;
}
/* Bezel line: mint on the centre tile, stepping to a 4px amber frame on hover or focus. */
.strip__media::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 3;
	box-shadow: inset 0 0 0 1px var(--c-rule);
	transition: box-shadow 120ms steps(3, end);
	pointer-events: none;
}
.strip__cell.is-center .strip__media::after { box-shadow: inset 0 0 0 1px var(--c-mint); }
.strip__cell:hover .strip__media::after,
.strip__cell:focus-visible .strip__media::after { box-shadow: inset 0 0 0 4px var(--c-amber); }
@media (hover: none) {
	.strip__cell.is-center .strip__media::after { box-shadow: inset 0 0 0 4px var(--c-amber); }
}
/* Rest: the real shot, dimmed and tinted under the scanlines so the row reads at a glance
   without competing with the hovered tile. Hover, focus or tap (.is-clean) drops both at once. */
.strip__cell.is-rest .strip__img,
.strip__cell.is-rest .strip__cover { filter: saturate(0.55) brightness(0.72) contrast(1.05); }
html[data-mode="manual"] .strip__cell.is-rest .strip__img,
html[data-mode="manual"] .strip__cell.is-rest .strip__cover { filter: saturate(0.5) brightness(0.9) sepia(0.25); }
.strip__cell.is-clean .strip__px,
.strip__cell.is-clean .strip__media::before { visibility: hidden; }
html[data-fx="off"] .strip__cell.is-rest .strip__img,
html[data-fx="off"] .strip__cell.is-rest .strip__cover { filter: none; }
/* No JS / FX off: nothing to sharpen, show the clean shot. */
.no-js .strip__px,
.no-js .strip__media::before,
html[data-fx="off"] .strip__px,
html[data-fx="off"] .strip__media::before { display: none; }

/* Type card for projects without screenshots: name, two lines of copy, pixel squares. */
.strip__type {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	padding: 10px 12px;
	color: var(--c-amber);
}
.strip__type-name {
	font-family: var(--font-pixel);
	font-size: clamp(.875rem, .7rem + .35vw, 1.125rem);
	line-height: 1.05;
	text-transform: uppercase;
	overflow-wrap: anywhere;
}
.strip__type-desc {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.3;
	color: var(--c-ink);
}
.strip__type-sq { display: flex; gap: 4px; margin-top: auto; }
.strip__type-sq i { width: 6px; height: 6px; background: var(--c-glyph); }
.strip__type-sq i:first-child { background: var(--c-amber); }

.strip__meta {
	display: flex;
	justify-content: space-between;
	gap: var(--space-2);
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.2;
	color: var(--c-dim);
}
.strip__st { white-space: nowrap; }
.st-live { color: var(--c-mint); }
.st-rel { color: var(--c-dim); }
.st-dev { color: var(--c-coral); }
.st-beta { color: var(--c-amber); }
.strip__name {
	font-family: var(--font-display);
	font-weight: 700;
	font-stretch: 100%;
	font-size: var(--fs-row);
	line-height: 1.05;
	letter-spacing: -.02em;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	transition: color var(--t-ui);
}
.strip__cell:hover .strip__name,
.strip__cell:focus-visible .strip__name { color: var(--c-amber); }
/* The status stays inline (no layout box), so the link reads exactly "01 Name, Live". */
.strip__name > .visually-hidden {
	position: static !important;
	width: auto;
	height: auto;
	margin: 0;
	font-size: 0;
	line-height: 0;
}

/* ASCII ticker: aria-hidden dot-leader line built from the list; steps one character at a time
   and only runs while the belt does. */
.strip__ticker {
	overflow: hidden;
	border-block: 1px solid var(--c-rule);
	padding-block: var(--space-2);
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.4;
	color: var(--c-ink);
	white-space: pre;
	-webkit-mask-image: linear-gradient(90deg, transparent, var(--c-ink) 3%, var(--c-ink) 97%, transparent);
	        mask-image: linear-gradient(90deg, transparent, var(--c-ink) 3%, var(--c-ink) 97%, transparent);
}
.strip__track {
	display: inline-block;
	will-change: transform;
	animation: strip-tick var(--tick-dur, 90s) steps(var(--tick-steps, 900), end) infinite;
}
.strip__track .dots { color: var(--c-dim); }
.strip__track .sq { color: var(--c-amber); }
.strip:not(.is-running) .strip__track { animation-play-state: paused; }
.no-js .strip__ticker { display: none; }
@keyframes strip-tick { to { transform: translateX(-50%); } }

@media (max-width: 991px) {
	.strip { --tile-w: 200px; }
	.strip__label { grid-column: 1 / 3; grid-row: 1; }
	.strip__ctl { grid-column: 3 / -1; grid-row: 1; }
	.strip__readout { grid-column: 1 / -1; grid-row: 2; }
}
@media (max-width: 767px) {
	.strip { --tile-w: min(58vw, 240px); }
	.strip__hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
	.strip__track { animation: none; }
}
@media print {
	.strip__ticker, .strip__toggle, .strip__px { display: none !important; }
}

/* ==========================================================================
   7. GLYPH RAIN DIVIDER
   ========================================================================== */

.rain {
	position: relative;
	height: 72px;
	margin-block: var(--space-30);
}
.rain canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	image-rendering: pixelated;
	-webkit-mask-image: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent);
	mask-image: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent);
}
.no-js .rain,
[data-fx="off"] .rain { visibility: hidden; }

/* ==========================================================================
   8. PROJECTS
   ========================================================================== */

.section-title { grid-column: 4 / 9; position: relative; }

.cabinet { scroll-margin-top: 96px; }
/* Links to a #p- cabinet hand keyboard focus to the cabinet (tabindex=-1, site.js): no ring
   after a pointer click, a quiet inset amber frame when the hand-off came from the keyboard. */
.cabinet:focus { outline: none; }
.cabinet:focus-visible { outline: 1px solid var(--c-amber); outline-offset: 12px; }
.badges {
	grid-column: 1;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-top: var(--space-2);
}
.badge {
	display: inline-block;
	padding: 4px 8px;
	border-radius: 0;
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	white-space: nowrap;
}
.badge--live { background-color: var(--c-mint); color: var(--c-bezel); }
.badge--dev { background-color: var(--c-coral); color: var(--c-bezel); }
.badge--tag { box-shadow: var(--shadow-tag); color: var(--c-ink); }

.cabinet__screen {
	position: relative;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	border-radius: 0;
	background-color: var(--c-screen);
	outline: 1px solid var(--c-rule);
	outline-offset: 8px;
	margin: 9px;
	touch-action: pan-y;
}

.cabinet__scan {
	position: absolute;
	inset: 0;
	z-index: 3;
	pointer-events: none;
	background-image: repeating-linear-gradient(rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, .18) 2px, rgba(0, 0, 0, .18) 3px);
}

/* Video / music load-in: a stepped scanline roll wipes down off the screenshot once (site.js
   adds .is-rolling for ~0.6s). Hover, focus or tap (.is-clean) hides it at once. */
.cabinet__screen.is-rolling .cabinet__scan {
	background-color: var(--c-screen);
	border-top: 2px solid var(--c-amber);
	animation: cab-roll 500ms steps(10, end) both;
}
@keyframes cab-roll {
	from { transform: translateY(0); }
	to { transform: translateY(100%); }
}

/* One-time entry stagger (site.js, FX on only): idx -> name -> badges -> bezel, 40ms apart. */
.cabinet.is-pre .badges { opacity: 0; transform: translateY(6px); }
.cabinet.is-pre .cabinet__screen { outline-color: transparent; }
.cabinet.is-stage .badges { transition: opacity 120ms steps(3, end), transform 120ms steps(3, end); }
.cabinet.is-stage .badges { transition-delay: 80ms; }
.cabinet.is-stage .cabinet__screen { transition: outline-color 160ms steps(4, end) 120ms; }

/* With JS: slides stack in the 16:10 screen. Without JS: every slide is a visible figure. */
.js .ss__slide {
	position: absolute;
	inset: 0;
}
.js .ss__slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: top center;
}
.js .ss__slide:not(.is-active) { display: none; }
.js .ss__cap {
	position: absolute !important;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}
.no-js .ss .cabinet__screen { aspect-ratio: auto; display: grid; gap: var(--space-4); background: none; }
.no-js .ss__cap { padding-top: var(--space-2); font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--c-dim); }
.no-js .ss__bar { display: none; }

/* Vertical 9:16 covers: a portrait screen centred in the column (never cropped to 16:10);
   without JS the covers sit in a row of three */
.ss--vertical .cabinet__screen {
	aspect-ratio: 9 / 16;
	width: min(352px, calc(100% - 18px));
	margin-inline: auto;
}
.js .ss--vertical .ss__slide img { object-position: center; }
.no-js .ss--vertical .cabinet__screen { width: auto; margin-inline: 9px; grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Mixed-aspect sets (render.php adds .ss--fit + --ss-ar): the frame takes the tallest slide's
   ratio and every slide is letterboxed on the screen colour, never stretched or cropped. */
.js .ss--fit .cabinet__screen { aspect-ratio: var(--ss-ar, 16 / 10); }
.js .ss--fit .ss__slide img { object-fit: contain; object-position: center; }

.pfx-layer,
.pfx-baked { image-rendering: pixelated; }
/* the hero field renders at DPR <= 1.5: scale it smoothly, not nearest-neighbour */
.screen .pfx-field { image-rendering: auto; }
.pfx-ascii { z-index: 2; transition: opacity 360ms steps(6, end); }
.is-resolved .pfx-ascii { opacity: 0; }
.pfx-glitch { z-index: 4; }
.pfx-dither { z-index: 2; }

/* Clean on hover: while a screenshot frame is hovered (mouse), keyboard-focused, or tapped clean
   (touch), every overlay (scanlines, ASCII / dither / glitch canvases, any pseudo tint) fades out
   in 150ms so the screenshot is pristine. Reduced motion / FX off make it instant (section 12). */
.cabinet__scan { transition: opacity 150ms linear; }
.cabinet__screen.is-clean .cabinet__scan,
.cabinet__screen.is-clean .pfx-layer,
.cabinet__screen.is-clean::before,
.cabinet__screen.is-clean::after { opacity: 0 !important; transition: opacity 150ms linear; }

.ss__bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
	margin-top: calc(var(--space-4) + 9px);
	/* The controls read their own width: narrow bars swap the dots for a 1/N counter. */
	container-type: inline-size;
}
.ss__btn,
.ss__dot {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 32px;
	padding: 4px 10px;
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	color: var(--c-ink);
	box-shadow: inset 0 0 0 1px var(--c-dim);
	cursor: pointer;
	transition: color var(--t-ui), box-shadow var(--t-ui), background-color var(--t-ui);
}
.ss__btn:hover { color: var(--c-amber); box-shadow: inset 0 0 0 1px var(--c-amber); }
.ss__dots { display: flex; gap: 4px; }
.ss__dot { min-width: 32px; padding: 4px 0; color: var(--c-dim); }
.ss__dot:hover { color: var(--c-amber); }
.ss__dot[aria-current="true"] { background-color: var(--c-amber); color: var(--c-bezel); box-shadow: inset 0 0 0 1px var(--c-amber); }
/* One control row: Prev, dots (or the 1/N counter), Next, and the Pixel view icon at the right
   end. The caption always sits on its own line underneath. */
.ss__count {
	display: none;
	min-width: 3.5em;
	justify-content: center;
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	color: var(--c-ink);
	font-variant-numeric: tabular-nums;
}
@container (max-width: 399px) {
	.ss__dots { display: none; }
	.ss__count { display: inline-flex; }
}
@container (max-width: 479px) {
	.ss__bar:has(.ss__dots > li:nth-child(5)) .ss__dots { display: none; }
	.ss__bar:has(.ss__dots > li:nth-child(5)) .ss__count { display: inline-flex; }
}
/* Pixel view toggle (FX on, every width): an icon button, "Pixel view" is its name. */
.ss__view { display: none; margin-left: auto; min-width: 36px; padding-inline: 8px; }
.js[data-fx="on"] .ss__view { display: inline-flex; }
.ss__view-ico {
	width: 14px;
	height: 14px;
	background-image:
		linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor),
		linear-gradient(currentColor, currentColor), linear-gradient(currentColor, currentColor);
	background-size: 6px 6px;
	background-position: 0 0, 8px 0, 0 8px, 8px 8px;
	background-repeat: no-repeat;
}
.ss__view[aria-pressed="true"] { color: var(--c-bezel); background-color: var(--c-amber); box-shadow: inset 0 0 0 1px var(--c-amber); }
.ss__caption { order: 10; flex: 1 0 100%; min-width: 0; margin: 0; overflow-wrap: anywhere; }

/* Primary CTA: 16px mono with a 44px-tall hit area (11px padding above and below); the amber
   underline sits under the text, not under the padding. */
.cabinet__link {
	min-height: 24px; /* WCAG 2.5.8 floor even where the 11px padding is trimmed */
	margin-top: calc(var(--space-4) - 11px);
	padding-block: 11px;
	font-family: var(--font-mono);
	font-size: 1rem;
	line-height: 1.375;
	color: var(--c-ink);
	background: linear-gradient(var(--c-amber), var(--c-amber)) no-repeat 0 calc(100% - 10px) / 100% 1px;
}
/* Two or more links: one wrapping row in the same CTA style */
.cabinet__links {
	display: flex;
	flex-wrap: wrap;
	gap: 8px var(--space-6); /* 8px between wrapped rows keeps neighbouring 44px hit areas apart */
	margin-top: calc(var(--space-4) - 11px);
}
.cabinet__links .cabinet__link { margin-top: 0; }

/* The Mystery School at >=992: three 9:16 covers per page (slideshow.js adds .is-paged). */
@media (min-width: 992px) {
	.js .ss.is-paged .cabinet__screen {
		display: grid;
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--space-2);
		width: auto;
		aspect-ratio: auto;
		margin-inline: 9px;
		background-image: var(--grad-scan);
	}
	.js .ss.is-paged .ss__slide { position: relative; inset: auto; aspect-ratio: 9 / 16; }
	.js .ss.is-paged .ss__view { display: none; }
}

/* Reels: the first four playlist reels, 2x2, each a link to it on /videos/. */
.cabinet__screen--reels,
.cabinet__screen--styles { aspect-ratio: auto; padding: var(--space-2); }
.reels-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-2);
}
.reels-grid__cell {
	position: relative;
	display: block;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: var(--c-bezel);
}
.reels-grid__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.reels-grid__title {
	position: absolute;
	left: 0;
	bottom: 0;
	z-index: 4;
	max-width: 100%;
	padding: 4px 8px;
	background: var(--c-bezel);
	color: var(--c-ink);
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.3;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.reels-grid__play { color: var(--c-amber); font-size: max(12px, .75em); }
.reels-grid__cell::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 5;
	box-shadow: inset 0 0 0 1px var(--c-rule);
	pointer-events: none;
	transition: box-shadow var(--t-ui);
}
.reels-grid__cell:hover::after,
.reels-grid__cell:focus-visible::after { box-shadow: inset 0 0 0 3px var(--c-amber); }
.reels-grid__cell:hover .reels-grid__title,
.reels-grid__cell:focus-visible .reels-grid__title { background: var(--c-amber); color: var(--c-bezel); }
.reels-grid__cell:hover .reels-grid__play,
.reels-grid__cell:focus-visible .reels-grid__play { color: var(--c-bezel); }
.reels-grid__cell:focus-visible { outline: 2px solid var(--c-amber); outline-offset: 2px; }

/* Styles: six real prompt-set names from the repository, pixel type on the palette. */
.styles-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--space-2);
}
.styles-grid__cell {
	display: grid;
	grid-template-rows: auto 1fr auto;
	gap: var(--space-2);
	min-height: 132px;
	padding: 12px;
	background: var(--c-bezel);
	color: var(--c-ink);
	font-family: var(--font-pixel);
	line-height: 1.1;
	box-shadow: inset 0 0 0 1px var(--c-rule);
}
.styles-grid__cell:nth-child(2) { background: var(--c-mint); color: var(--c-bezel); }
.styles-grid__cell:nth-child(3) { background: var(--c-amber); color: var(--c-bezel); }
.styles-grid__cell:nth-child(4) { background: var(--c-glyph); color: var(--c-ink); }
.styles-grid__cell:nth-child(5) { background: var(--c-coral); color: var(--c-bezel); }
.styles-grid__cell:nth-child(6) { background: var(--c-screen); color: var(--c-ink); }
.styles-grid__num { font-size: 2rem; line-height: 1; }
.styles-grid__name { align-self: end; font-size: 1rem; overflow-wrap: anywhere; }
.styles-grid__sq { display: flex; gap: 4px; }
.styles-grid__sq i { width: 8px; height: 8px; background: currentColor; }
.styles-grid__sq i:nth-child(2) { opacity: .6; }
.styles-grid__sq i:nth-child(3) { opacity: .3; }
/* one-shot stepped load-in (site.js adds .is-in once, on first view); never replays */
.js[data-fx="on"] .cabinet__screen--styles:not(.is-in) .styles-grid__cell { clip-path: inset(0 0 100% 0); }
.js .cabinet__screen--styles .styles-grid__cell { transition: clip-path 360ms steps(6, end); }
.js .cabinet__screen--styles .styles-grid__cell:nth-child(2) { transition-delay: 60ms; }
.js .cabinet__screen--styles .styles-grid__cell:nth-child(3) { transition-delay: 120ms; }
.js .cabinet__screen--styles .styles-grid__cell:nth-child(4) { transition-delay: 180ms; }
.js .cabinet__screen--styles .styles-grid__cell:nth-child(5) { transition-delay: 240ms; }
.js .cabinet__screen--styles .styles-grid__cell:nth-child(6) { transition-delay: 300ms; }
.js .cabinet__screen--styles.is-clean .styles-grid__cell { transition: none; }

/* Type card: fallback for a project with nothing to show yet. */
.cabinet__screen--card {
	display: grid;
	place-content: center;
	justify-items: center;
	gap: var(--space-4);
	aspect-ratio: 16 / 6;
	background-image: var(--grad-scan);
	text-align: center;
}
.card__name { font-family: var(--font-pixel); font-size: clamp(1.5rem, 3vw, 2.5rem); line-height: 1; color: var(--c-amber); }
.card__tag { font-family: var(--font-pixel); font-size: 1rem; line-height: 1; color: var(--c-dim); }

@media (max-width: 479px) {
	.styles-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.styles-grid__cell { min-height: 112px; padding: 10px; }
	.styles-grid__name { font-size: .875rem; }
	.reels-grid__title { font-size: .75rem; padding: 2px 6px; }
}

/* ==========================================================================
   9. CONTACT, CLOCK, FOOTER, WORDMARK
   ========================================================================== */

.contact {
	position: relative;
	padding-top: var(--space-60);
	padding-bottom: var(--space-30);
	row-gap: var(--space-12);
	isolation: isolate;
}
.contact__ground {
	position: absolute;
	inset: 0;
	z-index: -1;
	background: var(--c-bezel);
}
.contact__label { grid-column: 1 / 4; align-self: start; }
.contact__title { grid-column: 4 / 9; position: relative; }
/* STL[HH:MM]: St. Louis wall clock. One unbreakable line; the brackets and colon get a hair of
   side bearing (the display cut sets them tight against the figures) and the amber accent. */
.clock {
	grid-column: 4 / 9;
	margin-top: calc(var(--space-26) - var(--space-12));
	font-size: var(--fs-h2);
	line-height: 1;
	letter-spacing: -.02em;
	color: var(--c-dim);
	font-variant-numeric: tabular-nums lining-nums;
	white-space: nowrap;
}
.clock__time { display: inline-flex; align-items: baseline; }
/* No JS: the server time would go stale in a page cache, so mask the digits as STL[--:--]. */
.no-js .clock__h,
.no-js .clock__m { position: relative; color: transparent; }
.no-js .clock__h::after,
.no-js .clock__m::after { content: "--"; position: absolute; inset: 0; text-align: center; color: var(--c-dim); }
.clock__lbl { color: var(--c-ink); letter-spacing: 0; }
.clock__br,
.clock__sep { color: var(--c-amber); font-weight: 500; }
.clock__lbl + .clock__br { margin: 0 .06em 0 .08em; }
.clock__br:last-of-type { margin-left: .06em; }
.clock__sep { margin: 0 .04em; position: relative; top: -.06em; }
.contact__cta {
	grid-column: 4 / 9;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-4) var(--space-6);
}
.contact__note { flex-basis: 100%; }
.contact__email { user-select: all; }

.button {
	position: relative;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 12px 20px;
	border-radius: var(--radius-pill);
	background-color: var(--c-amber);
	color: var(--c-bezel);
	font-family: var(--font-pixel);
	font-size: 1rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color var(--t-ui);
}
/* Hover slice: drawn by an overlay, never by clipping or moving the button itself. clip-path on
   the button also clipped its hit area, so a quick click on the upper half was lost (review r2). */
.button:hover { background-color: var(--c-ink); }
.button::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	background: inherit;
	opacity: 0;
	pointer-events: none;
}
.button:hover::after { animation: cab-slice-fx 120ms steps(2, end) 1; }
@keyframes cab-slice-fx {
	0% { opacity: 1; clip-path: inset(0 0 50% 0); transform: translateX(4px); }
	50% { opacity: 1; clip-path: inset(50% 0 0 0); transform: translateX(-4px); }
	100% { opacity: 0; clip-path: inset(0); transform: none; }
}
/* Kept for the /videos/ play label (a span inside its button, so the button's hit area is whole). */
@keyframes cab-slice {
	0% { clip-path: inset(0 0 50% 0); transform: translateX(4px); }
	50% { clip-path: inset(50% 0 0 0); transform: translateX(-4px); }
	100% { clip-path: inset(0); transform: none; }
}

.site-footer {
	padding-block: var(--space-6);
	border-top: 1px solid var(--c-rule);
	align-items: center;
}
/* Link row: videos, Law School AV, socials, email (mono, >=24px targets, 8px row gap). */
.footer-links {
	grid-column: 1 / -1;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2) var(--space-6);
	margin-bottom: var(--space-4);
	padding-bottom: var(--space-4);
	border-bottom: 1px solid var(--c-rule);
}
.footer-links__a {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
	color: var(--c-ink);
	text-decoration: underline;
	text-decoration-color: var(--c-rule);
	text-underline-offset: 4px;
	transition: color var(--t-ui), text-decoration-color var(--t-ui);
}
.footer-links__a:hover,
.footer-links__a:focus-visible { color: var(--c-amber); text-decoration-color: var(--c-amber); }
.footer-links__ext { color: var(--c-amber); white-space: pre; }
.site-footer__copy { grid-column: 1 / 4; }
.back-top {
	grid-column: 4 / 9;
	justify-self: start;
	font-family: var(--font-mono);
	font-size: var(--fs-meta);
	line-height: 1.4;
}

.wordmark {
	position: sticky;
	bottom: 0;
	z-index: -1;
	display: flex;
	justify-content: space-between;
	padding-inline: var(--gutter);
	overflow: hidden;
	opacity: 0; /* only the footer reveal shows it (.is-joined), never under the index or cabinets */
	pointer-events: none;
	user-select: none;
	transition: opacity 120ms steps(3, end);
}
.wordmark.is-joined { opacity: 1; }
.wordmark__half {
	position: relative;
	display: block;
	font-size: var(--fs-mark);
	font-weight: 800;
	line-height: .8;
	letter-spacing: -.06em;
	padding-bottom: .06em;
	white-space: nowrap;
	color: var(--c-ink);
}
.wordmark.is-joined .wordmark__half:last-child { color: var(--c-amber); }
.end { height: 1px; }

/* ==========================================================================
   10. FALLBACK PAGES (index.php)
   ========================================================================== */

.page-plain {
	padding-top: calc(var(--nav-h) + var(--space-36) - 48px);
	padding-bottom: var(--space-30);
	row-gap: var(--space-12);
}
.page-plain__entry,
.page-plain__home,
.nf { grid-column: 4 / 9; }
.page-plain__home { justify-self: start; }
.page-plain__content { margin-top: var(--space-6); max-width: 60ch; }
.page-plain__content a { text-decoration: underline; text-underline-offset: 3px; }
.nf { display: grid; gap: var(--space-12); justify-items: start; }
.nf .screen { width: 100%; }

/* ==========================================================================
   11. RESPONSIVE (reference breakpoints 991 / 767 / 479)
   ========================================================================== */

@media (max-width: 991px) {
	:root {
		--cols: 6;
		--gutter: 1.5rem;
		--pad: 2rem;
		--rail-x: calc(var(--pad) + 2 * var(--col) + 1.5 * var(--gutter));
		--tile-w: 200px;
	}
	.section-title,
	.contact__title,
	.clock,
	.contact__cta,
	.page-plain__entry,
	.page-plain__home,
	.nf { grid-column: 3 / -1; }
	/* Stacked: title, lede, screen, bottom row, then the strip. The screen's width is capped by
	   the height left once everything else on the first screen (strip head + tiles too) is set. */
	.intro {
		--hero-fixed: calc(var(--nav-h) + var(--hero-top) + 1.76 * var(--fs-h1) + 2.2 * var(--lede-fs) + 3 * var(--hero-gap) + 24px + var(--hero-bottom) + var(--strip-gap) + var(--tile-w) * .625 + 150px);
		grid-template-rows: auto auto 1fr auto;
	}
	.intro__title { grid-column: 1 / -1; font-size: var(--fs-h1); }
	.intro__lede { grid-column: 1 / -1; grid-row: 2; max-width: 18em; }
	.screen {
		grid-column: 1 / -1;
		grid-row: 3;
		width: min(100%, max(320px, calc((100vh - var(--wpab, 0px) - var(--hero-fixed)) * 16 / 9)));
		width: min(100%, max(320px, calc((100svh - var(--wpab, 0px) - var(--hero-fixed)) * 16 / 9)));
	}
	.intro__jump { grid-column: 1 / 4; grid-row: 4; }
	.intro__hud { grid-column: 4 / -1; grid-row: 4; }
	.contact { padding-top: var(--space-30); }
	.contact__label { grid-column: 1 / 3; }
	.rain { display: none; }
	.rail { display: none; }

	.cabinet { scroll-margin-top: calc(var(--nav-h) + 72px); }
	html { scroll-padding-top: calc(var(--nav-h) + var(--wpab, 0px) + 72px); }
}

@media (max-width: 767px) {
	:root {
		--cols: 4;
		--gutter: .75rem;
		--pad: 1rem;
	}
	.rail { display: none; }
	.section-title,
	.contact__label,
	.contact__title,
	.clock,
	.contact__cta,
	.site-footer__copy,
	.back-top,
	.page-plain__entry,
	.page-plain__home,
	.nf { grid-column: 1 / -1; grid-row: auto; margin-top: 0; }
	/* Phones lead straight into the work. The decorative desktop monitor is redundant
	   beside the project strip and has no hover interaction on a touch screen. */
	:root { --strip-gap: 24px; }
	.intro {
		--hero-top: var(--space-4);
		--hero-gap: var(--space-4);
		--hero-bottom: var(--space-2);
		grid-template-rows: auto auto auto;
	}
	.screen { display: none; }
	.intro__jump { grid-column: 1 / 3; grid-row: 3; }
	.intro__hud { grid-column: 3 / -1; grid-row: 3; }
	.contact { padding-top: var(--space-12); row-gap: var(--space-6); }
	.ss__bar { column-gap: 4px; }
	.ss__dots { gap: 2px; }
	.ss__btn { padding-inline: 8px; font-size: .875rem; }
	.site-footer { row-gap: var(--space-2); }
	.wordmark { display: none; }
}

/* Tablets and phones: the menu is a full-width column of five short panels, scrollable if the
   window is short. */
@media (max-width: 991px) {
	.menu {
		left: var(--gutter);
		max-height: calc(100vh - var(--nav-h) - var(--wpab, 0px) - var(--space-4));
		max-height: calc(100svh - var(--nav-h) - var(--wpab, 0px) - var(--space-4));
		overflow-y: auto;
		overscroll-behavior: contain;
	}
	.menu__list { flex-direction: column; align-items: stretch; }
	.menu__panel { width: 100%; }
	.menu__list li:nth-child(n) .menu__panel { height: 96px; }
	.menu__label { font-size: 2.25rem; }
}

@media (max-width: 479px) {
	.site-nav { gap: var(--space-2); }
	.brand { font-size: .875rem; }
	.ss__btn,
	.ss__dot { min-height: 44px; min-width: 44px; }
	.clock { font-size: 1.75rem; }
}

/* 320px phones: the brand collapses to the mark + "MSM" (the full name stays the accessible
   name, clipped), the FX button drops its label (aria-label keeps the name), gaps tighten, and
   Menu stays fully on screen. */
@media (max-width: 359px) {
	:root { --pad: 12px; --gutter: 12px; }
	.brand__short { display: inline; font-family: var(--font-pixel); font-size: 1rem; line-height: 1; }
	.brand .roll__wrap {
		position: absolute;
		width: 1px;
		height: 1px;
		margin: -1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
	}
	.fx-toggle { gap: 0; min-width: 32px; }
	.fx-toggle__label { display: none; }
	.site-nav__tools { gap: 6px; }
}

/* Touch screens at every width (not only phones): 44px targets for the carousel controls, the
   project index and the project links (WCAG 2.5.5). */
@media (pointer: coarse) {
	.ss__btn,
	.ss__dot { min-height: 44px; min-width: 44px; }
	/* 44px dots need more room before they fit on the control row. */
	@container (max-width: 479px) {
		.ss__dots { display: none; }
		.ss__count { display: inline-flex; }
	}
	@container (max-width: 559px) {
		.ss__bar:has(.ss__dots > li:nth-child(5)) .ss__dots { display: none; }
		.ss__bar:has(.ss__dots > li:nth-child(5)) .ss__count { display: inline-flex; }
	}
	.cabinet__link { min-height: 44px; }
}

/* ==========================================================================
   12. REDUCED MOTION + FX OFF: every animation and transition stops
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*,
	*::before,
	*::after {
		animation: none !important;
		transition: none !important;
	}
}
html[data-fx="off"] { scroll-behavior: auto; }
html[data-fx="off"] *,
html[data-fx="off"] *::before,
html[data-fx="off"] *::after {
	animation: none !important;
	transition: none !important;
}

@media print {
	.site-nav, .rail, .menu, .rain, .wordmark, .screen, .ss__bar { display: none !important; }
	body { background: #fff; color: #000; }
}
