/* ==========================================================================
   CABINET — arcade shell
   --------------------------------------------------------------------------
   Everything is scoped under .cab and driven by custom properties written by
   cabinet.js from the config, so several cabinets can coexist on one page and
   the artwork can be swapped without touching this file.

   Layering is deliberate and is the whole trick:

     .cab-screen   z1   the game / menu / attract layers, black backing
     .cab-art      z2   the cabinet PNG, ON TOP, pointer-events: none
     .cab-ui       z3   controls that must stay clickable

   The artwork sits OVER the screen and its transparent screen hole acts as the
   mask. That means a few px of misalignment between the measured rect and the
   real hole is invisible — the bezel simply covers the overhang — instead of
   the game spilling onto the bezel. Measure with tools/measure_cabinet.py.
   ========================================================================== */

.cab {
	--cab-accent: #3eff6b;
	--cab-accent-alt: #ff2d55;
	--cab-ink: #e9e9ec;
	--cab-screen-bg: #000;

	/* Screen rect as a % of the artwork box — from config.cabinet.screen. */
	--cab-sx: 24.51%;
	--cab-sy: 32.353%;
	--cab-sw: 50.98%;
	--cab-sh: 32.68%;

	--cab-art-aspect: 408 / 612;
	--cab-art-ratio: 0.6667;      /* artWidth / artHeight, as a bare number */
	--cab-game-aspect: 4 / 3;

	/* Height budget for the cabinet. The host page can override this to make
	   room for a sticky header. */
	--cab-maxh: 90vh;
	--cab-maxw: 640px;

	display: flex;
	flex-direction: column;
	align-items: center;
	font-family: "Barlow Condensed", "Arial Narrow", Arial, sans-serif;
	color: var(--cab-ink);
	-webkit-tap-highlight-color: transparent;

	/* Fill the mount. Without this, mounting into a shrink-to-fit box (a flex
	   or grid item, a float, an inline-block) leaves the frame's min(100%, ...)
	   resolving against a content-sized parent, and the cabinet collapses to a
	   fraction of its intended size. */
	width: 100%;
}

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

/* --- cabinet body ------------------------------------------------------- */

/* svh so mobile browser chrome appearing/disappearing can't crop the cabinet.
   Declared as a fallback pair rather than inline, so the override stays in one
   place. */
@supports (height: 1svh) {
	.cab { --cab-maxh: 90svh; }
}

/* Width drives the box and aspect-ratio derives the height — never both.
   The screen is positioned as a PERCENTAGE of this box, so the box has to
   match the artwork's ratio exactly at every size. Setting an explicit height
   as well would let the two disagree the moment a narrow viewport clamped the
   width, and the screen would drift off the cutout. */
.cab-frame {
	position: relative;
	width: min(
		100%,
		var(--cab-maxw),
		calc(var(--cab-maxh) * var(--cab-art-ratio))
	);
	height: auto;
	aspect-ratio: var(--cab-art-aspect);
	line-height: 0;
}

.cab-art {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
	pointer-events: none;  /* clicks fall through to the screen beneath */
	user-select: none;
}

.cab-screen {
	position: absolute;
	left: var(--cab-sx);
	top: var(--cab-sy);
	width: var(--cab-sw);
	height: var(--cab-sh);
	z-index: 1;
	overflow: hidden;
	background: var(--cab-screen-bg);
	display: flex;
	align-items: center;
	justify-content: center;
	line-height: normal;

	/* Screen-relative type. Everything inside is sized in cqw/cqh so the UI
	   scales with the screen, not the page — the same markup has to read at a
	   181px phone cabinet and a 332px desktop one. Without this the cq units
	   would silently fall back to viewport size and the menu would be huge. */
	container-type: size;
}

/* --- stacked screen layers ---------------------------------------------- */

.cab-layer {
	position: absolute;
	inset: 0;
	display: none;
	align-items: center;
	justify-content: center;
	flex-direction: column;
	text-align: center;
	opacity: 0;
	transition: opacity 320ms ease;
}

.cab-layer.is-on {
	display: flex;
	opacity: 1;
}

/* Letterbox: the game keeps its own aspect and is centred, with the screen's
   black backing showing through as the bars. Never stretched. Doing this with
   aspect-ratio rather than a computed transform means resize and
   orientationchange are handled by the browser, with no JS listener to drift. */
.cab-viewport {
	position: relative;
	aspect-ratio: var(--cab-game-aspect);
	max-width: 100%;
	max-height: 100%;
	width: 100%;
	margin: auto;
	background: #000;
}

.cab-viewport > iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/* --- CRT treatment ------------------------------------------------------- */

.cab-fx {
	position: absolute;
	inset: 0;
	z-index: 5;
	pointer-events: none;
}

.cab.fx-scanlines .cab-fx::before {
	content: "";
	position: absolute;
	inset: 0;
	background: repeating-linear-gradient(
		to bottom,
		rgba(0, 0, 0, 0.32) 0 1px,
		rgba(0, 0, 0, 0) 1px 3px
	);
	mix-blend-mode: multiply;
}

.cab.fx-vignette .cab-fx::after {
	content: "";
	position: absolute;
	inset: 0;
	background: radial-gradient(
		ellipse at center,
		rgba(0, 0, 0, 0) 55%,
		rgba(0, 0, 0, 0.55) 100%
	);
}

.cab.fx-glow .cab-screen {
	box-shadow: inset 0 0 22px rgba(62, 255, 107, 0.06);
}

/* --- attract layer ------------------------------------------------------- */

.cab-attract-title {
	font-size: clamp(14px, 8cqw, 40px);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--cab-accent);
	margin: 0;
}

.cab-attract-sub {
	font-size: clamp(8px, 3.4cqw, 16px);
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--cab-ink);
	opacity: 0.75;
	margin: 6px 0 0;
	animation: cab-blink 1.4s steps(2, end) infinite;
}

@keyframes cab-blink {
	50% { opacity: 0.1; }
}

/* --- menu / carousel ----------------------------------------------------- */

.cab-menu-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2%;
	padding: 6% 12%;
	width: 100%;
}

.cab-menu-thumb {
	width: 46%;
	aspect-ratio: 1;
	object-fit: cover;
	border: 1px solid rgba(62, 255, 107, 0.5);
	background: #0a0a0b;
}

.cab-menu-title {
	font-size: clamp(12px, 7cqw, 34px);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--cab-accent);
	margin: 0;
	line-height: 1.1;
}

.cab-menu-hint {
	font-size: clamp(7px, 3cqw, 14px);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	opacity: 0.7;
	margin: 0;
}

.cab-menu-index {
	font-size: clamp(7px, 2.6cqw, 12px);
	letter-spacing: 0.2em;
	opacity: 0.45;
	margin: 0;
}

.cab-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 6;
	width: 12%;
	min-width: 22px;
	aspect-ratio: 1;
	display: grid;
	place-items: center;
	border: 0;
	background: rgba(0, 0, 0, 0.35);
	color: var(--cab-accent);
	font-size: clamp(12px, 5cqw, 26px);
	cursor: pointer;
	padding: 0;
	line-height: 1;
}

.cab-arrow:hover { background: rgba(62, 255, 107, 0.14); }
.cab-arrow.is-prev { left: 0; }
.cab-arrow.is-next { right: 0; }

/* A 12% arrow on a ~200px screen is a 24px target — under the ~44px a finger
   reliably hits. Swiping is the primary way to browse on touch, so these stay
   modest, but they should at least be tappable. */
.cab.has-touch .cab-arrow {
	min-width: 34px;
	background: rgba(0, 0, 0, 0.5);
}

/* The menu layer resolves horizontal swipes itself, so the browser must not
   claim them for scrolling first. */
.cab-menu { touch-action: pan-y; }

/* --- in-game overlay ----------------------------------------------------- */

.cab-gamebar {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 6;
	display: flex;
	gap: 4px;
	padding: 4px;
	justify-content: center;
	opacity: 0;
	transition: opacity 200ms ease;
	pointer-events: none;
}

/* Touch devices have no hover, so a hover-only Expand button is an invisible
   button — and on a ~200px framed screen it is the one control a phone player
   actually needs. Always show it when the pointer is coarse. */
.cab-screen:hover .cab-gamebar,
.cab.has-touch .cab-gamebar,
.cab-gamebar.is-shown {
	opacity: 1;
	pointer-events: auto;
}

.cab-btn {
	font-family: inherit;
	font-size: clamp(7px, 2.6cqw, 12px);
	letter-spacing: 0.12em;
	text-transform: uppercase;
	padding: 4px 9px;
	border: 1px solid rgba(233, 233, 236, 0.35);
	background: rgba(0, 0, 0, 0.7);
	color: var(--cab-ink);
	cursor: pointer;
	line-height: 1.2;
}

.cab-btn:hover {
	border-color: var(--cab-accent);
	color: var(--cab-accent);
}

/* --- expanded play mode --------------------------------------------------
   The framed screen is only ~180-330 CSS px, which is unplayable on a phone.
   Expanding re-styles the SAME DOM — the iframe is never re-created, so the
   game is not reloaded and play is not interrupted. */

.cab.is-expanded {
	position: fixed;
	inset: 0;
	z-index: 99999;
	background: #050506;
	padding: 0;
	justify-content: center;
}

/* height must stay auto: a percentage height on a column flex item resolves
   against the container and beats flex:1, so the frame would claim the whole
   viewport and push the touch controls off the bottom of the screen. */
.cab.is-expanded .cab-frame {
	/* Stays positioned so the screen's inset:0 still resolves against the
	   FRAME. Going static would hand the screen to .cab instead, and it would
	   size itself over the touch controls. */
	position: relative;
	width: 100%;
	height: auto;
	aspect-ratio: auto;
	max-width: none;
	flex: 1 1 0;
	min-height: 0;
}

.cab.is-expanded .cab-art { display: none; }

/* The leaderboard is page furniture, not part of play. */
.cab.is-expanded .cab-scores { display: none; }

.cab.is-expanded .cab-screen {
	position: absolute;
	inset: 0;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
}

.cab.is-expanded .cab-gamebar {
	opacity: 1;
	pointer-events: auto;
	top: 0;
	bottom: auto;
	justify-content: flex-end;
}

/* --- touch controls ------------------------------------------------------
   Per the spec these live in the expanded view, never squeezed into the
   ~200px framed screen. Shown when the device reports coarse pointer. */

.cab-touch {
	display: none;
	width: 100%;
	max-width: 640px;
	padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
	gap: 10px;
	align-items: center;
	justify-content: space-between;
	user-select: none;
	touch-action: none;
}

.cab.is-expanded.has-touch .cab-touch { display: flex; }

.cab-dpad {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-template-rows: repeat(3, 1fr);
	width: 132px;
	aspect-ratio: 1;
	gap: 4px;
}

.cab-pad {
	border: 1px solid rgba(233, 233, 236, 0.28);
	background: rgba(255, 255, 255, 0.06);
	color: var(--cab-ink);
	border-radius: 6px;
	display: grid;
	place-items: center;
	font-size: 15px;
	cursor: pointer;
	padding: 0;
	touch-action: none;
}

.cab-pad.is-down {
	background: var(--cab-accent);
	color: #050506;
}

.cab-pad[data-slot="up"]    { grid-area: 1 / 2; }
.cab-pad[data-slot="left"]  { grid-area: 2 / 1; }
.cab-pad[data-slot="right"] { grid-area: 2 / 3; }
.cab-pad[data-slot="down"]  { grid-area: 3 / 2; }

.cab-buttons {
	display: flex;
	gap: 12px;
	align-items: center;
}

.cab-fire {
	width: 62px;
	height: 62px;
	border-radius: 50%;
	border: 1px solid rgba(0, 0, 0, 0.5);
	background: var(--cab-accent-alt);
	color: #fff;
	font-family: inherit;
	font-size: 14px;
	letter-spacing: 0.08em;
	cursor: pointer;
	touch-action: none;
}

.cab-fire.is-down { filter: brightness(1.5); }

/* --- score panel --------------------------------------------------------- */

.cab-scores {
	width: 100%;
	max-width: 520px;
	margin-top: 14px;
	font-size: 13px;
	color: var(--cab-ink);
}

.cab-scores h3 {
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--cab-accent);
	margin: 0 0 6px;
	font-weight: 500;
}

.cab-scores ol {
	list-style: none;
	margin: 0;
	padding: 0;
	font-family: "Courier New", Courier, monospace;
	font-size: 12.5px;
}

.cab-scores li {
	display: flex;
	justify-content: space-between;
	padding: 2px 0;
	border-bottom: 1px solid rgba(233, 233, 236, 0.1);
}

.cab-scores .cab-empty {
	opacity: 0.5;
	font-style: italic;
}

.cab-scores-tools {
	display: flex;
	gap: 6px;
	margin-top: 8px;
}

/* --- initials entry ------------------------------------------------------ */

.cab-initials {
	position: absolute;
	inset: 0;
	z-index: 8;
	display: none;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 4%;
	background: rgba(0, 0, 0, 0.9);
	text-align: center;
}

.cab-initials.is-on { display: flex; }

.cab-initials-label {
	font-size: clamp(8px, 3.6cqw, 16px);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--cab-accent);
	margin: 0;
}

.cab-initials-input {
	font-family: "Courier New", Courier, monospace;
	font-size: clamp(16px, 9cqw, 44px);
	letter-spacing: 0.3em;
	text-align: center;
	text-transform: uppercase;
	width: 62%;
	background: transparent;
	border: 0;
	border-bottom: 2px solid var(--cab-accent);
	color: var(--cab-ink);
	padding: 2px 0;
	outline: none;
}

@media (prefers-reduced-motion: reduce) {
	.cab-layer { transition: none; }
	.cab-attract-sub { animation: none; }
}
