:root {
  --bg: #0f1720;
  --bg-card: #182028;
  --primary: #2dd4a7;
  --primary-dark: #1fae87;
  --accent: #ff7a5c;
  --text: #eef4f2;
  --text-dim: #8391a0;
  --success: #4ade80;
  --border: #2a3540;
  --radius: 16px;
  /* Glassmorphism tokens — translucent card fill + hairline highlight
     border, used on the main card and info blocks for a layered,
     "floating panel" feel over the dark background instead of flat
     opaque boxes. Card fill is deliberately darker/cooler than --bg
     (not just a translucent copy of it) so the blur reads as a lifted
     panel with real depth instead of a same-tone wash. */
  --glass-bg: rgba(19, 27, 36, 0.72);
  --glass-border: rgba(255, 255, 255, 0.08);
  --glass-blur: 20px;
  --shadow-color: rgba(0, 0, 0, 0.45);
}

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

/* ===== LAYOUT FOUNDATION — REBUILT ===== =====================================
   Old approach: #app-viewport was `position:fixed` + a JS-measured height
   variable (--app-vh), manually re-synced on a timer/resize listener, with a
   SEPARATE --keyboard-inset variable manually tracking the on-screen
   keyboard so panels could react to it via a `.keyboard-open` body class.
   That's three different things (fixed positioning, a JS-measured height,
   and JS-measured keyboard height) all trying to agree with each other and
   with the real browser viewport — any place they drifted out of sync is
   exactly what caused inputs/canvas to end up hidden behind the keyboard or
   half-shifted off-screen.

   New approach: nothing is fixed-positioned or JS-measured. `html`/`body`
   flow normally and use `100dvh` (the CSS unit that already tracks the
   *actual visible* viewport, keyboard included, natively, in every modern
   mobile browser — no JS needed). Screens are normal block content, so the
   browser's own native "scroll the focused input into view above the
   keyboard" behavior works automatically, the same way it does on every
   other website. This is a deliberate architecture change, not a tweak. */
html {
  height: 100%;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  overscroll-behavior-y: none;
}

/* #app-viewport is now a plain flow container, not fixed/centered. Each
   .screen inside decides its own layout — the home/waiting/game-over
   screens center their card via margin auto, the game screen fills the
   dynamic viewport height and manages its own internal flex layout (see
   .screen-game below). Because nothing here is fixed-positioned, opening
   the keyboard on the home screen simply shrinks the visible dvh like a
   normal webpage and the browser scrolls the focused input into view —
   exactly the behavior that was missing before. */
#app-viewport {
  width: 100%;
  min-height: 100vh;
  min-height: 100dvh;
  background-color: var(--bg);
  background-image:
    radial-gradient(ellipse 60% 40% at 15% -5%, rgba(45, 212, 167, 0.16), transparent 60%),
    radial-gradient(ellipse 55% 35% at 100% 15%, rgba(124, 92, 255, 0.13), transparent 55%),
    radial-gradient(ellipse 50% 30% at 90% 100%, rgba(255, 122, 92, 0.07), transparent 60%);
  background-attachment: fixed;
}

.screen {
  display: none;
  width: 100%;
  min-height: 100vh;
  min-height: 100dvh;
  max-width: 420px;
  margin: 0 auto;
  padding: 24px;
  padding-top: calc(24px + env(safe-area-inset-top));
  padding-bottom: calc(24px + env(safe-area-inset-bottom));
  flex-direction: column;
  align-items: center;
  justify-content: center;
  animation: fadeIn 0.3s ease;
}
.screen.active { display: flex; }

/* ===== DESKTOP/LAPTOP FRAME =====
   On a wide (mouse-driven) screen the 420px phone-width card would
   otherwise just sit flush left with a huge empty gray gap on the
   right. Give it a subtle framed "phone on a desk" presentation
   instead — a soft shadowed edge around the app column — so it reads
   as an intentional layout rather than a mobile page that forgot to
   go responsive. Purely cosmetic; nothing about game logic/canvas
   sizing changes, since .screen's own max-width is untouched. */
@media (min-width: 640px) and (hover: hover) and (pointer: fine) {
  body {
    display: flex;
    justify-content: center;
  }
  #app-viewport {
    max-width: 420px;
    min-height: 100vh;
    box-shadow: 0 0 0 1px var(--glass-border), 0 24px 80px rgba(0, 0, 0, 0.55);
  }
}

/* Defense-in-depth: explicitly force every non-active screen to stay
   hidden with !important. This guards against exactly the class of bug
   found in .screen-game before — a more specific or later-declared rule
   accidentally setting `display` on a screen without gating it behind
   .active, which silently shows two screens stacked on top of each
   other. Any screen NOT carrying .active is hidden, full stop, no
   matter what other rule exists for it elsewhere in this file. */
.screen:not(.active) { display: none !important; }

/* #screen-home starts content at the top (not vertically centered) since
   its content height varies a lot (collapsed vs. expanded "How it works").
   It's normal flow now, so it just grows taller than the viewport and the
   page scrolls — no special-cased overflow/max-height rules needed
   anymore, that was only necessary under the old fixed-height model. */
#screen-home {
  justify-content: flex-start;
  position: relative;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ===== ROTATE GUARD =====
   Hidden by default; shown ONLY when a small touch device (phone/tablet)
   is actually rotated into landscape — see media query below. Pure CSS,
   no JS/API dependency.

   IMPORTANT: this is scoped with `and (max-width: 900px)` and `and
   (hover: none)` so it ONLY fires for small handheld screens turned
   sideways. A laptop/desktop is permanently "landscape" by nature (wide
   screen, mouse instead of touch), so without that scoping this guard
   used to block the game entirely on any computer. The 420px card
   (see .screen max-width) already just centers nicely with room to
   spare on a wide monitor, so desktops/laptops need no guard at all —
   only a phone/tablet that's been physically turned sideways does. */
#rotate-guard {
  display: none;
}
@media (orientation: landscape) and (max-width: 900px) and (hover: none) and (pointer: coarse) {
  #rotate-guard {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 9999;
    align-items: center;
    justify-content: center;
    background: var(--bg);
  }
  /* Block everything underneath while rotated — the game screens are
     still there in the DOM (state isn't lost), just visually and
     interactively covered until the phone goes back to portrait. */
  #app-viewport > .screen {
    display: none !important;
  }
}
.rotate-guard-inner {
  text-align: center;
  padding: 32px;
  color: var(--text);
}
.rotate-guard-inner svg {
  color: var(--primary);
  margin-bottom: 16px;
  animation: rotateGuardSpin 1.8s ease-in-out infinite;
}
@keyframes rotateGuardSpin {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(90deg); }
}
.rotate-guard-inner p {
  font-size: 16px;
  font-weight: 700;
  margin: 0 0 6px;
}
.rotate-guard-inner .rotate-guard-sub {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
}

/* Top-corner utility buttons on the home screen (Menu + Contact Us). */
.home-corner-btn {
  position: absolute;
  top: 4px;
  left: 20px;
  width: 38px;
  height: 38px;
  border-radius: 19px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  color: var(--text-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 5;
}
.home-corner-btn:active { transform: scale(0.94); }
.home-corner-btn-right { left: auto; right: 20px; }

.brand { text-align: center; margin-bottom: 32px; }
.brand-logo {
  width: 76px;
  height: 76px;
  margin-bottom: 8px;
  filter: drop-shadow(0 4px 16px rgba(45,212,167,0.25));
}
.brand h1 {
  font-size: 36px;
  font-weight: 800;
  letter-spacing: -0.5px;
}
.brand h1 span { color: var(--primary); }
.tagline {
  color: var(--text-dim);
  font-size: 15px;
  font-style: italic;
  letter-spacing: 0.6px;
  margin-top: 6px;
}

.card {
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  padding: 28px 24px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
  box-shadow:
    0 20px 50px var(--shadow-color),
    inset 0 1px 0 rgba(255,255,255,0.05);
}

.btn {
  width: 100%;
  padding: 16px;
  border-radius: 12px;
  border: none;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.1s ease, opacity 0.2s ease;
  -webkit-appearance: none;
}
.btn:active { transform: scale(0.97); }
.btn:disabled {
  opacity: 1;
  pointer-events: none;
  background: var(--bg-card) !important;
  color: var(--text-dim) !important;
  border: 1px solid var(--border);
}

/* Explicit "ready to tap" state for Join Room — turns on once a valid-length
   code is typed, so it's visually obvious the button just became usable. */
.btn-secondary.ready {
  background: var(--primary);
  color: white;
  opacity: 1;
}

.field-hint {
  color: var(--accent);
  font-size: 12px;
  margin-top: -6px;
  align-self: flex-start;
}
.field-hint.hidden { display: none; }

/* Animated typing placeholder for the name field — a real placeholder
   attribute can't animate, so we overlay a span that types itself out
   and hide it the instant the person focuses or types. */
.input-wrap { position: relative; width: 100%; }
.input-wrap input { position: relative; z-index: 1; background: transparent; }
.typing-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  color: var(--text-dim);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: none;
  z-index: 0;
  overflow: hidden; /* clips the vertical slide so text never spills outside the input */
}
/* Without this rule, JS's wrap.classList.add('hidden') on focus/typing
   had no matching CSS and did nothing — the placeholder stayed visible
   and overlapped whatever the person typed, which is what caused the
   "Enter Nickname" / "Shiva" double-text glitch. */
.typing-placeholder.hidden { display: none; }

/* Fixed-height viewport a single phrase slides through — like a
   vertical carousel / odometer. Using ONE element (not two) that gets
   its text swapped instantly while off-screen avoids any two-element
   sync edge case, which is what caused the occasional "plays twice"
   flicker in an earlier version. */
.placeholder-mask {
  position: relative;
  width: 100%;
  height: 26px;
  overflow: hidden;
}
.placeholder-slide {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(0);
  opacity: 1;
  transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1), opacity 0.4s ease;
}
/* Slides fully out the top and fades, then (with transitions
   suspended) jumps to just below the window with new text, then
   transitions back to resting position — one continuous-feeling
   upward scroll per cycle, driven by a single element. */
.placeholder-mask.out .placeholder-slide {
  transform: translateY(-100%);
  opacity: 0;
}
.placeholder-mask.jump .placeholder-slide {
  transition: none !important;
  transform: translateY(100%);
  opacity: 0;
}

/* Gentle shake when someone taps a disabled action — replaces the old
   static red warning text with an in-the-moment nudge instead. */
@keyframes shakeField {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}
.input-wrap.shake input,
input.shake {
  animation: shakeField 0.35s ease;
  border-color: var(--accent) !important;
}

.share-row {
  display: flex;
  gap: 8px;
  width: 100%;
}
.share-row .btn { flex: 1; }

.btn-primary { background: var(--primary); color: white; }
.btn-primary.hidden { display: none; }
.btn-secondary { background: var(--border); color: var(--text); }
.btn-ghost { background: transparent; color: var(--text-dim); font-weight: 500; }
.btn-sm { padding: 10px; font-size: 14px; width: auto; padding-left: 20px; padding-right: 20px; }

.divider {
  display: flex;
  align-items: center;
  width: 100%;
  color: var(--text-dim);
  font-size: 13px;
  gap: 10px;
}
.divider.hidden { display: none; }
.divider::before, .divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.join-hint {
  width: 100%;
  text-align: center;
  color: var(--primary);
  font-size: 14px;
  font-weight: 600;
  margin: -4px 0 2px;
}
.join-hint.hidden { display: none; }

/* ===== MODE TABS (Play with Friend / Play with Computer) + SUBTABS
   (Create Room / Join Room) — home screen top-level choices. Both use
   the same pill-strip pattern: a bordered track with a sliding active
   segment, so the choice always reads as "one of these two", never as
   two separate stacked buttons. ===== */
.mode-tabs, .subtabs {
  display: flex;
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 4px;
  gap: 4px;
}
.mode-tab, .subtab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 8px;
  border-radius: 9px;
  background: transparent;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  border: none;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}
.mode-tab.active {
  background: var(--primary);
  color: #04211a;
}
/* Subtabs (Create Room / Join Room) sit directly above a big solid
   primary CTA button, so giving them the same solid-green fill as that
   button read as two stacked "Create Room" buttons. A soft highlight
   here keeps them clearly a segmented selector — not a second CTA —
   while the actual action stays on the one green button below. */
.subtab.active {
  background: rgba(45,212,167,0.14);
  color: var(--primary);
}
.mode-tab:not(.active):hover, .subtab:not(.active):hover {
  color: var(--text);
}

.mode-panel { width: 100%; display: flex; flex-direction: column; gap: 12px; }
.mode-panel.hidden { display: none; }

.subpanel { width: 100%; display: none; flex-direction: column; gap: 12px; }
.subpanel.active { display: flex; }

.mode-hint {
  width: 100%;
  text-align: center;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.4;
  margin: -2px 0 2px;
}

#btn-play-bot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* Room code is prefilled + locked when arriving via a shared link —
   dim it slightly so it visually reads as "already set", not editable. */
#input-join-code[readonly] {
  opacity: 0.75;
  cursor: default;
}

input[type="text"] {
  width: 100%;
  padding: 16px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-size: 20px;
  text-align: center;
  letter-spacing: 4px;
  text-transform: uppercase;
  font-weight: 700;
}
input[type="text"]:focus { outline: 2px solid var(--primary); }

/* Name field keeps whatever case the person actually typed — only the
   room-code field should force uppercase. Background must stay
   transparent so the animated typing placeholder underneath it (an
   absolutely-positioned sibling span) is actually visible — the shared
   input[type="text"] rule above gives every text input an opaque
   background, which otherwise completely hides the placeholder span.

   Deliberately overrides the shared input's large-centered-spaced
   styling (that's tuned for the 6-char ROOM CODE field) with a
   smaller, left-aligned, sentence-case field — how a name input
   actually reads, with room on the left for the user icon. */
.input-wrap-name {
  display: flex;
  align-items: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: border-color 0.15s ease;
}
.input-wrap-name:focus-within { border-color: var(--primary); }
.input-icon {
  position: absolute;
  left: 16px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-dim);
  z-index: 2;
  pointer-events: none;
}
#input-name {
  text-transform: none;
  letter-spacing: 0.2px;
  background: transparent;
  border: none;
  padding: 13px 16px 13px 44px;
  font-size: 16px;
  font-weight: 600;
  text-align: left;
}
#input-name:focus { outline: none; }
.input-wrap-name .typing-placeholder {
  justify-content: flex-start;
  padding-left: 44px;
}
.input-wrap-name .placeholder-slide { justify-content: flex-start; }

.status-msg {
  margin-top: 16px;
  color: var(--accent);
  font-size: 14px;
  text-align: center;
  min-height: 18px;
}

/* Developer credit — small, centered signature line under the logo.
   Understated on purpose: it should read like a quiet byline, not
   compete with the game's own title for attention. */
.credit-line {
  margin-top: 4px;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  letter-spacing: 0.2px;
}
.credit-line span {
  color: var(--primary);
  font-weight: 700;
}

.label { color: var(--text-dim); font-size: 13px; }

.room-code {
  font-size: 40px;
  font-weight: 800;
  letter-spacing: 8px;
  color: var(--primary);
  margin: 8px 0 16px;
}

.waiting-indicator {
  display: flex;
  gap: 6px;
  margin: 24px 0 8px;
}
.dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--primary);
  animation: bounce 1.4s infinite ease-in-out;
}
.dot:nth-child(2) { animation-delay: 0.2s; }
.dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes bounce {
  0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
  40% { transform: scale(1); opacity: 1; }
}

.waiting-text { color: var(--text-dim); font-size: 14px; margin-bottom: 20px; }

/* Waiting-room roster: one row per joined player (host included), 2-4
   total. Simple list rather than chips here — this screen has more
   vertical room than the in-game topbar and benefits from readable
   full names rather than truncated ones. */
.waiting-roster {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  margin: 14px 0;
}
.waiting-roster:empty { display: none; }
.waiting-roster-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: rgba(255,255,255,0.03);
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}
.waiting-roster-row .presence-dot { flex-shrink: 0; }
.waiting-roster-row .host-badge {
  margin-left: auto;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--primary);
}

.connection-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(74, 222, 128, 0.12);
  color: var(--success);
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 16px;
}
.pulse-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--success);
  animation: pulse 1.5s infinite;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(74,222,128,0.6); }
  70% { box-shadow: 0 0 0 8px rgba(74,222,128,0); }
  100% { box-shadow: 0 0 0 0 rgba(74,222,128,0); }
}

.ping-log {
  width: 100%;
  height: 180px;
  background: var(--bg);
  border-radius: 12px;
  border: 1px solid var(--border);
  overflow-y: auto;
  padding: 12px;
  font-size: 13px;
  color: var(--text-dim);
  margin: 12px 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ping-log .entry { color: var(--text); }
.ping-log .entry.sent { color: var(--primary); }
.ping-log .entry.recv { color: var(--success); }

#peer-id-label { color: var(--text); font-weight: 600; }

.scores-final {
  display: flex;
  gap: 24px;
  margin: 16px 0;
}
.scores-final div {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.scores-final span {
  font-size: 32px;
  font-weight: 800;
  color: var(--primary);
}
.scores-final small {
  color: var(--text-dim);
  font-size: 12px;
  margin-top: 2px;
}
.result-word {
  font-size: 22px;
  font-weight: 700;
  color: var(--accent);
  text-transform: capitalize;
  margin: 8px 0;
}

/* ===== GAME SCREEN — REBUILT AS A REAL FLEX LAYOUT =====
   Old approach: three panels each pinned to a fixed PERCENTAGE of a
   JS-measured height (16% / 50% / 34%), with a separate `.keyboard-open`
   rule set that manually swapped those percentages for different fixed
   values when a JS keyboard-tracker fired. Two independent systems
   (percentage split + manual override) had to agree, and any lag or
   mismatch between them is what left the canvas half-shifted or the chat
   log squeezed to nothing.

   New approach: one flexbox column, sized to 100dvh (the viewport unit
   that already accounts for the keyboard natively). Inside it:
     - .game-panel-top and the canvas toolbar take exactly the height
       their content needs (flex: 0 0 auto) — never more, never less.
     - .game-panel-mid (canvas) takes flex: 1 1 auto — it gets whatever
       space is actually left over. When the keyboard opens and 100dvh
       shrinks, this is the panel that naturally gives up space first,
       exactly like a normal responsive webpage.
     - .game-panel-bottom (chat) also takes flex: 0 0 auto sized by its
       own children, with the chat-log itself scrollable and a min-height
       so it's never squeezed to zero.
   No JS keyboard-tracking, no CSS custom properties measured at runtime,
   no `.keyboard-open` class — the browser's native dvh + flexbox
   reflow does all of this automatically, the same way it already works
   on ordinary responsive sites. */
.screen-game {
  position: relative; /* containing block for .reconnect-banner (position:absolute) below — needed now that nothing higher up the tree is position:fixed anymore */
  width: 100%;
  height: 100vh;
  height: 100dvh;
  max-width: 100%;
  margin: 0;
  padding: 8px;
  padding-top: calc(8px + env(safe-area-inset-top));
  padding-bottom: calc(8px + env(safe-area-inset-bottom));
  flex-direction: column;
  justify-content: flex-start;
  gap: 6px;
  overflow: hidden;
}
/* IMPORTANT: display must stay gated behind .active, same as every
   other .screen. A bare `.screen-game { display: flex }` here would
   override the base `.screen { display: none }` rule unconditionally
   (both are single-class selectors, so the one later in the file wins
   regardless of .active) — that was exactly the bug where the game
   screen stayed visible UNDERNEATH the home screen the whole time,
   because #screen-game never actually got hidden in the first place. */
.screen-game.active { display: flex; }

.game-panel-top,
.game-panel-mid,
.game-panel-bottom {
  width: 100%;
  min-height: 0; /* required for children to shrink/scroll instead of overflowing */
  display: flex;
  flex-direction: column;
}

/* Header: sized by its own content (topbar + voice strip + word banner +
   hints + clue), not a fixed percentage. On a very short viewport (e.g.
   keyboard open on a small phone) it simply keeps its natural height —
   it's the canvas panel below that gives up space, not this one, so the
   score/round/turn context never disappears. */
.game-panel-top {
  flex: 0 0 auto;
  gap: 2px;
  justify-content: flex-start;
}

/* Canvas panel: gets ALL remaining space after the header and chat panel
   take what they need. This is the one panel that's allowed to shrink —
   canvas.js already redraws on resize (see resizeCanvas()), so it stays
   correct at any size down to a small minimum. */
.game-panel-mid {
  flex: 1 1 auto;
  min-height: 90px;
  gap: 6px;
}

/* Chat panel: sized by its own content too. chat-log below has its own
   min-height + scroll so recent messages and the input row are always
   visible, however much (or little) vertical space ends up available. */
.game-panel-bottom {
  flex: 0 0 auto;
  box-sizing: border-box;
}

/* Voiceline FAB isn't useful real estate while the on-screen keyboard is
   covering the lower part of the screen (its own position:fixed bottom
   offset can't know where the OS keyboard actually starts). Hide it
   whenever a text input in the game screen has focus, and bring it back
   on blur. :has() covers modern browsers natively; .input-focused is a
   JS-driven fallback class (see guardInputFocusScroll() in app.js) for
   browsers without :has() support. */
.screen-game:has(input:focus) .voiceline-fab,
.screen-game.input-focused .voiceline-fab {
  display: none;
}

/* Topbar: two player identity chips (left = me, right = friend) flank a
   compact round/timer readout, with a settings gear at the far right.
   Names are no longer buried inside a right-aligned score string — each
   player gets their own clearly bounded chip so it's obvious at a
   glance who's who. */
.game-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 6px 8px;
  background: var(--bg-card);
  border-radius: 12px;
  border: 1px solid var(--border);
  flex-shrink: 0;
  gap: 6px;
}

/* Player chip strip: 2-4 chips laid out left-to-right in turn order
   (host first). Replaces the old fixed left=me/right=friend pair —
   with a variable roster size, "which side am I on" stops making
   sense, so every player (including "me") gets an equivalent chip and
   my own is picked out with .player-chip.me's accent border instead
   of a fixed position. Horizontally scrollable as a safety net on a
   very narrow phone with 4 long names, though chips shrink first via
   flex + the existing text-overflow ellipsis on .player-name. */
.player-chip-strip {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.player-chip-strip::-webkit-scrollbar { display: none; }

.player-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  background: rgba(255,255,255,0.03);
  border-radius: 10px;
  border: 1px solid transparent;
  min-width: 0; /* allow text-overflow ellipsis to actually kick in on long names */
  flex: 1 1 0;
  transition: border-color 0.2s, background 0.2s;
}
/* My own chip gets a subtle accent border so I can always spot myself
   at a glance in a 3-4 player strip. */
.player-chip.me { border-color: var(--primary); background: rgba(255,255,255,0.06); }
/* Current drawer's chip (anyone's, including mine) gets a highlighted
   background — the single most useful piece of info in a multiplayer
   topbar, since "whose turn is it" is no longer implied by chip side. */
.player-chip.is-drawer { background: rgba(255, 190, 60, 0.14); border-color: var(--accent, #ffbe3c); }
.player-chip.disconnected { opacity: 0.5; }
.player-chip-text { display: flex; flex-direction: column; min-width: 0; }
.player-name {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 64px;
}
.player-score { font-size: 11px; color: var(--text-dim); font-weight: 600; }

.topbar-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  gap: 1px;
}
.round-info { color: var(--text-dim); font-weight: 600; font-size: 11px; }
.timer {
  font-size: 20px;
  font-weight: 800;
  color: var(--primary);
  min-width: 32px;
  text-align: center;
  line-height: 1;
}
.timer.low { color: var(--accent); animation: pulse-text 1s infinite; }
@keyframes pulse-text { 50% { opacity: 0.5; } }

.settings-gear-btn {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-size: 16px;
  flex-shrink: 0;
  cursor: pointer;
}
.settings-gear-btn:hover { color: var(--text); }

/* Presence dot — green pulse when the peer's WebRTC connection is
   live, gray/static once it drops (see ConnectionMonitor in app.js). */
.presence-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-dim);
}
.presence-dot.online {
  background: #2ecc71;
  box-shadow: 0 0 0 0 rgba(46,204,113,0.6);
  animation: presencePulse 2s infinite;
}
.presence-dot.offline {
  background: var(--accent);
  animation: none;
}
@keyframes presencePulse {
  0% { box-shadow: 0 0 0 0 rgba(46,204,113,0.5); }
  70% { box-shadow: 0 0 0 5px rgba(46,204,113,0); }
  100% { box-shadow: 0 0 0 0 rgba(46,204,113,0); }
}

/* Reconnect banner — sits above the topbar, doesn't block the canvas
   or chat so play can continue locally while the link comes back. */
.reconnect-banner {
  position: absolute;
  top: 8px;
  left: 8px;
  right: 8px;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px;
  background: rgba(255,122,92,0.15);
  border: 1px solid var(--accent);
  border-radius: 10px;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
}
.reconnect-banner.hidden { display: none; }
.reconnect-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255,122,92,0.3);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Voice strip — no call/connecting drama at all. Just two small icon
   toggles (mic = send, speaker = hear), independent of each other.
   Voice connects itself silently in the background; the status text
   only appears while connecting or if the mic was blocked. */
.voice-strip {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-shrink: 0;
  padding: 2px 0;
}
.voice-icon-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-card);
  font-size: 15px;
  cursor: pointer;
  flex-shrink: 0;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
}
.voice-icon-btn.on { border-color: var(--primary); background: rgba(45,212,167,0.12); color: var(--primary); }
.voice-icon-btn:not(.on) { border-color: var(--accent); background: rgba(255,122,92,0.1); color: var(--accent); }
.voice-icon-btn:disabled { opacity: 0.4; }
.voice-status-text {
  font-size: 11px;
  color: var(--text-dim);
  font-style: italic;
}
.voice-status-text.hidden { display: none; }

.word-banner {
  width: 100%;
  text-align: center;
  padding: 4px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  min-height: 20px;
  flex-shrink: 0;
}
.word-banner .the-word {
  color: var(--primary);
  letter-spacing: 2px;
  text-transform: uppercase;
}

/* Hint tiles — guesser-only blank/reveal row under the banner.
   Unrevealed letters render as empty underline boxes so nothing about
   the word (length aside, which is the whole point) leaks visually. */
.hint-wrap {
  width: 100%;
  display: flex;
  justify-content: center;
  padding: 2px 4px 6px;
  flex-shrink: 0;
}
.hint-wrap.hidden { display: none; }
.hint-tiles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
  max-width: 100%;
}
.hint-tile {
  width: 18px;
  height: 22px;
  border-bottom: 2px solid var(--text-dim);
  display: inline-flex;
  align-items: flex-end;
  justify-content: center;
  font-weight: 700;
  font-size: 15px;
  color: var(--primary);
  text-transform: uppercase;
  flex-shrink: 0;
}
.hint-tile.revealed { border-bottom-color: var(--primary); }
.hint-gap { width: 10px; flex-shrink: 0; }

/* Clue line — rotating text hint under the hint tiles, guesser-only. */
.clue-line {
  width: 100%;
  text-align: center;
  padding: 2px 16px 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  flex-shrink: 0;
  min-height: 18px;
}
.clue-line.hidden { display: none; }
.clue-fade-in { animation: clueFadeIn 0.35s ease; }
@keyframes clueFadeIn {
  from { opacity: 0; transform: translateY(-3px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Canvas fills whatever space .game-panel-mid has left after the
   toolbar below takes its own intrinsic height. .game-panel-mid itself
   is flex:1 within the game screen (see above), so this whole area
   grows/shrinks naturally with real available space — including when
   the keyboard eats into 100dvh. canvas.js's resizeCanvas() redraws all
   strokes at the new size, so shrinking here never loses the drawing. */
.canvas-wrap {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  background: #ffffff;
  border-radius: 12px;
  overflow: hidden;
  touch-action: none;
}
#draw-canvas {
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}
.canvas-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15,15,20,0.85);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 20px;
}
.canvas-overlay.hidden { display: none; }
.canvas-overlay p { color: var(--text); font-size: 16px; font-weight: 600; }

.toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 4px;
  flex-shrink: 0;
  flex-wrap: nowrap;
}
.toolbar.disabled { opacity: 0.35; pointer-events: none; }

/* Eraser gets its own visual identity even though it reuses .btn-icon,
   so it doesn't get mistaken for the currently-selected color swatch. */
#btn-eraser.active { background: var(--accent); border-color: var(--accent); }

.color-swatches {
  display: flex;
  gap: 6px;
  flex: 1;
  overflow-x: auto;
  padding: 2px;
}
.swatch {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 2px solid var(--border);
  cursor: pointer;
}
.swatch.active { border-color: var(--text); transform: scale(1.15); }

.width-control { display: flex; gap: 3px; }
.btn-icon {
  background: var(--bg-card);
  border: 1px solid rgba(255,255,255,0.12);
  color: var(--text);
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  cursor: pointer;
  flex-shrink: 0;
}
.btn-icon.active { background: var(--primary); border-color: var(--primary); color: #062019; }

/* Shared sizing for every inline SVG icon (<use> sprite references).
   stroke uses currentColor, so an icon automatically matches whatever
   text/icon color its parent button has — including on hover/active
   states — without needing per-icon color overrides anywhere. */
/* Safety net: any plain <button> containing an .icon SVG inherits a
   visible theme color by default, even if that specific button class
   forgets to set one. Browsers apply their own default button text
   color otherwise, which reads near-invisible on this dark palette. */
button {
  color: var(--text);
}

.icon {
  display: block;
  flex-shrink: 0;
  color: currentColor;
}
/* Variant for icons sitting inline next to text (headings, banners) —
   vertical-align keeps them baseline-aligned with the surrounding text
   instead of the block default that .icon uses for standalone buttons. */
.icon-inline {
  display: inline-block;
  vertical-align: -4px;
  margin-right: 2px;
}

/* Brush-width buttons used to be literal ●⬤⚫ emoji glyphs (inconsistent
   size across devices/fonts); now a small solid circle drawn in CSS so
   it scales cleanly and reads clearly as "thin/medium/thick" at a glance. */
.width-dot .dot-preview {
  border-radius: 50%;
  background: currentColor;
  display: block;
}
.dot-sm { width: 5px; height: 5px; }
.dot-md { width: 9px; height: 9px; }
.dot-lg { width: 14px; height: 14px; }

/* ===== VOICELINE FAB + radial pie menu ===== */
.voiceline-fab {
  position: fixed;
  right: 12px;
  /* Sits just above the chat input row instead of directly over it —
     chat-input-row is ~54px tall including padding, so lifting the FAB
     that much clears the send button completely. Also rises with
     --keyboard-inset so it stays pinned just above the input row
     instead of getting buried under the keyboard when it's open. */
  bottom: calc(70px + env(safe-area-inset-bottom) + var(--keyboard-inset, 0px));
  transition: bottom 0.15s ease;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: none;
  background: var(--primary);
  color: white;
  font-size: 19px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 16px rgba(124,92,255,0.45);
  cursor: pointer;
  z-index: 30;
  transition: transform 0.2s ease, background 0.2s ease;
}
.voiceline-fab:active { transform: scale(0.92); }
.voiceline-fab.open {
  background: var(--accent);
  transform: rotate(45deg);
  box-shadow: 0 4px 16px rgba(255,92,138,0.45);
}

.voiceline-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 20;
}
.voiceline-backdrop.hidden { display: none; }

/* Free-Fire-style emote wheel: the ring is pinned to the exact center
   of the viewport (not to the FAB), so at any screen size every button
   has equal room in all directions and nothing can ever clip off an
   edge. A small center hub icon anchors it visually, like the
   character portrait in the middle of a game's radial wheel. */
.voiceline-menu {
  position: fixed;
  left: 50%;
  top: 50%;
  width: 64px;
  height: 64px;
  margin-left: -32px;
  margin-top: -32px;
  z-index: 25;
  pointer-events: none; /* re-enabled per-button below once expanded */
}
.voiceline-menu.hidden { display: none; }
.voiceline-menu.expanded { pointer-events: auto; }

.voiceline-menu::before {
  content: '🎤';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  background: var(--bg-card);
  border: 2px solid var(--primary);
  border-radius: 50%;
  box-shadow: 0 0 24px rgba(124,92,255,0.5);
  opacity: 0;
  transform: scale(0.5);
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;
}
.voiceline-menu.expanded::before { opacity: 1; transform: scale(1); }

/* Each button starts stacked at the wheel's center hub and flies out
   to its --tx/--ty offset (set inline via JS, evenly spaced in a full
   circle) once .expanded is added. */
.voiceline-btn {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 78px;
  margin-left: -39px;
  margin-top: -22px;
  padding: 10px 6px;
  border-radius: 20px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
  opacity: 0;
  transform: translate(0, 0) scale(0.4);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease;
}
.voiceline-menu.expanded .voiceline-btn {
  opacity: 1;
  transform: translate(var(--tx), var(--ty)) scale(1);
}
.voiceline-btn:active { transform: translate(var(--tx), var(--ty)) scale(0.88); }

/* ===== CHAT — Instagram-style bubbles =====
   Chat panel: takes a comfortable fixed-ish height (not a % of a
   JS-measured viewport, just a plain height value with a sane min/max
   clamp) — its parent .game-panel-bottom is flex:0 0 auto, so this is
   the actual size driver. On a normal-height viewport this comfortably
   fits several message rows; on a very short viewport (small phone,
   landscape, or keyboard eating into 100dvh) it clamps down to
   min-height so the canvas panel (flex:1) can claim the rest — see
   .game-panel-mid above. */
.chat-panel {
  width: 100%;
  height: clamp(140px, 30vh, 260px);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  min-height: 0; /* required so the inner scroller can actually shrink/scroll instead of overflowing the page */
}

.chat-log {
  flex: 1;
  min-height: 44px; /* guarantees at least a message row or two stays visible even at the panel's smallest clamp, instead of shrinking to zero next to the input row */
  overflow-y: auto;
  padding: 10px 10px 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  scroll-behavior: smooth;
}

.chat-row {
  display: flex;
  flex-direction: column;
  max-width: 78%;
  margin-bottom: 6px;
}
.chat-row.mine { align-self: flex-end; align-items: flex-end; }
.chat-row.theirs { align-self: flex-start; align-items: flex-start; }

.chat-sender {
  font-size: 11px;
  color: var(--text-dim);
  padding: 0 10px 2px;
  font-weight: 600;
}

.bubble {
  padding: 9px 13px;
  border-radius: 18px;
  font-size: 14px;
  line-height: 1.35;
  word-break: break-word;
  position: relative;
}
.chat-row.mine .bubble {
  background: var(--primary);
  color: white;
  border-bottom-right-radius: 5px;
}
.chat-row.theirs .bubble {
  background: var(--border);
  color: var(--text);
  border-bottom-left-radius: 5px;
}

.bubble-meta {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  color: var(--text-dim);
  padding: 3px 6px 0;
}
.bubble-meta .ticks { color: var(--text-dim); letter-spacing: -2px; }
.bubble-meta .ticks.seen { color: var(--primary); }

/* ===== TYPING INDICATOR =====
   Same bubble shell as a "theirs" message (left-aligned, .theirs bubble
   background) but holding three bouncing dots instead of text — the
   familiar WhatsApp/iMessage "…is typing" affordance. Rendered as its
   own transient .chat-row (id'd so it can be found and removed again)
   rather than reusing addChatMessage, since it's not a real message and
   must never get a msgId/ticks/timestamp or count toward chat history. */
.chat-row.typing-row {
  align-self: flex-start;
  align-items: flex-start;
}
.chat-row.typing-row .bubble {
  background: var(--border);
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 11px 15px;
}
.typing-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-dim);
  animation: typingBounce 1.2s infinite ease-in-out;
}
.typing-dot:nth-child(2) { animation-delay: 0.15s; }
.typing-dot:nth-child(3) { animation-delay: 0.3s; }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
  30% { transform: translateY(-4px); opacity: 1; }
}

.chat-row.system-row {
  align-self: center;
  max-width: 90%;
}
.chat-row.system-row .bubble {
  background: transparent;
  color: var(--text-dim);
  font-style: italic;
  font-size: 12px;
  padding: 4px 10px;
  text-align: center;
}
.chat-row.correct-row {
  align-self: center;
  max-width: 95%;
}
.chat-row.correct-row .bubble {
  background: rgba(74,222,128,0.14);
  color: var(--success);
  font-weight: 700;
  border-radius: 12px;
  text-align: center;
}

.chat-input-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
  background: var(--bg-card);
  position: relative;
  z-index: 2;
}
.chat-input-row input {
  flex: 1;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 10px 14px;
  color: var(--text);
  font-size: 14px;
  text-transform: none;
  letter-spacing: normal;
}
.btn-send { background: var(--primary); border-color: var(--primary); }

.emoji-picker {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 4px;
  padding: 8px;
  border-top: 1px solid var(--border);
  max-height: 110px;
  overflow-y: auto;
  flex-shrink: 0;
}
.emoji-picker.hidden { display: none; }
.emoji-picker span {
  font-size: 20px;
  text-align: center;
  cursor: pointer;
  padding: 4px;
}

/* ===== SETTINGS PANEL ===== */
.settings-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.55);
  z-index: 40;
}
.settings-backdrop.hidden { display: none; }

.settings-panel {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--bg-card);
  border-top: 1px solid var(--glass-border);
  border-radius: 20px 20px 0 0;
  padding: 16px 18px calc(20px + env(safe-area-inset-bottom));
  z-index: 41;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 -8px 32px rgba(0,0,0,0.3);
}
.settings-panel.hidden { display: none; }

.settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.settings-header h3 { font-size: 17px; font-weight: 800; color: var(--text); }

.settings-section {
  padding: 12px 0;
  border-top: 1px solid var(--border);
}
.settings-section:first-of-type { border-top: none; }

.settings-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 8px;
}

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 0;
  font-size: 14px;
  color: var(--text);
}

.settings-row-input input {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  color: var(--text);
  font-size: 14px;
  width: 130px;
  text-align: right;
}

.settings-hint {
  font-size: 12px;
  color: var(--accent);
  margin-top: 4px;
}

/* ===== CONTACT US FORM FIELDS (reuses settings-panel bottom-sheet) ===== */
.contact-field-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
  margin: 14px 0 6px;
}
.contact-field-label:first-child { margin-top: 0; }
.contact-optional { font-weight: 400; text-transform: none; color: var(--text-dim); }

.contact-select,
.contact-input,
.contact-textarea {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
}
.contact-input:focus,
.contact-textarea:focus {
  outline: none;
  border-color: var(--primary);
}
.contact-textarea { resize: vertical; min-height: 90px; }

/* Custom themed dropdown for Subject — replaces the native <select>,
   whose OS-rendered option list can't be restyled and looked jarring
   (light popup on a dark form). Built from the same button+menu pattern
   as the home-screen language picker, so it's consistent app-wide. */
.contact-select-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  color: var(--text-dim);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
}
.contact-select-btn.has-value { color: var(--text); }
.contact-select-btn .icon { color: var(--text-dim); flex-shrink: 0; transition: transform 0.15s ease; }
.contact-select-btn[aria-expanded="true"] .icon { transform: rotate(180deg); }

.contact-select-menu {
  position: relative;
  margin-top: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.contact-select-menu.hidden { display: none; }

.contact-select-option {
  background: transparent;
  border: none;
  border-radius: 7px;
  padding: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.contact-select-option:active { background: var(--bg-card); }
.contact-select-option.active { background: rgba(45,212,167,0.14); color: var(--primary); }

/* Simple on/off pill switch, reused for every toggle in the panel. */
.toggle-switch {
  width: 42px;
  height: 24px;
  border-radius: 12px;
  border: none;
  background: var(--border);
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.2s ease;
}
.toggle-switch.on { background: var(--primary); }
.toggle-knob {
  position: absolute;
  top: 3px; left: 3px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: white;
  transition: transform 0.2s ease;
}
.toggle-switch.on .toggle-knob { transform: translateX(18px); }

.settings-leave-btn {
  margin-top: 16px;
  color: var(--accent);
}

/* ================= SEO / About Section =================
   Shown directly in normal document flow below the primary card — no
   collapse/expand, no scroll-clipped inner box. Full content is always
   visible and indexed, and reachable by simply scrolling the page. */
.about-details {
  width: 100%;
  max-width: 420px;
  margin-top: 20px;
  text-align: left;
}

.about-inner {
  padding: 22px 18px;
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
}
.about-header { text-align: center; margin-bottom: 28px; }
.about-header h2 { font-size: 19px; font-weight: 800; letter-spacing: -0.2px; margin-bottom: 10px; }
.about-lede { color: var(--text-dim); font-size: 13px; line-height: 1.6; }
.about-lede strong { color: var(--primary); font-weight: 600; }

.about-block { margin-bottom: 28px; }
.about-block:last-of-type { margin-bottom: 0; }
.about-block h3 { font-size: 15px; font-weight: 700; margin-bottom: 12px; }

.how-to-steps { list-style: none; counter-reset: step; display: flex; flex-direction: column; gap: 12px; }
.how-to-steps li {
  counter-increment: step;
  position: relative;
  padding: 16px 16px 16px 48px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-dim);
  transition: transform 0.12s ease, border-color 0.12s ease;
}
.how-to-steps li:active { transform: scale(0.98); border-color: var(--primary); }
.how-to-steps li strong { color: var(--text); }
.how-to-steps li::before {
  content: counter(step);
  position: absolute;
  left: 14px; top: 50%;
  transform: translateY(-50%);
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--primary);
  color: #06231b;
  font-weight: 800;
  font-size: 11px;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
}

.feature-grid { display: flex; flex-direction: column; gap: 12px; }
.feature-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
  transition: transform 0.12s ease, border-color 0.12s ease;
}
.feature-card:active { transform: scale(0.98); border-color: var(--primary); }
.feature-card h4 { font-size: 13px; margin-bottom: 6px; }
.feature-card p { font-size: 12.5px; color: var(--text-dim); line-height: 1.6; }

.about-footer { font-size: 12px; color: var(--text-dim); border-top: 1px solid var(--border); padding-top: 16px; line-height: 1.5; }

/* Legal links row — "Game Rules | Terms of Service | Privacy Policy",
   sits below the About block. Each opens its own bottom sheet. */
.legal-links {
  width: 100%;
  max-width: 420px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
  padding-bottom: 8px;
}
.legal-link {
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
  padding: 4px 0;
}
.legal-link:active { color: var(--primary); }
.legal-sep { color: var(--border); font-size: 12px; }

/* Legal bottom sheets (Rules/Terms/Privacy) — taller max-height than the
   Settings panel since this is prose content, not a few toggle rows. */
.legal-panel { max-height: 85vh; }
.legal-body { padding: 4px 0 8px; }
.legal-body p {
  font-size: 13px;
  line-height: 1.6;
  color: var(--text-dim);
  margin-bottom: 14px;
}
.legal-body p:last-child { margin-bottom: 0; }

/* ===== HAMBURGER MENU (home screen) ===== */
.menu-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px 0 2px;
}

.menu-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: transparent;
  border: none;
  border-radius: 12px;
  padding: 13px 10px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  width: 100%;
}
.menu-list-item:active { background: var(--bg); }
.menu-list-item-left { display: flex; align-items: center; gap: 10px; color: var(--text); }
.menu-list-item .icon:last-child { color: var(--text-dim); flex-shrink: 0; }

/* Sub-panels (About / Settings / Donate / Follow) share the settings-panel
   look but need a leading back-arrow + trailing close in the header,
   instead of just a close button like the root panels. */
.sub-panel .settings-header { gap: 8px; }
.menu-back-btn { margin-right: 2px; }
.sub-panel .settings-header h3 { flex: 1; }

.about-dev-body p, .donate-body p { font-size: 13px; line-height: 1.6; color: var(--text-dim); margin-bottom: 14px; }
.about-dev-body p:last-child, .donate-body p:last-child { margin-bottom: 0; }

.donate-qr-wrap {
  display: flex;
  justify-content: center;
  margin: 4px 0 16px;
}
.donate-qr-img {
  width: 200px;
  height: 200px;
  border-radius: 14px;
  object-fit: cover;
  border: 1px solid var(--border);
}

.donate-upi-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
}
.donate-upi-id { font-size: 14px; font-weight: 700; color: var(--text); letter-spacing: 0.2px; }
#donate-copy-hint { text-align: center; }

/* Segmented Light/Dark and English/Hinglish toggles — two-option pill
   switch, matches the app's rounded/glass visual language rather than
   a plain <select> or native toggle. */
.segmented-toggle {
  display: flex;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 3px;
  gap: 2px;
}
.segmented-option {
  background: transparent;
  border: none;
  border-radius: 7px;
  padding: 7px 12px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  cursor: pointer;
}
.segmented-option.active { background: var(--primary); color: #062019; }

/* ===== LIGHT THEME =====
   Deliberately NOT an inverted copy of dark mode. Dark mode is built on
   a cool navy-charcoal canvas; simply flattening that to "mint-on-white"
   reads flat and washes out contrast (translucent glass cards over a
   near-white page basically disappear). Light mode instead gets its own
   identity: a warm, slightly cream paper base (not clinical #fff) with
   deep forest-teal ink for text and a punchier, more saturated primary
   — so surfaces stay readable through the glass blur and the palette
   still feels intentional rather than "dark mode with the lights on". */
body[data-theme="light"] {
  --bg: #f4f1e8;
  --bg-card: #fffdf7;
  --primary: #0d9c78;
  --primary-dark: #0b7d61;
  --accent: #e8572f;
  --text: #1c2420;
  --text-dim: #6b7268;
  --success: #0d9c78;
  --border: #e2dcc8;
  --glass-bg: rgba(255, 253, 247, 0.82);
  --glass-border: rgba(28, 36, 32, 0.08);
  --glass-blur: 20px;
  --shadow-color: rgba(60, 50, 20, 0.12);
}

body[data-theme="light"] #app-viewport {
  background-color: var(--bg);
  background-image:
    radial-gradient(ellipse 55% 35% at 10% -5%, rgba(13, 156, 120, 0.10), transparent 55%),
    radial-gradient(ellipse 50% 30% at 100% 10%, rgba(232, 87, 47, 0.07), transparent 55%);
}

/* Corner buttons and settings gear sit directly on the ambient gradient
   background (not on a card), so they need real opacity here — the
   dark-mode glass values are too see-through against a light page and
   the icon loses definition. */
body[data-theme="light"] .home-corner-btn,
body[data-theme="light"] .settings-gear-btn {
  color: var(--primary-dark);
  background: rgba(255, 253, 247, 0.92);
  border-color: var(--border);
  box-shadow: 0 2px 10px rgba(60, 50, 20, 0.06);
}

body[data-theme="light"] .settings-backdrop,
body[data-theme="light"] .menu-backdrop {
  background: rgba(28, 36, 32, 0.42);
}

body[data-theme="light"] .card,
body[data-theme="light"] .about-inner,
body[data-theme="light"] .settings-panel,
body[data-theme="light"] .menu-drawer {
  box-shadow: 0 16px 40px var(--shadow-color);
}

/* Room-code field: force a real opaque surface + darker ink border —
   on a warm-cream page, --bg alone reads too close to --bg-card to
   register as "a field" without this extra definition. */
body[data-theme="light"] input[type="text"] {
  border-color: #b9c9c0;
  background: #ffffff;
}
body[data-theme="light"] .input-wrap-name {
  border-color: #b9c9c0;
  background: #ffffff;
}

/* Inactive tab/segment/secondary fills: a pale mint wash instead of
   neutral gray — keeps the "colorful, branded" feel even in the
   unselected state. */
body[data-theme="light"] .mode-tab:not(.active),
body[data-theme="light"] .subtab:not(.active),
body[data-theme="light"] .btn-secondary {
  background: #e2f2ec;
  color: var(--primary-dark);
}

body[data-theme="light"] .segmented-toggle,
body[data-theme="light"] .menu-segmented {
  background: #eae5d4;
}

body[data-theme="light"] .btn:disabled {
  background: #eae5d4 !important;
  color: #97917d !important;
  border-color: var(--border);
}

/* Info/how-to-play blocks and step number chips read flat without an
   accent — give the numbered circles the coral accent instead of
   plain green so the page has two colors doing visible work, same as
   dark mode's mint+coral pairing. */
body[data-theme="light"] .how-to-steps li::before {
  background: var(--accent);
  color: #fff8f5;
}

body[data-theme="light"] .how-to-steps li,
body[data-theme="light"] .feature-card,
body[data-theme="light"] .contact-select-btn,
body[data-theme="light"] .contact-input,
body[data-theme="light"] .contact-textarea,
body[data-theme="light"] .contact-select-menu,
body[data-theme="light"] .menu-segmented-btn.active,
body[data-theme="light"] .subtab.active {
  background: #ffffff;
}
body[data-theme="light"] .menu-segmented-btn.active,
body[data-theme="light"] .subtab.active,
body[data-theme="light"] .lang-option.active {
  color: var(--primary-dark);
  box-shadow: inset 0 0 0 1px rgba(13,156,120,0.25);
}

body[data-theme="light"] .brand-logo {
  filter: drop-shadow(0 4px 16px rgba(13,156,120,0.18));
}
