/* Guess the Word — Phase 2: designer-tool theme.
   Mobile-first: everything below is written for a phone viewport by default.
   The only concession to larger screens is pinning `.screen` to a phone-width
   column (see below) so the layout never just stretches out on desktop. */

:root {
  --canvas: #eceef1;
  --surface: #ffffff;
  --surface-alt: #f4f5f7;
  --border: #d7d9de;
  --border-strong: #c3c6cc;
  --text-primary: #17181b;
  --text-secondary: #6b6e76;
  --text-tertiary: #9497a0;
  --accent: #2d6cdf;
  --accent-soft: #eaf0fc;
  --accent-contrast: #ffffff;
  --success: #3fa066;
  --success-soft: #e3f5ea;
  --danger: #d9455f;
  --danger-soft: #fbe7ea;
  --warning: #c98a1f;
  --gold: #b8860b;
  --gold-bg: #f7eedb;
  /* Timer: green, then yellow, amber and red as the round runs down. */
  --timer-green: #2f9461;
  --timer-yellow: #c9a10c;
  --timer-amber: #d9741a;
  --timer-red: #d9455f;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 18px;
  --shadow-sm: 0 2px 10px rgba(20, 20, 30, 0.06);
  --shadow-md: 0 12px 40px rgba(20, 20, 30, 0.12);
  --scrim: rgba(20, 20, 30, 0.45); /* behind the pause dialog */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light;
}

/* Dark palette. `ui.js` (plus the no-flash inline script in index.html's
   <head>) always resolves and sets data-theme="light"|"dark" on <html> —
   from a saved explicit choice, or else from the system preference — so
   this attribute selector alone covers both cases; no media query needed. */
:root[data-theme="dark"] {
  --canvas: #1b1c1f;
  --surface: #232428;
  --surface-alt: #2a2b30;
  --border: #3a3b40;
  --border-strong: #4a4b52;
  --text-primary: #f2f2f4;
  --text-secondary: #a7a9b1;
  --text-tertiary: #7a7c84;
  --accent: #5b8def;
  --accent-soft: rgba(91, 141, 239, 0.16);
  --accent-contrast: #ffffff;
  --success: #4fbd80;
  --success-soft: rgba(79, 189, 128, 0.16);
  --danger: #e5677e;
  --danger-soft: rgba(229, 103, 126, 0.18);
  --warning: #e0b155;
  --gold: #f5c451;
  --gold-bg: #3a3222;
  --timer-green: #4fbd80;
  --timer-yellow: #f2d04b;
  --timer-amber: #f0963c;
  --timer-red: #ea6470;
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 12px 40px rgba(0, 0, 0, 0.5);
  --scrim: rgba(14, 15, 17, 0.72);
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  margin: 0;
  font-family: var(--font-ui);
  /* Shows on either side of the phone-width column once the viewport is
     wider than it; identical to the app background on an actual phone. */
  background: var(--canvas);
  color: var(--text-primary);
  overflow-x: hidden;
}

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

.hidden {
  display: none !important;
}

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

.btn {
  padding: 0.9em 1.6em;
  font-size: 1rem;
  font-weight: 600;
  border-radius: var(--radius-md);
  border: none;
  min-height: 44px;
  transition: background 0.2s var(--ease), transform 0.15s var(--ease);
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  width: min(240px, 100%);
  height: 56px;
  padding: 0;
  font-size: 19px;
  font-weight: 800;
  background: var(--accent);
  color: var(--accent-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
}

.btn-secondary {
  width: min(240px, 100%);
  height: 50px;
  padding: 0;
  font-size: 17px;
  background: var(--surface-alt);
  color: var(--text-primary);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
}

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

/* A 44px circular icon-only button — back/home/sound/stats/settings nav
   across the redesigned screens. Extends .theme-toggle's existing look
   (surface-alt, 1px border, circular) to the 44px touch-target size the
   redesign uses everywhere instead of that button's own 32px. */
.icon-btn {
  width: 44px;
  height: 44px;
  flex: none;
  box-sizing: border-box;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  transition: background 0.2s var(--ease), transform 0.15s var(--ease);
}

.icon-btn:active {
  transform: scale(0.94);
}

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

.icon-btn svg {
  width: 20px;
  height: 20px;
}

/* ---------- Screens ---------- */

.screen {
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: env(safe-area-inset-top, 0px);
  display: flex;
  flex-direction: column;
  max-width: 480px;
  margin: 0 auto;
  background: var(--surface);
  position: relative;
}

@media (min-width: 481px) {
  .screen {
    box-shadow: var(--shadow-md);
  }
}

/* ---------- Offline badge ---------- */
/* Lives on the Start screen now (the old app-bar it used to sit in was
   removed as part of the redesign — Settings' theme segmented control
   took over theme control, and there was nothing else left for a bar to
   hold). Small, unobtrusive — not an error state, just a heads-up. (Phase 4) */
.offline-badge {
  display: table;
  margin: 10px auto 0;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 600;
  color: var(--text-secondary);
  background: var(--surface-alt);
  border: 1px solid var(--border);
  padding: 0.2em 0.55em;
  border-radius: 999px;
  white-space: nowrap;
}

/* ---------- Start screen ---------- */

.start-screen {
  position: relative;
  overflow: hidden;
  padding: 0 24px 36px;
}

/* Faint, non-interactive letter tiles scattered behind the hero. */
.start-bg-tiles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  font-family: var(--font-mono);
  font-weight: 800;
}

.start-bg-tiles span {
  position: absolute;
  width: 40px;
  height: 42px;
  border-radius: 9px;
  background: var(--surface-alt);
  opacity: 0.45;
  color: var(--border-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}

.start-nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 0 0;
}

.start-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin-top: 72px;
}

.hero-heading {
  font-size: 44px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
}

.hero-tiles {
  display: flex;
  gap: 8px;
}

.hero-tile {
  width: 64px;
  height: 70px;
  border-radius: 12px;
  background: var(--accent);
  box-shadow: 0 5px 0 color-mix(in srgb, var(--accent) 62%, black);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 38px;
  font-weight: 800;
  color: var(--accent-contrast);
}

.hero-tile:nth-child(1) { transform: rotate(-3deg); }
.hero-tile:nth-child(2) { transform: translateY(-4px) rotate(2deg); }
.hero-tile:nth-child(3) { transform: rotate(-1deg); }

.hero-tile-blank {
  background: var(--success-soft);
  box-shadow: 0 5px 0 color-mix(in srgb, var(--success) 55%, black);
  border: 2px dashed var(--success);
  box-sizing: border-box;
  color: var(--success);
  transform: translateY(-2px) rotate(4deg);
}

.hero-subtitle {
  margin: 4px 0 0;
  max-width: 290px;
  text-align: center;
  font-size: 17px;
  line-height: 1.5;
  color: var(--text-secondary);
}

.start-actions {
  position: relative;
  margin-top: auto;
  padding-top: 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* ---------- Shared screen header (How to play / Stats / Settings) ---------- */

.screen-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 24px 0;
}

/* Stats and Settings already pad the whole screen by 24px, so their header
   mustn't add its own 24px on top; otherwise the back arrow sits 24px to
   the right of the content below it. */
.stats-screen .screen-header,
.settings-screen .screen-header {
  padding-left: 0;
  padding-right: 0;
}

.screen-title {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
}

/* ---------- How to play ---------- */

.htp-example {
  margin: 24px 24px 0;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 22px 16px 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.htp-example-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-weight: 800;
}

.htp-chip {
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--text-primary);
  font-size: 18px;
}

.htp-plus {
  color: var(--text-tertiary);
  font-size: 16px;
}

.htp-slots {
  display: flex;
  gap: 4px;
}

.htp-slot {
  width: 30px;
  height: 40px;
  border-radius: 8px;
  border: 2px dashed var(--border-strong);
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}

.htp-slot-filled {
  border-style: solid;
  border-color: var(--success);
  color: var(--success);
  background: var(--success-soft);
  animation: example-pop 2.4s ease-in-out infinite;
}

@keyframes example-pop {
  0%, 40%, 100% { transform: scale(1); }
  20% { transform: scale(1.12); }
}

.htp-caption {
  margin: 0;
  text-align: center;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-secondary);
}

.htp-caption strong {
  color: var(--text-primary);
  font-weight: 600;
}

.htp-pills {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}

.htp-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 10px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}

.htp-steps {
  list-style: none;
  margin: 28px 0 0;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.htp-steps li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.htp-step-num {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 16px;
}

.htp-step-title {
  font-size: 16px;
  font-weight: 600;
}

.htp-step-body {
  margin-top: 4px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-secondary);
}

.htp-actions {
  margin-top: auto;
  padding: 24px 24px 36px;
  display: flex;
  justify-content: center;
}

/* ---------- Stats ---------- */

.stats-screen {
  padding: 0 24px 28px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.stats-best-card {
  margin-top: 24px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.stats-trophy {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-md);
  background: var(--gold-bg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.stats-best-label {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

.stats-best-value {
  font-size: 1.9rem;
  font-weight: 800;
  line-height: 1.2;
}

.stats-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.stats-tile {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.stats-tile-value {
  font-size: 1.25rem;
  font-weight: 800;
}

.stats-tile-label {
  font-size: 0.75rem;
  color: var(--text-secondary);
}

.stats-chart-card {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.stats-chart-heading {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

.stats-chart-title {
  font-size: 0.92rem;
  font-weight: 600;
}

.stats-chart-subtitle {
  font-size: 0.8rem;
  color: var(--text-secondary);
}

.stats-chart {
  height: 104px;
  display: flex;
  align-items: flex-end;
  gap: 7px;
}

.stats-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  height: 100%;
}

.stats-bar-value {
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--text-tertiary);
}

.stats-bar.best .stats-bar-value {
  color: var(--text-primary);
}

.stats-bar-fill {
  width: 100%;
  border-radius: 5px 5px 2px 2px;
  background: color-mix(in srgb, var(--accent) 45%, var(--surface-alt));
}

.stats-bar.best .stats-bar-fill {
  background: var(--accent);
}

.stats-empty {
  margin: 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-secondary);
}

/* ---------- Settings ---------- */

.settings-screen {
  padding: 0 24px 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.settings-screen .settings-group:first-of-type {
  margin-top: 24px;
}

.settings-group {
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px;
}

.settings-row + .settings-row {
  border-top: 1px solid var(--border);
}

.settings-row-stacked {
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}

.settings-row-text {
  min-width: 0;
}

.settings-row-label {
  font-size: 0.95rem;
  font-weight: 600;
}

.settings-row-desc {
  margin-top: 2px;
  font-size: 0.78rem;
  color: var(--text-secondary);
  line-height: 1.4;
}

.settings-row-action {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-ui);
  text-align: left;
  cursor: pointer;
}

.settings-row-action svg {
  flex: none;
  color: var(--text-tertiary);
}

/* A real iOS-style switch built from a track + a sliding thumb (not a
   native checkbox), so it can be themed consistently with the rest of this
   component set across both light and dark mode. */
.switch {
  flex: none;
  width: 46px;
  height: 28px;
  border-radius: 999px;
  border: none;
  background: var(--border-strong);
  position: relative;
  transition: background 0.2s var(--ease);
}

.switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform 0.2s var(--ease);
}

.switch.on {
  background: var(--accent);
}

.switch.on .switch-thumb {
  transform: translateX(18px);
}

/* --canvas (not --surface-alt) for the track, deliberately: this control
   sits inside a .settings-group that's already --surface-alt, and --canvas
   is reliably darker than both --surface and --surface-alt in each theme,
   so the track reads as "recessed" regardless of what it's nested in —
   the same relationship .terms-filter relies on where it sits directly on
   a --surface page background instead. */
.theme-segmented {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 10px;
  background: var(--canvas);
  border: 1px solid var(--border);
}

.theme-segment-btn {
  flex: 1;
  height: 36px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: 0.85rem;
  font-weight: 600;
}

.theme-segment-btn.active {
  background: var(--surface);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

.settings-version {
  margin: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-tertiary);
}

.camera-toggle {
  display: flex;
  align-items: center;
  gap: 0.6em;
  font-size: 0.95rem;
  cursor: pointer;
}

.camera-toggle input {
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
}

.camera-privacy-note {
  margin: -0.4rem 0 0;
  font-size: 0.78rem;
  color: var(--text-tertiary);
  text-align: center;
}

/* Lets the player visually confirm offline caching actually finished before
   they rely on it (e.g. before switching to airplane mode for a demo) —
   rather than having to guess how long the background download takes. */
.offline-ready-status {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
  padding: 0.35em 0.8em;
  border-radius: 999px;
}

.offline-ready-status.preparing {
  color: var(--text-secondary);
  background: var(--surface-alt);
}

.offline-ready-status.ready {
  color: var(--success);
  background: var(--success-soft);
}

.camera-status-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
}

.camera-status-message {
  margin: 0;
  color: var(--text-secondary);
}

/* ---------- Game screen top controls (pause / sound) ---------- */

.game-top-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 1.25rem 0;
}

/* Hidden in AR mode — camera mode has no pause/sound row of its own; the
   HUD's existing icon-free layout is kept as-is there. */
#game-screen.ar-active .game-top-controls {
  display: none;
}

/* ---------- HUD (toolbar) ---------- */

/* Three columns — the two outer ones share the leftover space equally, so
   the middle (auto-width) column always lands exactly centered across the
   bar regardless of how wide the timer or tries happen to be. Same
   markup in both the normal and AR screens, so this applies to both. */
.hud {
  padding: 1rem 1.25rem 0;
}

/* Bordered card split into three equal columns by hairlines, each with an
   uppercase label above its value — TIME / SCORE / TRIES. */
.hud-card {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.hud-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 4px 9px;
}

.hud-score {
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
}

.hud-label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
}

.hud-value {
  height: 40px;
  display: flex;
  align-items: center;
  font-size: 1.3rem;
  font-weight: 700;
}

.hud-hearts {
  display: flex;
  gap: 2px;
  height: 40px;
  align-items: center;
}

.heart {
  width: 22px;
  height: 22px;
  fill: var(--danger);
  stroke: var(--danger);
  stroke-width: 2;
  stroke-linejoin: round;
  transition: fill 0.2s var(--ease), stroke 0.2s var(--ease), transform 0.2s var(--ease);
}

.heart.lost {
  fill: none;
  stroke: var(--border-strong);
  transform: scale(0.88);
}

.hud-timer-ring {
  position: relative;
  width: 48px;
  height: 40px;
}

@keyframes timer-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.08); }
}

.hud-timer.pulse {
  animation: timer-pulse 1s ease-in-out infinite;
}

.timer-value {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  transition: color 0.2s linear;
}

/* Each second is its own digit, stacked in the same spot. A new digit rolls
   up into place and the old one rolls out upward. */
.timer-cell {
  position: relative;
  display: block;
  width: 0.62em;
  height: 1.2em;
  line-height: 1.2em;
  text-align: center;
  overflow: hidden;
}
.timer-digit {
  display: block;
  height: 100%;
}
.timer-digit.roll-in {
  animation: timer-roll-in 0.25s ease-out;
}
/* The outgoing digit leaves the flow so the incoming one takes its place. */
.timer-digit.roll-out {
  position: absolute;
  inset: 0;
  animation: timer-roll-out 0.25s ease-in forwards;
}
@keyframes timer-roll-in {
  from { transform: translateY(70%); opacity: 0; }
  to { transform: none; opacity: 1; }
}
@keyframes timer-roll-out {
  from { transform: none; opacity: 1; }
  to { transform: translateY(-70%); opacity: 0; }
}

/* ---------- AR mode (camera + face tracking) ---------- */
/* #ar-layer sits as the first child of #game-screen (see index.html), so it
   paints behind the HUD/board/input-bar (later siblings) without needing
   explicit z-index — see the comment above .hud's ar-active override below
   for why the HUD still needs an opaque-ish background of its own.

   position: absolute (not fixed) deliberately, contained within #game-screen
   (.screen, which is position: relative and capped at max-width: 480px) —
   so on a wide desktop window the camera feed stays inside the same
   phone-width frame as the rest of the app instead of covering the full
   browser viewport edge to edge. On an actual phone .screen already fills
   the viewport, so this is a no-op there. */

.ar-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #000;
  pointer-events: none;
}

.camera-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1); /* mirror for a natural, selfie-style view */
}

.move-into-frame {
  position: absolute;
  bottom: 20%;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  background: var(--surface);
  color: var(--text-primary);
  padding: 0.5em 1.1em;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}

/* Pause card shown when the player returns after leaving the app
   mid-camera-game. The game has already switched to typing behind it. */
.resume-card {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 30;
  width: min(320px, calc(100% - 32px));
  padding: 1.5rem 1.25rem 1.25rem;
  background: var(--surface);
  border-radius: var(--radius-lg);
  /* The first shadow is a page-wide scrim, so the card reads as a modal
     over the paused board. */
  box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.35), var(--shadow-md);
  text-align: center;
}

.resume-title {
  margin: 0 0 0.4rem;
  font-size: 1.15rem;
  color: var(--text-primary);
}

.resume-body {
  margin: 0 0 1.1rem;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--text-secondary);
}

.resume-card .btn {
  width: 100%;
}

/* Quiet pill near the bottom of the camera view, where the input bar sits
   in typing mode: "Switch to typing" and "Tap to speak" (never both). */
.ar-pill-btn {
  position: fixed;
  bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  min-height: 44px;
  padding: 0.55em 1.2em;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-primary);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s var(--ease);
}

.ar-pill-btn:active {
  transform: translateX(-50%) scale(0.97);
}

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

/* Small, non-blocking indicator while the face-tracking model downloads in
   the background (Phase 4) — gameplay and the camera view are never gated
   on this, so it's deliberately a quiet corner note, not a loading screen. */
/* left/top are set in JS (positionArHint() in ui.js), tracking the card's
   own on-screen position every frame — not a fixed screen position, which
   previously put this right around the player's mouth/chin regardless of
   where the card (and face) actually were. translate: -50% -100% anchors
   the bubble's bottom-center tip at (left, top), i.e. just above the card.
   Kept as the standalone `translate`/`scale` properties (not `transform`)
   so the pop-in animation below can animate `scale` alone without
   fighting this positioning — same technique already used for the
   wrong-answer shake on the AR-tracked card. */
.ar-hint {
  /* fixed, not absolute: positionArHint() in ui.js assigns viewport-space
     coordinates from getBoundingClientRect() straight to left/top, the
     same way #word-card.ar-tracked already does above. With `absolute`
     those coordinates would instead be relative to the nearest positioned
     ancestor (#ar-layer) — invisible on a real phone (where .screen fills
     the viewport so that ancestor starts at the same origin anyway), but
     wrong the moment it doesn't, e.g. the centered phone-width column on
     a wider screen used for testing. */
  position: fixed;
  /* #word-card.ar-tracked sets z-index: 1 explicitly, so without a
     z-index here the card always wins (an explicit z-index beats
     z-index: auto regardless of DOM order) — the card is pinned to the
     tracked head position and the hint sits right at its edge, so they
     overlap often enough that this was genuinely visible, not a rare
     edge case ("falls behind the card"). One higher keeps the hint on
     top whenever they touch. */
  z-index: 2;
  left: 0;
  top: 0;
  translate: -50% -100%;
  scale: 1;
  width: max-content;
  max-width: calc(100% - 32px);
  margin: 0;
  padding: 0.65em 1em 0.65em 2.3em;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1.5px solid var(--warning);
  color: var(--text-primary);
  font-size: 0.95rem;
  line-height: 1.4;
  text-align: center;
  box-shadow: var(--shadow-md);
  animation: ar-hint-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* The same "i" glyph as the typing-mode hint button, so this reads as the
   same kind of hint rather than a generic status note. */
.ar-hint::before {
  content: "i";
  position: absolute;
  left: 0.65em;
  top: 50%;
  translate: 0 -50%;
  width: 1.3em;
  height: 1.3em;
  border-radius: 50%;
  background: var(--warning);
  color: var(--surface);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.85em;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Hidden when the HUD clamp (positionArHint() in ui.js) has pushed the
   bubble down near/into the card instead of clear above it — the pointer
   would otherwise touch the card's middle rather than its top edge. */
.ar-hint--clamped::after {
  display: none;
}

/* positionArHint() flips to below the card when there isn't room above
   (e.g. a two-line definition over a card tracking near the top of the
   frame) — anchor the bubble's top-center instead of its bottom-center. */
.ar-hint--below {
  translate: -50% 0;
}

/* A small pointer touching the card, so the bubble visually reads as
   coming FROM the card rather than floating unrelated nearby. Points
   down at a card below by default; .ar-hint--below::after further down
   flips it to point up at a card above instead — that rule must come
   AFTER this one in the file, since both selectors have equal specificity
   and CSS falls back to source order for properties declared in both. */
.ar-hint::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -6px;
  width: 11px;
  height: 11px;
  background: var(--surface);
  border-right: 1.5px solid var(--warning);
  border-bottom: 1.5px solid var(--warning);
  translate: -50% 0;
  rotate: 45deg;
}

.ar-hint--below::after {
  top: -6px;
  bottom: auto;
  border-right: none;
  border-bottom: none;
  border-left: 1.5px solid var(--warning);
  border-top: 1.5px solid var(--warning);
}

@keyframes ar-hint-pop {
  from {
    opacity: 0;
    scale: 0.7;
  }
  60% {
    opacity: 1;
    scale: 1.06;
  }
  to {
    opacity: 1;
    scale: 1;
  }
}

.model-load-progress {
  position: absolute;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  color: var(--text-secondary);
  padding: 0.3em 0.9em;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.03em;
}

.voice-load-progress {
  top: 3rem; /* below the face-tracking progress note, in case both show */
}

/* The HUD previously got a translucent, blurred backing in AR mode (to stay
   legible over the live camera feed) — removed per feedback: the HUD now
   floats directly over the video with no panel behind it at all, leaving
   more visible room for the word card. (The matching rule for .input-bar
   was dead code by this point anyway — the input bar is always hidden in
   AR mode now, see activateArMode() in ui.js.) */

/* Over the live camera feed the HUD has no opaque screen behind it, and the
   video can be any brightness — independent of the app's light/dark theme —
   so text, ring and swatches that look fine on one background vanish on
   another (reported on light backgrounds). Two compact "chips" (timer +
   score, and tries) each carry their own mostly-opaque, blurred backing in
   the theme's surface colour, so the theme's text colours always sit on the
   surface colour they were designed for, whatever the video shows. A full
   width bar was removed earlier for eating into the room the word card
   needs; chips only cover the elements themselves. The HUD's own
   border-bottom is dropped too — it separates the HUD from the board on an
   opaque screen, and floating over video it just reads as a stray line. */
#game-screen.ar-active .hud {
  border-bottom: none;
  align-items: flex-start;
  padding: 0.6rem 0.75rem;
}

/* One blurred translucent card over the video, now that the default (non-AR)
   HUD is already a single bordered card rather than three separate chips. */
#game-screen.ar-active .hud-card {
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow-sm);
}

#game-screen.ar-active .board {
  position: relative;
}

/* Positioned every frame by ui.js (left/top + a translate+scale transform)
   while the face is tracked; otherwise behaves like the normal centered card. */
#word-card.ar-tracked {
  position: fixed;
  z-index: 1;
  margin: 0;
}

.word-card.faded {
  opacity: 0.72; /* still readable over a bright camera feed — it was 0.55 */
}

/* ---------- Board / word card ---------- */

.board {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
}

.word-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 2.25rem 2.5rem;
  min-width: 260px;
  max-width: 90vw;
  text-align: center;
  box-shadow: var(--shadow-sm);
  transition: background 0.3s var(--ease), box-shadow 0.3s var(--ease), border-color 0.3s var(--ease), transform 0.2s var(--ease);
}

/* The in-game card reads as a selected text layer in a design tool: a
   dashed selection outline plus corner handles (added below). */
#word-card {
  border-style: dashed;
  border-width: 2px;
  border-color: var(--accent);
  /* Fixed width, so the card does not change size when the clue appears
     (its width would otherwise follow the longer clue sentence). */
  width: min(340px, 90vw);
}

/* The merged answer after a correct guess is centred in the card, so its
   bottom padding matches the top one (the clue is hidden at that point). */
#word-card.correct {
  padding-bottom: calc(2.25rem + 0.5rem); /* + the merged line's own top margin */
}

.handle {
  position: absolute;
  width: 8px;
  height: 8px;
  background: var(--surface);
  border: 1.5px solid var(--accent);
  border-radius: 2px;
}

.handle-tl { top: -5px; left: -5px; }
.handle-tr { top: -5px; right: -5px; }
.handle-bl { bottom: -5px; left: -5px; }
.handle-br { bottom: -5px; right: -5px; }

.word-card.correct .handle {
  border-color: var(--success);
}

.word-card.wrong .handle {
  border-color: var(--danger);
}

.word-card.correct {
  background: var(--success-soft);
  border-color: var(--success);
  box-shadow: 0 0 0 4px var(--success-soft);
}

.word-card.wrong {
  background: var(--danger-soft);
  border-color: var(--danger);
  animation: shake 0.35s ease;
}

/* The shake still visibly read as unstable/jittery in AR mode even once it
   stopped displacing the card (see the translate-based fix below) — on
   top of the card already moving slightly every frame to follow the face,
   an extra wiggle read as the whole thing being shaky rather than a
   distinct "wrong" cue. Fully disabled for the AR-tracked card; the red
   background/border above is still the wrong-answer signal, just without
   any motion. Non-AR mode keeps the shake as originally specified. */
#word-card.ar-tracked.wrong {
  animation: none;
}

/* Uses the standalone `translate` property, not `transform: translateX(...)`
   — in AR mode, ui.js sets the card's position/scale via an inline
   `transform` every frame (to follow the tracked face), and animating
   `transform` here would override that inline value for the animation's
   duration, yanking the card away from its tracked spot and snapping it
   back once the shake ended. `translate` composes with `transform`
   instead of replacing it, so the card shakes in place — relative to
   wherever it currently is above the face — without ever displacing from
   it. (In non-AR mode, where no inline transform is set, this renders
   identically to the old transform-based version.) */
@keyframes shake {
  0%, 100% { translate: 0 0; }
  20% { translate: -8px 0; }
  40% { translate: 8px 0; }
  60% { translate: -5px 0; }
  80% { translate: 5px 0; }
}

.chain-toast {
  position: absolute;
  top: -1.9rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.3em 0.9em;
  border-radius: 999px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  white-space: nowrap;
}

.chain-toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(-8px);
}

.hint-btn {
  position: absolute;
  top: 0.7rem;
  left: 0.7rem;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1.5px solid var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 700;
  font-style: italic;
  font-family: Georgia, "Times New Roman", serif;
  line-height: 1;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: hint-pop 0.25s ease;
}

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

@keyframes hint-pop {
  0% { transform: scale(0.4); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

.near-miss {
  margin: 0.75rem 0 0;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--warning);
}

.near-miss.very-close {
  color: var(--success);
}

/* Visible status line below the word box (wrong guess / time's up / out of
   tries) — see setStatusLine()/clearStatusLine() in ui.js. */
.status-line {
  margin: 0.9rem 0 0;
  text-align: center;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text-secondary);
}

/* Camera mode: a pill over the video, above the hint caption. */
.near-miss-pill {
  position: absolute;
  bottom: 34%;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  padding: 0.45em 1.1em;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}





.card-main-word {
  font-size: clamp(2rem, 8vw, 3.2rem);
  font-weight: 800;
  letter-spacing: 0.02em;
  margin-top: 0.5rem;
}

.card-slots {
  display: flex;
  gap: 0.4em;
  justify-content: center;
  margin-top: 1.2rem;
  flex-wrap: wrap;
}

.slot {
  width: clamp(1.6rem, 6vw, 2.2rem);
  height: clamp(2.2rem, 8vw, 2.8rem);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(1.2rem, 5vw, 1.6rem);
  font-weight: 700;
  font-family: var(--font-mono);
  border-bottom: 3px solid var(--border-strong);
  text-transform: uppercase;
}

.slot.filled {
  border-color: var(--accent);
}

/* Only the blank that just changed plays the pop, not every filled blank. */
.slot.fresh {
  animation: slot-pop 0.12s ease-out;
}

.slot.locked {
  border-color: var(--text-tertiary);
}

@keyframes slot-pop {
  0% { transform: scale(1.3); }
  100% { transform: scale(1); }
}

.card-merged {
  display: none;
  font-size: clamp(1.8rem, 7vw, 2.6rem);
  font-weight: 800;
  color: var(--success);
  margin-top: 0.5rem;
  letter-spacing: 0.02em;
}

.word-card.correct .card-main-word,
.word-card.correct .card-slots {
  display: none;
}

.word-card.correct .card-merged {
  display: block;
}

/* ---------- Input bar ---------- */

.input-bar {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0.8rem 1rem calc(0.8rem + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(to top, var(--surface) 60%, transparent);
}

.guess-input {
  flex: 1;
  min-width: 0;
  height: 56px;
  box-sizing: border-box;
  font-size: 1.1rem;
  padding: 0 1em;
  border-radius: var(--radius-md);
  border: 2px solid var(--accent);
  background: var(--surface);
  color: var(--text-primary);
  text-transform: uppercase;
}

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

.guess-submit-btn {
  flex: none;
  width: 56px;
  height: 56px;
  box-sizing: border-box;
  border: none;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
}

.guess-submit-btn:active {
  transform: scale(0.94);
}

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

/* The answer box is out of sight: the letter slots show the guess, and the
   keyboard's Go key (or the last letter) submits it. The box stays in the
   page, focusable, because focusing it is what opens the phone's keyboard;
   tapping the board focuses it (ui.js). */
#guess-form.input-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  opacity: 0;
  background: none;
}

#guess-form .guess-submit-btn {
  display: none;
}

/* ---------- Game over screen (styled like an exported artboard) ---------- */

#gameover-screen {
  align-items: center;
  padding: 1.5rem 1rem 2rem;
}

@keyframes gameover-enter {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

.gameover-wrap {
  width: 100%;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  /* 1.5rem (24px) horizontal, matching .screen-header's left inset exactly —
     otherwise the Home icon-button here sits a few px off from the back
     icon-button on every other screen (Stats/Settings/How to play). */
  padding: 0.5rem 1.5rem 1.75rem;
  animation: gameover-enter 0.4s var(--ease);
}

.gameover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.gameover-header .gameover-nav {
  padding: 0;
}

@keyframes badge-pop {
  0% { transform: scale(0.5); opacity: 0; }
  70% { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); }
}

.score-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.gameover-subtitle {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.score-hero-value {
  font-size: 3.6rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
}

.score-hero-label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-tertiary);
}

.best-badge {
  margin-top: 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border-radius: 999px;
  font-size: 0.82rem;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  font-weight: 500;
}

.best-badge strong {
  color: var(--text-primary);
}

.best-badge-new {
  background: var(--gold-bg);
  border: none;
  color: var(--gold);
  font-weight: 700;
  animation: badge-pop 0.5s var(--ease);
}

.gameover-actions {
  display: flex;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}

.copy-confirm {
  min-height: 1.2em;
  font-size: 0.85rem;
  text-align: center;
  color: var(--success);
  margin: 0.2rem 0 0;
}

.terms-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 0.75rem;
}

.terms-heading h2 {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
}

.terms-filter {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 10px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
}

.terms-filter-btn {
  height: 30px;
  padding: 0 10px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 5px;
}

.terms-filter-btn span {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--text-tertiary);
}

.terms-filter-btn.active {
  background: var(--surface);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

.terms-filter-btn.active span {
  color: var(--accent);
}

/* Color-coded regardless of active state — an ID selector so it always
   outranks the generic `.active span` rule above. */
#filter-correct-count {
  color: var(--success);
}

#filter-missed-count {
  color: var(--danger);
}

.terms-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.term-row-divider {
  border-top: 1px solid var(--border);
}

.term-row-btn {
  width: 100%;
  min-height: 52px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border: none;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
}

.term-row-btn.open-bg {
  background: var(--surface);
}

.term-status-badge {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: var(--success-soft);
  color: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
}

.term-status-badge svg {
  width: 14px;
  height: 14px;
}

.term-status-badge.missed {
  background: var(--danger-soft);
  color: var(--danger);
}

.term-row-name {
  flex: 1;
  min-width: 0;
  font-size: 0.95rem;
  font-weight: 600;
}

.term-row-pts {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.88rem;
  font-weight: 800;
  color: var(--success);
}

.term-row-pts.missed {
  color: var(--danger);
}

.term-row-chevron {
  flex: none;
  display: flex;
  color: var(--success);
  transition: transform 0.2s var(--ease);
}

.term-row-chevron.missed {
  color: var(--danger);
}

.term-row-chevron.open {
  transform: rotate(180deg);
}

/* Matches .term-row-btn.open-bg's background exactly — the row above it and
   this panel are one continuous surface, not a seam of two different tones. */
.term-row-def {
  background: var(--surface);
  padding: 0 14px 14px 52px;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-secondary);
}

.term-row-empty {
  padding: 1.1rem;
  text-align: center;
  font-size: 0.9rem;
  color: var(--text-secondary);
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- On-screen keyboard (typing mode) ----------
   ui.js adds html.kb-open while the input has focus and the visual
   viewport has shrunk by a keyboard, and keeps --vv-height / --vv-top at the
   visible area's height and its top edge (visualViewport.offsetTop), every
   frame. The game screen is fixed to exactly that area, so it stays in view
   whatever iOS has scrolled underneath, and the layout tightens (smaller HUD and controls, less
   padding) so the HUD, the word card and the input all fit above the
   keyboard even on a small phone. */
html.kb-open,
html.kb-open body {
  overflow: hidden;
}

html.kb-open #game-screen {
  position: fixed;
  top: var(--vv-top, 0px);
  left: 0;
  right: 0;
  width: 100%;
  height: var(--vv-height, 100dvh);
  min-height: 0;
}

/* Only the board may shrink. If the content is taller than the visible
   area, the board scrolls inside itself instead of pushing the input bar
   below the keyboard. When that happened, iOS scrolled the page to bring
   the focused input back into view, and the pause/sound row and the HUD
   went off the top of the screen. */
html.kb-open .game-top-controls,
html.kb-open .hud,
html.kb-open .input-bar {
  flex: none;
}

/* Smaller pause/sound row while typing. */
html.kb-open .game-top-controls {
  padding: 0.4rem 1rem 0;
}

html.kb-open .game-top-controls .icon-btn {
  width: 36px;
  height: 36px;
}

html.kb-open .game-top-controls .icon-btn svg {
  width: 18px;
  height: 18px;
}

/* Smaller HUD while typing: the TIME/SCORE/TRIES labels stay, with less
   spacing and a smaller ring. */
html.kb-open .hud {
  align-items: center;
  padding: 0.4rem 1rem 0;
}

html.kb-open .hud-item {
  padding: 4px 4px 5px;
  gap: 2px;
}

html.kb-open .hud-label {
  font-size: 0.6rem;
}

html.kb-open .hud-value,
html.kb-open .hud-hearts,
html.kb-open .hud-timer-ring,
html.kb-open .timer-ring {
  height: 30px;
}

html.kb-open .hud-timer-ring,
html.kb-open .timer-ring {
  width: 30px;
}

html.kb-open .board {
  flex: 1 1 0;
  padding: 0.4rem 1rem;
  min-height: 0;
  overflow-y: auto;
  align-items: center;
}

/* Centred while it fits; when it doesn't, it starts at the top of the board
   rather than being cut off above it. */
html.kb-open .board > .word-card {
  margin-block: auto;
}

html.kb-open .word-card {
  padding: 0.7rem 1.25rem;
}

/* Same centring for the merged answer while the keyboard is open: the bottom
   padding matches the smaller top padding above, plus the merged line's top
   margin. */
html.kb-open #word-card.correct {
  padding-bottom: calc(0.7rem + 0.5rem);
}

html.kb-open .card-main-word {
  margin-top: 0;
  font-size: 2rem;
}

html.kb-open .card-slots {
  margin-top: 0.6rem;
}

html.kb-open .hint-text,
html.kb-open .status-line,
html.kb-open .near-miss {
  margin-top: 0.5rem;
  font-size: 0.82rem;
}

html.kb-open .hint-text {
  padding: 0.4em 0.7em;
}

html.kb-open .input-bar {
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
}

html.kb-open .guess-input,
html.kb-open .guess-submit-btn {
  height: 46px;
}

html.kb-open .guess-submit-btn {
  width: 46px;
}

/* ---------- Pause screen (pause.js) ----------
   From pause-screen/pause.css, mapped to this project's tokens so it
   follows the light and dark themes. */

/* While paused the puzzle is hidden: the main word becomes a blank bar,
   and the slots, typed guess, hint and messages turn invisible (their
   shapes stay). */
.gtw-is-paused [data-pause-skeleton] {
  color: transparent !important;
  text-shadow: none !important;
  background: var(--surface-alt);
  border-radius: var(--radius-sm);
  user-select: none;
}

.gtw-is-paused [data-pause-hide],
.gtw-is-paused [data-pause-hide] * {
  color: transparent !important;
  text-shadow: none !important;
  user-select: none;
}

.gtw-is-paused [data-pause-hide]::placeholder {
  color: transparent !important;
}

.pause-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
  background: var(--scrim);
  animation: pause-fade 0.18s var(--ease);
}

.pause-overlay[hidden] {
  display: none;
}

.pause-dialog {
  width: 100%;
  max-width: 320px;
  box-sizing: border-box;
  padding: 32px 24px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 24px;
  box-shadow: var(--shadow-md);
  color: var(--text-primary);
  font-family: var(--font-ui);
  animation: pause-pop 0.2s var(--ease);
}

.pause-dialog:focus {
  outline: none;
}

.pause-dialog__icon {
  width: 64px;
  height: 64px;
  border-radius: 18px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.pause-dialog__icon svg {
  width: 28px;
  height: 28px;
  fill: currentColor;
}

.pause-dialog__title {
  margin: 18px 0 0;
  font-size: 26px;
  font-weight: 800;
}

.pause-dialog__desc {
  margin: 8px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--text-secondary);
}

.pause-dialog__desc strong {
  color: var(--text-primary);
  font-weight: 700;
}

.pause-dialog__actions {
  margin-top: 26px;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.pause-btn {
  width: 240px;
  max-width: 100%;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: var(--radius-md);
  font: inherit;
  cursor: pointer;
}

.pause-btn svg {
  width: 18px;
  height: 18px;
}

.pause-btn--resume {
  height: 56px;
  border: 0;
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 18px;
  font-weight: 800;
}

.pause-btn--resume svg {
  fill: currentColor;
}

.pause-btn--resume:active {
  filter: brightness(0.92);
}

.pause-btn--exit {
  height: 50px;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--danger);
  font-size: 16px;
  font-weight: 600;
}

.pause-btn--exit svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

.pause-dialog__note {
  margin: 14px 0 0;
  font-size: 12px;
  color: var(--text-tertiary);
}

@keyframes pause-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes pause-pop {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .pause-overlay,
  .pause-dialog {
    animation: none;
  }
}

/* ---------- Short phones (e.g. iPhone SE in Safari) ----------
   A more compact game screen so the HUD, the card with a two-line hint and
   the game keyboard fit without scrolling. Last in the file so it wins over
   the base rules above. */
@media (max-height: 640px) {
  .game-top-controls {
    padding-top: 0.4rem;
  }

  .game-top-controls .icon-btn {
    width: 38px;
    height: 38px;
  }

  .hud {
    padding-top: 0.4rem;
  }

  .hud-item {
    padding: 5px 4px;
    gap: 2px;
  }

  .hud-value,
  .hud-hearts,
  .hud-timer-ring {
    height: 32px;
    width: 40px;
  }

  #game-screen .board {
    padding: 0.5rem 1rem;
  }

  .word-card {
    padding: 0.9rem 1.25rem;
  }

  #word-card.correct {
    padding-bottom: calc(0.9rem + 0.5rem);
  }

  .card-main-word {
    margin-top: 0;
    font-size: 1.8rem;
  }

  .card-slots {
    margin-top: 0.5rem;
  }

  .near-miss,
  .status-line {
    margin-top: 0.5rem;
    font-size: 0.8rem;
  }


}

/* ---------- Privacy notice banner (first visit) ---------- */

.privacy-banner {
  position: fixed;
  left: 50%;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  width: min(440px, calc(100% - 24px));
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
}

.privacy-banner__text {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--text-secondary);
}

.privacy-banner__text a {
  color: var(--accent);
}

.privacy-banner__actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

.privacy-banner__btn {
  width: auto;
  min-width: 96px;
  height: 40px;
  font-size: 0.85rem;
}

.settings-row-desc a {
  color: var(--accent);
}
