/* ==========================================================================
   Type the World — page-specific styles.
   Loaded on top of global.css: palette, box-sizing reset, base typography,
   body background/color and heading defaults all come from there.
   ========================================================================== */

:root {
	--font-mono: "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
}

.hidden { display: none !important; }

/* .flashy-text / <flashy> now live in global.css — shared site-wide so
   markdown content can use them too, not just this page and names.css. */

.screen {
	flex: 1 0 auto;
	width: 100%;
	max-width: var(--content-width);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 2rem 1rem;
}


/* ==========================================================================
   Shared bits
   ========================================================================== */

.screen h1 {
	font-size: clamp(2rem, 6vw, 3.25rem);
	letter-spacing: 0.01em;
}

p.lede {
	max-width: 460px;
	margin: 0 auto 1.75rem;
	text-align: center;
	color: var(--gray-dark);
}

button {
	font-family: inherit;
	cursor: pointer;
}

.btn-primary {
	background: var(--accent-dark);
	color: var(--white);
	border: none;
	font-weight: bold;
	font-size: 0.95rem;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	padding: 0.9rem 2.25rem;
	border-radius: 3px;
	transition: transform 0.12s ease, background 0.12s ease, color 0.12s ease;
}

.btn-primary:hover {
	background: var(--accent);
	color: var(--black);
	transform: translateY(-1px);
}

.btn-primary:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.btn-danger {
	background: var(--white);
	color: var(--error);
	border: 2px solid var(--error);
	font-weight: bold;
	font-size: 0.85rem;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	padding: 0.9rem 1.5rem;
	border-radius: 3px;
	transition: background 0.12s ease, color 0.12s ease;
}

.btn-danger:hover {
	background: var(--error);
	color: var(--white);
}

.btn-danger:focus-visible {
	outline: 3px solid var(--error);
	outline-offset: 2px;
}

.btn-primary:disabled,
.btn-danger:disabled {
	opacity: 0.5;
	cursor: default;
	transform: none;
}


/* ==========================================================================
   End panel (lives inside the slideshow viewport, bounded by its edges)
   ========================================================================== */

.end-panel {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	width: 100%;
}


/* ==========================================================================
   Game window (persistent — hud/card/input footprint never disappears)
   ========================================================================== */

#game-window {
	position: relative;
	width: 100%;
	max-width: 640px;
	margin: 0 auto;
}

.hud {
	width: 100%;
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 0.9rem;
}

.pause-btn {
	background: transparent;
	color: var(--gray-dark);
	border: 2px solid var(--gray-light);
	border-radius: 3px;
	font-size: 0.75rem;
	padding: 0.4rem 0.9rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
}

.pause-btn:hover:not(:disabled) {
	border-color: var(--accent-dark);
	color: var(--accent-dark);
}

.pause-btn:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.pause-btn:disabled {
	opacity: 0.4;
	cursor: default;
}

.hud-label {
	display: block;
	margin-bottom: 0.2rem;
	font-size: 0.65rem;
	color: var(--gray);
}

#tally,
#timer {
	font-size: 1.25rem;
	color: var(--black);
}

#timer { transition: color 0.2s ease; }

#timer.timer-warning {
	color: var(--error);
	animation: pulse 1s infinite;
}

.timer-value {
	background: none;
	border: none;
	padding: 0;
	font: inherit;
	cursor: pointer;
	border-radius: 3px;
}

.timer-value:hover:not(:disabled) {
	color: var(--accent-dark);
}

.timer-value:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.timer-value:disabled {
	cursor: default;
}

.timer-input {
	font: inherit;
	font-size: 1.25rem;
	color: var(--black);
	width: 3.5em;
	text-align: right;
	background: none;
	border: none;
	border-bottom: 2px solid var(--accent-dark);
	padding: 0;
}

.timer-input:focus {
	outline: none;
}

@keyframes pulse {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.45; }
}

.progress-track {
	width: 100%;
	height: 3px;
	margin-bottom: 1.5rem;
	background: var(--accent-light);
	display: flex;
}

/* flex-grow/shrink (not a fixed percentage basis) so the 249 segments
   always exactly fill the track's width between them — a fixed basis of
   100%/249 accumulates sub-pixel rounding error across that many items,
   leaving a sliver of the track's own background exposed at the end. */
.progress-seg {
	flex: 1 1 0;
	height: 100%;
}

/* Deliberately more saturated/vivid than the site's usual muted --accent-
   dark/--warn/--error text tokens — at 3px tall those read as one solid
   color, so they need more contrast between them than body text does. */
.progress-seg-correct { background: #0ad115; }
.progress-seg-corrected { background: #e6b800; }
.progress-seg-wrong { background: #e0272c; }

/* No longer used by the game itself (see .slideshow-viewport/.cell below)
   — kept because the names page's inline silhouette expansion (names.js)
   still builds one of these on click, deliberately without the crop-mark
   corners the game version used to have. */
.card {
	position: relative;
	width: 100%;
	aspect-ratio: 640 / 480;
	padding: 1.75rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--accent-light);
	border-radius: 4px;
}

/* Shared by any silhouette image on this site — the names page's inline
   expansion, and the grid game's per-cell .cell-img below. */
.silhouette-img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	filter: brightness(0) saturate(100%); /* force solid ink-black silhouette */
	opacity: 1;
}


/* ==========================================================================
   Slideshow — three cells visible at a time: the last-attempted cell, the
   one currently being played (middle), and one upcoming preview. The track
   slides left by one cell's width each time a new country activates.
   ========================================================================== */

.slideshow-viewport {
	position: relative;
	width: 100%;
	aspect-ratio: 4 / 1.35; /* three 4:3 cells side by side, plus a hair of breathing room */
	overflow: hidden;
	border-radius: 4px;
	background: var(--accent-light);
}

.slideshow-track {
	display: flex;
	height: 100%;
	transition: transform 0.4s ease;
}

.cell {
	position: relative;
	flex: 0 0 calc(100% / 3);
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--white);
	overflow: hidden;
	transition: background-color 0.15s ease;
}

.cell-img {
	max-width: 78%;
	max-height: 68%;
	object-fit: contain;
	filter: brightness(0) saturate(100%);
	opacity: 1;
}

.cell.active {
	outline: 2px solid var(--accent-dark);
	outline-offset: -2px;
	z-index: 1;
}

/* Only the background changes for a resolved cell — the silhouette itself
   stays fully black (no opacity dimming), so the color is purely a wash
   behind it, never masking the shape.
   wrong/skipped both mean "moved on without a correct answer" — same red,
   matching the review page's own red "Skipped" category (a wrong guess is
   folded into that category too, see game.js). */
.cell.wrong,
.cell.skipped {
	background: var(--error-wash);
}

.cell.correct { background: var(--accent-light); }

/* Matched, but only after a backspace correction along the way. */
.cell.corrected { background: var(--warn-wash); }

/* Comes after .wrong/.skipped so it wins when both could apply — a live,
   in-progress correction is more actionable than a past submission's
   outcome. */
.cell.mistake { background: var(--warn-wash); }

.mistake-char {
	background: var(--warn);
	color: var(--white);
	border-radius: 2px;
	padding: 0 1px;
}

.cell-typed {
	position: absolute;
	bottom: 1px;
	left: 2px;
	right: 2px;
	text-align: center;
	font-family: var(--font-mono);
	font-size: 0.55rem;
	color: var(--accent-dark);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	pointer-events: none;
}

/* Bounded to the slideshow viewport itself, never spilling into the
   hud/input row below. Tall content (a long review list) scrolls within
   this box rather than growing past it.
   justify-content:center would center-and-clip an overflowing child (its
   top spills past the scroll container and becomes unreachable) — instead
   the container packs from the start and each child gets auto vertical
   margins below, which centers it when there's room to spare but pins it
   to the top and scrolls normally once it's taller than the box. */
.card-cover {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-start;
	background: var(--accent-light);
	border-radius: 4px;
	padding: 1.25rem;
	overflow-y: auto;
	/* Reserve the scrollbar's gutter always, whether or not this tab's
	   content is actually tall enough to need it — otherwise switching to a
	   short tab (e.g. one country) removes the scrollbar and the content
	   area gets wider, visibly resizing the window between tabs. */
	scrollbar-gutter: stable;
}

.card-cover > * {
	margin-top: auto;
	margin-bottom: auto;
	flex-shrink: 0;
}

.cover-label {
	font-size: 1.75rem;
	letter-spacing: 0.05em;
	text-align: center;
	color: var(--accent-dark);
}

.answer-row {
	display: flex;
	align-items: stretch;
	gap: 0.6rem;
	margin-top: 1.4rem;
	width: 100%;
	height: 3.4rem;
}

.answer-row .btn-primary,
.answer-row .btn-danger {
	padding: 0 1rem;
	font-size: 0.85rem;
}

.answer-row .action-full,
.answer-row .action-primary {
	flex: 1;
}

#answer-input {
	flex: 1;
	font-family: inherit;
	font-size: 1.25rem;
	padding: 0 1rem;
	color: var(--black);
	background: var(--white);
	border: 2px solid var(--gray-light);
	border-radius: 3px;
}

#answer-input::placeholder { color: var(--gray); }

#answer-input:focus {
	outline: none;
	border-color: var(--accent-dark);
}

#answer-input:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 1px;
}

#answer-input:disabled,
#skip-btn:disabled {
	opacity: 0.5;
	cursor: default;
}

#skip-btn {
	background: transparent;
	color: var(--gray-dark);
	border: 2px solid var(--gray-light);
	border-radius: 3px;
	font-size: 0.85rem;
	padding: 0 1rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
}

#skip-btn:hover {
	border-color: var(--accent-dark);
	color: var(--accent-dark);
}

#skip-btn:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.hint {
	margin-top: 0.4rem;
	font-size: 0.8rem;
	text-align: center;
	color: var(--gray);
}

.hint kbd {
	font-family: var(--font-mono);
	background: var(--accent-light);
	padding: 1px 6px;
	border-radius: 3px;
}


/* ==========================================================================
   End panel (inside the card-cover, replacing a separate end screen)
   ========================================================================== */

#end-stats {
	text-align: center;
}

#end-stats h2 { margin-bottom: 1.25rem; }

.stat-row {
	display: flex;
	justify-content: center;
	gap: 1.75rem;
}

.stat {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.stat-tab {
	background: none;
	border: none;
	border-bottom: 2px solid transparent;
	font: inherit;
	cursor: pointer;
	padding: 0 0.1rem 0.3rem;
}

.stat-tab:hover { opacity: 0.8; }

.stat-tab:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.stat-tab.active[data-tab="correct"] { border-bottom-color: var(--accent-dark); }
.stat-tab.active[data-tab="corrected"] { border-bottom-color: var(--warn); }
.stat-tab.active[data-tab="skipped"] { border-bottom-color: var(--error); }

.stat-num {
	font-size: 1.6rem;
	color: var(--accent-dark);
}

.stat-num-correct { color: var(--accent-dark); }
.stat-num-corrected { color: var(--warn); }
.stat-num-skipped { color: var(--error); }

.stat-label {
	margin-top: 0.25rem;
	font-size: 0.7rem;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--gray);
}

#end-list { width: 100%; }

#end-list h3 {
	font-family: var(--font-mono);
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--gray);
	padding-bottom: 0.5rem;
	margin-bottom: 0.25rem;
	border-bottom: 1px solid var(--gray-light);
}

.clean-sweep {
	text-align: center;
	font-size: 1.1rem;
}

.clean-sweep-correct { color: var(--accent-dark); }
.clean-sweep-corrected { color: var(--warn); }
.clean-sweep-skipped { color: var(--error); }

.review-list {
	list-style: none;
	margin: 0;
	padding: 0 0 0.4rem;
}

.review-list li {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	padding: 0.4rem 0.25rem;
	font-size: 0.9rem;
}

.review-name {
	padding-top: 0.1rem; /* optically align with the first line of a multi-line attempts stack */
	flex: 1;
	min-width: 0;
}

.review-list li:hover {
	background: var(--accent-light);
}

.review-guess {
	font-family: var(--font-mono);
	font-size: 0.75rem;
	text-align: right;
	word-break: break-word;
}

.review-guess-match { color: var(--accent-dark); }
.review-guess-corrected { color: var(--warn); }
.review-guess-wrong { color: var(--error); }

/* Vertical stack, right-aligned under the country name — a round that took
   a few tries shows every string it saw, oldest first, red attempts above
   the eventual green/yellow one it landed on. */
.review-attempts {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 0.25rem;
	flex: 1;
	min-width: 0;
}


/* ==========================================================================
   Keystroke-error tally (aggregated across every round, not per-country —
   which specific letters the player keeps getting wrong, corrected or not)
   ========================================================================== */

.keystroke-stats {
	margin-top: 1rem;
}

.keystroke-group {
	margin-bottom: 1rem;
}

.keystroke-group h4 {
	margin: 0 0 0.4rem;
	font-size: 0.65rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--gray-dark);
}

.keystroke-tally {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.keystroke-tally li {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	font-family: var(--font-mono);
	font-size: 0.85rem;
	background: var(--accent-light);
	border-radius: 3px;
	padding: 0.3rem 0.55rem;
}

.op-from { color: var(--gray-dark); }
.op-arrow { color: var(--gray); font-size: 0.75rem; }
.op-corrected { color: var(--warn); font-weight: bold; }
.op-missed { color: var(--error); font-weight: bold; }

.op-count {
	color: var(--gray);
	font-size: 0.7rem;
}

.names-link {
	display: block;
	margin-top: 1.5rem;
	font-size: 0.85rem;
	text-align: center;
}


/* ==========================================================================
   Run history — every completed game (finished, timed out, or given up),
   most recent first, persisted in localStorage (see game.js recordRun()).
   Scrolls internally once it outgrows a handful of rows rather than
   pushing the rest of the page down.
   ========================================================================== */

.history-section {
	width: 100%;
	max-width: 640px;
	margin: 2.5rem auto 0;
}

.history-scroll {
	max-height: 260px;
	overflow-y: auto;
	border: 1px solid var(--gray-light);
	border-radius: 4px;
}

.history-table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.85rem;
}

.history-table th,
.history-table td {
	padding: 0.5rem 0.75rem;
	text-align: left;
}

.history-table th {
	position: sticky;
	top: 0;
	background: var(--white);
	font-size: 0.65rem;
	color: var(--gray);
	border-bottom: 1px solid var(--gray-light);
}

.history-table th.num,
.history-table td.num {
	text-align: right;
}

.history-table tbody tr:not(:last-child) td {
	border-bottom: 1px solid var(--gray-light);
}

.history-table tbody tr:nth-child(even) td {
	background: var(--accent-light);
}

.history-table tbody tr:hover td {
	background: var(--accent-light);
}

.history-actions {
	display: flex;
	justify-content: flex-end;
	margin-top: 0.6rem;
}

.clear-history-btn {
	background: none;
	border: none;
	padding: 0.2rem 0.4rem;
	font-size: 0.8rem;
	color: var(--gray);
	text-decoration: underline;
}

.clear-history-btn:hover:not(:disabled) {
	color: var(--error);
}

.clear-history-btn:focus-visible {
	outline: 3px solid var(--accent-dark);
	outline-offset: 2px;
}

.clear-history-btn:disabled {
	opacity: 0.4;
	cursor: default;
	text-decoration: none;
}

.history-correct { color: var(--accent-dark); }
.history-corrected { color: var(--warn); }
.history-skipped { color: var(--error); }

.history-flawless {
	margin-left: 0.3rem;
	color: var(--accent-dark);
	font-size: 0.75rem;
}

.history-empty {
	text-align: center;
	color: var(--gray);
	padding: 1.25rem 0.75rem;
}


/* ==========================================================================
   Shift+Space preview (see preview.js): the active game cell's silhouette,
   scaled to fit, shown in a fixed pane in the center third of the screen
   rather than following the cursor, so it never covers what you're typing.
   The white backdrop lives on the outer pane; the silhouette itself is a
   separate absolutely-positioned layer so the ink-black filter forced onto
   it doesn't also blacken the backdrop.
   ========================================================================== */

.zoom-preview {
	position: fixed;
	z-index: 50;
	left: 33.333vw;
	width: 33.333vw;
	top: 50%;
	transform: translateY(-50%);
	aspect-ratio: 4 / 3;
	background: var(--white);
	border: 2px solid var(--accent-dark);
	border-radius: 4px;
	box-shadow: var(--box-shadow);
	overflow: hidden;
	pointer-events: none;
}

.zoom-preview-img {
	position: absolute;
	inset: 0;
	background-repeat: no-repeat;
	background-size: contain;
	background-position: center;
	filter: brightness(0) saturate(100%); /* match the game's ink-black silhouette style */
}


/* ==========================================================================
   Progress-segment hover preview (see preview.js) — a small box that
   follows the cursor, tinted to match that round's outcome. Only ever
   shown for already-resolved (colored) segments; unresolved ones carry no
   data-code at all, so hovering ahead never previews a future country.
   ========================================================================== */

.seg-preview {
	position: fixed;
	z-index: 50;
	width: 140px;
	height: 105px;
	padding: 0.4rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--white);
	border: 2px solid var(--accent-dark);
	border-radius: 4px;
	box-shadow: var(--box-shadow);
	pointer-events: none;
}

.seg-preview img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	filter: brightness(0) saturate(100%);
}

.seg-preview.tint-correct { background: var(--accent-light); }
.seg-preview.tint-corrected { background: color-mix(in srgb, var(--warn) 15%, white); }
.seg-preview.tint-wrong { background: color-mix(in srgb, var(--error) 15%, white); }


/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 480px) {
	.card { padding: 1rem; }
	.stat-row { gap: 1rem; flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation: none !important;
		transition: none !important;
	}
}
