* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-size: 16px; font-family: 'Arial', sans-serif; background: #ffffff; color: #000; text-align: center; }
p { padding: 15px 0px; }

canvas { display: block; margin: 0 auto; }

/* --- Touch devices --- */
/* The notch/rounded-corner insets, republished as custom properties so JS can
   read the resolved numbers back (env() is not otherwise visible to script).
   Zero on every device without them. */
:root {
	--safe-left: env(safe-area-inset-left, 0px);
	--safe-right: env(safe-area-inset-right, 0px);
	/* Added for the touch menu button, which sits in the top corner where a
	   landscape phone's notch actually is. Left/right were enough while every
	   fixed control lived along the bottom. */
	--safe-top: env(safe-area-inset-top, 0px);
	/* Touch-zone geometry, in one place because it is tuned against a real
	   phone rather than derived. The gap is centred on the screen because that
	   is where the home indicator is: a thumb reaching for "right" used to
	   arrive at the 50% line and trip the app switcher. */
	/* Fourth pass, tuned on the phone rather than derived. The move pair's outer
	   edge comes in another two ball widths (a ball is ~37px on a 742px-wide
	   court, so ~74px, ~8.7% of an 852pt viewport), landing at 19.4% instead of
	   28%. The two are now equal -- they were 17/11, which read as one long
	   button and one stub. Jump still matches their sum, so the layout stays
	   symmetric about the centre: 19.4% of controls, a 61.2% dead strip, 19.4%
	   of controls. */
	--zone-move-left-w: 9.7%;
	--zone-move-right-w: 9.7%;
	--zone-gap-w: 61.2%;        /* dead centre: 19.4%..80.6% */
}
/* None of the browser's own touch gestures do anything useful over this game:
   the canvas already sizes itself to the window, so pinch-zoom only crops it,
   and a swipe meant for a slime should never scroll the page instead. The
   court is a fixed 2:1 box that can overhang a narrow portrait window (see
   CANVAS_MIN_W, helpers.js) — the rotate prompt covers that case, and
   overflow-x keeps the page from sliding sideways behind it meanwhile. */
html, body { overflow-x: hidden; overscroll-behavior: none; }
body {
	-webkit-text-size-adjust: 100%;          /* don't reflow our own HUD text */
	-webkit-tap-highlight-color: transparent; /* no grey flash on every tap */
	padding-left: var(--safe-left);
	padding-right: var(--safe-right);
}
canvas { touch-action: none; user-select: none; -webkit-user-select: none; }
button { touch-action: manipulation; }      /* skips the double-tap-zoom wait */

/* --- Portrait-phone rotate prompt (Slime.html, updateRotatePrompt) --- */
.rotate-prompt {
	position: fixed;
	inset: 0;
	z-index: 50;  /* above the drawers (40), which a rotate must also outrank */
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 18px;
	background: #0a0c12; /* opaque: the title buttons and corner controls are
	                        fixed-position and would otherwise show through */
	color: #fff;
	padding: 24px;
}
.rotate-prompt.hidden { display: none; }
/* A phone outline that tips through the turn being asked for — cheaper and
   sharper than shipping an icon, and it re-reads on every loop. */
.rotate-prompt-phone {
	width: 52px;
	height: 88px;
	border: 3px solid #fff;
	border-radius: 11px;
	animation: rotate-prompt-tip 2.4s ease-in-out infinite;
}
@keyframes rotate-prompt-tip {
	0%, 28% { transform: rotate(0deg); }
	52%, 100% { transform: rotate(-90deg); }
}
/* The scene has to survive its parent's rotation. The phone turns -90deg, so
   content inside it turns too; rotating the scene +90deg cancels that out and
   it lands upright on screen. Because the two rotations sum to zero, the box
   is authored at its FINAL on-screen size (82x46, the phone's interior once
   sideways) rather than in the phone's portrait coordinates. */
.rotate-prompt-mini {
	position: absolute;
	width: 82px;
	height: 46px;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%) rotate(90deg);
	overflow: hidden;
	border-radius: 3px;
	/* Held back until the tip finishes at 52% of the cycle, so the payoff reads
	   as the RESULT of turning rather than something already there. */
	opacity: 0;
	animation: rotate-prompt-reveal 2.4s ease-in-out infinite;
}
@keyframes rotate-prompt-reveal {
	0%, 46% { opacity: 0; }
	60%, 92% { opacity: 1; }
	100% { opacity: 0; }
}
.mini-ground {
	position: absolute;
	left: 0; right: 0; bottom: 0;
	height: 9px;
	background: rgba(255, 255, 255, 0.22);
}
.mini-net {
	position: absolute;
	left: 50%;
	bottom: 9px;
	margin-left: -1px;
	width: 2px;
	height: 15px;
	background: rgba(255, 255, 255, 0.65);
}
/* Domes, the same half-circle the real game is built from. */
.mini-slime {
	position: absolute;
	bottom: 9px;
	width: 18px;
	height: 9px;
	border-radius: 9px 9px 0 0;
}
.mini-slime-a { left: 11px; background: #ffe600; animation: mini-hop-a 2.4s ease-in-out infinite; }
.mini-slime-b { right: 11px; background: #fff;    animation: mini-hop-b 2.4s ease-in-out infinite; }
.mini-ball {
	position: absolute;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: #ffe600;
	animation: mini-rally 2.4s ease-in-out infinite;
}
/* One rally, timed to the window the scene is actually visible in: the ball
   leaves the yellow slime, clears the net and arrives as the loop fades. */
@keyframes mini-rally {
	0%, 55%   { left: 16px; bottom: 18px; }
	70%       { left: 40px; bottom: 34px; }
	86%, 100% { left: 62px; bottom: 18px; }
}
@keyframes mini-hop-a {
	0%, 52%, 62%, 100% { height: 9px; }
	57% { height: 13px; }
}
@keyframes mini-hop-b {
	0%, 80%, 92%, 100% { height: 9px; }
	86% { height: 13px; }
}
@media (prefers-reduced-motion: reduce) {
	.rotate-prompt-phone { animation: none; transform: rotate(-90deg); }
	/* The scene still shows -- it is the point of the picture -- but nothing in
	   it moves, and it no longer waits for a tip that never happens. */
	.rotate-prompt-mini { animation: none; opacity: 1; }
	.mini-ball { animation: none; left: 40px; bottom: 30px; }
	.mini-slime-a, .mini-slime-b { animation: none; }
}
/* --- On-screen touch controls (Slime.html, updateTouchControls) --- */
/* A full-viewport layer that ignores pointers except on the buttons, so the
   court behind it keeps receiving its own taps. Pinned to the viewport edges
   rather than positioned off the canvas each frame: the gutters they live in
   are reserved by fitCanvasToWindow (helpers.js), so the edges ARE the
   gutters. Vertically centred, where thumbs rest on a phone held sideways. */
.touch-controls {
	position: fixed;
	inset: 0;
	z-index: 25;  /* over the canvas and corner controls, under the drawers */
	pointer-events: none;
}
.touch-controls.hidden { display: none; }
.touch-cluster {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	display: flex;
	gap: 8px;
	pointer-events: auto;
}
.touch-cluster-move { left: calc(var(--safe-left) + 10px); }
.touch-cluster-jump { right: calc(var(--safe-right) + 10px); }
.touch-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 58px;
	height: 76px;
	padding: 0;
	border: 2px solid rgba(255, 255, 255, 0.5);
	border-radius: 14px;
	/* Deliberately theme-neutral: these sit over eight different skies, and a
	   translucent dark plate with a white glyph reads on all of them. */
	background: rgba(12, 14, 22, 0.45);
	color: #fff;
	cursor: pointer;
	touch-action: none;      /* the button handles the gesture, not the browser */
	user-select: none;
	-webkit-user-select: none;
}
.touch-button-jump { width: 72px; height: 92px; border-radius: 18px; }
.touch-button svg { width: 26px; height: 26px; fill: currentColor; }
.touch-button-jump svg { width: 32px; height: 32px; }
.touch-button.pressed {
	background: rgba(255, 255, 255, 0.32);
	border-color: rgba(255, 255, 255, 0.85);
}

.rotate-prompt-title { font: 700 22px 'Arial', sans-serif; }
.rotate-prompt-sub { font: 400 15px 'Arial', sans-serif; opacity: 0.75; }

/* Visible only to screen readers (standard clip-based hide) */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* --- Title screen start buttons --- */
.title-buttons {
	position: fixed;
	z-index: 15;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 12px;
	transform: translate(-50%, -50%);
	pointer-events: none;
}
.title-buttons.hidden { display: none; }
.title-button-row {
	display: flex;
	align-items: flex-start;
	gap: 20px;
	justify-content: center;
	flex-wrap: wrap;
}
.title-button-group {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 6px;
}
.title-button {
	pointer-events: auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 16px 34px;
	font: 700 20px 'Arial', sans-serif;
	color: #fff;
	background: var(--button-accent, #2563eb);
	border: none;
	border-radius: 999px;
	cursor: pointer;
	box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
	transition: filter 0.15s ease, transform 0.1s ease;
	white-space: nowrap;
}
/* A fixed hover color doesn't work once the fill itself is themed (see
   --button-accent above, applyThemeToPage in themes.js) — darken whatever
   the current accent is instead. */
.title-button:hover { filter: brightness(0.88); }
.title-button:active { transform: translateY(1px); }
.title-hint {
	font: 600 12px 'Arial', sans-serif;
	color: #fff;
	background: rgba(0, 0, 0, 0.55);
	padding: 6px 14px;
	border-radius: 999px;
	display: none; /* toggled on by updateTitleButtons() in helpers.js */
}

/* --- Title-screen theme browser (.theme-picker, Slime.html) --- */
/* Home-site line under the title-screen controls. Hidden by default and
   revealed only when build.mjs --itch has stamped <html data-target="itch">,
   so the real site never tells visitors to go visit itself. Same translucent
   treatment as .theme-picker-row above it, which is what makes it legible
   over all eight themes' skies without per-theme work. */
.itch-home { display: none; }
[data-target="itch"] .itch-home {
	display: inline-block;
	margin-top: 8px;
	padding: 5px 12px;
	border-radius: 999px;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	font: 600 12px 'Arial', sans-serif;
	text-decoration: none;
	white-space: nowrap;
}
[data-target="itch"] .itch-home:hover,
[data-target="itch"] .itch-home:focus-visible { background: rgba(0, 0, 0, 0.75); }

.theme-picker {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 6px;
}
.theme-picker-row {
	display: flex;
	align-items: center;
	gap: 4px;
	background: rgba(0, 0, 0, 0.55);
	border-radius: 999px;
	padding: 2px;
}
/* Same themed fill as .title-button, at a size that reads as secondary to
   the two start buttons above it. */
.theme-arrow {
	pointer-events: auto;
	width: 30px;
	height: 30px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font: 700 20px 'Arial', sans-serif;
	line-height: 1;
	color: #fff;
	background: var(--button-accent, #2563eb);
	border: none;
	border-radius: 50%;
	cursor: pointer;
	transition: filter 0.15s ease;
}
.theme-arrow:hover { filter: brightness(0.88); }
.theme-name {
	font: 700 13px 'Arial', sans-serif;
	color: #fff;
	min-width: 132px; /* widest theme name, so stepping through doesn't
	                     shuffle the arrows left and right under the cursor */
	text-align: center;
	white-space: nowrap;
}
/* Same translucent scrim as .title-hint, and for the same reason: these sit
   directly on the themed scene, so on a white-sky theme (High Contrast)
   white dots on their own were invisible. */
.theme-dots {
	display: flex;
	gap: 5px;
	background: rgba(0, 0, 0, 0.55);
	border-radius: 999px;
	padding: 5px 8px;
}
.theme-dot {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.45);
}
.theme-dot.on { background: #fff; }

/* --- One-time "try Performance mode" hint (perf-hint.js) --- */
.perf-hint {
	position: fixed;
	z-index: 15;
	transform: translate(-50%, 0);
	font: 600 13px 'Arial', sans-serif;
	color: #fff;
	background: rgba(0, 0, 0, 0.7);
	padding: 8px 16px;
	border-radius: 999px;
	pointer-events: none;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.perf-hint.hidden { display: none; }

/* --- 2P pre-match options --- */
.two-player-options {
	position: fixed;
	z-index: 15;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
	transform: translate(-50%, -50%);
	pointer-events: none;
}
.two-player-options.hidden { display: none; }
.tpo-column {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
}
/* Same pill as .title-button (already themed via --button-accent), just
   smaller — four of these stack where .title-button normally sits alone. */
.tpo-button {
	pointer-events: auto;
	padding: 10px 24px;
	font-size: 16px;
	white-space: nowrap;
}
.tpo-back {
	pointer-events: auto;
	background: none;
	border: none;
	color: #fff;
	font: 600 13px 'Arial', sans-serif;
	text-decoration: underline;
	text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
	cursor: pointer;
	padding: 4px 8px;
}

/* --- Replay scrubbing controls --- */
.replay-controls {
	position: fixed;
	z-index: 15;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	transform: translate(-50%, 0);
}
.replay-controls.hidden { display: none; }
.replay-controls-row {
	display: flex;
	align-items: center;
	gap: 10px;
}
.replay-controls input[type="range"] {
	width: 200px;
	accent-color: #2563eb;
	cursor: pointer;
}
.replay-return-button {
	padding: 8px 16px;
	font: 600 13px 'Arial', sans-serif;
	color: #fff;
	background: rgba(0, 0, 0, 0.55);
	border: 1px solid rgba(255, 255, 255, 0.35);
	border-radius: 999px;
	cursor: pointer;
	white-space: nowrap;
	transition: background 0.15s ease;
}
.replay-return-button:hover { background: rgba(0, 0, 0, 0.75); }
/* Quiet exit hint, off to the side of the controls rather than a center-
   court banner (see the Slime.html comment above .replay-controls). */
.replay-hint {
	font: 600 12px 'Arial', sans-serif;
	color: #fff;
	background: rgba(0, 0, 0, 0.55);
	padding: 4px 12px;
	border-radius: 999px;
}

/* --- Persistent "recording light" replay indicator (corner-anchored) --- */
.replay-indicator {
	position: fixed;
	z-index: 15;
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 6px 12px;
	font: 700 12px 'Arial', sans-serif;
	letter-spacing: 0.5px;
	color: #fff;
	background: rgba(0, 0, 0, 0.55);
	border-radius: 999px;
	pointer-events: none;
}
.replay-indicator.hidden { display: none; }
.replay-dot {
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: #e11d48;
	animation: replay-dot-pulse 1.2s ease-in-out infinite;
}
@keyframes replay-dot-pulse {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.3; }
}

/* --- Corner trigger buttons (settings gear + "How to play") --- */
.corner-controls {
	position: fixed;
	bottom: 16px;
	right: 16px;
	z-index: 20;
	display: flex;
	align-items: center;
	gap: 10px;
}
/* --- Whole-screen touch zones (beta) ---
   The right half jumps; the left half splits into move-left and move-right.
   Fixed to the viewport rather than to the canvas: the court is centred and
   the zones are not, and a thumb at the very edge of the glass should still
   count. Below .corner-controls (20) and the menu button (25) on purpose, so
   those stay tappable through the jump zone. */
.touch-zones {
	position: fixed;
	inset: 0;
	z-index: 12;
	touch-action: none;          /* no scroll/zoom/double-tap while steering */
	-webkit-tap-highlight-color: transparent;
	-webkit-user-select: none;
	user-select: none;
}
.touch-zones.hidden { display: none; }

.touch-zone {
	position: absolute;
	top: 0;
	/* All the way to the glass. Earlier versions held back the home-indicator
	   inset, then the legend band too, and both cost grip height -- the thing
	   the low grip is good for, since fingers down there don't cover the slimes.
	   The inset is given up deliberately: the indicator is CENTRED, and the
	   controls now sit in the outer fifth of each side, so the part of that
	   strip a thumb actually lands on is far from where the gesture starts. The
	   legend is pointer-events: none, so a tap on the word LEFT falls through to
	   the zone it names. */
	bottom: 0;
	/* Stays invisible even when pressed. Tinting the zone itself washed the
	   whole column across the court, which reads as a browser selection
	   highlight rather than as game feedback -- Anil could not tell which it
	   was. The press shows on the label instead (below), where the control
	   actually appears to be. */
	background: transparent;
}

/* Left, right, a deliberate gap over the home indicator, then jump. */
#zoneLeft  { left: 0; width: var(--zone-move-left-w); }
#zoneRight { left: var(--zone-move-left-w); width: var(--zone-move-right-w); }
#zoneJump  {
	left: calc(var(--zone-move-left-w) + var(--zone-move-right-w) + var(--zone-gap-w));
	right: 0;
	width: auto;
}

/* The legend sits over the strip of height fitCanvasToWindow reserves, so it
   never covers the HUD. pointer-events: none is load-bearing -- a thumb
   resting on a label must still drive the zone underneath it. */
.touch-zone-legend {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 22px;
	display: flex;
	align-items: center;
	pointer-events: none;
	font: 700 11px 'Arial', sans-serif;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.82);
	/* No background here: it moves to the segments, so the dead strip can show
	   the page through and read as a gap rather than part of one long bar. */
}
/* Widths mirror the zones exactly, so a label always sits over the area it
   names -- that correspondence is the whole point of the strip. */
.touch-zone-legend span {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 100%;
	background: rgba(0, 0, 0, 0.42);
}
/* The gap is the page's own background, which is what makes the end of each
   pressable area visible instead of inferred. */
.touch-zone-legend .zone-gap { background: transparent; }

/* Press feedback, on the label rather than the column. The legend follows all
   three zones in the DOM, so a sibling selector can do this without touching
   the JS. The segment is far wider than a thumb, so the lit edges show even
   with a finger on it. */
#zoneLeft.pressed  ~ .touch-zone-legend span:nth-child(1),
#zoneRight.pressed ~ .touch-zone-legend span:nth-child(2),
#zoneJump.pressed  ~ .touch-zone-legend span:nth-child(4) {
	background: rgba(255, 255, 255, 0.34);
	color: #fff;
}
.touch-zone-legend span { transition: background 90ms ease, color 90ms ease; }
/* Each label sits over the zone it names, gap included -- the empty middle
   segment is how a player learns there is nothing to press there. */
.touch-zone-legend span:nth-child(1) { width: var(--zone-move-left-w); }
.touch-zone-legend span:nth-child(2) { width: var(--zone-move-right-w); }
.touch-zone-legend span:nth-child(3) { width: var(--zone-gap-w); }
.touch-zone-legend span:nth-child(4) { flex: 1 1 auto; }
/* Hairlines on the boundaries: the labels say where the zones are, these say
   exactly where one stops. */
.touch-zone-legend span + span { box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.28); }
/* The gap gets no divider on its far side: one line marks where "right"
   stops, and the next marks where "jump" starts, which is the honest picture
   of a dead strip between them. */
.touch-zone-legend .zone-gap { box-shadow: none; }

/* --- Consolidated touch menu (beta) ---
   One target replacing pause/settings/how-to-play on a touch device. Top
   right on purpose: thumbs rest along the bottom edge, and the coming
   full-screen touch zones want the bottom left and right for movement and
   jump. Hidden unless the build is beta AND there is no fine pointer, so
   desktop and the live site are untouched. */
.touch-menu-toggle { display: none; }
html.zone-controls .touch-menu-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	position: fixed;
	/* Inside the notch/rounded-corner insets the page already reads back
	   (safeAreaInsets, helpers.js), not flush to the glass. */
	top: calc(var(--safe-top, 0px) + 10px);
	right: calc(var(--safe-right, 0px) + 10px);
	z-index: 25;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(20, 22, 30, 0.62);
	color: #fff;
	line-height: 1;
	cursor: pointer;
	/* The zones this button sits over are pointer-driven; without this a press
	   here can also scroll or zoom the page on some mobile browsers. */
	touch-action: manipulation;
	-webkit-tap-highlight-color: transparent;
}
html.zone-controls .touch-menu-toggle:active { background: rgba(20, 22, 30, 0.85); }
/* Same currentColor idiom as .touch-button svg above. */
.touch-menu-toggle svg { width: 22px; height: 22px; fill: currentColor; }

/* The three it replaces stand down — but .tip-prompt lives in the same row
   and must not, since the run-end nudge still earns its place. */
html.zone-controls .corner-controls .icon-btn,
html.zone-controls .corner-controls .help-toggle { display: none; }

/* Menu entries reuse .pause-menu-button; the Tip one is an anchor, so it
   needs the bits a <button> got for free. */
#pauseMenuTip {
	display: block;
	text-align: center;
	text-decoration: none;
	/* An anchor otherwise takes the drawer's link colour and reads as disabled
	   next to the real buttons. */
	color: #fff;
	box-sizing: border-box;
}
#pauseMenuTip:hover, #pauseMenuTip:focus-visible { color: #fff; }

/* --- Tip prompt (updateTipPrompt, helpers.js) ---
   Sits in .corner-controls beside the other buttons, so it inherits the same
   chrome in every theme and never overlaps the canvas art. Gold at all times
   so it reads as a thing to press rather than another grey control; .loud is
   the periodic nudge, which pulses a glow instead of changing colour -- the
   button keeps one identity and just breathes for a few seconds. */
.tip-prompt {
	display: inline-flex;
	align-items: center;
	padding: 9px 14px;
	font: 600 13px 'Arial', sans-serif;
	color: #2a1c05;
	background: #ffce4d;
	border-radius: 999px;
	text-decoration: none;
	white-space: nowrap;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
	transition: background 140ms ease;
}
.tip-prompt:hover, .tip-prompt:focus-visible { color: #2a1c05; background: #ffe08a; }
.tip-prompt.loud { animation: tip-glow 2.2s ease-in-out 3; }
@keyframes tip-glow {
	0%, 100% { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); }
	50%      { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 16px 5px rgba(255, 206, 77, 0.8); }
}
/* Same preference the interludes honour (interlude.js): no pulsing for
   anyone who asked for reduced motion. They still get a steady stronger
   glow, so the periodic nudge isn't lost -- just held still. */
@media (prefers-reduced-motion: reduce) {
	.tip-prompt.loud {
		animation: none;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), 0 0 14px 4px rgba(255, 206, 77, 0.75);
	}
}
.tip-prompt.hidden { display: none; }

/* --- Step-up offer (updateStepUpOffer, helpers.js) ---
   The tip prompt's shape, deliberately not its gold: the two can share the
   row on a finished run, and two identical pills side by side would read as
   one offer split in half. */
.step-up-prompt {
	display: inline-flex;
	align-items: center;
	padding: 9px 14px;
	font: 600 13px 'Arial', sans-serif;
	color: #fff;
	background: #2563eb;
	border: none;
	border-radius: 999px;
	cursor: pointer;
	white-space: nowrap;
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
	transition: background 140ms ease;
}
.step-up-prompt:hover, .step-up-prompt:focus-visible { background: #3b7bff; }
.step-up-prompt.hidden { display: none; }

.help-toggle {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 9px 15px;
	font: 600 14px 'Arial', sans-serif;
	color: #fff;
	background: #2563eb;
	border: none;
	border-radius: 999px;
	cursor: pointer;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
	transition: background 0.15s ease, transform 0.1s ease;
}
.help-toggle:hover { background: #1d4ed8; }
.help-toggle:active { transform: translateY(1px); }
.help-toggle .help-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 18px;
	height: 18px;
	font-weight: 700;
	background: rgba(255, 255, 255, 0.22);
	border-radius: 50%;
}
.icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	font-size: 20px;
	line-height: 1;
	color: #fff;
	background: #2563eb;
	border: none;
	border-radius: 50%;
	cursor: pointer;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
	transition: background 0.15s ease, transform 0.1s ease;
}
.icon-btn:hover { background: #1d4ed8; }
.icon-btn:active { transform: translateY(1px); }

/* --- Backdrop --- */
.help-backdrop {
	position: fixed;
	inset: 0;
	z-index: 30;
	background: rgba(0, 0, 0, 0.45);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.25s ease, visibility 0.25s ease;
}
.help-backdrop.open { opacity: 1; visibility: visible; }

/* --- Slide-in drawer --- */
.help-drawer {
	position: fixed;
	top: 0;
	right: 0;
	z-index: 40;
	width: 380px;
	max-width: 90vw;
	height: 100%;
	background: #1e2233;
	color: #e6e9f0;
	text-align: left;
	box-shadow: -4px 0 24px rgba(0, 0, 0, 0.35);
	transform: translateX(100%);
	transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
	display: flex;
	flex-direction: column;
}
.help-drawer.open { transform: translateX(0); }

.help-drawer header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 18px 20px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.1);
	flex: 0 0 auto;
}
.help-drawer header h2 { font-size: 18px; font-weight: 700; color: #fff; }
.help-close {
	background: none;
	border: none;
	color: #aab;
	font-size: 26px;
	line-height: 1;
	cursor: pointer;
	padding: 0 4px;
	transition: color 0.15s ease;
}
.help-close:hover { color: #fff; }

.help-body { padding: 8px 20px 28px; overflow-y: auto; flex: 1 1 auto; }

.help-section { margin-top: 22px; }
.help-section h3 {
	font-size: 13px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 1px;
	color: #7c8bd0;
	margin-bottom: 10px;
}
.help-section p { padding: 0; margin-bottom: 8px; font-size: 14px; line-height: 1.5; color: #c7ccda; }

/* Key / description rows */
.help-row {
	display: flex;
	align-items: baseline;
	gap: 12px;
	padding: 6px 0;
	font-size: 14px;
	line-height: 1.4;
	border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.help-row:last-child { border-bottom: none; }
.help-keys { flex: 0 0 108px; display: flex; flex-wrap: wrap; gap: 4px; }
.help-desc { flex: 1; color: #c7ccda; }

kbd {
	display: inline-block;
	min-width: 22px;
	padding: 2px 7px;
	font: 600 12px 'Arial', sans-serif;
	text-align: center;
	color: #1e2233;
	background: #e6e9f0;
	border-radius: 5px;
	box-shadow: 0 2px 0 #a9b0c4;
}

/* Scoring list */
.help-score { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; font-size: 14px; border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
.help-score:last-child { border-bottom: none; }
.help-score .label { color: #c7ccda; }
.help-score .value { color: #fff; font-weight: 600; white-space: nowrap; }
.help-score .flawless-icon { color: #ffd54f; } /* the match-point gold (MATCH_POINT_PIP_GLOW_COLOR) */
.help-note { margin-top: 12px; font-size: 13px; font-style: italic; color: #8b93a7; }
/* First links in the drawer arrived with the Privacy section. Underlined
   rather than colour-only, so they read as links in the High Contrast
   theme and for anyone who can't separate the hues. */
.help-section a { color: #9fc4ff; text-decoration: underline; }
.help-section a:hover, .help-section a:focus-visible { color: #c9ddff; }

/* Settings */
.help-setting { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; font-size: 14px; color: #c7ccda; }
.help-setting input { margin-top: 3px; width: 16px; height: 16px; flex: 0 0 auto; cursor: pointer; }
.help-setting strong { color: #fff; font-weight: 600; }
.help-setting .help-note { margin-top: 3px; font-style: normal; display: block; }

.help-select-setting label { display: block; color: #fff; font-weight: 600; font-size: 14px; margin-bottom: 8px; }
.help-select-setting select {
	width: 100%;
	padding: 8px 10px;
	font: 14px 'Arial', sans-serif;
	color: #fff;
	background: #262b40;
	border: 1px solid rgba(255, 255, 255, 0.15);
	border-radius: 8px;
	cursor: pointer;
}
.help-select-setting .help-note { margin-top: 8px; font-style: normal; display: block; }

/* Pause menu action buttons — same color/radius/shadow as .title-button,
   but block/full-width to sit in the drawer's padded column instead of
   floating over the canvas. */
.pause-menu-button {
	display: block;
	width: 100%;
	padding: 12px 20px;
	font: 700 15px 'Arial', sans-serif;
	color: #fff;
	background: #2563eb;
	border: none;
	border-radius: 999px;
	cursor: pointer;
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
	transition: background 0.15s ease, transform 0.1s ease;
}
.pause-menu-button:hover { background: #1d4ed8; }
.pause-menu-button:active { transform: translateY(1px); }
.pause-menu-button + .help-note { margin-top: 8px; }
.pause-menu-button + .pause-menu-button,
/* Resume sits directly above the restart ROW, and neither of the other two
   selectors matches a div -- so this pair had no gap at all. */
.pause-menu-button + #pauseMenuRestartRow,
#pauseMenuRestartRow + .pause-menu-button { margin-top: 16px; }

/* A landscape phone gives the drawer about 340px of body height, and the
   consolidated menu's six entries plus their notes need more than that, so
   the nav fell below the fold. Tightened rather than left to scroll: the
   whole point of the menu is that everything in it is reachable. Scoped to
   short screens on touch, so the desktop drawer is unchanged. */
@media (max-height: 480px) {
	html.touch-mode #pauseMenuDrawer .pause-menu-button { padding: 9px 18px; font-size: 14px; }
	html.touch-mode #pauseMenuDrawer .pause-menu-button + .pause-menu-button,
	html.touch-mode #pauseMenuDrawer .pause-menu-button + #pauseMenuRestartRow,
	html.touch-mode #pauseMenuDrawer #pauseMenuRestartRow + .pause-menu-button { margin-top: 10px; }
	html.touch-mode #pauseMenuDrawer .help-section { margin-top: 14px; }
	/* The explanatory lines are the first thing to go: they cost ~40px each and
	   the buttons they describe say the same thing in fewer words. */
	html.touch-mode #pauseMenuDrawer .help-note { display: none; }
}

/* Scroll affordance. iOS hides scrollbars until you actually scroll, so a
   drawer taller than its body looks like it simply ends -- which is how the
   consolidated menu's nav entries went unnoticed. Set by syncDrawerScrollHint
   (helpers.js) when a panel opens, since CSS alone can't tell. */
.help-body.is-scrollable {
	-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent 100%);
	mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent 100%);
}
.help-body.is-scrolled-to-end { -webkit-mask-image: none; mask-image: none; }

/* Respect the OS/browser reduce-motion preference: cut the decorative UI
   transitions (drawer slide, backdrop fade, button hover/close) to instant.
   Gameplay itself draws on canvas and has no CSS transitions to gate. */
@media (prefers-reduced-motion: reduce) {
	.icon-btn,
	.help-backdrop,
	.help-drawer,
	.help-close,
	.replay-return-button {
		transition: none;
	}
	.replay-dot {
		animation: none;
	}
}
