/* ============================================================
   CITY THEME — Buffalo, NY (light / default)
   To reskin for another city: replace this block only. Nothing
   below this point should reference a color literal or a team
   name — everything reads from these custom properties.

   Three color roles, kept strictly separate so nothing is
   ambiguous:
   - Team colors: ONLY used on the wordmark letters (jersey look).
   - Feedback colors (green/amber/gray): ONLY used on game tiles
     and keyboard keys — the standard word-game color language,
     unrelated to any team.
   - Accent/danger: ONLY used on UI chrome (buttons, links, toasts).

   The night theme is the `:root[data-theme="dark"]` block right
   after this `:root` — it overrides the "Page & panel", "Feedback"
   and "Neutral surfaces" groups below. Team colors stay the same
   in both. `--shadow` is an rgb triplet fed to `rgba(var(--shadow), a)`
   so drop shadows can go black on dark; new surfaces must use the
   neutral-surface tokens, never literal #fff / rgba(22,33,58,...).
   ============================================================ */
@font-face {
  font-family: 'Bills Mafia';
  src: url('Bills Mafia.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Self-hosted (was Google Fonts — a render-blocking third-party request).
   Inter is the variable file, one download covers 400/600/700/800; Caveat
   is the tagline only. Latin subset only (all copy is basic Latin + typographic
   punctuation, which the Latin subset covers). */
@font-face {
  font-family: 'Inter';
  src: url('fonts/inter-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Caveat';
  src: url('fonts/caveat-latin.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Page & panel */
  --bg: #f5f6f8;
  --panel: #ffffff;
  --panel-border: #e1e4ea;
  --text: #16213a;
  --text-dim: #6b7280;

  /* Team accents — five Buffalo programs, used only on the wordmark */
  --team-1: #c60c30; /* Bills red */
  --team-2: #00338d; /* Bills royal blue */
  --team-3: #fcb514; /* Sabres gold */
  --team-4: #002654; /* Sabres navy */
  --team-5: #005bbb; /* UB Blue (University at Buffalo) */
  --team-6: #1a1a1a; /* Braves black */
  --team-7: #c60c30; /* Bills red (repeat, bookends the wordmark) */

  /* Feedback — the standard word-game color language, deliberately
     NOT tied to any team color so the meaning is never ambiguous.
     (Correct is the one deliberate exception — see .correct-letter,
     styled after a Bills jersey number instead.) */
  --tile-present: #e3b341;
  --tile-absent: #6b7280;
  --tile-empty-border: #c7cbd1;

  /* UI chrome — one accent, one danger, used everywhere consistently */
  --accent: #00338d;
  --danger: #c60c30;

  /* Neutral surfaces — tokenised so the night theme can reskin them in one
     block (see :root[data-theme="dark"] below). The light values here are the
     originals that used to be hardcoded throughout this sheet. */
  --panel-2: #fbfcfe;                    /* bottom stop of panel / overlay gradients */
  --tile-face-hi: #ffffff;               /* empty game tile */
  --tile-face-lo: #f7f9fc;
  --key-hi: #f1f2f5;                     /* letter keys + close-modal chips */
  --key-lo: #e2e4e9;
  --key-special-hi: #dfe2e8;             /* DEL / ENT keys */
  --key-special-lo: #cbcfd8;
  --pill-hi: #ffffff;                    /* .open-button header pills */
  --pill-lo: #f4f5f8;
  --edge-hi: rgba(255, 255, 255, 0.6);   /* inset top-highlight on light chrome */
  --shadow: 22, 33, 58;                  /* rgb triplet for rgba() drop shadows */
  --wordmark-trim: 1px var(--text);      /* -webkit-text-stroke on the .mark-N letters:
                                            contrasts with the PAGE, not the letter, so
                                            a white trim doesn't vanish on the white header */

  --font-display: 'Bills Mafia', Impact, 'Arial Narrow', sans-serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-script: 'Caveat', 'Segoe Script', 'Bradley Hand', cursive;  /* wordmark tagline only */
}

/* ============================================================
   NIGHT THEME
   Applied by setting data-theme="dark" on <html>. The header
   toggle flips it; a small inline <head> script restores the
   saved choice (or honours prefers-color-scheme) before first
   paint so there's no flash. Per the rules up top this overrides
   only the page / panel, feedback and neutral-surface tokens —
   the team colors on the wordmark are identical in both themes.
   ============================================================ */
:root[data-theme="dark"] {
  --bg: #0b1120;
  --panel: #141d31;
  --panel-2: #111a2c;
  --panel-border: #2b3752;
  --text: #eef1f7;
  --text-dim: #97a1b5;

  --tile-present: #e3b341;
  --tile-absent: #4b5568;
  --tile-empty-border: #37425c;

  --accent: #3f74d6;
  --danger: #e0556c;

  --tile-face-hi: #1c2740;
  --tile-face-lo: #161f34;
  --key-hi: #263349;
  --key-lo: #1c2740;
  --key-special-hi: #2f3d55;
  --key-special-lo: #222e42;
  --pill-hi: #202c46;
  --pill-lo: #1a2439;
  --edge-hi: rgba(255, 255, 255, 0.1);
  --shadow: 0, 0, 0;
  --wordmark-trim: 2px #ffffff;   /* the white jersey trim reads well on the dark header */
}

* {
  margin: 0;
  box-sizing: border-box;
}

p {
  margin: 10px 0;
}

body {
  min-height: 100vh;
  background:
    radial-gradient(circle at 15% -10%, color-mix(in srgb, var(--team-1) 10%, transparent), transparent 40%),
    radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--team-2) 12%, transparent), transparent 38%),
    radial-gradient(circle at 50% 100%, color-mix(in srgb, var(--team-3) 10%, transparent), transparent 45%),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font-body);
}

h3 {
  color: var(--accent);
}

/* ---------------- Header ---------------- */

.site-header {
  position: relative;
  display: flex;
  flex-direction: row;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  padding: 14px 20px;
  background: var(--panel);
  border-bottom: 1px solid var(--panel-border);
}

/* Left / right control zones flank the wordmark. Equal flex so the wordmark
   stays dead-centre no matter how many pills sit on each side. */
.header-side {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.header-side--end {
  justify-content: flex-end;
}

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  padding: 8px 10px;
  font-size: 1rem;
  line-height: 1;
}

.site-header::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 4px;
  background: linear-gradient(90deg,
    var(--team-1), var(--team-2), var(--team-3),
    var(--team-4), var(--team-5), var(--team-6), var(--team-7));
  box-shadow: 0 3px 8px -3px rgba(var(--shadow), 0.35);
}

.wordmark {
  margin: 0 10px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 6vw, 2.8rem);
  letter-spacing: 0.06em;
}

/* Sits on its own wrapped row (`.site-header` is flex-wrap: wrap and this is
   flex-basis 100%), so it centres under the wordmark without ever squeezing
   the pills — at any width. */
.tagline {
  flex: 0 0 100%;
  margin: 5px 0 0;
  text-align: center;
  font-family: var(--font-script);
  font-weight: 600;
  font-size: 1.2rem;
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--text-dim);
}

/* Keep the parenthetical aside whole so it wraps as one unit under the main
   line on narrow screens instead of breaking mid-phrase. */
.tagline-aside {
  white-space: nowrap;
}

/* Jersey lettering: team-color glyph with a thin trim stroke, the way a
   number reads on a jersey rather than a flat-filled logotype. The trim
   (`--wordmark-trim`) is themed to contrast with the page — a hairline dark
   keyline on the white day header, the classic white trim on the dark one. */
.mark-1, .mark-2, .mark-3, .mark-4, .mark-5, .mark-6, .mark-7 {
  -webkit-text-stroke: var(--wordmark-trim);
  -webkit-text-fill-color: transparent;
  color: transparent;
  paint-order: stroke fill;
}

/* Each letter is the team color with a gentle top-down sheen — a lighter
   crown easing to a slightly deeper foot, same restrained gloss as the game
   tiles, clipped to the glyph. No outer shadow: the white trim does the
   lifting. */
.mark-1 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-1) 78%, white), var(--team-1) 46%, color-mix(in srgb, var(--team-1) 86%, black)); }
.mark-2 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-2) 78%, white), var(--team-2) 46%, color-mix(in srgb, var(--team-2) 86%, black)); }
.mark-3 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-3) 78%, white), var(--team-3) 46%, color-mix(in srgb, var(--team-3) 86%, black)); }
.mark-4 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-4) 78%, white), var(--team-4) 46%, color-mix(in srgb, var(--team-4) 86%, black)); }
.mark-5 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-5) 78%, white), var(--team-5) 46%, color-mix(in srgb, var(--team-5) 86%, black)); }
.mark-6 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-6) 72%, white), var(--team-6) 46%, color-mix(in srgb, var(--team-6) 88%, black)); }
.mark-7 { background: linear-gradient(180deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04) 34%, rgba(255,255,255,0) 62%), linear-gradient(180deg, color-mix(in srgb, var(--team-7) 78%, white), var(--team-7) 46%, color-mix(in srgb, var(--team-7) 86%, black)); }

/* Must come *after* the `background:` shorthands above — the shorthand resets
   background-clip to border-box, so clipping the fill to the glyph has to be
   re-declared here or the gradient paints the whole letter box. */
.mark-1, .mark-2, .mark-3, .mark-4, .mark-5, .mark-6, .mark-7 {
  -webkit-background-clip: text;
  background-clip: text;
}

#close-stats-modal {
  padding: 10px;
  cursor: pointer;
  font-weight: 700;
  font-size: large;
}

#messages {
  padding-top: 10px;
  font-size: large;
  font-weight: 700;
  color: var(--danger);
}

/* ---------------- Game panel ---------------- */

#game-wrapper {
  min-width: 300px;
  max-width: 500px;
  min-height: 400px;
  margin-top: 20px;
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  box-shadow:
    0 1px 2px rgba(var(--shadow), 0.04),
    0 8px 16px rgba(var(--shadow), 0.06),
    0 24px 48px rgba(var(--shadow), 0.10);
  padding: 8px 0 16px;
}

#game-board {
  width: 80%;
  max-width: 360px;
  padding: 10px;
}

#game-keyboard {
  padding: 10px;
}

.word-row {
  display: flex;
  flex-direction: row;
  width: 100%;
  align-items: center;
  gap: 5px;
  touch-action: manipulation;
  margin: 5px 0;
}

#game-keyboard button {
  font-family: var(--font-body);
  font-weight: 700;
  border: 0;
  padding: 0;
  margin: 0;
  min-height: 48px;
  border-radius: 8px;
  cursor: pointer;
  user-select: none;
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  text-transform: uppercase;
  box-shadow: inset 0 1px 0 var(--edge-hi), 0 2px 0 rgba(var(--shadow), 0.15);
  transition: transform 0.05s ease, background 0.15s ease, box-shadow 0.05s ease;
  -webkit-tap-highlight-color: transparent;
}

#game-keyboard button:active {
  transform: translateY(2px);
  box-shadow: inset 0 1px 3px rgba(var(--shadow), 0.2);
}

#game-keyboard button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

#game-keyboard .key-default {
  background: linear-gradient(180deg, var(--key-hi) 0%, var(--key-lo) 100%);
  color: var(--text);
}

#game-keyboard .special-key {
  background: linear-gradient(180deg, var(--key-special-hi) 0%, var(--key-special-lo) 100%);
  color: var(--text);
  min-width: 13%;
}

.game-tile {
  display: flex;
  flex: 1 1 0px;
  aspect-ratio: 1 / 1;
  /* Without this, a flex item's automatic minimum size keeps the tile as
     tall as its line-box, so at narrow widths the tile stops being square
     (taller than wide). Letting it shrink lets aspect-ratio win. */
  min-width: 0;
  min-height: 0;
  border: 2px solid var(--tile-empty-border);
  border-radius: 10px;
  margin: 1px;
  background: linear-gradient(180deg, var(--tile-face-hi) 0%, var(--tile-face-lo) 100%);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 2.4rem;
  font-weight: 400;
  padding: 4px;
  justify-content: center;
  align-items: center;
  text-transform: uppercase;
  box-shadow: inset 0 1px 3px rgba(var(--shadow), 0.05);
  transition: border-color 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
}

.centered {
  margin: 0 auto;
  text-align: center;
  vertical-align: middle;
}

.left-aligned {
  text-align: left;
}

.keyboard-row {
  display: flex;
  flex-direction: row;
  width: 100%;
  gap: 6px;
  margin: 0 auto 6px;
  touch-action: manipulation;
}

/* Feedback colors — shared between board tiles and keyboard keys so the
   two stay visually in sync. This is the only place color carries
   meaning about the guess; it never overlaps with team or UI colors.

   Exception, by request: a correct tile is styled after an actual Bills
   jersey number — royal blue fabric, white letter, red trim — rather
   than plain green. Only the board tiles get the trim stroke (they use
   the jersey display font); the keyboard key stays a plain filled key
   since its font isn't chunky enough for an outline to read cleanly. */
/* Revealed tiles / keys carry a soft top-down sheen on the light-to-dark
   color body — the same restrained gloss as the wordmark. */
.correct-letter,
.correct-key-letter {
  background:
    linear-gradient(180deg, rgba(255,255,255,0.28), rgba(255,255,255,0.04) 38%, rgba(255,255,255,0) 60%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--team-2) 82%, white) 0%,
      var(--team-2) 45%,
      color-mix(in srgb, var(--team-2) 86%, black) 100%);
  border-color: var(--team-2);
  color: #ffffff;
}

.correct-letter {
  -webkit-text-fill-color: #ffffff;
  -webkit-text-stroke-width: 1.5px;
  -webkit-text-stroke-color: var(--team-1);
  paint-order: stroke fill;
}

.contains-letter {
  background:
    linear-gradient(180deg, rgba(255,255,255,0.28), rgba(255,255,255,0.04) 38%, rgba(255,255,255,0) 60%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--tile-present) 82%, white) 0%,
      var(--tile-present) 45%,
      color-mix(in srgb, var(--tile-present) 84%, black) 100%);
  border-color: var(--tile-present);
  color: #241a00;
}

.nope-letter,
.nope-key-letter {
  background:
    linear-gradient(180deg, rgba(255,255,255,0.22), rgba(255,255,255,0.03) 38%, rgba(255,255,255,0) 60%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--tile-absent) 78%, white) 0%,
      var(--tile-absent) 45%,
      color-mix(in srgb, var(--tile-absent) 84%, black) 100%);
  border-color: var(--tile-absent);
  color: #ffffff;
}

/* A revealed tile reads as a small chip: a faint highlight along the top
   edge, and a soft shadow tinted to the tile's own color underneath. */
.game-tile.correct-letter {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 5px 12px -3px color-mix(in srgb, var(--team-2) 45%, transparent);
}

.game-tile.contains-letter {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 5px 12px -3px color-mix(in srgb, var(--tile-present) 45%, transparent);
}

.game-tile.nope-letter {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 4px 10px -3px rgba(var(--shadow), 0.22);
}

.modal-messages {
  font-size: large;
  color: var(--danger);
  font-weight: 700;
  text-transform: uppercase;
}

.accent-text {
  color: var(--accent);
}

.open-button {
  padding: 8px 16px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--pill-hi) 0%, var(--pill-lo) 100%);
  border: 1px solid var(--panel-border);
  box-shadow: inset 0 1px 0 var(--edge-hi), 0 1px 2px rgba(var(--shadow), 0.06);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.open-button:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: inset 0 1px 0 var(--edge-hi), 0 2px 8px -1px color-mix(in srgb, var(--accent) 30%, transparent);
}

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

/* Flip face-down then face-up; the JS swaps the tile's color class at the
   90deg edge-on midpoint (0.25s) so the flip is what appears to reveal it. */
.letterAnimation {
  animation: letterAnimation 0.5s ease-in-out both;
}

@keyframes letterAnimation {
  0% { transform: rotateX(0deg); }
  50% { transform: rotateX(90deg); }
  100% { transform: rotateX(0deg); }
}

.shake {
  animation: tileShake 0.5s ease;
}

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

.celebrate {
  animation: tileCelebrate 0.4s ease;
}

@keyframes tileCelebrate {
  0%, 100% { transform: translateY(0); }
  40% { transform: translateY(-10px); }
}

.word-row .game-tile:nth-child(1) { animation-delay: 0s; }
.word-row .game-tile:nth-child(2) { animation-delay: 0.08s; }
.word-row .game-tile:nth-child(3) { animation-delay: 0.16s; }
.word-row .game-tile:nth-child(4) { animation-delay: 0.24s; }
.word-row .game-tile:nth-child(5) { animation-delay: 0.32s; }

@media (prefers-reduced-motion: reduce) {
  .letterAnimation,
  .shake,
  .celebrate {
    animation: none;
  }
}

.letter-border {
  border-color: var(--text-dim);
  transform: scale(1.03);
}

.overlay {
  font-size: large;
  border: 1px solid var(--panel-border);
  border-radius: 20px;
  width: 70vw;
  max-width: 400px;
  height: 75vh;
  max-height: 500px;
  position: absolute;
  z-index: 50;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 30px;
  margin: 0 auto;
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  color: var(--text);
  box-shadow:
    0 1px 2px rgba(var(--shadow), 0.05),
    0 24px 60px rgba(var(--shadow), 0.25);
  overflow-y: auto;
}

.close-button {
  text-align: right;
}

#close-help-modal,
#close-stats-modal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--key-hi) 0%, var(--key-lo) 100%);
  box-shadow: inset 0 1px 0 var(--edge-hi);
  color: var(--text);
  transition: background 0.15s ease, color 0.15s ease;
}

#close-help-modal:hover,
#close-stats-modal:hover,
#close-credits-modal:hover {
  background: var(--danger);
  color: #ffffff;
}

#close-credits-modal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--key-hi) 0%, var(--key-lo) 100%);
  box-shadow: inset 0 1px 0 var(--edge-hi);
  color: var(--text);
  transition: background 0.15s ease, color 0.15s ease;
}

/* Credits opens from the footer, so it must centre in the viewport, not the
   document; the content is short, so let it size to fit. */
#credits-overlay {
  position: fixed;
  height: auto;
  max-height: 80vh;
  font-size: 1rem;
  line-height: 1.55;
}

#credits-overlay .credits-title {
  font-family: var(--font-body);
  font-size: 1.15rem;
  color: var(--accent);
}

#credits-overlay a {
  color: var(--accent);
  text-underline-offset: 2px;
}

.large-message {
  padding: 20px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: x-large;
}

.medium-message {
  font-size: 16px;
  font-weight: 700;
}

.actions-row {
  padding-top: 20px;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
}

.share-btn {
  border: none;
  border-radius: 999px;
  width: 100px;
  height: 44px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 80%, white) 0%,
    var(--accent) 55%,
    color-mix(in srgb, var(--accent) 85%, black) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 4px 10px -2px color-mix(in srgb, var(--accent) 50%, transparent);
  color: #ffffff;
  font-family: var(--font-body);
  font-weight: 700;
  cursor: pointer;
  transition: filter 0.15s ease;
}

.share-btn:hover {
  filter: brightness(1.1);
}

.alert-wrapper {
  width: 250px;
  padding: 10px 16px;
  font-size: large;
  font-weight: 700;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 80%, white) 0%,
    var(--accent) 55%,
    color-mix(in srgb, var(--accent) 85%, black) 100%);
  color: #ffffff;
  border-radius: 999px;
  position: absolute;
  z-index: 999;
  top: 30%;
  left: 50%;
  transform: translate(-50%, -50%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 12px 30px rgba(var(--shadow), 0.3);
}

.small-button {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 80%, white) 0%,
    var(--accent) 55%,
    color-mix(in srgb, var(--accent) 85%, black) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 2px 6px -1px color-mix(in srgb, var(--accent) 45%, transparent);
  color: #ffffff;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  border: none;
  border-radius: 999px;
  min-width: 50px;
  min-height: 25px;
  max-height: 25px;
  cursor: pointer;
}

/* ---------------- Phone / narrow viewport ----------------
   Everything above is authored for desktop widths. Below ~430px the
   header row runs out of room for its two pills plus the wordmark, the
   fixed-width overlay leaves too little text column, and the share row
   can't hold its label and button side by side.

   Layout also switches from "centered card floating on the page" to a
   full-height app shell: body is a flex column, the wrapper grows to
   fill the viewport (100dvh, so the mobile URL bar doesn't cover it),
   and the board flexes to absorb the leftover space between the header
   and keyboard. #ad-slot sits below the keyboard and reserves whatever
   --ad-height is set to (0 when no ad), so a future banner doesn't
   reflow the game. */
@media (max-width: 430px) {
  body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
  }

  .site-header {
    padding: 12px 10px;
    justify-content: space-between;
  }

  .header-side {
    gap: 5px;
  }

  .wordmark {
    margin: 0 5px;
    font-size: clamp(1.55rem, 6.4vw, 2.4rem);
    letter-spacing: 0.03em;
  }

  .tagline {
    margin-top: 3px;
    font-size: 1rem;
  }

  .open-button {
    padding: 7px 10px;
    font-size: 0.74rem;
  }

  .icon-button {
    padding: 6px 7px;
    min-width: 32px;
    font-size: 0.9rem;
  }

  /* Tightest phones: the wordmark plus two pills a side genuinely runs out
     of room, so trim the wordmark spacing further before anything overlaps. */
  @media (max-width: 350px) {
    .wordmark {
      margin: 0 3px;
      font-size: 1.4rem;
      letter-spacing: 0;
    }

    .tagline {
      font-size: 0.92rem;
    }

    .open-button {
      padding: 6px 8px;
      font-size: 0.7rem;
    }

    .icon-button {
      padding: 6px 6px;
      min-width: 30px;
    }
  }

  #game-wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    min-height: 0;
    width: auto;
    margin: 12px 10px;
    margin-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    border-radius: 16px;
    gap: 8px;
  }

  #game-header {
    flex: none;
  }

  #messages {
    padding-top: 4px;
  }

  /* The board is a square that shrinks to fit the space between the header
     and keyboard: capped by width on tall phones (max-width), by height on
     short ones (max-height in dvh, which tracks the *visible* viewport as
     the Safari toolbars move). Tiles fill their cell — the board's
     aspect-ratio keeps them square, so no per-tile aspect-ratio is needed.
     overflow:hidden is a last-resort guard against sub-pixel bleed. */
  #game-board {
    flex: 0 1 auto;
    min-height: 0;
    /* One value drives both dimensions so the board stays exactly square:
       the smallest of the wrapper width, a hard cap, and ~half the visible
       viewport height (dvh tracks the Safari toolbars). */
    width: 54vh;
    width: min(100%, 360px, 52dvh);
    max-width: 100%;
    aspect-ratio: 1 / 1;
    height: auto;
    align-self: center;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: clamp(3px, 1.3vw, 5px);
    overflow: hidden;
  }

  .word-row {
    flex: 1 1 0;
    min-height: 0;
    width: 100%;
    align-items: stretch;
    gap: clamp(3px, 1.3vw, 5px);
    margin: 0;
  }

  .game-tile {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    aspect-ratio: auto;
    margin: 0;
    border-radius: 8px;
    font-size: clamp(1.25rem, 6.6vw, 2rem);
  }

  #game-keyboard {
    flex: none;
    padding: 5px 5px 7px;
  }

  #game-keyboard button {
    min-height: 42px;
  }

  .keyboard-row {
    gap: 5px;
    margin-bottom: 4px;
  }

  #ad-slot {
    flex: none;
    width: 100%;
    min-height: var(--ad-height, 0px);
  }

  .overlay {
    width: min(92vw, 400px);
    height: auto;
    max-height: 82vh;
    padding: 24px 20px;
    font-size: 1rem;
  }

  .large-message {
    padding: 12px;
    font-size: 1.4rem;
  }

  .actions-row {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }

  .share-btn {
    width: 100%;
  }

  .alert-wrapper {
    width: auto;
    max-width: 80vw;
  }
}

/* ---------------- Indexable page copy ----------------
   Always-visible About / How-to-play / FAQ + footer. Sits below the
   game (below the fold on phones) so search engines and AI answer
   engines have real crawlable text describing the game. Chrome-role
   colours only; no team or feedback colours here. */
.page-info,
.site-footer {
  width: 92%;
  max-width: 640px;
  margin: 0 auto;
  text-align: left;
}

.page-info {
  margin-top: 28px;
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--panel-border);
  border-radius: 16px;
  color: var(--text);
  overflow: hidden;
}

/* The whole block is one native <details>, collapsed by default. The text
   stays in the DOM either way, so it's fully indexable while collapsed. */
.page-info-disclosure summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  padding: 15px 20px;
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 800;
  color: var(--accent);
  list-style: none;
}

.page-info-disclosure summary::-webkit-details-marker {
  display: none;
}

.page-info-disclosure summary::after {
  content: "+";
  flex: none;
  font-size: 1.35rem;
  line-height: 1;
}

.page-info-disclosure[open] summary::after {
  content: "\2013";
}

.page-info-disclosure[open] summary {
  border-bottom: 1px solid var(--panel-border);
}

.page-info-disclosure summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.page-info-body {
  padding: 6px 20px 20px;
  line-height: 1.6;
}

.page-info h2 {
  margin: 22px 0 8px;
  font-family: var(--font-body);
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--accent);
}

.page-info h2:first-child {
  margin-top: 0;
}

.page-info h3 {
  margin: 14px 0 2px;
  font-size: 1rem;
  font-weight: 700;
}

.page-info p {
  margin: 6px 0;
  color: var(--text);
}

.page-info .faq {
  margin-top: 4px;
}

.page-info .faq h3 {
  margin-top: 16px;
}

.page-info .faq p {
  color: var(--text-dim);
}

.page-info .how-to-play {
  margin: 8px 0;
  padding-left: 20px;
}

.page-info .how-to-play li {
  margin: 6px 0;
}

.site-footer {
  margin-top: 18px;
  margin-bottom: 28px;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-dim);
  text-align: center;
}

.site-footer p {
  margin: 6px 0;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.link-button:hover {
  text-decoration: none;
}

.link-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (max-width: 430px) {
  .page-info {
    margin-top: 18px;
    border-radius: 14px;
  }

  .page-info-disclosure summary {
    padding: 14px 16px;
  }

  .page-info-body {
    padding: 4px 16px 18px;
    font-size: 0.95rem;
  }
}
