/* Clear (default) — light, high contrast, blue actions. Red is reserved
   for errors (see docs/USABILITY_GUIDELINES.md). */
:root {
  --color-bg: #F7F8FA;
  --color-surface: #FFFFFF;
  --color-surface-alt: #E8ECF2;
  --color-text: #14181F;
  --color-text-muted: #4A5361;
  --color-accent: #1D4ED8;
  --color-accent-secondary: #1D4ED8;
  --color-on-accent: #FFFFFF;
  --color-success: #15803D;
  --color-on-success: #FFFFFF;
  --color-danger: #B91C1C;
  --color-on-danger: #FFFFFF;
  --color-warning: #B45309;
  --color-border: #C9CFD8;
  --color-selected: rgba(29, 78, 216, 0.16);
  --color-success-bg: rgba(21, 128, 61, 0.14);
  --color-danger-bg: rgba(185, 28, 28, 0.12);
  --color-present: #F2B705;
  --color-on-present: #14181F;
  --color-present-ring: #92400E;

  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;

  --radius: 12px;
  --font-base: 18px;
  --font-sm: 15px;
  --font-lg: 24px;
  --tap-min: 48px;
  --btn-h: 56px;
}

/* Clear Dark — the same Clear family (blue actions, neutral surfaces),
   deliberately tuned for a dark background rather than a straight
   invert: the accent lightens to #7AA2FF so it still reads as "tap me"
   at 4.5:1 on dark surfaces, and success/danger/present shift to lighter,
   slightly desaturated tones that hold contrast without turning
   fluorescent. Selectable explicitly in Admin > Appearance via
   data-theme="dark". Clear itself (:root, above) stays light regardless
   of the phone's own dark-mode setting — this is the only way to get a
   dark look, deliberately, not an automatic fallback. */
:root[data-theme="dark"] {
  --color-bg: #0F1115;
  --color-surface: #1B1F27;
  --color-surface-alt: #2A303B;
  --color-text: #F5F7FA;
  --color-text-muted: #B4BCC8;
  --color-accent: #7AA2FF;
  --color-accent-secondary: #7AA2FF;
  --color-on-accent: #0B1220;
  --color-success: #4ADE80;
  --color-on-success: #0B1220;
  --color-danger: #F87171;
  --color-on-danger: #1A0505;
  --color-warning: #FBBF24;
  --color-border: #3A4150;
  --color-selected: rgba(122, 162, 255, 0.25);
  --color-success-bg: rgba(74, 222, 128, 0.18);
  --color-danger-bg: rgba(248, 113, 113, 0.2);
  --color-present: #E0B04F;
}

/* Dark themes: shared tokens (they used to cascade from :root when it was
   dark; :root is light now, so they must be restated here). */
:root[data-theme="classic"],
:root[data-theme="soft"],
:root[data-theme="playful"] {
  --color-on-accent: #FFFFFF;
  --color-success: #4caf80;
  --color-on-success: #0B1220;
  --color-danger: #e0654f;
  --color-warning: #E0B04F;
  /* These three used to read "var(--color-x)" (each pointing at itself), which
     is invalid CSS: every tint compared as empty and rendered transparent. */
  --color-selected: rgba(122, 162, 255, 0.25);
  --color-success-bg: rgba(74, 222, 128, 0.18);
  --color-danger-bg: rgba(248, 113, 113, 0.2);
  --color-present: #e0b04f;
}

/* Classic Tool — bold Swiss red on deep charcoal (from SAW Design Brief) */
:root[data-theme="classic"] {
  --color-bg: #0F0F10;
  --color-surface: #1C1C1E;
  --color-surface-alt: #242428;
  --color-text: #F5F5F7;
  --color-text-muted: #A9A9B0;
  --color-accent: #E63946;
  --color-accent-secondary: #E63946;
  --color-border: #2A2A2D;
}

/* Soft Utility — warmer, calmer terracotta accent */
:root[data-theme="soft"] {
  --color-bg: #121212;
  --color-surface: #1C1C1E;
  --color-surface-alt: #262626;
  --color-text: #F8F5F0;
  --color-text-muted: #A89F91;
  --color-accent: #C45C4A;
  --color-accent-secondary: #C45C4A;
  --color-border: #2A2A2A;
}

/* Playful Contrast — deep navy base, bold red, soft gold highlights */
:root[data-theme="playful"] {
  --color-bg: #0F0F10;
  --color-surface: #1D3557;
  --color-surface-alt: #24406b;
  --color-text: #F5F5F7;
  --color-text-muted: #BCC6D9;
  --color-accent: #E63946;
  --color-accent-secondary: #E9C46A; /* used sparingly — icons, badges, special states */
  --color-accent-text: #FF6B76; /* red accent as text on navy needs to be lighter */
  --color-border: #2a4a75;
}

* { box-sizing: border-box; }

html {
  overflow-x: hidden;
  width: 100%;
}

body {
  margin: 0;
  overflow-x: hidden;
  max-width: 100vw;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: var(--font-base);
  -webkit-tap-highlight-color: transparent;
}

.app-header {
  position: relative;
  background: #0F0F10;
  padding: var(--space-sm) var(--space-md);
  padding-top: calc(var(--space-sm) + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--color-border);
}
.app-header-logo {
  display: block;
  max-width: 128px;
  width: 100%;
  height: auto;
}
/* Version and build note: small and muted, under the Admin screens only. */
.app-footer {
  padding: var(--space-md);
  text-align: center;
  font-size: var(--font-sm);
  color: var(--color-text-muted);
}

.plugin-nav-row {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  border-bottom: 1px solid var(--color-border);
}
.admin-nav-btn {
  flex: 0 0 auto;
  background: var(--color-surface);
  color: var(--color-text);
  border: none;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-lg);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}
.admin-nav-btn.active {
  color: var(--color-accent);
}

.hamburger-btn {
  position: relative;
  flex: 0 0 auto;
  background: var(--color-surface);
  color: var(--color-text);
  border: none;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-lg);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}

.hamburger-menu {
  position: fixed;
  inset: 0;
  z-index: 100;
}
.hamburger-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
}
.hamburger-panel {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(80vw, 320px);
  background: var(--color-bg);
  border-right: 1px solid var(--color-border);
  padding-top: env(safe-area-inset-top, 0px);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.hamburger-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-md);
  border-bottom: 1px solid var(--color-border);
}
.hamburger-panel-header h2 {
  margin: 0;
  font-size: var(--font-lg);
}
.hamburger-close-btn {
  background: transparent;
  border: none;
  color: var(--color-text-muted);
  font-size: var(--font-lg);
  padding: var(--space-xs);
}
.hamburger-list {
  display: flex;
  flex-direction: column;
  padding: var(--space-sm);
  gap: var(--space-xs);
}
.hamburger-section-header {
  color: var(--color-text-muted);
  font-size: var(--font-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: var(--space-sm) var(--space-xs) 0;
}
.hamburger-section-header:first-child {
  margin-top: 0;
}
.hamburger-item {
  text-align: left;
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md);
  font-size: var(--font-base);
}
.hamburger-item.active {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

/* "What's new" — a dot on the ☰ button and a "New" word on the menu row. */
.hamburger-btn.has-news::after {
  content: "";
  position: absolute;
  top: 7px;
  right: 3px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--color-accent);
  border: 2px solid var(--color-surface);
}
.news-badge {
  margin-left: var(--space-sm);
  padding: 2px var(--space-sm);
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-size: var(--font-sm);
  font-weight: 600;
}
.whatsnew-entry {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md);
  margin-bottom: var(--space-md);
}
.whatsnew-entry-title {
  margin: 0 0 var(--space-sm);
  font-size: var(--font-lg);
}
.whatsnew-section-heading {
  margin: var(--space-md) 0 var(--space-xs);
  font-size: var(--font-base);
  color: var(--color-text-muted);
}
.whatsnew-list {
  margin: 0;
  padding-left: var(--space-lg);
}
.whatsnew-list li {
  margin-bottom: var(--space-sm);
  line-height: 1.4;
  font-size: var(--font-base);
}
.whatsnew-list code {
  font-family: ui-monospace, monospace;
  font-size: var(--font-sm);
  background: var(--color-surface-alt);
  padding: 1px 4px;
  border-radius: 4px;
}

.plugin-container {
  padding: var(--space-md);
}
.empty-state {
  color: var(--color-text-muted);
  text-align: center;
  margin-top: var(--space-lg);
}

/* Admin screen */
.admin-section-heading {
  margin: 0 0 var(--space-md);
  font-size: var(--font-lg);
  color: var(--color-accent);
}

.admin-category-header {
  color: var(--color-text-muted);
  font-size: var(--font-sm);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: var(--space-md) 0 var(--space-xs);
}
.admin-category-header:first-child {
  margin-top: 0;
}
.admin-game-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-sm);
}
.admin-game-name {
  font-size: var(--font-base);
}
.btn-icon {
  background: var(--color-surface);
  color: var(--color-accent-text, var(--color-accent));
  border: 2px solid var(--color-accent);
  border-radius: var(--radius);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.btn-icon:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 2px;
}
/* Disabled stays readable: never faded-out. */
.btn-icon:disabled {
  background: var(--color-surface-alt);
  border-color: var(--color-border);
  color: var(--color-text-muted);
  cursor: not-allowed;
}

.toggle-switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 48px; /* full tap target; the visible track is inset below */
  flex-shrink: 0;
}
.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.toggle-slider {
  position: absolute;
  inset: 7px 0;
  background: var(--color-text-muted);
  border: 2px solid var(--color-text-muted);
  border-radius: 24px;
  transition: background 0.15s;
}
.toggle-slider::before {
  content: "";
  position: absolute;
  height: 26px;
  width: 26px;
  left: 2px;
  top: 2px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  border-radius: 50%;
  transition: transform 0.15s;
}
.toggle-switch input:checked + .toggle-slider {
  background: var(--color-accent);
  border-color: var(--color-accent);
}
.toggle-switch input:checked + .toggle-slider::before {
  transform: translateX(26px);
}
.toggle-switch input:disabled + .toggle-slider {
  opacity: 0.5;
}
.toggle-switch input:focus-visible + .toggle-slider {
  outline: 3px solid var(--color-text);
  outline-offset: 2px;
}

.admin-diagnostics-actions {
  display: flex;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.btn-danger {
  background: var(--color-danger);
}

.log-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.log-entry {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  font-size: var(--font-sm);
  border-bottom: 1px solid var(--color-border);
  padding-bottom: var(--space-xs);
}
.log-time {
  color: var(--color-text-muted);
}
.log-level {
  text-transform: uppercase;
  font-weight: bold;
}
.log-level-error .log-level { color: var(--color-danger); }
.log-level-warn .log-level { color: #e0b04f; }
.log-level-info .log-level { color: var(--color-text-muted); }
.log-source {
  color: var(--color-accent);
}
.log-message {
  flex-basis: 100%;
}

/* Phrasebook */
.phrasebook-controls {
  display: flex;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
  flex-wrap: wrap;
}
.phrasebook-pack-select,
.phrasebook-search {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-sm);
  font-size: var(--font-base);
}
.phrasebook-search {
  flex: 1;
  min-width: 150px;
}
.phrasebook-pack-header {
  color: var(--color-text-muted);
  font-size: var(--font-sm);
  margin-bottom: var(--space-sm);
}
.phrasebook-category h3 {
  font-size: var(--font-base);
  color: var(--color-accent);
  margin: var(--space-md) 0 var(--space-sm);
}
.phrasebook-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}
.phrasebook-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: var(--space-sm);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-sm);
  align-items: baseline;
}
.phrasebook-base {
  color: var(--color-text-muted);
}

/* Dashboard */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-sm);
}
/* Card-style <button>s: browsers give buttons their own text colour and font,
   which rendered black-on-dark in dark mode. Inherit ours. */
button.card {
  color: var(--color-text);
  font: inherit;
}
.dashboard-tile {
  text-align: left;
  cursor: pointer;
}
.dashboard-tile-title {
  color: var(--color-text);
  font-weight: bold;
  font-size: var(--font-sm);
  margin: 0 0 var(--space-xs);
}
.dashboard-tile-value {
  font-size: 1.25rem;
  font-weight: bold;
  margin: 0 0 var(--space-xs);
}
.dashboard-tile-subtitle {
  font-size: var(--font-sm);
  color: var(--color-text-muted);
  margin: 0 0 var(--space-xs);
}
.dashboard-tile-updated {
  font-size: 0.7rem;
  color: var(--color-text-muted);
  margin: 0;
}

/* Appearance / theme picker */
.theme-option {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  width: 100%;
  text-align: left;
  cursor: pointer;
}
.theme-option-active {
  border-color: var(--color-accent);
}
.theme-swatch {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 2px solid var(--color-border);
}
.theme-swatch-clear { background: linear-gradient(135deg, #F7F8FA 50%, #1D4ED8 50%); border: 1px solid #C9CFD8; }
.theme-swatch-dark { background: linear-gradient(135deg, #0F1115 50%, #7AA2FF 50%); }
.theme-swatch-classic { background: linear-gradient(135deg, #0F0F10 50%, #E63946 50%); }
.theme-swatch-soft { background: linear-gradient(135deg, #121212 50%, #C45C4A 50%); }
.theme-swatch-playful { background: linear-gradient(135deg, #1D3557 50%, #E9C46A 50%); }
.theme-option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.theme-option-name {
  font-weight: bold;
}
.theme-option-desc {
  font-size: var(--font-sm);
  color: var(--color-text-muted);
}

/* Games / Word Guess (Wordle-style). Tile size is set from JS via --wt so all
   six rows fit the screen; falls back to a width-based size. Every state has
   a non-colour marker (data-mark, drawn by ::after) per
   docs/USABILITY_GUIDELINES.md: correct = solid fill + check, present =
   thick ring + dot, absent = dimmed + cross. */
.wordle-topbar {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--tap-min);
  margin-bottom: var(--space-sm);
}
.wordle-heading {
  flex: 1 1 auto;
  min-width: 0;
}
.wordle-title {
  margin: 0;
  font-size: var(--font-lg);
  line-height: 1.15;
}
.wordle-status {
  margin: 0;
  font-size: var(--font-sm);
  line-height: 1.25;
  color: var(--color-text-muted);
}
.wordle-topbar .btn {
  flex: 0 0 auto;
  min-height: var(--tap-min);
  font-size: var(--font-base);
}
.wordle-board {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  align-items: center;
  margin-bottom: var(--space-sm);
}
.wordle-row {
  display: flex;
  gap: var(--space-xs);
}
.wordle-tile {
  --wt-size: var(--wt, min(15vw, 68px));
  position: relative;
  width: var(--wt-size);
  height: var(--wt-size);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: calc(var(--wt-size) * 0.65);
  line-height: 1;
  border: 2px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface);
  color: var(--color-text);
  text-transform: uppercase;
}
.wordle-tile-filled {
  border-color: var(--color-text);
}
.wordle-tile-correct {
  background: var(--color-success);
  border-color: var(--color-success);
  color: var(--color-on-success);
}
.wordle-tile-present {
  background: var(--color-present);
  border: 4px solid var(--color-present-ring);
  color: var(--color-on-present);
}
.wordle-tile-absent {
  background: var(--color-surface-alt);
  border-color: var(--color-border);
  color: var(--color-text-muted);
}
/* Corner marker: same corner on every state so it can be scanned at a glance. */
.wordle-tile[data-mark]::after {
  content: attr(data-mark);
  position: absolute;
  top: 1px;
  right: 3px;
  font-size: max(13px, calc(var(--wt-size) * 0.26));
  font-weight: 900;
  line-height: 1;
}
.wordle-tile-correct[data-mark]::after { color: var(--color-on-success); }
.wordle-tile-present[data-mark]::after { color: var(--color-present-ring); top: -1px; right: 0; }
.wordle-tile-absent[data-mark]::after { color: var(--color-text-muted); }

.wordle-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px 10px;
  list-style: none;
  margin: 0 0 var(--space-sm);
  padding: 0;
  font-size: var(--font-sm);
  color: var(--color-text-muted);
}
.wordle-legend li {
  display: flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.wordle-swatch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 3px solid var(--color-border);
  border-radius: 5px;
  font-size: 13px;
  font-weight: 900;
  line-height: 1;
}
.wordle-swatch.wordle-tile-present { border-width: 3px; color: var(--color-present-ring); }

/* Slot under the board: the legend normally, a plain-words notice when a
   guess needs attention. Fixed height so the keyboard never jumps. */
.wordle-info {
  min-height: 2.6em;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.wordle-legend[hidden],
.wordle-notice[hidden] { display: none; }
.wordle-notice {
  margin: 0;
  text-align: center;
  font-size: var(--font-sm);
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-text);
}
.wordle-notice-error { color: var(--color-danger); }

.wordle-result {
  text-align: center;
  margin-bottom: var(--space-sm);
}
.wordle-result-title {
  font-size: var(--font-lg);
  font-weight: bold;
  margin: 0 0 var(--space-xs);
}
.wordle-result .empty-state {
  margin: 0;
}
.wordle-stats {
  color: var(--color-text-muted);
  font-size: var(--font-sm);
  margin: var(--space-xs) 0 0;
}
.wordle-end-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.wordle-end-actions .btn {
  min-height: var(--btn-h);
  font-size: 1.25rem;
}

/* Keyboard: spans the full screen width (bleeds through the 16px container
   padding), 56px keys. Also used by the Mini Crossword. */
.wordle-keyboard {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  align-items: stretch;
  width: calc(100% + 24px);
  margin: var(--space-sm) -12px 0;
}
.wordle-keyboard-row {
  display: flex;
  gap: 4px;
  width: 100%;
}
.wordle-key {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: var(--btn-h);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 1.5rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface-alt);
  color: var(--color-text);
  text-transform: uppercase;
  -webkit-tap-highlight-color: transparent;
}
.wordle-key-wide {
  flex: 1.5 1 0;
  font-size: 1rem;
  text-transform: none;
}
.wordle-key-enter {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-on-accent);
}
.wordle-key[data-mark]::after {
  content: attr(data-mark);
  position: absolute;
  top: 1px;
  right: 3px;
  font-size: 0.8rem;
  font-weight: 900;
  line-height: 1;
}
.wordle-key-correct {
  background: var(--color-success);
  border-color: var(--color-success);
  color: var(--color-on-success);
}
/* "Present" = yellow fill + brown ring + dot (colour is never the only signal).
   The heavier ring is drawn inset so the key keeps the same 1px border (and
   therefore the same width) as every other key: a wider border would make
   yellow keys wider and nudge their neighbours sideways. */
.wordle-key-present {
  background: var(--color-present);
  border-color: var(--color-present-ring);
  box-shadow: inset 0 0 0 2px var(--color-present-ring);
  color: var(--color-on-present);
}
.wordle-key-gone {
  visibility: hidden;
  pointer-events: none;
}
.wordle-key-correct[data-mark]::after { color: var(--color-on-success); }
.wordle-key-present[data-mark]::after { color: var(--color-present-ring); top: -1px; right: 1px; }
@media (min-width: 640px) {
  .wordle-keyboard {
    width: 100%;
    max-width: 600px;
    margin-inline: auto;
  }
}

/* Shared action bar (Word Search, Crossword, Sudoku, sharing bar). */
.wordle-mode-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.wordle-mode-bar .btn {
  flex: 1 1 140px;
  min-height: var(--btn-h);
  font-size: 1.15rem;
}

.word-search-hint {
  text-align: center;
}
.word-search-grid {
  display: grid;
  /* minmax(0, 1fr): a wide glyph can never stretch a column, so the board
     always spans exactly the full content width (max 600px). */
  grid-template-columns: repeat(var(--ws-size, 10), minmax(0, 1fr));
  gap: 2px;
  width: 100%;
  max-width: 600px;
  margin: 0 auto var(--space-md);
  /* Dragging across letters selects a word, so the grid (and only the grid)
     must not scroll, select text or open the long-press menu. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.word-search-cell {
  position: relative;
  overflow: hidden;
  aspect-ratio: 1 / 1;
  width: 100%;
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Letter ≈ 65% of the tile (10 columns in ~358px at 390px wide), sized
     against viewport width; the max matches the 600px board cap. */
  font-size: clamp(1.1rem, 5.6vw, 2.35rem);
  line-height: 1;
  font-weight: bold;
  text-transform: uppercase;
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  padding: 0;
}
/* FOUND: heavy solid border + a filled corner triangle. Both are per-cell,
   so a cell where two found words cross looks exactly like any other found
   cell. Never colour alone. */
.word-search-cell-found {
  background: var(--color-success-bg);
  border: 3px solid var(--color-success);
}
.word-search-cell-found::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 11px;
  height: 11px;
  background: var(--color-success);
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}
/* SELECTED (first letter tapped, waiting for the last): filled accent tile
   with an inset DASHED ring. A different fill, a different line style (dashed
   vs solid) and no corner triangle, so it can't be mistaken for found. If the
   cell is also part of a found word, the found border still shows around it. */
.word-search-cell-selected {
  background: var(--color-accent);
  color: var(--color-on-accent);
  border-color: var(--color-accent);
  outline: 2px dashed var(--color-on-accent);
  outline-offset: -5px;
}
.word-search-cell-selected.word-search-cell-found {
  border-color: var(--color-success);
}
.word-search-cell-selected.word-search-cell-found::after {
  background: var(--color-on-accent);
}
.word-search-cell:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 1px;
  z-index: 1;
}
.word-search-word-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-md);
  justify-content: center;
  padding: 0;
  margin: 0 0 var(--space-md);
}
.word-search-word-list li {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--font-base);
  font-weight: 600;
  color: var(--color-text);
  text-transform: uppercase;
}
/* FOUND word: a ✓ before it AND a line through it, plus muted text. The
   ✓ is inline-block-ish (own flex item) so the line-through doesn't cross it. */
.word-search-word-found {
  color: var(--color-text-muted);
}
.word-search-word-found .word-search-word-text {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}
.word-search-tick {
  color: var(--color-success);
  font-weight: 900;
}
.word-search-result-back {
  margin-top: var(--space-sm);
}
/* Screen-reader-only text (announced, not drawn). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.crossword-active-clue {
  text-align: center;
  font-size: calc(var(--font-base) * 1.15);
  font-weight: bold;
  line-height: 1.25;
  /* pull up under the game selector so board + keyboard fit at 360x740 */
  margin: calc(var(--space-sm) * -1) 0 var(--space-sm);
}
/* Mini Crossword. Colours come only from theme tokens. Focus cues:
   - selected cell: 2px accent ring, drawn inside the cell (no bars)
   - active word:   light tint
   - active clue:   a ▶ marker plus bold (see .crossword-clue-item-active) */
.crossword-grid {
  display: grid;
  grid-template-columns: repeat(var(--cw-size, 5), 1fr);
  gap: 2px;
  max-width: 600px;
  margin: 0 auto var(--space-sm);
  padding: 2px;
  background: var(--color-text-muted);
  border-radius: 4px;
}
.crossword-cell {
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface);
  /* buttons don't inherit colour; without this the cell's own text colour
     is the browser default (black), unreadable on dark themes */
  color: var(--color-text);
  border: 0;
  border-radius: 0;
  padding: 10px 0 0;
}
.crossword-cell-black {
  background: var(--color-text-muted);
}
.crossword-cell-letter {
  font-size: clamp(1.8rem, 11.5vw, 3.5rem);
  line-height: 1;
  font-weight: bold;
  color: var(--color-text);
  text-transform: uppercase;
}
.crossword-cell-number {
  position: absolute;
  top: 2px;
  left: 4px;
  font-size: var(--font-sm);
  line-height: 1;
  color: var(--color-text-muted);
}
.crossword-cell-active {
  background: linear-gradient(var(--color-selected), var(--color-selected)), var(--color-surface);
}
.crossword-cell-selected {
  z-index: 1;
  box-shadow: inset 0 0 0 2px var(--color-accent);
}
.crossword-cell:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: -3px;
  z-index: 2;
}
.crossword-result {
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-sm);
}
.crossword-result .empty-state {
  margin: 0;
}
.crossword-result .wordle-stats {
  margin: 4px 0 0;
}
.crossword-grid + .wordle-keyboard {
  margin-top: var(--space-sm);
  gap: 6px;
}
.crossword-clues {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  margin-top: var(--space-md);
}
.crossword-clue-heading {
  margin: 0 0 var(--space-xs);
}
.crossword-clue-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.crossword-clue-item {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  font-size: calc(var(--font-base) * 1.1);
  color: var(--color-text);
  padding: 4px 8px 4px 0;
  border-radius: 4px;
  cursor: pointer;
}
/* Fixed-width marker slot so clue text stays aligned whether or not the
   ▶ is showing. */
.crossword-clue-item::before {
  content: "";
  flex: 0 0 1.6em;
  text-align: center;
  font-size: 0.85em;
}
.crossword-clue-item-active {
  font-weight: bold;
  background: var(--color-selected);
}
.crossword-clue-item-active::before {
  content: "\25B6";
}
.crossword-clue-item:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 1px;
}

.memory-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  width: 100%;
  max-width: 600px;
  margin: 0 auto var(--space-md);
}
/* Card states never rely on colour alone (docs/USABILITY_GUIDELINES.md):
   face-down = striped card back with a strong outline; flipped = heavy
   ring; matched = outlined, no fill, dimmed face, and a check badge. */
.memory-card {
  color: var(--color-text);
  position: relative;
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Face fills ~65% of the card. Card width = (content width - 3 gaps) / 4,
     content width = min(viewport - 2 x 16px padding, 600px). */
  font-size: clamp(2rem, calc((min(100vw - 32px, 600px) - 24px) / 4 * var(--memory-face-scale, 0.52)), 6rem);
  line-height: 1;
  background: repeating-linear-gradient(45deg, var(--color-surface-alt) 0 7px, var(--color-surface) 7px 14px);
  border: 2px solid var(--color-text-muted);
  border-radius: 10px;
  padding: 0;
}
.memory-card:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 3px;
}
.memory-card-flipped {
  background: var(--color-surface);
  border-color: var(--color-text);
  box-shadow: 0 0 0 3px var(--color-text);
}
.memory-card-matched {
  background: var(--color-bg);
  border-color: var(--color-success);
}
.memory-card-matched .memory-card-face {
  opacity: 0.6;
}
.memory-card-matched::after {
  content: "\2713";
  position: absolute;
  top: 4px;
  right: 4px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-text);
  color: var(--color-bg);
  font-size: var(--font-sm);
  font-weight: 700;
  line-height: 1;
}
.memory-theme-bar {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.memory-theme-bar .btn {
  font-size: var(--font-base);
  padding: 8px 14px;
}
/* Active theme: check mark (added in JS) + heavy ring + alt fill. Not a
   solid accent fill, so it can't be mistaken for the screen's primary. */
.memory-theme-active {
  background: var(--color-surface-alt);
  box-shadow: 0 0 0 2px var(--color-accent);
  font-weight: 800;
}

.sudoku-grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  width: 100%;
  max-width: 600px;
  margin: 0 auto var(--space-md);
  border: 3px solid var(--color-text);
}
.sudoku-cell {
  position: relative;
  isolation: isolate; /* lets the conflict stripes sit behind the digit */
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(1.5rem, 7vw, 2.4rem);
  font-weight: 400; /* entered digits: regular */
  line-height: 1;
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  padding: 0;
}
/* Given digits: bold on a tinted cell. Entered digits: regular on white. */
.sudoku-cell-given {
  font-weight: 800;
  color: var(--color-text);
  background: var(--color-surface-alt);
}
/* 3x3 box borders stay heavier than cell borders in every theme. */
.sudoku-cell-box-left {
  border-left: 3px solid var(--color-text);
}
.sudoku-cell-box-top {
  border-top: 3px solid var(--color-text);
}
/* Same digit as the selected one: tint + a dot in the corner (shape, not just colour). */
.sudoku-cell-highlighted {
  background: var(--color-selected);
}
.sudoku-cell-highlighted::after {
  content: "";
  position: absolute;
  top: 3px;
  right: 3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-text);
  pointer-events: none;
}
/* Selected cell: thick inset border (it already stands out, so no dot on it). */
.sudoku-cell-selected {
  box-shadow: inset 0 0 0 4px var(--color-text);
}
.sudoku-cell-selected::after {
  display: none;
}
/* Conflict: danger colour + diagonal stripes + wavy underline (+ a warning
   line in the status text). Reads without colour. */
.sudoku-cell-conflict {
  color: var(--color-danger);
  background: var(--color-danger-bg);
  text-decoration: underline wavy var(--color-danger);
  text-decoration-thickness: 2px;
  text-underline-offset: 1px; /* small: a bigger offset pushes the wave out of the cell and clips it */
}
.sudoku-cell-conflict::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.4;
  background: repeating-linear-gradient(135deg, var(--color-danger) 0 2px, transparent 2px 7px);
  pointer-events: none;
}
.sudoku-keypad {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
}
.sudoku-key {
  position: relative;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 1.6rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface-alt);
  color: var(--color-text);
}
.sudoku-key-wide {
  grid-column: span 2;
  font-size: 1.05rem;
}
.sudoku-key:disabled {
  cursor: default;
}
/* Digit fully placed: still readable, but struck through with a tick and a
   dashed border, so it looks switched off (not just faded or missing). */
.sudoku-key-done,
.sudoku-key-done:disabled {
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  border: 2px dashed var(--color-text-muted);
  text-decoration: line-through;
  text-decoration-thickness: 3px;
}
.sudoku-key-done::after {
  content: "\2713";
  position: absolute;
  top: 1px;
  right: 6px;
  font-size: 1rem;
  font-weight: 800;
  color: var(--color-text);
  text-decoration: none;
}
.sudoku-key-active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-on-accent);
}
.sudoku-key-legend {
  margin: var(--space-sm) 0 0;
  text-align: center;
  font-size: var(--font-sm);
  color: var(--color-text-muted);
}
/* Finished screen: result card, then a full-width primary, then secondary. */
.sudoku-end-actions {
  display: grid;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

/* Backup */
.backup-import-input {
  display: block;
  margin-top: var(--space-sm);
}
.phrasebook-native {
  font-weight: bold;
}
.phrasebook-pron {
  font-size: var(--font-sm);
  color: var(--color-text-muted);
  font-style: italic;
}

.toolkit-toast {
  position: fixed;
  left: var(--space-md);
  right: var(--space-md);
  bottom: calc(var(--space-lg) + var(--space-md) + env(safe-area-inset-bottom, 0px));
  max-width: 480px;
  margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--color-danger);
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  color: var(--color-text);
  font-size: var(--font-sm);
  text-align: center;
  z-index: 500;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: none;
}
.toolkit-toast-visible {
  opacity: 1;
  transform: translateY(0);
}
.toolkit-toast-warn {
  border-color: var(--color-accent);
}
.toolkit-toast-error {
  border-color: var(--color-danger);
}

.crash-overlay {
  position: fixed;
  inset: 0;
  background: #200a0a;
  color: #ffb4a8;
  padding: var(--space-md);
  padding-top: calc(var(--space-md) + env(safe-area-inset-top, 0px));
  overflow: auto;
  z-index: 9999;
  font-size: var(--font-sm);
}
.crash-overlay pre {
  white-space: pre-wrap;
  word-break: break-word;
  border-bottom: 1px solid #402020;
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-sm);
}

/* Shared components plugins may use */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-md);
  margin-bottom: var(--space-sm);
}
.btn {
  background: var(--color-accent);
  color: var(--color-on-accent);
  border: 2px solid var(--color-accent);
  border-radius: var(--radius);
  min-height: var(--tap-min);
  padding: 10px var(--space-md);
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
}
.btn:focus-visible,
.sudoku-key:focus-visible,
.wordle-key:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 2px;
}
.btn-secondary {
  background: var(--color-surface);
  color: var(--color-accent-text, var(--color-accent));
  border-color: var(--color-accent);
}
.btn.btn-danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-on-danger, #fff);
}
/* Full-width primary action, thumb-sized. One per screen. */
.btn-block {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--btn-h);
  font-size: 1.25rem;
}
/* Disabled stays readable: never faded-out text. */
.btn:disabled {
  background: var(--color-surface-alt);
  border-color: var(--color-border);
  color: var(--color-text-muted);
  cursor: not-allowed;
}
