/* ==========================================================================
   WordPlay
   Tile + keyboard state colours are Wordle's canonical palette so the game
   reads identically; the surrounding chrome is softer (rounded, card-based).
   ========================================================================== */

:root {
  /* Canonical tile palette, light - value-corrected.
     Wordle's own #6aaa64 / #c9b458 carry white letters at 2.78:1 and 2.07:1.
     Tile glyphs are large bold type, so the WCAG floor is 3:1, and both miss
     it; the yellow misses it in EVERY theme and every clone. Each colour here
     keeps its hue and is darkened only in value until white clears the gate,
     measured, not guessed. Contrast is a gate, fidelity is a preference. */
  --correct: #629d5c;   /* white 3.23:1 */
  --present: #a08f46;   /* white 3.22:1 */
  --absent:  #787c7e;   /* white 4.21:1 */
  --tile-fg: #ffffff;

  /* chrome - light */
  --bg:          #ffffff;
  --surface:     #f2f5fa;
  --surface-2:   #e4e9f2;
  --surface-3:   #d8dfea;
  --ink:         #2b3648;
  --ink-muted:   #6b7789;
  --border:      #cbd3de;
  --tile-border: #c3ccd9;
  --tile-bg:     #f9fbfd;
  --key-bg:      #e0e5ee;
  --key-fg:      #2b3648;
  --modal-bg:    #ffffff;
  --overlay:     rgba(28, 36, 50, 0.45);
  --toast-bg:    #2b3648;
  --toast-fg:    #ffffff;
  --shadow:      0 10px 30px rgba(24, 33, 48, 0.12);
  --shadow-sm:   0 2px 6px rgba(24, 33, 48, 0.07);

  --r-tile: 10px;
  --r-key:  9px;
  --r-card: 14px;

  --header-h:   106px;
  --keyboard-h: 200px;
}

:root[data-theme="dark"] {
  --correct: #538d4e;   /* white 3.97:1 - Wordle's own, already passes */
  --present: #a28e35;   /* white 3.25:1 - #b59f3b was 2.63:1 */
  --absent:  #3a3a3c;   /* white 11.35:1 */

  --bg:          #121213;
  --surface:     #1d1e20;
  --surface-2:   #2a2b2e;
  --surface-3:   #3a3a3c;
  --ink:         #f5f6f7;
  --ink-muted:   #9aa0a6;
  --border:      #3a3a3c;
  --tile-border: #3a3a3c;
  --tile-bg:     transparent;
  --key-bg:      #818384;
  --key-fg:      #ffffff;
  --modal-bg:    #1a1b1d;
  --overlay:     rgba(0, 0, 0, 0.6);
  --toast-bg:    #ffffff;
  --toast-fg:    #121213;
  --shadow:      0 10px 30px rgba(0, 0, 0, 0.5);
  --shadow-sm:   0 2px 6px rgba(0, 0, 0, 0.4);
}

/* Colour-blind safe pair - DEFINED HERE, ENFORCED AT THE END OF THIS FILE.
   See the "HIGH CONTRAST WINS" block after the themes: a skin declares its
   own --present with exactly this specificity and simply came later in the
   source, so High Contrast was silently losing to whichever theme was on. */

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

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: Nunito, "Segoe UI", system-ui, -apple-system, Helvetica, Arial, sans-serif;
  font-weight: 600;
  -webkit-font-smoothing: antialiased;
  user-select: none;
  transition: background-color 200ms ease, color 200ms ease;
}

button { font-family: inherit; color: inherit; }

#game {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-width: 520px;
  margin: 0 auto;
  padding: 0 8px;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

/* ============================================================ mode pills */
#modes {
  display: flex;
  justify-content: center;
  gap: 6px;
  padding: 10px 0 6px;
  flex: 0 0 auto;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 18px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-muted);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease;
}
.pill svg { width: 20px; height: 20px; fill: currentColor; }
.pill:hover { background: var(--surface); }
.pill[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
}
.pill[aria-selected="true"][data-mode="unlimited"] { color: var(--correct); }

/* ================================================================ toolbar */
#toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 2px 0 8px;
  flex: 0 0 auto;
}

#toolbar .side { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; }
#toolbar .side.right { justify-content: flex-end; }

#title {
  margin: 0;
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -0.01em;
  white-space: nowrap;
  pointer-events: none;
}

.icon-btn {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 160ms ease, transform 120ms ease;
}
.icon-btn:hover { background: var(--surface-2); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 22px; height: 22px; fill: currentColor; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 11px;
  background: var(--surface);
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
  transition: background-color 160ms ease;
}
.chip:hover { background: var(--surface-2); }
.chip span:first-child { font-size: 17px; line-height: 1; }

/* ================================================================== board */
#board-wrap {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  min-height: 0;
}

#board {
  display: grid;
  grid-template-rows: repeat(6, 1fr);
  gap: 6px;
  width: 340px;
  max-width: 100%;
  aspect-ratio: 340 / 408;
  max-height: 100%;
}

.row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }

.tile {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border: 2px solid var(--tile-border);
  border-radius: var(--r-tile);
  background: var(--tile-bg);
  color: var(--ink);
  font-size: clamp(1.4rem, 7vw, 2rem);
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  transition: border-color 120ms ease;
}

.tile[data-state="tbd"] { border-color: var(--ink-muted); }
.tile[data-state="correct"],
.tile[data-state="present"],
.tile[data-state="absent"] { color: var(--tile-fg); border-color: transparent; }
.tile[data-state="correct"] { background: var(--correct); }
.tile[data-state="present"] { background: var(--present); }
.tile[data-state="absent"]  { background: var(--absent); }

/* =============================================================== keyboard */
#keyboard {
  flex: 0 0 auto;
  height: var(--keyboard-h);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 7px;
  padding-bottom: 10px;
}

.krow { display: flex; gap: 6px; justify-content: center; touch-action: manipulation; }
.krow .spacer { flex: 0.5; }

.key {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-key);
  background: var(--key-bg);
  color: var(--key-fg);
  font-size: 15px;
  font-weight: 800;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background-color 180ms ease, color 180ms ease, transform 90ms ease;
}
.key.wide { flex: 1.6; font-size: 12.5px; letter-spacing: 0.02em; }
.key svg { width: 22px; height: 22px; fill: currentColor; }
.key:active { transform: scale(0.95); }
.key[data-state="correct"] { background: var(--correct); color: #fff; }
.key[data-state="present"] { background: var(--present); color: #fff; }
.key[data-state="absent"]  { background: var(--absent);  color: #fff; }

/* ================================================================ effects */
@keyframes pop { from { transform: scale(0.86); } 45% { transform: scale(1.08); } }
.tile.pop { animation: pop 110ms ease-out; }

@keyframes flip {
  0%   { transform: rotateX(0); }
  50%  { transform: rotateX(-90deg); }
  100% { transform: rotateX(0); }
}
.tile.flip { animation: flip 520ms ease forwards; }

@keyframes shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}
.row.shake { animation: shake 560ms; }

@keyframes bounce {
  0%, 20% { transform: translateY(0); }
  40%     { transform: translateY(-26px); }
  50%     { transform: translateY(4px); }
  60%     { transform: translateY(-12px); }
  80%     { transform: translateY(2px); }
  100%    { transform: translateY(0); }
}
.tile.bounce { animation: bounce 950ms; }

@media (prefers-reduced-motion: reduce) {
  .tile.flip, .tile.pop, .tile.bounce, .row.shake { animation: none !important; }
}

/* ================================================================ toaster */
#toaster {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  width: max-content;
  max-width: 92vw;
}

.toast {
  background: var(--toast-bg);
  color: var(--toast-fg);
  padding: 12px 18px;
  border-radius: 12px;
  font-weight: 800;
  font-size: 14.5px;
  text-align: center;
  box-shadow: var(--shadow);
  animation: toast-in 160ms ease;
}
.toast.out { animation: toast-out 280ms ease forwards; }
@keyframes toast-in  { from { opacity: 0; transform: translateY(-10px); } }
@keyframes toast-out { to   { opacity: 0; transform: translateY(-6px); } }

/* ================================================================= modals */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: var(--overlay);
  animation: fade 150ms ease;
}
.modal-backdrop[hidden] { display: none; }
@keyframes fade { from { opacity: 0; } }

.modal {
  position: relative;
  width: 100%;
  max-width: 480px;
  max-height: 88vh;
  overflow-y: auto;
  padding: 22px 22px 26px;
  border-radius: 20px;
  background: var(--modal-bg);
  color: var(--ink);
  box-shadow: var(--shadow);
  animation: rise 220ms cubic-bezier(.2,.8,.2,1);
}
.modal.narrow { max-width: 360px; }
@keyframes rise { from { transform: translateY(24px) scale(.98); opacity: 0; } }

.modal .close {
  position: absolute;
  top: 12px;
  right: 12px;
  background: transparent;
}
.modal .close:hover { background: var(--surface); }

.modal h2 {
  margin: 4px 0 6px;
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.modal h4 {
  margin: 20px 0 8px;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.modal p, .modal li { font-size: 15px; font-weight: 600; line-height: 1.5; margin: 8px 0; }
.modal .lede { font-size: 17px; font-weight: 700; margin-top: 0; }
.modal .small { font-size: 13.5px; color: var(--ink-muted); }
.modal ul { padding-left: 20px; margin: 10px 0; }
.modal hr { border: 0; border-top: 1px solid var(--border); margin: 20px 0; }
.scope-note {
  margin: 0 0 4px !important;
  font-size: 13px !important;
  color: var(--ink-muted);
  font-weight: 700;
}

.example { display: flex; gap: 5px; margin: 10px 0 2px; }
.example .tile { width: 42px; height: 42px; font-size: 1.15rem; border-radius: 8px; }

/* ================================================================== stats */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 9px;
  margin-top: 10px;
}
.stat-card {
  background: var(--surface);
  border-radius: var(--r-card);
  padding: 14px 6px 11px;
  text-align: center;
}
.stat-card .num { font-size: 28px; font-weight: 800; line-height: 1.05; }
.stat-card .lbl {
  margin-top: 4px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.dist-row {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 800;
}
.dist-row .n { width: 16px; color: var(--ink-muted); }
.dist-row .track {
  flex: 1;
  height: 26px;
  background: var(--surface);
  border-radius: 8px;
  overflow: hidden;
}
.dist-row .fill {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: 100%;
  min-width: 30px;
  padding: 0 9px;
  border-radius: 8px;
  background: var(--surface-3);
  color: var(--ink);
  font-size: 12px;
  transition: width 420ms cubic-bezier(.2,.8,.2,1);
}
.dist-row.current .fill { background: var(--correct); color: #fff; }

.stats-footer { display: flex; align-items: center; margin-top: 20px; }
.stats-footer > div { flex: 1; text-align: center; }
.stats-footer h4 { margin-top: 0; }
.stats-footer .divider { flex: 0 0 1px; background: var(--border); align-self: stretch; margin: 0 14px; }
#countdown { font-size: 27px; font-weight: 800; font-variant-numeric: tabular-nums; }

.btn-share {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  max-width: 170px;
  height: 50px;
  border: 0;
  border-radius: 12px;
  background: var(--correct);
  color: #fff;
  font-size: 17px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 110ms ease, filter 160ms ease;
}
.btn-share:hover { filter: brightness(1.06); }
.btn-share:active { transform: scale(0.97); }
.btn-share svg { width: 20px; height: 20px; fill: currentColor; }

.btn-ghost {
  display: block;
  margin: 22px auto 0;
  padding: 10px 22px;
  border: 1px solid var(--border);
  border-radius: 11px;
  background: transparent;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-muted);
  cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease;
}
.btn-ghost:hover { background: var(--surface); color: var(--ink); }

/* =============================================================== settings */
.setting {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 15px 0;
  border-bottom: 1px solid var(--border);
}
.setting .title { font-size: 16.5px; font-weight: 700; }
.setting .desc { font-size: 12.5px; font-weight: 600; color: var(--ink-muted); margin-top: 3px; line-height: 1.35; }

.switch { position: relative; width: 44px; height: 26px; flex: 0 0 44px; cursor: pointer; }
.switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.switch .track {
  position: absolute; inset: 0;
  background: var(--surface-3);
  border-radius: 999px;
  transition: background-color 200ms ease;
  pointer-events: none;
}
.switch .thumb {
  position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,.3);
  transition: transform 200ms cubic-bezier(.2,.8,.2,1);
  pointer-events: none;
}
.switch input:checked ~ .track { background: var(--correct); }
.switch input:checked ~ .thumb { transform: translateX(18px); }
.switch input:focus-visible ~ .track { outline: 2px solid var(--ink); outline-offset: 2px; }

.modal-footer {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 20px !important;
  font-size: 12px !important;
  color: var(--ink-muted);
}
.modal-footer a { color: inherit; }

/* =============================================================== language */
.lang-list { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.lang-opt {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 15px;
  border: 2px solid transparent;
  border-radius: var(--r-card);
  background: var(--surface);
  font-size: 15.5px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease;
}
.lang-opt:hover { background: var(--surface-2); }
.lang-opt[aria-current="true"] { border-color: var(--correct); }
.lang-opt .fl { font-size: 22px; line-height: 1; }
.lang-opt .meta { flex: 1; }
.lang-opt .cnt { font-size: 11.5px; font-weight: 700; color: var(--ink-muted); margin-top: 2px; }
.lang-opt .beta {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: 999px;
  background: var(--present);
  color: #fff;
}

/* ============================================================= responsive */
@media (max-height: 760px) {
  :root { --keyboard-h: 182px; }
  .key { height: 50px; }
  #board { width: 310px; }
}
@media (max-height: 670px) {
  :root { --keyboard-h: 162px; }
  .key { height: 44px; }
  #modes { padding: 6px 0 4px; }
  .pill { padding: 7px 14px; font-size: 14px; }
  .icon-btn, .chip { height: 34px; }
  .icon-btn { width: 34px; flex-basis: 34px; }
}
@media (max-height: 580px) {
  :root { --keyboard-h: 144px; }
  .key { height: 38px; font-size: 13px; }
  #title { display: none; }
}
@media (max-width: 400px) {
  #title { display: none; }
  .krow { gap: 5px; }
  .stat-card .num { font-size: 24px; }
}

/* ===== result card, hints, history, install ===== */

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

body.modal-open { overflow: hidden; }

/* ---- a hinted letter: present, but clearly not typed ---- */
.tile.ghost {
  color: var(--ink-muted);
  opacity: .45;
  border-style: dashed;
  border-color: var(--tile-border);
  font-style: italic;
}

/* ---- install chip ---- */
.chip.install { gap: 5px; }
.chip.install svg { width: 15px; height: 15px; fill: currentColor; }

/* ---- the end-of-round card ---- */
.modal.result { text-align: center; }

.result-head {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-top: 4px;
}

.result-word {
  font-size: clamp(30px, 9vw, 40px);
  font-weight: 800;
  letter-spacing: .09em;
  color: var(--correct);
  margin: 6px 0 10px;
}

.result-def {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 12px 14px;
  margin: 0 0 16px;
  text-align: left;
}

.result-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 16px;
}
.result-stats .num { font-size: 22px; font-weight: 800; }
.result-stats .lbl {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-muted);
  margin-top: 2px;
}

.result-actions {
  display: flex;
  gap: 10px;
  align-items: stretch;
}
.result-actions .btn-share,
.result-actions .btn-ghost { flex: 1; margin: 0; }

.result-next {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin: 12px 0 0;
  font-variant-numeric: tabular-nums;
}

/* ---- solved-word history ---- */
.history {
  max-height: 230px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 2px;
}

.hist-item {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 9px 11px;
  text-align: left;
}
.hist-item .hw {
  font-weight: 800;
  font-size: 13px;
  letter-spacing: .08em;
  color: var(--correct);
}
.hist-item .hd {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-muted);
  margin-top: 2px;
}

.modal ol { margin: 0 0 4px; padding-left: 20px; }
.modal ol li { margin-bottom: 7px; }

@media (prefers-reduced-motion: reduce) {
  .tile.ghost { transition: none; }
}


/* ===== corrections found in browser testing ===== */

/*
  [hidden] must win.
  .icon-btn is display:grid and .chip is display:inline-flex, and both beat the
  user-agent's [hidden]{display:none}. Without this the Daily board showed the
  Unlimited-only "new word" and "hint" buttons, and the install chip appeared
  on browsers that never fired beforeinstallprompt.
*/
[hidden] { display: none !important; }

/* The lang chip carries an icon, not a flag emoji. */
.chip .globe { width: 16px; height: 16px; fill: currentColor; display: block; }
.chip span:first-child { font-size: 14px; display: flex; align-items: center; }

/* A <p> in a flex container splits into one item per text node, which spread
   the help credit line into "A free game by" ... "JLR Dev" ... ".". */
.modal-footer.plain {
  display: block;
  text-align: center;
  margin-top: 22px !important;
}

/* Two-letter language badge. */
.lang-opt .fl {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 10px;
  background: var(--surface-2);
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .04em;
}
.lang-opt[aria-current="true"] .fl { background: var(--correct); color: #fff; }

/* The title must never be the thing that gets truncated. */
#title { flex: 0 0 auto; }
#toolbar .side { flex: 1 1 0; min-width: 0; }
#toolbar .side > * { flex: 0 0 auto; }

@media (max-width: 400px) {
  #toolbar { gap: 4px; }
  #toolbar .side { gap: 4px; }
  .icon-btn { width: 34px; height: 34px; flex-basis: 34px; }
  .chip { height: 34px; padding: 0 10px; font-size: 13px; }
  .chip.install span { display: none; }
  .chip.install { padding: 0 9px; }
  #title { font-size: 19px; }
}


/* ===== premium pass: depth, lighting, dvh ===== */

/*
  Depth, not decoration.

  One light source, top-left. Every raised surface gets a 1px light rim on its
  top edge and a soft shadow below; every recessed surface gets the inverse.
  The tile state colours are untouched - green/yellow/grey are the rules of the
  game, and a player reads them before they read anything else on the screen.
*/

:root {
  /* the page itself: a very soft vertical wash plus two wide colour pools */
  --page-wash:
    radial-gradient(120% 70% at 12% -8%,  rgba(79, 142, 247, .10) 0%, rgba(79, 142, 247, 0) 60%),
    radial-gradient(110% 65% at 92% 4%,   rgba(106, 170, 100, .09) 0%, rgba(106, 170, 100, 0) 58%),
    linear-gradient(180deg, #ffffff 0%, #f4f7fb 46%, #eef2f8 100%);

  --rim-top:    rgba(255, 255, 255, .95);
  --rim-bottom: rgba(16, 24, 40, .06);

  --lift-1: 0 1px 0 var(--rim-top) inset,
            0 -1px 0 var(--rim-bottom) inset,
            0 1px 2px rgba(16, 24, 40, .06),
            0 3px 8px -2px rgba(16, 24, 40, .08);

  --lift-2: 0 1px 0 var(--rim-top) inset,
            0 2px 4px rgba(16, 24, 40, .07),
            0 8px 20px -6px rgba(16, 24, 40, .14);

  --sink-1: inset 0 2px 5px rgba(16, 24, 40, .07),
            inset 0 -1px 0 var(--rim-top);
}

:root[data-theme="dark"] {
  --page-wash:
    radial-gradient(120% 70% at 12% -8%, rgba(79, 142, 247, .16) 0%, rgba(79, 142, 247, 0) 60%),
    radial-gradient(110% 65% at 92% 4%,  rgba(106, 170, 100, .10) 0%, rgba(106, 170, 100, 0) 58%),
    linear-gradient(180deg, #1b2333 0%, #151b27 48%, #11151e 100%);

  --rim-top:    rgba(255, 255, 255, .07);
  --rim-bottom: rgba(0, 0, 0, .40);

  --lift-1: 0 1px 0 var(--rim-top) inset,
            0 -1px 0 var(--rim-bottom) inset,
            0 1px 2px rgba(0, 0, 0, .40),
            0 4px 10px -3px rgba(0, 0, 0, .45);

  --lift-2: 0 1px 0 var(--rim-top) inset,
            0 3px 8px rgba(0, 0, 0, .45),
            0 14px 30px -8px rgba(0, 0, 0, .65);

  --sink-1: inset 0 2px 6px rgba(0, 0, 0, .45),
            inset 0 -1px 0 var(--rim-top);
}

/* ---- the page ---- */
body {
  background: var(--page-wash);
  background-attachment: fixed;
}

/* A dynamic viewport unit keeps the keyboard on screen when a mobile browser
   shows and hides its URL bar. 100vh is left first as the fallback. */
html, body { height: 100vh; height: 100dvh; }
#game { height: 100%; }

/* ---- tiles: matte, milled surfaces --------------------------------------
   No gloss. A top-to-bottom white wash on a dark tile is the single cheapest
   thing a UI can do - it reads as a 2008 plastic button and it was exactly
   what JL's clients flagged. Depth here comes from ONE hairline light edge
   along the top, a hairline dark edge along the bottom, and an ambient
   shadow beneath. That is how a milled key or an anodised panel actually
   catches light, and it stays honest at any tile size.                    */
.tile {
  background: var(--tile-bg);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .04) inset,
    0 1px 2px rgba(0, 0, 0, .10);
  transition: border-color 140ms ease, box-shadow 200ms ease,
              background-color 140ms ease, transform 140ms ease;
}
:where(:root[data-theme="dark"]) .tile {
  background: var(--tile-bg);
}

/* The row being typed: lifted a hair and edged with the ink colour, so the
   eye finds it without a highlight shouting for attention. */
.tile[data-state="tbd"] {
  background: color-mix(in srgb, var(--tile-bg) 92%, var(--ink) 8%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .07) inset,
    0 2px 6px -1px rgba(0, 0, 0, .18);
}

.tile[data-state="correct"],
.tile[data-state="present"],
.tile[data-state="absent"] {
  /* Flat colour, one hairline of light on the top edge only. No text
     shadow: crisp type on flat colour is what reads as expensive. */
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .10) inset,
    0 1px 3px rgba(0, 0, 0, .16);
  text-shadow: none;
}
.tile[data-state="correct"] { background: var(--correct); }
.tile[data-state="present"] { background: var(--present); }
.tile[data-state="absent"]  { background: var(--absent); }

/* ---- keys: matte caps with a real bottom edge, not a shine ---- */
.key {
  background: var(--key-bg);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .05) inset,
    0 2px 0 rgba(0, 0, 0, .16),
    0 2px 5px -2px rgba(0, 0, 0, .25);
  transition: background-color 180ms ease, color 180ms ease,
              transform 90ms ease, box-shadow 90ms ease;
}
:where(:root[data-theme="dark"]) .key {
  background: var(--key-bg);
}
.key:active {
  transform: translateY(2px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .04) inset,
    0 0 0 rgba(0, 0, 0, .16),
    0 1px 2px rgba(0, 0, 0, .22);
}
.key[data-state="correct"],
.key[data-state="present"],
.key[data-state="absent"] {
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .10) inset,
    0 2px 0 rgba(0, 0, 0, .18),
    0 2px 5px -2px rgba(0, 0, 0, .25);
  text-shadow: none;
}
.key[data-state="correct"] { background: var(--correct); }
.key[data-state="present"] { background: var(--present); }
.key[data-state="absent"]  { background: var(--absent); }

/* ---- Enter answers before it is pressed ----------------------------------
   Red the moment five letters are down and the guess would be rejected;
   a quiet green when it would be accepted. The colour is carried by the
   BORDER and the label, not a fill, so it never competes with a scored
   key sitting next to it.                                                */
.key[data-key="enter"] { transition: color 140ms ease, box-shadow 140ms ease, background-color 140ms ease; }
.key[data-key="enter"].bad {
  color: #ff6b6b;
  background: color-mix(in srgb, var(--key-bg) 82%, #ff6b6b 18%);
  box-shadow:
    0 0 0 2px color-mix(in srgb, #ff6b6b 62%, transparent) inset,
    0 2px 0 rgba(0, 0, 0, .16),
    0 2px 5px -2px rgba(0, 0, 0, .25);
}
.key[data-key="enter"].ready {
  color: color-mix(in srgb, var(--correct) 70%, #fff);
  box-shadow:
    0 0 0 2px color-mix(in srgb, var(--correct) 58%, transparent) inset,
    0 2px 0 rgba(0, 0, 0, .16),
    0 2px 5px -2px rgba(0, 0, 0, .25);
}
:root[data-theme="light"] .key[data-key="enter"].bad { color: #c02626; }
:root[data-theme="light"] .key[data-key="enter"].ready { color: color-mix(in srgb, var(--correct) 80%, #000); }

/* High contrast already recolours correct/present; the Enter cue must not
   imply green means "right", so it drops to a plain outline there. */
:root[data-contrast="high"] .key[data-key="enter"].ready { color: var(--ink); }

/* ---- chrome: pills, chips and icon buttons sit on the page, not in it ---- */
#modes {
  margin: 0 auto;
  padding: 5px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: var(--sink-1);
  backdrop-filter: blur(6px);
  width: max-content;
  max-width: 100%;
}
#modes { margin-top: 8px; margin-bottom: 8px; }

/* Same rule as the tiles: matte fills, one hairline edge, no wash. */
.pill[aria-selected="true"] {
  background: var(--modal-bg);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .06) inset,
    0 1px 3px rgba(0, 0, 0, .18);
}

.icon-btn, .chip {
  background: var(--surface);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .05) inset,
    0 1px 2px rgba(0, 0, 0, .14);
}
.icon-btn:active { box-shadow: var(--sink-1); }

.chip.install {
  background: var(--accent, #4f8ef7);
  color: #fff;
}

/* ---- raised surfaces in the modals ---- */
.modal { box-shadow: var(--lift-2), 0 40px 80px -30px rgba(16, 24, 40, .35); }
.stat-card, .hist-item, .result-def, .lang-opt {
  box-shadow: var(--lift-1);
}
.dist-row .track { box-shadow: var(--sink-1); }
.dist-row .fill { background: var(--absent); }
.dist-row.current .fill { background: var(--correct); }

.btn-share {
  background: var(--correct);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .10) inset,
    0 1px 3px rgba(0, 0, 0, .18);
}
.btn-share:active { transform: translateY(1px); box-shadow: var(--sink-1); }

.toast { box-shadow: var(--lift-2); }

/* Depth is decoration; motion is not. Both are dropped when asked. */
@media (prefers-reduced-motion: reduce) {
  .key, .tile, .icon-btn, .btn-share { transition: none; }
}


/* ===== toolbar: brand left, controls right ===== */

/*
  The old toolbar centred the title between two button groups, so the title was
  the first thing to be squeezed - it rendered as "Wor" on a narrow window.
  Brand left, controls right: the title now has a whole flex track of its own
  and the buttons wrap out of the way instead of crushing it.
*/
#toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 0 10px;
  flex: 0 0 auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  flex: 0 1 auto;
}

.brand-mark {
  display: flex;
  gap: 3px;
  flex: 0 0 auto;
}
.brand-mark b {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  font-size: 12.5px;
  font-weight: 800;
  background: var(--surface-2);
  color: var(--ink);
  box-shadow: var(--lift-1);
}
.brand-mark b.on {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--correct) 88%, #fff) 0%, var(--correct) 100%);
  color: #fff;
}

#title {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.015em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  pointer-events: none;
}

#toolbar .side.right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex: 0 0 auto;
}

/* Narrow: the wordmark stands down to the tile mark, which still says WP. */
@media (max-width: 430px) {
  #title { display: none; }
  .brand-mark b { width: 26px; height: 26px; font-size: 14px; border-radius: 7px; }
  #toolbar .side.right { gap: 5px; }
  .icon-btn { width: 34px; height: 34px; flex-basis: 34px; }
  .icon-btn svg { width: 20px; height: 20px; }
  .chip { height: 34px; padding: 0 10px; font-size: 13px; }
  .chip.install span { display: none; }
  .chip.install { padding: 0 9px; }
}

@media (max-width: 360px) {
  #toolbar .side.right { gap: 4px; }
  .icon-btn { width: 31px; height: 31px; flex-basis: 31px; }
  .chip { height: 31px; padding: 0 8px; }
}


/* ===== board fills the space it is given ===== */

/*
  The board was a fixed 340x408 box centred in whatever height was left, so on
  a tall phone it sat marooned in dead space.

  It now takes the full height of its track and derives its width from the
  aspect ratio. The max-height is expressed in viewport WIDTH (408/340 = 1.2),
  which is what keeps the tiles square on a narrow screen - a plain
  max-width:100% would clamp the width while the height stayed put and the
  tiles would stretch.
*/
#board {
  height: 100%;
  width: auto;
  max-width: 100%;
  aspect-ratio: 340 / 408;
  max-height: min(540px, calc((100vw - 28px) * 1.2));
  gap: 7px;
}

.row { gap: 7px; }

#board-wrap { padding: 4px 0 10px; }

/* The wordmark stands down on phones, and cannot clip at any width.
   --------------------------------------------------------------------------
   This block used to re-show the title at 430px and hide it only below 378px,
   so on every current iPhone - 390, 393, 402 and 430pt - the heading was drawn
   and then cut mid-word: "WordPla". Reported from a handset, not caught here.

   378 was a guess, and no single number can be right: Unlimited mode adds the
   New-word and Hint buttons, so the space the title has to fit into changes
   while the game is being played. The fix is therefore two independent ones.

   1. Below 480px the wordmark stands down to the W|P tiles, which still read
      as the brand. That covers every phone in portrait with room to spare.
   2. At any width, the heading may shrink and ellipsise. `flex: 0 0 auto`
      earlier in this file forbade that, which is why it hard-cut with no "..."
      rather than degrading. Belt and braces: if a control is ever added and
      480px stops being enough, the worst case becomes "WordP..." and not a
      word sliced in half. */
@media (min-width: 481px) {
  #title { display: block; font-size: 18px; }
}
@media (max-width: 480px) {
  #title { display: none; }
}
#title { flex: 0 1 auto; min-width: 0; }


/* ===== premium pass 2: type, ink, finish ===== */

/*
  House display type and house ink.

  Space Grotesk 700 carries the wordmark, modal headings and every number -
  it is the JLR Dev display face. Nunito stays on the tiles and keys, where a
  rounder, friendlier letterform is what a word game needs.

  The ink moves to house navy. The three tile colours do NOT move: green,
  yellow and grey are the rules of this game, and a player decodes them before
  they read a single word of chrome.
*/

:root {
  --display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
  --accent:  #4f8ef7;

  --ink:         #0a1628;
  --ink-muted:   #5b6b82;
  --surface:     #eef2f8;
  --surface-2:   #e2e8f2;
  --border:      #d4dce8;
  --tile-border: #cbd5e3;
  --key-bg:      #dde4ee;
  --key-fg:      #0a1628;
  --toast-bg:    #0a1628;
}

:root[data-theme="dark"] {
  --ink:         #eef3fb;
  --ink-muted:   #93a2b8;
  --bg:          #0b1220;
  --surface:     #17202f;
  --surface-2:   #1f2a3b;
  --surface-3:   #273349;
  --border:      #2b374b;
  --tile-border: #33405a;
  --tile-bg:     #141d2c;
  --key-bg:      #253044;
  --key-fg:      #eef3fb;
  --modal-bg:    #121a28;
  --toast-bg:    #eef3fb;
  --toast-fg:    #0a1628;
  --overlay:     rgba(4, 8, 16, .66);
}

/* ---- display face ---- */
#title,
.modal h2,
.result-word,
.result-head,
.stat-card .num,
.result-stats .num,
#countdown,
.brand-mark b {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.02em;
}

#title { font-size: 21px; letter-spacing: -0.03em; }
.modal h2 { letter-spacing: -0.025em; }
#countdown { letter-spacing: 0; font-variant-numeric: tabular-nums; }

.pill { font-family: var(--display); font-weight: 600; letter-spacing: -0.01em; }

/* ---- the toolbar can no longer overlap ----
   The wordmark gets the flexible track and truncates with an ellipsis; the
   controls keep their intrinsic width. Previously neither side could shrink,
   so the Install chip was painted straight over "WordPlay". */
.brand { flex: 1 1 auto; min-width: 0; overflow: hidden; }
#title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
#toolbar .side.right { flex: 0 0 auto; }

/* ---- install: an accent square, not a banner ---- */
.chip.install {
  width: 38px;
  padding: 0;
  justify-content: center;
  border-radius: 11px;
  color: #fff;
  background: var(--accent);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .14) inset,
    0 4px 12px -3px color-mix(in srgb, var(--accent) 55%, transparent);
}
.chip.install svg { width: 18px; height: 18px; fill: currentColor; }
@media (max-width: 430px) { .chip.install { width: 34px; } }
@media (max-width: 360px) { .chip.install { width: 31px; } }

/* ---- finish: a soft vignette so the board sits IN the page ---- */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(130% 85% at 50% 42%,
    rgba(10, 22, 40, 0) 55%, rgba(10, 22, 40, .055) 100%);
}
:root[data-theme="dark"] body::after {
  background: radial-gradient(130% 85% at 50% 42%,
    rgba(0, 0, 0, 0) 48%, rgba(0, 0, 0, .40) 100%);
}

/* ---- tiles and keys: crisper letterforms ---- */
.tile { font-weight: 800; letter-spacing: 0.01em; }
.key  { font-family: var(--display); font-weight: 600; letter-spacing: 0.01em; }
.key.wide { font-size: 12.5px; letter-spacing: .04em; }

/* ---- selected mode pill picks up the accent ---- */
.pill[aria-selected="true"] { color: var(--ink); }
.pill[aria-selected="true"][data-mode="daily"] svg { color: var(--accent); }
.pill[aria-selected="true"][data-mode="unlimited"] { color: var(--correct); }

/* ---- focus, visible and on-brand (WCAG 2.2) ---- */
:where(button, input, a):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 10px;
}


/* ===== install row ===== */

/*
  Install is an offer, not a control, so it no longer sits in the toolbar
  fighting the wordmark for width. It is the first row of Settings, where
  someone looking for it will look, and it hides itself once installed.
*/
.install-row {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  margin: 16px 0 4px;
  padding: 14px 15px;
  border: 0;
  border-radius: var(--r-card);
  text-align: left;
  cursor: pointer;
  color: #fff;
  background: var(--accent);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .14) inset,
    0 8px 22px -8px color-mix(in srgb, var(--accent) 65%, transparent);
  transition: transform 90ms ease, box-shadow 90ms ease;
}
.install-row:active { transform: translateY(1px); }

.install-row .ico {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  border-radius: 11px;
  background: rgba(255, 255, 255, .18);
}
.install-row .ico svg { width: 20px; height: 20px; fill: #fff; }

.install-row .txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.install-row .title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.015em;
}
.install-row .desc { font-size: 12.5px; line-height: 1.4; color: rgba(255, 255, 255, .86); }


/* ===== phone: no accidental zoom, no collapsing keys ===== */

/*
  A word game is a grid of small targets, so a stray pinch or a double tap on a
  key must not rescale the page - the board is already sized to fit the screen
  exactly, and zooming can only take part of it off-screen.

  touch-action: manipulation is what actually kills double-tap-to-zoom; the
  viewport meta alone does not, and several mobile browsers ignore
  user-scalable entirely.
*/
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { touch-action: manipulation; overscroll-behavior: none; }
#game { touch-action: manipulation; }

/*
  Under a scaled-up page the keyboard rows used to crush every key to a sliver,
  because nothing stopped flex from shrinking them past legibility. A floor on
  the key width keeps the row readable; it is the row that gives way first.
*/
.key { min-width: 20px; }
.key.wide { min-width: 44px; }
#keyboard .krow { flex-wrap: nowrap; }

/* ==========================================================================
   THEMES  -  five finishes, one rule
   --------------------------------------------------------------------------
   A theme changes the MATERIAL the board is made of, never the meaning of a
   colour. Correct stays green, present stays yellow, absent stays grey in
   every one of them; only their weight shifts so they sit correctly on that
   surface. High Contrast still overrides all five, because accessibility
   outranks taste.

   `data-theme` (dark|light) drives the structural rules; `data-skin` names
   the finish. Midnight and Mist ARE the dark and light bases, so they carry
   no overrides - the three below are the additional materials.
   ========================================================================== */

/* ---- Graphite: neutral studio charcoal. No hue at all, which is why it
        reads as equipment rather than decoration. ---- */
:root[data-skin="graphite"] {
  --page-wash:
    radial-gradient(120% 70% at 12% -8%, rgba(255, 255, 255, .05) 0%, rgba(255, 255, 255, 0) 60%),
    linear-gradient(180deg, #1a1a1c 0%, #121214 48%, #0d0d0f 100%);
  --bg:          #101012;
  --surface:     #1a1a1d;
  --surface-2:   #232326;
  --surface-3:   #2c2c30;
  --ink:         #f2f2f3;
  --ink-muted:   #9b9b9f;
  --border:      #2e2e32;
  --tile-border: #35353a;
  --tile-bg:     #17171a;
  --key-bg:      #2b2b30;
  --key-fg:      #f2f2f3;
  --modal-bg:    #151517;
  --toast-bg:    #f2f2f3;
  --toast-fg:    #101012;
  --accent:      #d5d5d8;
  --correct:     #538d4e;   /* white 3.97:1 */
  --present:     #a28e35;   /* white 3.25:1 */
  --absent:      #3a3a3c;   /* white 11.35:1 */
}

/* ---- Forest: deep pine. The green tile has to work harder here, so it is
        lifted a step and the absent grey is given a green cast to sit back. ---- */
:root[data-skin="forest"] {
  --page-wash:
    radial-gradient(120% 70% at 12% -8%, rgba(79, 197, 140, .12) 0%, rgba(79, 197, 140, 0) 60%),
    radial-gradient(110% 65% at 92% 4%,  rgba(200, 160, 60, .08) 0%, rgba(200, 160, 60, 0) 58%),
    linear-gradient(180deg, #12211b 0%, #0d1915 48%, #0a130f 100%);
  --bg:          #0a130f;
  --surface:     #132019;
  --surface-2:   #1a2a21;
  --surface-3:   #23372b;
  --ink:         #eaf4ee;
  --ink-muted:   #8fa79a;
  --border:      #24382c;
  --tile-border: #2b4335;
  --tile-bg:     #11201a;
  --key-bg:      #21362a;
  --key-fg:      #eaf4ee;
  --modal-bg:    #0f1b15;
  --toast-bg:    #eaf4ee;
  --toast-fg:    #0a130f;
  --accent:      #4fc58c;
  --correct:     #4f9d5d;
  --present:     #a98c37;   /* white 3.23:1 */
  --absent:      #35473c;
}

/* ---- Ivory: warm light paper. Pure white next to warm paper looks broken,
        so the whole chrome moves warm together - including the greys. ---- */
:root[data-skin="ivory"] {
  --page-wash:
    radial-gradient(120% 70% at 12% -8%, rgba(200, 150, 80, .12) 0%, rgba(200, 150, 80, 0) 60%),
    radial-gradient(110% 65% at 92% 4%,  rgba(106, 170, 100, .08) 0%, rgba(106, 170, 100, 0) 58%),
    linear-gradient(180deg, #fffdf9 0%, #faf6ee 46%, #f4efe4 100%);
  --bg:          #fffdf9;
  --surface:     #f4efe4;
  --surface-2:   #ebe4d6;
  --surface-3:   #e0d7c5;
  --ink:         #241f18;
  --ink-muted:   #6d6354;
  --border:      #ddd4c3;
  --tile-border: #d5cab6;
  --tile-bg:     #fffdf9;
  --key-bg:      #e8e1d3;
  --key-fg:      #241f18;
  --modal-bg:    #fffdf9;
  --toast-bg:    #241f18;
  --toast-fg:    #fffdf9;
  --overlay:     rgba(45, 36, 22, .42);
  --accent:      #b1763a;
  --correct:     #5f9d59;
  --present:     #aa8c37;   /* white 3.22:1 */
  --absent:      #8a8275;
  --rim-top:     rgba(255, 255, 255, .95);
  --rim-bottom:  rgba(60, 45, 25, .07);
}

/* ---- the picker ---- */
.setting.themes { display: block; }
.setting.themes .desc { margin-bottom: 12px; }

.theme-list {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}

.theme-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 9px 4px 8px;
  border: 0;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  color: var(--ink-muted);
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  transition: color 140ms ease, box-shadow 140ms ease, background-color 140ms ease;
}
.theme-opt:hover { color: var(--ink); }
.theme-opt[aria-checked="true"] {
  color: var(--ink);
  background: var(--surface);
  box-shadow: 0 0 0 2px var(--accent) inset;
}

/* The swatch is the theme's own board in miniature: page, tile, correct.
   A single flat colour chip would not tell you what you are choosing. */
.theme-swatch {
  width: 100%;
  max-width: 42px;
  aspect-ratio: 1;
  border-radius: 9px;
  overflow: hidden;
  display: grid;
  grid-template-rows: 1fr 1fr;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset, 0 1px 3px rgba(0, 0, 0, .25);
}
.theme-swatch i { display: block; }
.theme-swatch i:last-child {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.theme-swatch i:last-child b { display: block; }

@media (max-width: 360px) {
  .theme-opt { font-size: 10px; padding: 7px 2px 6px; }
  .theme-list { gap: 6px; }
}


/* ==========================================================================
   HIGH CONTRAST WINS
   --------------------------------------------------------------------------
   This block is LAST on purpose. `:root[data-contrast="high"]` and
   `:root[data-skin="forest"]` score identically, so whichever appears later
   in the file takes the token - and with the skins defined above, choosing a
   theme quietly cancelled the colour-blind palette. Measured, not assumed:
   an audit across all five themes found Graphite still serving the yellow at
   2.63:1 WITH high contrast on.

   The published Wordle values (#f5793a / #85c0f9) carry white letters at
   2.73:1 and 1.93:1 - the mode that exists for accessibility was the least
   legible thing in the app. Same orange/blue pairing, darkened in value only
   until white clears the 3:1 floor for large bold type.
   ========================================================================== */
:root[data-contrast="high"],
:root[data-contrast="high"][data-skin] {
  --correct: #e06f35;   /* white 3.23:1 */
  --present: #6694c0;   /* white 3.20:1 */
}

/* ==========================================================================
   LEGAL LINKS
   --------------------------------------------------------------------------
   Quiet, but present on every screen the player can reach. Google Play and the
   App Store both refuse a submission without a reachable privacy policy, and a
   copyright line on its own protects nothing if the terms it refers to cannot
   be found.
   ========================================================================== */

.legal-links {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.legal-links a {
  color: var(--ink-muted);
  font-size: 13px;
  text-decoration: none;
}
.legal-links a:hover { color: var(--ink); text-decoration: underline; }
