/* เกมออกทริป (Trip Game) — front-end theme
   Light, modern, mobile-first. White / light-blue / blue / orange. */

@font-face {
	font-family: 'DBH';
	src: url('../fonts/DBH.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

/* Digital-clock style face used only for the timer digits (.tg-timer-value
   below) — deliberately not part of the page-wide font picker on the
   "ฟอนต์" admin screen, which only lists files for that separate,
   whole-page font swap. */
@font-face {
	font-family: 'Digital-Dismay';
	src: url('../fonts/Digital-Dismay.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

/* Headings (h1-h5) and <p> text are deliberately excluded from the
 * app-wide font below, so the site theme's own Additional CSS
 * (h1-h5 / body,p font rules) governs them instead -- the game's own
 * font stack still applies to everything else (buttons, labels, UI
 * chrome), and the Digital-Dismay timer digits keep their own
 * higher-specificity rule further down, untouched. */
#tg-app,
#tg-app * {
	box-sizing: border-box;
}
#tg-app,
#tg-app *:not(h1, h2, h3, h4, h5, p) {
	font-family: 'db', 'SF Thonburi', 'Sarabun', sans-serif !important;
	font-weight: normal !important;
}

#tg-app {
	--tg-white: #ffffff;
	--tg-bg: #f2f8ff;
	--tg-bg-soft: #e8f3ff;
	--tg-blue-light: #dbeeff;
	--tg-blue: #2f7fed;
	--tg-blue-dark: #1c5fc2;
	--tg-orange: #ff8a3d;
	--tg-orange-light: #ffcc00;
	--tg-orange-dark: #f06a1a;
	--tg-text: #223047;
	--tg-text-light: #7186a3;
	--tg-success: #2ecc71;
	--tg-danger: #ff5c5c;
	--tg-border-gray: #cfd8e3;
	--tg-radius: 20px;
	--tg-radius-sm: 12px;
	--tg-shadow: 0 10px 30px rgba(30, 41, 59, 0.14);
	--tg-shadow-sm: 0 4px 14px rgba(30, 41, 59, 0.1);
	/* Fixed accent colour for outline icons landing on a plain white/
	   near-white surface (.tg-card, .tg-badge) — see the .tg-icon rules
	   below. Same value + same naming convention as the sibling
	   word-guess-game plugin's --wg-icon-accent, so the two games read
	   as one consistent icon theme. */
	--tg-icon-accent: #ff6a3d;

	color: var(--tg-text);
	background: none;
	min-height: 100dvh;
	display: flex;
	flex-direction: column;
	align-items: stretch;
	-webkit-tap-highlight-color: transparent;
	touch-action: manipulation;
	user-select: none;

	/* Break out of the theme's content column so the game fills the
	   full browser width instead of leaving white margins left/right. */
	width: 100vw;
	max-width: 100vw;
	margin-left: calc(50% - 50vw);
	margin-right: calc(50% - 50vw);
}

/* -------------------------------------------------- full-screen background
   Set from the admin's "พื้นหลังเกม" page (a random active image is
   picked in PHP on every page load, so a plain refresh can show a
   different one). Fixed + inset:0 so it always fills the browser
   viewport ("fullscreen") no matter the device size.

   z-index: -1 (not 0) is deliberate. A position:fixed element at
   z-index 0 would still paint ABOVE normal, non-positioned page
   content regardless of source order (e.g. a logo image the site
   owner drops on the page above the [trip_game] shortcode in the
   block editor) — that's the "logo disappears once a background is
   on" symptom. At z-index: -1 this background sits in the slot
   between the plain page canvas and normal in-flow content, so any
   ordinary content on the page (the logo, headings, anything else
   dropped in the page editor) automatically stays visible above it
   with zero extra CSS/class needed on that content. #tg-app's own
   screens still render above it too, since .tg-screen below sets its
   own z-index: 1.

   Split into two layers so the per-image opacity/blur/overlay-colour
   controls (admin/views/backgrounds.php) can work together:
   - .tg-bg-wrap: the fixed, viewport-filling box. `overflow: hidden`
     clips the oversized inner layer back down once it's blurred, and
     any custom overlay colour lives on THIS element so it shows
     through wherever the image above it is faded out.
   - .tg-bg: the actual image, sized/positioned to fully cover the
     wrapper. Its own inline style carries the per-image opacity and
     blur — and, only when blurred, a negative inset so the blurred
     edges bleed past the wrapper instead of fading the picture out
     right at the edge of the screen. */
.tg-bg-wrap {
	position: fixed;
	inset: 0;
	width: 100%;
	height: 100%;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

.tg-bg {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center center;
	background-repeat: no-repeat;
	pointer-events: none;
}

.tg-screen {
	position: relative;
	z-index: 1;
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-start;
	padding: max(20px, env(safe-area-inset-top)) 18px max(20px, env(safe-area-inset-bottom));
	width: 100%;
	max-width: 620px;
	margin: 0 auto;
	gap: 16px;
	animation: tg-fade-in 0.25s ease;
}

@keyframes tg-fade-in {
	from { opacity: 0; transform: translateY(8px); }
	to { opacity: 1; transform: translateY(0); }
}

/* Public live scoreboard (?scores=1) — meant to be cast on a big
   screen or opened on a desktop to watch the race, so it should use
   the available width instead of staying capped at phone width. */
.tg-screen--scores {
	max-width: 1000px;
}

.tg-scores-grid {
	width: 100%;
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.tg-screen--loading {
	align-items: center;
	justify-content: center;
	min-height: 100dvh;
}

.tg-spinner {
	width: 44px;
	height: 44px;
	border-radius: 50%;
	border: 4px solid var(--tg-blue-light);
	border-top-color: var(--tg-blue);
	animation: tg-spin 0.8s linear infinite;
}

@keyframes tg-spin {
	to { transform: rotate(360deg); }
}

/* -------------------------------------------------- header / progress */

.tg-topbar {
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	/* No sticky positioning / background strip here (tried once, undone
	   per feedback — it read as an unwanted white bar rather than the
	   plain "just no logo up top" look that was actually asked for).
	   buildChrome() in game.js still leaves the "Mind2u Game" logo out
	   of this bar during play (that part stays); the logo shows
	   normally again on the join screen and the results page. */
	/* .tg-screen's own flex `gap: 16px` (shared by every screen, join
	   and results included) would otherwise leave this much space
	   before the card below — pulled back down to 3px with a negative
	   margin here instead of touching that shared gap value, so only
	   the topbar-to-card spacing on stage screens changes. */
	margin-bottom: -13px;
}

.tg-topbar .tg-timer {
	margin-left: auto;
}

.tg-logo {
	font-weight: 400;
	font-size: clamp(15px, 4vw, 18px);
	color: var(--tg-blue-dark);
	display: flex;
	align-items: center;
	gap: 6px;
}

/* Join-screen heading only — stacks the logo image (or, as a last-
   resort fallback if it ever fails to resolve, a colourful emoji
   clock) above the label instead of the small inline outline icon
   every other .tg-logo uses (public scoreboard heading, etc. are
   untouched). align-items:center (inherited from .tg-logo above) now
   centers the mark/text horizontally since the flex direction
   switched to column. */
.tg-logo--stacked {
	flex-direction: column;
	gap: 4px;
	font-size: 20px;
}

.tg-logo-emoji {
	font-size: 40px;
	line-height: 1;
}

/* Logo image — the admin's custom upload, or (by default) this
   plugin's own bundled colourful car mark, assets/img/logo.svg — see
   TG_Game::resolve_logo_url() / the "โลโก้หน้าแรก" admin card. Replaces
   the emoji+text mark above inside the same .tg-logo--stacked
   container. */
.tg-logo-image {
	width: 220px;
	max-width: 80%;
	height: auto;
	display: inline-block;
}

.tg-timer {
	/* No badge/pill look (per explicit request) — bare icon + digits
	   straight on whatever's behind them, so white is the only colour
	   that reads on both the plain page background and a busy photo
	   background. */
	background: none;
	border: none;
	box-shadow: none;
	color: var(--tg-white);
	font-weight: 400;
	font-variant-numeric: tabular-nums;
	padding: 1px 4px;
	font-size: calc(clamp(14px, 3.6vw, 17px) + 5px);
	display: inline-flex;
	align-items: center;
	gap: 4px;
	/* Auto-sizing pill (no fixed width) — grows on its own to fit
	   .tg-timer-value below, whatever that font needs. */
	white-space: nowrap;
}

/* Digital-Dismay only on the digits themselves, not the clock icon
   next to them. #tg-app prefix is needed to outweigh the page-wide
   font picker's own `#tg-app * { font-family: ... !important }` rule
   (admin's "ฟอนต์" screen, class-tg-shortcode.php::enqueue_font()) —
   that rule and this one are both !important, so it comes down to
   selector specificity, and the extra ID here wins. Size/spacing are
   a first pass (this font reads narrower/taller than the UI font at
   the same px) — nudge later once seen live. */
#tg-app .tg-timer-value {
	font-family: 'Digital-Dismay', 'DBH', monospace !important;
	font-size: calc(1.2em + 3px);
	letter-spacing: 1px;
}

/* -------------------------------------------------- inline icons
   Same outline/line-icon system as the sibling word-guess-game plugin
   (see ICON_PATHS/icon() in game.js) — small stroke-only SVGs coloured
   via `currentColor` by default (.tg-icon has no colour of its own, so
   it just inherits whatever text colour it sits next to), overridden
   to the fixed --tg-icon-accent for an icon landing on its own on a
   plain white/near-white surface (a .tg-card, a .tg-badge) where the
   surrounding text colour would otherwise be too faint. Icons inside a
   BUTTON, or the brand logo mark, always keep using currentColor
   even when that happens to sit inside a card — a button's own
   background/text pairing (or the logo's own fixed blue) already
   handles its own contrast. */
.tg-icon {
	width: 1em;
	height: 1em;
	flex: 0 0 auto;
	vertical-align: -0.15em;
}

.tg-card .tg-icon,
.tg-badge .tg-icon {
	color: var(--tg-icon-accent, #ff6a3d);
}

.tg-card .tg-btn .tg-icon,
.tg-logo .tg-icon {
	color: currentColor;
}

.tg-progress-dots {
	display: flex;
	align-items: center;
	gap: 3px;
	flex: 0 1 120px;
	min-width: 56px;
}

.tg-progress-dots span {
	flex: 1;
	height: 6px;
	border-radius: 999px;
	background: var(--tg-blue-light);
	transition: background 0.25s ease;
}

.tg-progress-dots span.is-done {
	background: var(--tg-blue);
}

.tg-progress-dots span.is-current {
	background: var(--tg-orange);
}

/* -------------------------------------------------- generic card / button */

.tg-card {
	width: 100%;
	background: var(--tg-white);
	border-radius: var(--tg-radius);
	box-shadow: var(--tg-shadow);
	padding: 22px 20px;
	display: flex;
	flex-direction: column;
	gap: 14px;
	align-items: stretch;
}

.tg-title {
	font-size: clamp(20px, 5.5vw, 26px);
	font-weight: 400;
	color: var(--tg-blue-dark);
	text-align: center;
	margin: 0;
}

.tg-subtitle {
	font-size: clamp(13px, 3.6vw, 15px);
	color: var(--tg-text-light);
	text-align: center;
	margin: -6px 0 0;
}

/* Small cross-link to the sibling "เกมทายคำ" (Word Guess Game) plugin —
   join screen only, deliberately understated (plain outline pill) so
   it doesn't compete with the real nickname/start flow above it. */
.tg-crosslink-btn {
	appearance: none;
	align-self: center;
	margin-top: 10px;
	padding: 8px 16px;
	border: 2px solid var(--tg-border-gray);
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.9);
	color: #1a1a1a;
	font-size: 13px;
	font-weight: 700;
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	cursor: pointer;
	transition: transform 0.15s ease-out, background-color 0.15s ease-out,
		border-color 0.15s ease-out, color 0.15s ease-out;
}

.tg-crosslink-row {
	align-self: center;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 8px;
	margin-top: 10px;
}

.tg-crosslink-row .tg-crosslink-btn {
	margin-top: 0;
}

.tg-crosslink-btn .tg-icon {
	width: 14px;
	height: 14px;
}

/* Hover: lifts up + turns coral with white text/icon (both the plain
   gray "เกมใบ้คำ" link and the blue "--scores" modifier below) — the
   same coral used for the rank-1 .tg-medal circle. Higher specificity
   than .tg-crosslink-btn--scores's own background/color (2 classes vs
   1, via :hover), so no !important needed. Skips :disabled to match
   the .tg-btn hover convention elsewhere in this file. */
.tg-crosslink-btn:hover:not(:disabled) {
	transform: translateY(-3px);
	background: #ff6f61;
	border-color: #ff6f61;
	color: var(--tg-white);
}

.tg-crosslink-btn:hover:not(:disabled) .tg-icon {
	color: var(--tg-white);
}

/* Press: sinks back down. :active covers mouse/pointer; .is-pressed
   would cover a JS touchstart/touchend toggle if this pill ever needs
   one (see the .tg-btn press-feedback comment above for why), though
   these links don't wire that up today. */
.tg-crosslink-btn:active,
.tg-crosslink-btn.is-pressed {
	transform: translateY(1px) scale(0.95);
	transition-duration: 0.05s;
}

/* Modifier for the "ดูคะแนนเกมนี้" (view this game's scores) link —
   same pill shape/size as .tg-crosslink-btn above, but in the game's
   own blue so it doesn't get mistaken for the gray "switch games"
   cross-link right below it. */
.tg-crosslink-btn--scores {
	border-color: var(--tg-blue);
	background: var(--tg-blue-light);
	color: var(--tg-blue-dark);
}

.tg-crosslink-btn--scores .tg-icon {
	color: var(--tg-blue-dark);
}

/* Developer credit — join screen only, pinned at the bottom below both
   cross-link pills. Sits directly on the page's own background image
   (not inside a .tg-card), so it's white with a soft shadow for
   legibility against whatever photo/colour is behind it, kept small
   and slightly translucent so it doesn't compete with the real UI. */
.tg-credit {
	align-self: center;
	margin-top: 10px;
	margin-bottom: 0;
	font-size: 13px;
	color: var(--tg-white);
	opacity: 0.85;
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.tg-btn {
	appearance: none;
	border: none;
	cursor: pointer;
	border-radius: var(--tg-radius-sm);
	padding: 15px 22px;
	font-size: clamp(15px, 4vw, 18px);
	font-weight: 400;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	position: relative;
	transition: transform 0.15s ease-out, box-shadow 0.15s ease-out, opacity 0.12s ease;
	box-shadow:
		0 4px 0 var(--tg-btn-shade, rgba(30, 41, 59, 0.28)),
		0 6px 14px rgba(30, 41, 59, 0.18),
		inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

/* Lifts toward the viewer on hover (the "3px" hover tilt); the flat
   bottom edge (the 3D-ish "0 Npx 0 shade" layer) shrinks to match, so
   the button reads as rising up rather than just floating. */
.tg-btn:hover:not(:disabled) {
	transform: translateY(-3px);
	box-shadow:
		0 7px 0 var(--tg-btn-shade, rgba(30, 41, 59, 0.28)),
		0 14px 22px rgba(30, 41, 59, 0.22),
		inset 0 1px 0 rgba(255, 255, 255, 0.45);
}

/* :active covers real pointer/mouse presses; .is-pressed is toggled from
   JS on touchstart/touchend (see game.js) because iOS/Android often
   don't hold :active for the full duration of a tap, which is why the
   "press down" feel can go missing on phones even though it works with
   a mouse. Keeping both means the feedback is reliable everywhere. */
.tg-btn:active,
.tg-btn.is-pressed {
	transform: translateY(3px) scale(0.95);
	box-shadow:
		0 1px 0 var(--tg-btn-shade, rgba(30, 41, 59, 0.28)),
		0 2px 6px rgba(30, 41, 59, 0.18),
		inset 0 1px 0 rgba(255, 255, 255, 0.25);
	transition-duration: 0.05s;
}

.tg-btn:disabled {
	opacity: 0.45;
	cursor: not-allowed;
	transform: none;
	box-shadow: var(--tg-shadow-sm);
}

.tg-btn--block {
	width: 100%;
}

/* Auto-width button that hugs its own label instead of stretching
   (used for the nickname "OK" confirm step). */
.tg-btn--fit {
	align-self: center;
	width: auto;
	padding-left: 32px;
	padding-right: 32px;
}

/* "Hero" call-to-action button — fully rounded (pill) and narrower than
   full width, used for START and the "next stage" buttons so they read
   as the one big tappable action on screen. */
.tg-btn--hero {
	align-self: center;
	width: 70%;
	border-radius: 999px;
}

.tg-player-name {
	text-align: center;
	font-size: 80px;
	line-height: 1.1;
	font-weight: 400;
	color: var(--tg-blue-dark);
	margin: 0;
	word-break: break-word;
}

.tg-btn--primary {
	background: linear-gradient(160deg, #7db4ff 0%, var(--tg-blue) 50%, var(--tg-blue-dark) 100%);
	color: var(--tg-white);
	--tg-btn-shade: #123e82;
}

.tg-btn--accent {
	background: linear-gradient(160deg, #ffb673 0%, var(--tg-orange) 50%, var(--tg-orange-dark) 100%);
	color: var(--tg-white);
	--tg-btn-shade: #b3480d;
}

.tg-btn--ghost {
	background: linear-gradient(160deg, #ffffff 0%, var(--tg-blue-light) 55%, #c3e2ff 100%);
	color: var(--tg-blue-dark);
	--tg-btn-shade: #a9cdf0;
}

.tg-input {
	width: 50%;
	align-self: center;
	border: 2px solid var(--tg-blue-light);
	border-radius: var(--tg-radius-sm);
	padding: 14px 16px;
	font-size: clamp(15px, 4.2vw, 18px);
	color: var(--tg-text);
	background: var(--tg-bg-soft);
	outline: none;
	text-align: center;
}

.tg-input:focus {
	border-color: var(--tg-blue);
}

/* -------------------------------------------------- level buttons (Easy/Medium/Hard)
   Sit at the top of the join screen (renderJoin(), game.js), always in
   one row — including on phones, per explicit request — so text sizes
   down with clamp() rather than wrapping to a second row. Each button
   is a .tg-btn (same hover-lift/press-sink 3D feel as every other
   button in the game) plus this gradient skin. */

.tg-level-btns {
	display: flex;
	flex-direction: row;
	gap: 8px;
	width: 100%;
}

.tg-level-btn {
	flex: 1 1 0;
	min-width: 0;
	border-radius: 999px;
	/* 135deg = "to bottom right", so the lighter/brighter shade (listed
	   first) sits at the top-left corner, per explicit request. Same
	   stops as .tg-btn--primary's vivid blue (the "ตกลง" button) rather
	   than the earlier pale #80bfef/#539cd5 pair, per explicit "สีจาง
	   ไป อยากได้สีสดขึ้น" feedback — was reading as washed-out/opaque
	   next to the other buttons on the same screen. */
	background: linear-gradient(135deg, #7db4ff 0%, var(--tg-blue) 55%, var(--tg-blue-dark) 100%);
	color: var(--tg-white);
	font-size: clamp(12px, 3.8vw, 17px);
	padding: 13px 6px;
	white-space: nowrap;
	box-shadow: none;
}

/* No dark 3D drop-shadow on these — flat, per explicit request —
   unlike the default .tg-btn hover/press shadow layers. */
.tg-level-btn:hover:not(:disabled),
.tg-level-btn:active,
.tg-level-btn.is-pressed {
	box-shadow: none;
}

/* Marks the player's chosen level — a rose-pink ring held 2px off the
   button's own edge, with the button's own gradient swapping to match,
   per explicit request. outline (not border) so the ring never shifts
   the button's own size or padding. */
.tg-level-btn--selected {
	/* Same brightening pass as .tg-level-btn above — was a pale
	   #f1989b/#fe7091 salmon, bumped to a punchier rose-pink so the
	   "selected" state reads as clearly as the unselected blue does. */
	background: linear-gradient(135deg, #ff9bb0 0%, #fe3d72 100%);
	outline: 2px solid #ff9b9b;
	outline-offset: 2px;
}

/* Difficulty badge in the "currently playing" live list (buildScoreCards(),
   game.js) — sits between the nickname and the stage badge. */
.tg-badge--level {
	background: var(--tg-orange-light);
	color: var(--tg-orange-dark);
}

.tg-alert {
	border-radius: var(--tg-radius-sm);
	padding: 10px 14px;
	font-size: 14px;
	text-align: center;
	font-weight: 400;
}

.tg-alert--error {
	background: #ffe9e9;
	color: #c0392b;
}

.tg-alert--success {
	background: #e6fbef;
	color: #1e8e51;
}

.tg-shake {
	animation: tg-shake 0.35s ease;
}

@keyframes tg-shake {
	10%, 90% { transform: translateX(-2px); }
	20%, 80% { transform: translateX(4px); }
	30%, 50%, 70% { transform: translateX(-8px); }
	40%, 60% { transform: translateX(8px); }
}

/* -------------------------------------------------- stage 1: math */

.tg-math-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.tg-math-row {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	font-size: clamp(20px, 6vw, 28px);
	font-weight: 400;
	background: var(--tg-bg-soft);
	border-radius: var(--tg-radius-sm);
	padding: 10px 14px;
	border: 2px solid transparent;
}

.tg-math-answer {
	width: 3.2em;
	text-align: center;
	border: 3px solid var(--tg-border-gray);
	border-radius: 10px;
	padding: 8px 4px;
	font-size: inherit;
	font-weight: 400;
	background: var(--tg-white);
	transition: border-color 0.15s ease;
}

.tg-math-answer:focus {
	outline: none;
	border-color: var(--tg-border-gray);
}

.tg-math-answer.is-correct {
	border-color: var(--tg-blue);
	background: var(--tg-blue-light);
}

.tg-math-answer.is-wrong {
	border-color: var(--tg-danger);
	background: #fff1f1;
}

/* -------------------------------------------------- ด่าน 1.2: remember the number
   Tail-of-stage-1 interlude (renderStage1b() in game.js) — a big
   placeholder that turns into a bold red 2-digit number once the
   player presses the roll button. */

.tg-secret-number {
	align-self: center;
	font-size: clamp(56px, 18vw, 96px);
	font-weight: 400;
	line-height: 1;
	color: var(--tg-border-gray);
	letter-spacing: 2px;
	font-variant-numeric: tabular-nums;
	margin: 10px 0;
}

.tg-secret-number.is-revealed {
	color: var(--tg-danger);
}

/* -------------------------------------------------- stage 4 (quiz) */

.tg-quiz-question {
	font-size: clamp(17px, 4.6vw, 20px);
	font-weight: 400;
	text-align: center;
	color: var(--tg-text);
	margin: 0 0 4px;
}

.tg-quiz-choices {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.tg-quiz-choice {
	appearance: none;
	border: 3px solid var(--tg-border-gray);
	border-radius: var(--tg-radius-sm);
	background: var(--tg-white);
	color: var(--tg-text);
	padding: 14px 16px;
	font-size: clamp(15px, 4vw, 17px);
	font-weight: 400;
	text-align: left;
	cursor: pointer;
	transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.1s ease-out;
}

.tg-quiz-choice:hover:not(:disabled):not(.is-correct):not(.is-wrong) {
	transform: translateY(-2px);
	border-color: var(--tg-blue);
	box-shadow: 0 6px 14px rgba(30, 41, 59, 0.12);
}

.tg-quiz-choice:active {
	transform: scale(0.98);
}

.tg-quiz-choice:disabled {
	cursor: not-allowed;
	opacity: 0.7;
}

.tg-quiz-choice.is-correct {
	border-color: var(--tg-blue);
	background: var(--tg-blue-light);
}

.tg-quiz-choice.is-wrong {
	border-color: var(--tg-danger);
	background: #fff1f1;
}

/* -------------------------------------------------- stage 3: jigsaw */

.tg-jigsaw-toggle {
	align-self: center;
}

.tg-jigsaw-preview {
	width: min(34vw, 27vh, 150px);
	max-width: 100%;
	border-radius: var(--tg-radius-sm);
	overflow: hidden;
	box-shadow: var(--tg-shadow-sm);
	align-self: center;
}

.tg-jigsaw-preview img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Theme/Customizer has a global `img { border-radius: 20px; }` rule
	   that would otherwise round this <img> itself at 20px — bigger
	   than the 12px the parent already clips to — leaving a ring of
	   background color showing through at the corners. Force it back
	   to match its container so only the container's radius shows. */
	border-radius: inherit;
}

.tg-jigsaw-board {
	width: min(84vw, 60vh, 420px);
	aspect-ratio: 1 / 1;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-template-rows: repeat(3, 1fr);
	gap: 0;
	align-self: center;
	background: var(--tg-white);
	border: 2px solid var(--tg-blue-light);
	border-radius: var(--tg-radius-sm);
	overflow: hidden;
	box-shadow: var(--tg-shadow);
	padding: 0;
}

.tg-jigsaw-piece {
	position: relative;
	background-size: 300% 300%;
	background-repeat: no-repeat;
	border-radius: 0;
	cursor: pointer;
	transition: transform 0.14s cubic-bezier(0.33, 1, 0.68, 1);
}

.tg-jigsaw-piece:active,
.tg-jigsaw-piece.is-pressed {
	transform: scale(0.92);
	transition-duration: 0.05s;
}

.tg-jigsaw-piece.is-selected {
	z-index: 5;
	transform: scale(1.05);
	box-shadow: 0 0 0 3px var(--tg-orange-light), 0 6px 18px rgba(0, 0, 0, 0.22);
}

.tg-jigsaw-piece.is-correct::after {
	content: "";
	position: absolute;
	inset: 0;
	border: 1px solid var(--tg-blue);
	border-radius: 0;
	pointer-events: none;
}

.tg-jigsaw-piece.is-wrong::after {
	content: "";
	position: absolute;
	inset: 0;
	border: 1px solid var(--tg-white);
	border-radius: 0;
	pointer-events: none;
}

/* -------------------------------------------------- stage 8: จับคู่คำกับสี */

.tg-colormatch-board {
	width: 100%;
	max-width: 420px;
	align-self: center;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.tg-colormatch-row {
	display: flex;
	align-items: stretch;
	gap: 10px;
}

.tg-colormatch-word {
	flex: 1;
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 56px;
	padding: 10px 14px;
	background: var(--tg-white);
	border-radius: var(--tg-radius-sm);
	box-shadow: var(--tg-shadow-sm);
	color: var(--tg-blue-dark);
	font-size: clamp(20px, 5vw, 28px);
	font-weight: 700;
	cursor: pointer;
	transition: transform 0.14s cubic-bezier(0.33, 1, 0.68, 1);
}

.tg-colormatch-word:active,
.tg-colormatch-word.is-pressed {
	transform: scale(0.96);
	transition-duration: 0.05s;
}

.tg-colormatch-word.is-correct {
	box-shadow: 0 0 0 2px var(--tg-blue), var(--tg-shadow-sm);
}

.tg-colormatch-word.is-wrong {
	box-shadow: 0 0 0 1px var(--tg-blue-light), var(--tg-shadow-sm);
}

/* Must come AFTER .is-correct/.is-wrong in source order: the JS always
 * adds is-correct/is-wrong alongside is-selected on the tapped cell, and
 * with equal specificity (two classes each) the LATER rule in the
 * stylesheet wins — so this block used to be silently overridden by
 * .is-correct/.is-wrong above it and the orange selection ring never
 * actually rendered, regardless of cache. Keep this last. */
.tg-colormatch-word.is-selected {
	z-index: 5;
	transform: scale(1.04);
	box-shadow: 0 0 0 2px rgba(255, 138, 61, 0.45), var(--tg-shadow-sm);
}

.tg-colormatch-swatch {
	flex: 0 0 clamp(70px, 24vw, 130px);
	border-radius: var(--tg-radius-sm);
	box-shadow: var(--tg-shadow-sm);
}

/* -------------------------------------------------- stage 9: จับคู่รูปทรงและสี */

.tg-shapematch-board {
	width: 100%;
	max-width: 440px;
	align-self: center;
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.tg-shapematch-row {
	display: flex;
	align-items: stretch;
	justify-content: center;
	gap: 7px;
}

.tg-shapematch-cell {
	position: relative;
	flex: 1;
	/* Kept a bit smaller than the old 76px now that a 3rd movable row
	   (4 rows on screen total) needs to fit comfortably on a phone. */
	max-width: 64px;
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--tg-white);
	border-radius: var(--tg-radius-sm);
	box-shadow: var(--tg-shadow-sm);
	cursor: pointer;
	transition: transform 0.14s cubic-bezier(0.33, 1, 0.68, 1);
}

.tg-shapematch-cell:active,
.tg-shapematch-cell.is-pressed {
	transform: scale(0.94);
	transition-duration: 0.05s;
}

.tg-shapematch-cell.is-correct {
	box-shadow: var(--tg-shadow-sm);
}

.tg-shapematch-cell.is-wrong {
	box-shadow: var(--tg-shadow-sm);
}

/* Must come AFTER .is-correct/.is-wrong in source order — same reason as
 * .tg-colormatch-word.is-selected above: equal specificity, JS always
 * pairs is-selected with is-correct/is-wrong on the tapped cell, so
 * whichever rule is declared later in the stylesheet wins. Keep this
 * last so the orange selection ring actually shows. */
.tg-shapematch-cell.is-selected {
	z-index: 5;
	transform: scale(1.08);
	box-shadow: 0 0 0 1px var(--tg-orange), var(--tg-shadow-sm);
}

.tg-shapematch-icon {
	width: 68%;
	height: 68%;
	filter: drop-shadow(0 3px 3px rgba(20, 30, 50, 0.25));
}

/* The fixed "answer key" row — never clickable, painted with a faint
   grey background so it visibly reads as the template every other row
   is being matched against, per explicit request ("ปูพื้นเทาจางๆ พอให้
   รู้ว่า เป็นแม่แบบ"). */
.tg-shapematch-row--template {
	background: rgba(34, 48, 71, 0.06);
	border-radius: var(--tg-radius-sm);
	padding: 6px 0;
	margin-top: 2px;
}

.tg-shapematch-cell--template {
	cursor: default;
	background: transparent;
	box-shadow: none;
}

/* -------------------------------------------------- stage 10: หยิบจับอารมณ์ */

.tg-emotionmatch {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 16px;
	width: 100%;
}

/* Overlay spanning the whole stage (both the slots row AND the pool
   below it) that all 16 icons + the floating name tag actually live
   in — introduced so a drag never has to leave its own container to
   reach the slots (see stage10-emotionmatch.js). The layer itself is
   click-through (pointer-events: none) so taps still land on the
   slots underneath; only the icons opt back into being interactive. */
.tg-emotionmatch-iconlayer {
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 2;
}

.tg-emotionmatch-slots {
	display: flex;
	gap: 14px;
	justify-content: center;
	flex-wrap: wrap;
}

.tg-emotionmatch-slot {
	width: 78px;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 6px;
}

/* --slot-tint is set per-slot from stage10-emotionmatch.js (a light
   version of that slot's target emotion's own colour, per explicit
   request: "ช่องโจทก์ 3 ช่องวงกลม ให้ใส่สีพื้นอ่อนๆ ของอารมณ์นั้น เป็นไกด์") —
   falls back to the original neutral tint if JS hasn't set it. */
.tg-emotionmatch-slot-hole {
	position: relative;
	width: 64px;
	height: 64px;
	border-radius: 50%;
	background: var(--slot-tint, rgba(34, 48, 71, 0.06));
	box-shadow: inset 0 0 0 2px rgba(34, 48, 71, 0.12);
	display: flex;
	align-items: center;
	justify-content: center;
	transition: box-shadow 0.15s ease;
}

/* Hovering a dragged icon over an empty slot — quick visual cue for
   where it'll land if released here, same orange the rest of the game
   uses for "currently selected/targeted". */
.tg-emotionmatch-slot-hole.is-hover {
	box-shadow: inset 0 0 0 2px var(--tg-orange), var(--tg-shadow-sm);
}

.tg-emotionmatch-slot-hole.is-filled {
	background: transparent;
	box-shadow: 0 0 0 2px var(--tg-success), var(--tg-shadow-sm);
}

.tg-emotionmatch-slot-hole.is-wrong {
	animation: tg-emotionmatch-shake 0.35s ease;
}

.tg-emotionmatch-slot-label {
	font-size: 13px;
	font-weight: 700;
	color: var(--tg-blue-dark);
	text-align: center;
	line-height: 1.2;
}

/* The floating pool holding all 16 icons (this round's 3 targets mixed
   in with 13 decoys) — a fixed-height stage so the ambient drift
   animation (stage10-emotionmatch.js) has stable bounds to move within.
   touch-action:none stops the browser's own scroll/zoom gestures from
   fighting with a finger dragging an icon around on mobile. */
.tg-emotionmatch-pool {
	position: relative;
	width: 100%;
	height: 260px;
	border-radius: var(--tg-radius-sm);
	background: rgba(34, 48, 71, 0.04);
	box-shadow: var(--tg-shadow-sm);
	overflow: hidden;
	touch-action: none;
}

/* Positioned purely through `transform: translate3d(...)` (see
   placeIconStyle() in stage10-emotionmatch.js), never left/top —
   left/top changes force the browser to re-run layout on every single
   animation frame for all 16 icons at once, which is what was making
   the ambient wander/drag motion look stuttery rather than smooth
   ("การเคลื่อนที่ ของไอคอนทุกตัว ดูยังสะดุดๆ ไม่นุ่มนวล"); transform lets the
   browser move the icon on the compositor alone, the same technique
   the smooth reference page the user linked relies on. left/top stay
   pinned at 0 so translate3d's pixel values are the icon's only
   position input — will-change hints the browser to keep this layer
   composited ahead of time instead of promoting it mid-drag. */
.tg-emotionmatch-icon {
	position: absolute;
	left: 0;
	top: 0;
	width: 58px;
	height: 58px;
	border-radius: 50%;
	cursor: grab;
	touch-action: none;
	will-change: transform;
	/* .tg-emotionmatch-iconlayer (its parent) is pointer-events: none so
	   clicks pass through to the slots underneath it — icons opt back
	   in individually so they stay tappable/draggable. */
	pointer-events: auto;
}

.tg-emotionmatch-icon .tg-emotionmatch-svg {
	width: 100%;
	height: 100%;
	display: block;
	pointer-events: none;
	filter: drop-shadow(0 3px 3px rgba(20, 30, 50, 0.25));
}

.tg-emotionmatch-icon.is-selected,
.tg-emotionmatch-icon.is-dragging {
	box-shadow: 0 0 0 2px var(--tg-orange), var(--tg-shadow-sm);
	cursor: grabbing;
}

/* Once correctly placed, the icon is moved INTO its slot's hole
   (stage10-emotionmatch.js's lockIconIntoSlot()) — drop the pool's
   absolute positioning so it just fills the (now transparent) hole. */
.tg-emotionmatch-slot-hole .tg-emotionmatch-icon.is-placed {
	position: static;
	width: 100%;
	height: 100%;
	margin: 0;
	cursor: default;
	box-shadow: none;
}

/* Small floating name tag shown next to whichever icon is currently
   selected/being dragged, per explicit request ("เมื่อคลิกตัวใด ก็จะมีชื่อ
   โชว์ขึ้นบอกว่า เป็นอารมณ์ไหนสั้นๆ ตัวเล็กได้"). */
/* Also positioned via transform (see showTag()/pointermove in
   stage10-emotionmatch.js — the JS composes its own translate(x, y)
   with the -50%/-100% anchor offset below into one transform string,
   since setting `transform` inline replaces rather than adds to this
   rule) rather than left/top, for the same smoothness reason as
   .tg-emotionmatch-icon above — the tag tracks the pointer every
   frame during a drag right alongside the icon. */
.tg-emotionmatch-tag {
	position: absolute;
	left: 0;
	top: 0;
	transform: translate(-50%, -100%);
	background: rgba(28, 28, 30, 0.85);
	color: var(--tg-white);
	font-size: 12px;
	font-weight: 600;
	padding: 3px 9px;
	border-radius: 8px;
	white-space: nowrap;
	pointer-events: none;
	will-change: transform;
	z-index: 6;
}

.tg-emotionmatch-tag.is-hidden {
	display: none;
}

@keyframes tg-emotionmatch-shake {
	0%,
	100% {
		transform: translateX(0);
	}
	25% {
		transform: translateX(-4px);
	}
	75% {
		transform: translateX(4px);
	}
}

/* -------------------------------------------------- stage 4: memory match */

.tg-memory-grid {
	width: 100%;
	max-width: 460px;
	align-self: center;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 4px;
}

@media (orientation: landscape) {
	.tg-memory-grid {
		grid-template-columns: repeat(4, 1fr);
		max-width: 560px;
	}
}

.tg-memory-card {
	aspect-ratio: 1 / 1;
	perspective: 800px;
	touch-action: manipulation;
	transition: transform 0.14s cubic-bezier(0.33, 1, 0.68, 1);
}

/* Soft "press" feedback on tap — same easing/duration as the jigsaw
   piece's own :active squish, kept off already-resolved cards so a
   stray tap on a matched pair doesn't wobble it. This is a separate
   transform on the outer card, not .tg-memory-card__inner (which
   already owns the flip's rotateY), so the two combine without
   fighting each other. */
.tg-memory-card:not(.is-matched):active {
	transform: scale(0.93);
	transition-duration: 0.05s;
}

.tg-memory-card__inner {
	position: relative;
	width: 100%;
	height: 100%;
	transition: transform 0.35s cubic-bezier(0.4, 0.2, 0.2, 1);
	transform-style: preserve-3d;
	border-radius: 3px;
	box-shadow: var(--tg-shadow-sm);
}

.tg-memory-card.is-flipped .tg-memory-card__inner,
.tg-memory-card.is-matched .tg-memory-card__inner {
	transform: rotateY(180deg);
}

.tg-memory-card__face {
	position: absolute;
	inset: 0;
	backface-visibility: hidden;
	border-radius: 3px;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
}

.tg-memory-card__front {
	background: linear-gradient(135deg, var(--tg-blue), var(--tg-blue-dark));
}

.tg-memory-card__front::after {
	content: "?";
	color: rgba(255, 255, 255, 0.85);
	font-size: clamp(22px, 6vw, 30px);
	font-weight: 400;
}

/* Admin picked one shared image (stage 4 "ภาพพื้นหลังการ์ดปิด" setting) to
   replace the plain blue "?" gradient entirely — every closed card shows
   the same photo, full clarity, no dark overlay and no "?" mark on top
   (per explicit request — the photo alone IS the closed-card look).
   --tg-memory-photo is set inline per-card by stage4-memory.js. */
.tg-memory-card__front.has-photo {
	background-image: var(--tg-memory-photo);
	background-size: cover;
	background-position: center;
}

.tg-memory-card__front.has-photo::after {
	content: none;
}

/* Admin picked a custom two-colour gradient (stage 4 "สีกราเดียนต์การ์ดปิด"
   setting) to replace the default blue-gradient closed-card look — used
   only while no card-back image above is set (an image always wins, see
   TG_REST_API::stage4_payload()). Unlike the photo case, the "?" mark
   stays: this is just a recolour of the same card, not a different kind
   of face. --tg-memory-grad1/2/-angle are set inline per-card by
   stage4-memory.js (identical on every card, same as the photo case). */
.tg-memory-card__front.has-gradient {
	background: linear-gradient(var(--tg-memory-grad-angle, 135deg), var(--tg-memory-grad1), var(--tg-memory-grad2));
}

.tg-memory-card__back {
	transform: rotateY(180deg);
	background: var(--tg-white);
}

.tg-memory-card__back img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Same theme `img { border-radius: 20px; }` override as the jigsaw
	   preview — without this the photo itself gets rounded at 20px
	   (bigger than the 3px card face), showing white at the corners. */
	border-radius: inherit;
}

/* No matched/mismatch border — a correct pair just stays face-up and
   a wrong pair flips back over, so the flip itself is the feedback. */

/* -------------------------------------------------- ด่านที่ 9: confirm the number
   renderStageFinalCode() in game.js — a short, large-type input for
   typing back the 2-digit code shown once on "ด่าน 1.2". */

.tg-code-input {
	width: 42%;
	font-size: clamp(28px, 8vw, 40px);
	letter-spacing: 6px;
	font-variant-numeric: tabular-nums;
}

/* The 15-second countdown for entering the code (separate from the
   main elapsed-time .tg-timer badge in the topbar) — same pill shape
   as .tg-timer, turning red and blinking in its last 5 seconds
   (.is-urgent, toggled from the countdown tick in
   renderStageFinalCode()) so running low is hard to miss. Running out
   entirely ends the game — see goToGameOver()/.tg-badge--game-over. */
.tg-final-timer {
	align-self: center;
	background: var(--tg-white);
	border: 2px solid var(--tg-blue-light);
	color: var(--tg-blue-dark);
	font-weight: 400;
	font-variant-numeric: tabular-nums;
	padding: 8px 18px;
	border-radius: 999px;
	box-shadow: var(--tg-shadow-sm);
	font-size: clamp(16px, 4.2vw, 20px);
	display: inline-flex;
	align-items: center;
	gap: 6px;
	transition: color 0.15s ease, border-color 0.15s ease;
}

.tg-final-timer.is-urgent {
	color: var(--tg-danger);
	border-color: var(--tg-danger);
	animation: tg-final-timer-blink 0.8s steps(2, start) infinite;
}

@keyframes tg-final-timer-blink {
	50% { opacity: 0.4; }
}

/* -------------------------------------------------- finish + leaderboard */

.tg-finish-time {
	font-size: clamp(30px, 9vw, 44px);
	font-weight: 400;
	color: var(--tg-orange-dark);
	text-align: center;
	font-variant-numeric: tabular-nums;
}

.tg-table {
	width: 100%;
	border-collapse: collapse;
	overflow: hidden;
	border-radius: var(--tg-radius-sm);
}

.tg-table th,
.tg-table td {
	padding: 10px 12px;
	text-align: left;
	font-size: 14px;
}

.tg-table thead th {
	background: var(--tg-blue-light);
	color: var(--tg-blue-dark);
}

.tg-table tbody tr:nth-child(odd) {
	background: var(--tg-bg-soft);
}

.tg-table td:first-child,
.tg-table th:first-child {
	width: 46px;
	text-align: center;
}

.tg-medal {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	font-weight: 400;
	color: var(--tg-white);
	font-size: 13px;
}

.tg-medal--1 { background: #ff6f61; } /* อันดับ 1: ชมพู-ส้มสด (คอรัล) */
.tg-medal--2 { background: #ff8a3d; } /* อันดับ 2: ส้ม (เทียบ –ทง-ออเรนจ์) */
.tg-medal--3 { background: #7ec8e3; color: var(--tg-blue-dark); } /* อันดับ 3: ฟ้าอ่อน – ตัวหนังสือเข้มขึ้นเพื่อความชัดเจนบนพื้นสีอ่อน */

/* "ทำเนียบแชมป์" (Hall of Fame) — public scoreboard only (?scores=1),
   pinned above everything else, built by buildHallOfFameCard() in
   game.js. .tg-hof-wrap is the plain wrapper <div> renderPublicScores()
   rebuilds every refresh tick — needs width:100% explicitly, since a
   bare block-level <div> shrinks to its (narrower) table content under
   .tg-screen's centering flex layout instead of stretching like every
   sibling .tg-card here, which made the card look noticeably narrower
   than the "กระดานคะแนนสด" card right below it. Reuses .tg-table for
   the header/row banding, but the difficulty-name header cells need
   the full column width instead of .tg-table's 46px "#"-column rule
   above, hence the override. */
.tg-hof-wrap {
	width: 100%;
}

/* Fixed layout: a narrow shared rank column (1/2/3, one medal per
   row) on the left, per explicit "เอาตัวเลข 1 2 3 ไว้คอลัมซ้ายสุด ใส่
   ที่เดียวของแถว" request — replaces the old design where the medal
   repeated inside all 3 difficulty cells, which read as cluttered.
   The remaining width splits evenly across Easy/Medium/Hard; a long
   nickname in one still wraps (word-break on .tg-hof-name below)
   instead of stretching its column wider than its siblings. */
.tg-hof-table {
	table-layout: fixed;
}

.tg-hof-table th,
.tg-hof-table td {
	width: 28%;
	text-align: center;
}

/* Same specificity as .tg-table's own td:first-child/th:first-child
   46px "#"-column rule above (needed so this actually overrides it —
   the general .tg-hof-table rule just above this one alone loses to
   that more specific selector regardless of source order). Narrower
   than the 3 data columns — just wide enough for one .tg-medal. */
.tg-hof-table td:first-child,
.tg-hof-table th:first-child {
	width: 16%;
}

.tg-hof-cell {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
}

.tg-hof-name {
	font-size: 14px;
	font-weight: 400;
	color: var(--tg-blue-dark);
	word-break: break-word;
}

/* #tg-app prefix (not just .tg-hof-time) needed to outweigh the
   page-wide font picker's own `#tg-app * { font-family: ... !important }`
   rule near the top of this file (and the admin-configurable inline
   version of it) — both are !important, so it comes down to selector
   specificity, and the extra ID here wins. Same pattern already used
   by #tg-app .tg-timer-value below. */
#tg-app .tg-hof-time {
	font-family: 'Digital-Dismay', 'DBH', monospace !important;
	font-size: 19px;
	letter-spacing: 1px;
	color: var(--tg-danger);
	font-variant-numeric: tabular-nums;
}

/* Time column on the results screen + public scoreboard leaderboard
   tables (buildLeaderboardTable() in game.js) — Digital-Dismay applied
   only on หน้าดูคะแนน per explicit "หน้าเล่นโอเคแล้ว ใส่เฉพาะหน้าดูคะแนน"
   request — NOT #tg-app .tg-timer-value (the in-game topbar timer),
   which stays as-is. This font reads visibly smaller than the UI font
   at the same declared px, so it gets +2px over .tg-table td's normal
   14px, matching the same +2px bump given to .tg-hof-time above. */
#tg-app .tg-time-cell {
	font-family: 'Digital-Dismay', 'DBH', monospace !important;
	font-size: 18px;
	letter-spacing: 1px;
}

.tg-hof-cell--empty {
	color: var(--tg-text-light);
	font-size: 14px;
	padding: 8px 0;
}

.tg-live-item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 8px;
	padding: 8px 4px;
	font-size: 14px;
	border-bottom: 1px solid var(--tg-blue-light);
}

.tg-live-item:last-child {
	border-bottom: none;
}

.tg-badge {
	background: var(--tg-blue-light);
	color: var(--tg-blue-dark);
	border-radius: 999px;
	padding: 3px 10px;
	font-size: 12px;
	font-weight: 400;
	display: inline-flex;
	align-items: center;
	gap: 4px;
}

/* A player who ran out of time on ด่านที่ 9 without ever entering the
   right code (status 'game_over' — see TG_Game::game_over_player() /
   the badge swap in buildScoreCards(), game.js) — same pill shape as
   the ordinary stage-progress badge, recoloured with the same red used
   for the countdown's own urgency state below so the two read as one
   idea ("ran out of time"). */
.tg-badge--game-over {
	background: #ffe9e9;
	color: #c0392b;
}

/* Same game-over badge, shrunk to sit inline next to a time value in
   the leaderboard table (buildLeaderboardTable(), game.js) rather than
   the roomier live-status list it was originally designed for. */
.tg-badge--sm {
	padding: 1px 7px;
	font-size: 10px;
}

.tg-badge--sm .tg-icon {
	width: 0.9em;
	height: 0.9em;
}

/* Older rounds' finished-score tables (same nickname replaying the
 * game later the same trip) — tucked away by default so the newest
 * round's table is what people see first. */
.tg-round-summary {
	padding: 0;
	overflow: hidden;
}

.tg-round-details {
	width: 100%;
}

.tg-round-details > summary {
	list-style: none;
	cursor: pointer;
	padding: 14px 18px;
	font-size: 15px;
	color: var(--tg-blue-dark);
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.tg-round-details > summary::-webkit-details-marker {
	display: none;
}

.tg-round-details > summary::after {
	content: "▾";
	transition: transform 0.15s ease;
}

.tg-round-details[open] > summary::after {
	transform: rotate(180deg);
}

.tg-round-details .tg-table {
	margin: 0 18px 16px;
	width: calc(100% - 36px);
}

/* -------------------------------------------------- build version tag */

.tg-version-tag {
	position: fixed;
	bottom: 6px;
	right: 8px;
	font-size: 11px;
	color: var(--tg-text-light);
	opacity: 0.55;
	z-index: 9998;
	pointer-events: none;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* -------------------------------------------------- celebration firework
   Real particle fireworks drawn on a full-screen canvas (see game.js
   `celebrate()`) instead of an emoji animation — colorful bursts of
   circles that radiate out and fade. */

.tg-fireworks-canvas {
	position: fixed;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
	z-index: 9999;
}
