/* The `hidden` attribute only hides an element while nothing else sets `display`. Every
   author rule beats the user agent's `[hidden] { display: none }`, so `class="btn" hidden`
   renders as a perfectly visible button, and setting `el.hidden = true` from JS does
   nothing either. That shipped: the daily trainer's «Дальше» button was on screen through
   every round, which let a player skip a puzzle without solving it. Nothing about the
   markup or the JS looks wrong when this happens, so it is neutralised once, here.
   tests/solver.test.mjs asserts this rule exists. */
[hidden] {
  display: none !important;
}

/* ===== CSS Variables & Reset ===== */
:root {
  --font-display: 'Unbounded', sans-serif;
  --font-body: 'Golos Text', sans-serif;

  --color-bg: #f0f2f5;
  --color-surface: #ffffff;
  --color-surface-alt: #f7f8fa;
  --color-border: #e2e5ea;
  --color-border-thick: #bcc3ce;
  --color-text: #1a1d23;
  --color-text-secondary: #6b7280;
  --color-text-muted: #9ca3af;

  --color-primary: #4f46e5;
  --color-primary-hover: #4338ca;
  --color-primary-light: #eef2ff;
  --color-primary-glow: rgba(79, 70, 229, 0.15);

  --color-accent: #06b6d4;
  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error: #ef4444;
  --color-error-light: #fef2f2;

  --color-cell-selected: #e0e7ff;
  --color-cell-highlight: #f0f4ff;
  --color-cell-same-num: #dbeafe;
  --color-cell-given: var(--color-text);
  --color-cell-user: var(--color-primary);
  --color-cell-error: var(--color-error);
  --color-cell-notes: var(--color-text-secondary);

  /* Duel: you are always the primary indigo, the opponent is always rose. Keeping the
     two hues far apart is what makes the opponent heat-map readable at a glance. */
  --color-duel-you: var(--color-primary);
  --color-duel-you-bg: rgba(79, 70, 229, 0.10);
  --color-duel-opponent: #e11d48;
  --color-duel-opponent-bg: rgba(225, 29, 72, 0.10);
  --color-duel-both-bg: rgba(139, 92, 246, 0.12);

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.08);
  --shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.1);

  --transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);

  /* One layout system for every surface. Desktop uses a 12-column frame; content
     widths are spans of that frame, and all vertical spacing comes from this scale. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --grid-columns: 12;
  --grid-gutter: 24px;
  --container-wide: 1180px;
  --container-content: 780px;
  --container-reading: 680px;
  --page-gutter: 24px;

  --board-size: min(480px, calc(100vw - 32px));
  --cell-size: calc(var(--board-size) / 9);
}

[data-theme="dark"] {
  --color-bg: #0f1117;
  --color-surface: #1a1d27;
  --color-surface-alt: #22252f;
  --color-border: #2d3140;
  --color-border-thick: #3d4255;
  --color-text: #e8eaed;
  --color-text-secondary: #9aa0ad;
  --color-text-muted: #6b7280;

  --color-primary: #818cf8;
  --color-primary-hover: #a5b4fc;
  --color-primary-light: rgba(129, 140, 248, 0.12);
  --color-primary-glow: rgba(129, 140, 248, 0.2);

  --color-error-light: rgba(239, 68, 68, 0.12);

  --color-cell-selected: rgba(129, 140, 248, 0.25);
  --color-cell-highlight: rgba(129, 140, 248, 0.08);
  --color-cell-same-num: rgba(129, 140, 248, 0.15);
  --color-cell-user: #a5b4fc;
  --color-cell-notes: var(--color-text-muted);

  --color-duel-you-bg: rgba(129, 140, 248, 0.16);
  --color-duel-opponent: #fb7185;
  --color-duel-opponent-bg: rgba(251, 113, 133, 0.18);
  --color-duel-both-bg: rgba(167, 139, 250, 0.20);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.35);
  --shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.4);
}

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 16px;
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: var(--font-body);
  background: var(--color-bg);
  color: var(--color-text);
  min-height: 100dvh;
  line-height: 1.5;
  overflow-x: hidden;
  transition: background var(--transition), color var(--transition);
}

button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
  font-size: inherit;
}

/* ===== Layout ===== */
#app {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  width: 100%;
  max-width: calc(var(--container-wide) + 2 * var(--page-gutter));
  margin: 0 auto;
  padding: 0 var(--page-gutter);
}

/* ===== Header ===== */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--space-5) 0;
}

#app:not(.app--wide) .header,
#app:not(.app--wide) > .main,
#app:not(.app--wide) > .seo-content,
#app:not(.app--wide) > .footer {
  width: 100%;
  max-width: var(--container-content);
  margin-left: auto;
  margin-right: auto;
}

.header__logo {
  display: flex;
  align-items: center;
  gap: 10px;
}

.header__icon {
  font-size: 28px;
  color: var(--color-primary);
  line-height: 1;
}

.header__title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  background: linear-gradient(135deg, var(--color-primary), var(--color-accent));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* ===== Buttons ===== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 18px;
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 0.875rem;
  transition: all var(--transition);
  white-space: nowrap;
  text-decoration: none; /* .btn is also used on <a> (duel share + navigation links) */
}

.btn:disabled {
  opacity: 0.55;
  cursor: default;
  transform: none;
}

.btn--primary {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 2px 8px var(--color-primary-glow);
}

.btn--primary:hover {
  background: var(--color-primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 4px 16px var(--color-primary-glow);
}

.btn--primary:active {
  transform: translateY(0);
}

.btn--ghost {
  padding: 8px;
  border-radius: var(--radius-sm);
  color: var(--color-text-secondary);
}

.btn--ghost:hover {
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.btn--lang {
  min-width: 36px;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.btn--lg {
  padding: 12px 32px;
  font-size: 1rem;
  border-radius: var(--radius-lg);
}

/* ===== Game Bar ===== */
.game-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}

.difficulty-selector {
  display: flex;
  gap: 4px;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  padding: 4px;
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--color-border);
}

.difficulty-btn {
  padding: 6px 14px;
  border-radius: var(--radius-md);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  transition: all var(--transition);
}

.difficulty-btn:hover {
  color: var(--color-text);
  background: var(--color-surface-alt);
}

.difficulty-btn.active {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 2px 8px var(--color-primary-glow);
}

/* ===== Game Stats ===== */
.game-stats {
  display: flex;
  justify-content: center;
  gap: 32px;
  margin-bottom: 16px;
}

.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.stat__label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.stat__value {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--color-text);
}

#mistakes.error {
  color: var(--color-error);
  animation: shake 0.4s ease;
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

/* ===== Board ===== */
.board-container {
  position: relative;
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

.board {
  display: grid;
  grid-template-columns: repeat(9, var(--cell-size));
  grid-template-rows: repeat(9, var(--cell-size));
  background: var(--color-surface);
  border: 2.5px solid var(--color-text);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  user-select: none;
  -webkit-user-select: none;
}

.cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: calc(var(--cell-size) * 0.45);
  font-weight: 600;
  border: 0.5px solid var(--color-border);
  cursor: pointer;
  transition: background var(--transition);
  background: var(--color-surface);
  color: var(--color-cell-given);
}

.cell:hover {
  background: var(--color-cell-highlight);
}

/* Thick borders for 3x3 boxes */
.cell[data-col="2"], .cell[data-col="5"] {
  border-right: 2px solid var(--color-border-thick);
}
.cell[data-col="3"], .cell[data-col="6"] {
  border-left: 2px solid var(--color-border-thick);
}
.cell[data-row="2"], .cell[data-row="5"] {
  border-bottom: 2px solid var(--color-border-thick);
}
.cell[data-row="3"], .cell[data-row="6"] {
  border-top: 2px solid var(--color-border-thick);
}

/* Cell states */
.cell--selected {
  background: var(--color-cell-selected) !important;
  box-shadow: inset 0 0 0 2px var(--color-primary);
  z-index: 2;
}

.cell--highlighted {
  background: var(--color-cell-highlight) !important;
}

.cell--same-number {
  background: var(--color-cell-same-num) !important;
}

.cell--user {
  color: var(--color-cell-user);
}

.cell--error {
  color: var(--color-cell-error) !important;
  background: var(--color-error-light) !important;
  animation: cellError 0.4s ease;
}

@keyframes cellError {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.1); }
}

.cell--given {
  font-weight: 700;
  color: var(--color-cell-given);
}

.cell--correct-reveal {
  animation: correctPop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes correctPop {
  0% { transform: scale(0.5); opacity: 0.3; }
  100% { transform: scale(1); opacity: 1; }
}

/* Notes */
.cell__notes {
  position: absolute;
  inset: 1px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  pointer-events: none;
}

.cell__note {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(var(--cell-size) * 0.2);
  font-weight: 500;
  color: var(--color-cell-notes);
  font-family: var(--font-body);
  line-height: 1;
}

/* ===== Start Overlay (pre-game) ===== */
.start-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: var(--radius-lg);
  z-index: 8;
  transition: opacity 0.5s ease, visibility 0.5s ease;
}

[data-theme="dark"] .start-overlay {
  background: rgba(15, 17, 23, 0.65);
}

.start-overlay.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.start-overlay__content {
  text-align: center;
  padding: 24px;
}

.start-overlay__icon {
  width: 80px;
  height: 80px;
  margin: 0 auto 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary);
  color: #fff;
  border-radius: 50%;
  box-shadow: 0 8px 32px var(--color-primary-glow), 0 0 0 8px rgba(79, 70, 229, 0.08);
  animation: startPulse 2s ease-in-out infinite;
}

[data-theme="dark"] .start-overlay__icon {
  box-shadow: 0 8px 32px var(--color-primary-glow), 0 0 0 8px rgba(129, 140, 248, 0.1);
}

@keyframes startPulse {
  0%, 100% { transform: scale(1); box-shadow: 0 8px 32px var(--color-primary-glow), 0 0 0 8px rgba(79, 70, 229, 0.08); }
  50% { transform: scale(1.05); box-shadow: 0 12px 40px var(--color-primary-glow), 0 0 0 12px rgba(79, 70, 229, 0.12); }
}

.start-overlay__icon svg {
  margin-left: 4px;
}

.start-overlay__title {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 700;
  margin-bottom: 6px;
}

.start-overlay__text {
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  max-width: 280px;
  margin: 0 auto 20px;
  line-height: 1.5;
}

.start-overlay__btn {
  padding: 14px 40px;
  font-size: 1.05rem;
}

/* ===== Game Overlay (win/lose) ===== */
.game-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  border-radius: var(--radius-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
  z-index: 10;
}

[data-theme="dark"] .game-overlay {
  background: rgba(15, 17, 23, 0.92);
}

.game-overlay.visible {
  opacity: 1;
  pointer-events: all;
}

.overlay-content {
  text-align: center;
  padding: 24px;
}

.overlay-icon {
  font-size: 3rem;
  margin-bottom: 12px;
  animation: bounce 0.6s ease infinite alternate;
}

@keyframes bounce {
  from { transform: translateY(0); }
  to { transform: translateY(-8px); }
}

.overlay-title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 700;
  margin-bottom: 4px;
}

.overlay-text {
  color: var(--color-text-secondary);
  margin-bottom: 16px;
}

.overlay-stats {
  display: flex;
  justify-content: center;
  gap: 24px;
  margin-bottom: 20px;
}

.overlay-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.overlay-stat__value {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--color-primary);
}

.overlay-stat__label {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* ===== Controls ===== */
.controls {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 24px;
}

.controls__tools {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.tool-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 16px;
  border-radius: var(--radius-md);
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  transition: all var(--transition);
  position: relative;
}

.tool-btn:hover {
  background: var(--color-surface);
  color: var(--color-primary);
  box-shadow: var(--shadow-sm);
}

.tool-btn.active {
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.tool-btn svg {
  flex-shrink: 0;
}

.hint-count {
  position: absolute;
  top: 4px;
  right: 8px;
  background: var(--color-primary);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

/* ===== Number Pad ===== */
.controls__numbers {
  display: flex;
  justify-content: center;
  gap: 6px;
}

.num-btn {
  width: calc(var(--board-size) / 9 - 2px);
  max-width: 52px;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 600;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  transition: all var(--transition);
  box-shadow: var(--shadow-sm);
}

.num-btn:hover {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
  color: var(--color-primary);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.num-btn:active {
  transform: translateY(0);
}

.num-btn.completed {
  opacity: 0.3;
  pointer-events: none;
}

.num-btn.num-btn--active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
  box-shadow: 0 4px 12px var(--color-primary-glow);
}

/* ===== Game Tip ===== */
.game-tip {
  text-align: center;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin-bottom: 14px;
  min-height: 1.2em;
  transition: all var(--transition);
}

.game-tip.highlight {
  color: var(--color-primary);
}

/* ===== Numpad Labels ===== */
.numpad-label {
  text-align: center;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  margin-bottom: 6px;
}

.numpad-hint {
  text-align: center;
  font-size: 0.7rem;
  color: var(--color-text-muted);
  margin-top: 6px;
  font-style: italic;
}

/* ===== Tooltips ===== */
[data-tooltip] {
  position: relative;
}

[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--color-text);
  color: var(--color-bg);
  font-size: 0.7rem;
  font-weight: 400;
  font-style: normal;
  line-height: 1.4;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  max-width: 220px;
  white-space: normal;
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease, transform 0.15s ease;
  z-index: 20;
  box-shadow: var(--shadow-md);
}

[data-tooltip]::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--color-text);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
  z-index: 20;
}

[data-tooltip]:hover::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

[data-tooltip]:hover::before {
  opacity: 1;
}

@media (max-width: 480px) {
  [data-tooltip]::after,
  [data-tooltip]::before {
    display: none;
  }
}

/* ===== Rules Modal ===== */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
  padding: 16px;
}

.modal-backdrop.visible {
  opacity: 1;
  pointer-events: all;
}

.modal {
  background: var(--color-surface);
  border-radius: var(--radius-xl);
  max-width: 520px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: var(--shadow-xl);
  transform: translateY(16px) scale(0.97);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.modal-backdrop.visible .modal {
  transform: translateY(0) scale(1);
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px 0;
  position: sticky;
  top: 0;
  background: var(--color-surface);
  z-index: 1;
}

.modal__title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
}

.modal__close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 1.4rem;
  color: var(--color-text-muted);
  transition: all var(--transition);
  flex-shrink: 0;
}

.modal__close:hover {
  background: var(--color-surface-alt);
  color: var(--color-text);
}

.modal__body {
  padding: 20px 24px 24px;
}

.rules-section {
  margin-bottom: 20px;
}

.rules-section:last-child {
  margin-bottom: 0;
}

.rules-section h3 {
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-primary);
  margin-bottom: 8px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.rules-section > p {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.rules-steps {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.rules-step {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.rules-step__num {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 700;
  border-radius: 50%;
}

.rules-step strong {
  display: block;
  font-size: 0.85rem;
  margin-bottom: 2px;
}

.rules-step p {
  font-size: 0.8rem;
  color: var(--color-text-secondary);
  line-height: 1.5;
}

.rules-tools {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.rules-tool {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.rules-tool__icon {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-size: 1rem;
  border-radius: var(--radius-sm);
}

.rules-tool strong {
  display: block;
  font-size: 0.85rem;
  margin-bottom: 1px;
}

.rules-tool p {
  font-size: 0.8rem;
  color: var(--color-text-secondary);
  line-height: 1.5;
}

.rules-tool kbd {
  display: inline-block;
  padding: 1px 5px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  color: var(--color-text-secondary);
}

.rules-tips {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rules-tips li {
  font-size: 0.8rem;
  color: var(--color-text-secondary);
  line-height: 1.5;
  padding-left: 20px;
  position: relative;
}

.rules-tips li::before {
  content: '→';
  position: absolute;
  left: 0;
  color: var(--color-primary);
  font-weight: 600;
}

/* ===== SEO Content ===== */
.seo-content {
  width: 100%;
  max-width: var(--container-reading);
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border);
}

.seo-content h1 {
  font-family: var(--font-display);
  font-size: clamp(1.55rem, 2.4vw, 2rem);
  line-height: 1.25;
  margin-bottom: var(--space-4);
}

.seo-content h2 {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  margin-top: var(--space-7);
  margin-bottom: var(--space-3);
}

.seo-content h3 {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  margin-top: var(--space-6);
  margin-bottom: var(--space-2);
}

.seo-content p {
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--color-text-secondary);
  margin-bottom: var(--space-4);
}

.seo-content ul {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.seo-content ul li {
  font-size: 0.85rem;
  color: var(--color-text-secondary);
  padding-left: 18px;
  position: relative;
  line-height: 1.6;
}

.seo-content ul li::before {
  content: '✓';
  position: absolute;
  left: 0;
  color: var(--color-success);
  font-weight: 700;
}

/* FAQ */
.faq {
  margin-top: var(--space-6);
}

.faq summary {
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary h3 {
  display: inline;
  color: var(--color-primary);
}

.faq summary h3::after {
  content: ' ▸';
  font-size: 0.8em;
}

.faq[open] summary h3::after {
  content: ' ▾';
}

.faq__item {
  margin-top: var(--space-4);
}

.faq__item h4 {
  font-size: 0.875rem;
  font-weight: 600;
  margin-bottom: 4px;
}

.faq__item p {
  font-size: 0.825rem;
  color: var(--color-text-secondary);
  line-height: 1.6;
}

/* ===== Footer ===== */
.footer {
  width: 100%;
  margin-top: var(--space-7);
  padding: var(--space-5) 0;
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  border-top: 1px solid var(--color-border);
}

.footer__links {
  margin-top: var(--space-3);
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  align-items: center;
}

.footer__link {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--transition);
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}

.footer__link:hover {
  color: var(--color-primary);
}

.footer__sep {
  color: var(--color-border);
}

/* ===== Responsive ===== */
@media (max-width: 480px) {
  :root {
    --board-size: calc(100vw - 24px);
    --page-gutter: 12px;
    --grid-gutter: 16px;
  }

  #app {
    padding: 0 var(--page-gutter);
  }

  .header__title {
    font-size: 1.25rem;
  }

  .difficulty-selector {
    gap: 2px;
    padding: 3px;
  }

  .game-stats {
    gap: 24px;
  }

  .tool-btn {
    padding: 8px 12px;
  }

  /* The number pad is normally one row of nine, sized to the board columns so the digits
     line up under them. On a phone that alignment costs more than it is worth: it made the
     most-tapped control in the game 35px, well under the 44px floor Apple and Google both
     publish, and mis-taps in a sudoku are expensive because a wrong digit is a mistake
     against your three. Two rows of five instead, which is the shape /reshit/ already uses
     and measured at 49px. */
  .controls__numbers {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
    /* width is load-bearing: .controls is a flex container, so without it this grid is a
       shrink-to-fit flex item, the 1fr tracks resolve against 130px, and the buttons come
       out 20px. That is worse than the 35px this block exists to fix, and it looks fine
       in a screenshot until you measure it. */
    width: 100%;
    max-width: var(--board-size);
    margin: 0 auto;
    justify-content: stretch;
  }

  .num-btn {
    width: auto;
    max-width: none;
    aspect-ratio: auto;
    min-height: 48px;
    font-size: 1.25rem;
    border-radius: var(--radius-md);
  }

  /* Was 25px. A segmented control is still a tap target. */
  .difficulty-btn {
    padding: 11px 10px;
    font-size: 0.75rem;
    min-height: 44px;
  }

  .game-bar {
    flex-direction: column;
    align-items: stretch;
  }

  .game-bar .btn--primary {
    align-self: center;
  }
}

@media (max-width: 360px) {
  .difficulty-btn {
    padding: 4px 7px;
    font-size: 0.7rem;
  }

  .controls__tools {
    gap: 4px;
  }

  .tool-btn {
    padding: 6px 8px;
    font-size: 0.65rem;
  }

  .tool-btn span:not(.hint-count) {
    display: none;
  }
}

/* ===== Leaderboard ===== */
.lb-tabs {
  display: flex;
  gap: 4px;
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  padding: 4px;
  margin-bottom: 16px;
}

.lb-tab {
  flex: 1;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: 0.775rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  transition: all var(--transition);
  text-align: center;
}

.lb-tab:hover {
  color: var(--color-text);
}

.lb-tab.active {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 2px 8px var(--color-primary-glow);
}

.lb-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 160px;
}

.lb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 160px;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.lb-row {
  display: grid;
  grid-template-columns: 28px 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
}

.lb-row--gold { border-color: #f59e0b; background: rgba(245, 158, 11, 0.06); }
.lb-row--silver { border-color: #9ca3af; background: rgba(156, 163, 175, 0.06); }
.lb-row--bronze { border-color: #cd7f32; background: rgba(205, 127, 50, 0.06); }

.lb-rank {
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 700;
  text-align: center;
  color: var(--color-text-muted);
}

.lb-row--gold .lb-rank { color: #f59e0b; }
.lb-row--silver .lb-rank { color: #9ca3af; }
.lb-row--bronze .lb-rank { color: #cd7f32; }

.lb-date {
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.lb-score {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--color-primary);
  text-align: right;
}

.lb-meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.lb-time {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-text);
}

.lb-mistakes {
  font-size: 0.7rem;
  color: var(--color-text-muted);
}

/* ===== Overlay actions ===== */
.overlay-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

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

.board {
  animation: fadeIn 0.4s ease;
}

/* ===== Accessibility ===== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* ===== Gamification: daily challenge, streak, worldwide leaderboard ===== */
.streak-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 700;
  font-size: 0.85rem;
  color: #e8590c;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 4px 10px;
  box-shadow: var(--shadow-sm);
}

.game-bar__actions { display: flex; gap: 8px; align-items: center; }

.btn--daily { white-space: nowrap; }

/* Duel entry point. Rose rather than indigo so the growth surface reads as its own
   thing next to the daily, and matches the opponent colour used on the duel board. */
.btn--duel {
  white-space: nowrap;
  color: var(--color-duel-opponent);
  font-weight: 700;
}
.btn--duel:hover {
  background: var(--color-duel-opponent-bg);
  color: var(--color-duel-opponent);
}
.btn--daily.active {
  background: var(--color-primary-light);
  color: var(--color-primary);
  border-color: var(--color-primary);
}

.overlay-daily {
  margin-top: 12px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-primary);
}

.lb-controls { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.seg {
  display: inline-flex;
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  padding: 3px;
  gap: 2px;
  flex: 1;
}
.seg button {
  flex: 1;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.78rem;
  color: var(--color-text-secondary);
  transition: all var(--transition);
}
.seg button.active {
  background: var(--color-surface);
  color: var(--color-primary);
  box-shadow: var(--shadow-sm);
}

.lb-me {
  background: var(--color-primary-light);
  color: var(--color-primary);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font-weight: 700;
  font-size: 0.85rem;
  text-align: center;
  margin-bottom: 6px;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(20px);
  background: var(--color-text);
  color: var(--color-bg);
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition), transform var(--transition);
  z-index: 100;
}
.toast.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ===== Duel (duel.html) ===== */
.duel-main {
  max-width: 560px;
  margin: 0 auto;
  padding: 0 16px 40px;
}

/* --- Head-to-head HUD --- */
.duel-lead {
  text-align: center;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--color-text-secondary);
  min-height: 20px;
  margin-bottom: 8px;
}
.duel-lead__delta { color: var(--color-duel-opponent); }
.duel-lead--ahead .duel-lead__delta { color: var(--color-duel-you); }

.duel-hud {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.duel-vs {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  letter-spacing: 0.05em;
}

.duel-player {
  background: var(--color-surface);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 9px 11px;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--transition), opacity var(--transition);
  min-width: 0;
}
.duel-player--me { border-color: var(--color-duel-you); }
.duel-player--them { border-color: var(--color-duel-opponent); }
.duel-player--offline { opacity: 0.5; }
.duel-player--empty { border-style: dashed; }

.duel-player__top {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 7px;
}

.duel-player__avatar {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.65rem;
  font-weight: 800;
  color: #fff;
  background: var(--color-duel-you);
}
.duel-player--them .duel-player__avatar { background: var(--color-duel-opponent); }

.duel-player__name {
  font-weight: 700;
  font-size: 0.85rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
  min-width: 0;
}

.duel-player__count {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  flex: none;
}

.duel-bar {
  height: 6px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  overflow: hidden;
}
.duel-bar__fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--color-duel-you);
  transition: width 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.duel-player--them .duel-bar__fill { background: var(--color-duel-opponent); }

/* --- Legend: the board's colour key --- */
.duel-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 14px;
  margin-bottom: 10px;
  font-size: 0.72rem;
  color: var(--color-text-secondary);
}
.duel-legend__item { display: inline-flex; align-items: center; gap: 5px; }
.duel-legend__swatch {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  border: 1.5px solid var(--color-border-thick);
  background: var(--color-surface-alt);
}
.duel-legend__swatch--mine {
  background: var(--color-duel-you-bg);
  border-color: var(--color-duel-you);
}
.duel-legend__swatch--theirs {
  background: var(--color-duel-opponent-bg);
  border-color: var(--color-duel-opponent);
}
.duel-legend__swatch--both {
  background: var(--color-duel-both-bg);
  border-color: var(--color-duel-you);
  box-shadow: inset 0 0 0 1.5px var(--color-duel-opponent);
}

/* --- Board cell states --- */
/* You closed it: your digit, your colour. */
.cell--duel-mine {
  background: var(--color-duel-you-bg) !important;
  color: var(--color-duel-you);
  font-weight: 700;
}
/* They closed it: their colour, and deliberately NO digit — the whole point of the
   mechanic is that you see where they are, never what they wrote. */
.cell--duel-theirs {
  background: var(--color-duel-opponent-bg) !important;
  box-shadow: inset 0 0 0 1.5px var(--color-duel-opponent);
}
/* Both of you got there. Your digit stays visible; their ring stays on. */
.cell--duel-both {
  background: var(--color-duel-both-bg) !important;
  box-shadow: inset 0 0 0 1.5px var(--color-duel-opponent);
  color: var(--color-duel-you);
  font-weight: 700;
}
.cell--duel-theirs::after {
  content: '';
  position: absolute;
  top: 3px;
  right: 3px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--color-duel-opponent);
}

/* Input lockout after a wrong digit — the anti-brute-force penalty, made visible. */
.duel-board-wrap { position: relative; }
.duel-board-wrap--locked .board { filter: saturate(0.5); }
.duel-board-wrap--locked .cell { cursor: not-allowed; }

.duel-toast {
  margin: 10px auto 0;
  max-width: 100%;
  text-align: center;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-duel-opponent);
  background: var(--color-duel-opponent-bg);
  border: 1px solid var(--color-duel-opponent);
  border-radius: var(--radius-md);
  padding: 7px 12px;
  opacity: 0;
  transition: opacity var(--transition);
}
.duel-toast.visible { opacity: 1; }
.duel-toast--warn {
  color: var(--color-warning);
  background: rgba(245, 158, 11, 0.12);
  border-color: var(--color-warning);
}

.duel-meta {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin: 10px 0 4px;
  font-size: 0.78rem;
  color: var(--color-text-secondary);
}
.duel-meta__value {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--color-text);
}

/* --- Panels: lobby, join, countdown, result --- */
.duel-panel {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  text-align: center;
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-radius: var(--radius-lg);
  z-index: 10;
}
.duel-panel.visible { display: flex; }
.duel-panel__inner { width: 100%; max-width: 340px; }

.duel-panel__icon { font-size: 2.2rem; margin-bottom: 8px; }
.duel-panel__title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
  margin-bottom: 8px;
}
.duel-panel__text {
  font-size: 0.86rem;
  color: var(--color-text-secondary);
  margin-bottom: 16px;
  line-height: 1.5;
}
.duel-panel__actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: stretch;
}

.duel-link {
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}
.duel-link__input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-body);
  font-size: 0.78rem;
  padding: 9px 11px;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}

.duel-share {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-bottom: 14px;
}
/* Ghost buttons read as plain text here, and these two are the whole growth loop —
   they need to look pressable. */
.duel-share .btn {
  flex: 1;
  padding: 9px 12px;
  border: 1.5px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
}
.duel-share .btn:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
  background: var(--color-surface);
}

.duel-waiting {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-text-secondary);
}
.duel-waiting::before {
  content: '';
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--color-border-thick);
  border-top-color: var(--color-primary);
  animation: duelSpin 0.8s linear infinite;
}
@keyframes duelSpin { to { transform: rotate(360deg); } }

.duel-count {
  font-family: var(--font-display);
  font-size: 4.5rem;
  font-weight: 800;
  line-height: 1;
  color: var(--color-primary);
  animation: duelCount 1s ease;
}
@keyframes duelCount {
  0% { transform: scale(0.6); opacity: 0; }
  40% { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

.duel-result__stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 16px;
}
.duel-result__card {
  background: var(--color-surface);
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 10px 8px;
}
.duel-result__card--win { border-color: var(--color-success); }
.duel-result__name {
  font-weight: 700;
  font-size: 0.8rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 4px;
}
.duel-result__time {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
}
.duel-result__sub {
  font-size: 0.7rem;
  color: var(--color-text-secondary);
  margin-top: 2px;
}

.duel-status {
  text-align: center;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-warning);
  min-height: 18px;
  margin-top: 8px;
}

.duel-diff {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  padding: 3px;
}
.duel-diff button {
  flex: 1;
  padding: 7px 4px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.75rem;
  color: var(--color-text-secondary);
  transition: all var(--transition);
}
.duel-diff button.active {
  background: var(--color-surface);
  color: var(--color-primary);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 480px) {
  .duel-main { padding: 0 10px 32px; }
  .duel-hud { gap: 6px; }
  .duel-player { padding: 7px 9px; }
  .duel-player__name { font-size: 0.78rem; }
  .duel-vs { font-size: 0.65rem; }
  .duel-legend { font-size: 0.66rem; gap: 3px 10px; }
  .duel-count { font-size: 3.4rem; }
}

@media (max-width: 360px) {
  .duel-player__count { display: none; }
  .duel-share { flex-wrap: wrap; }
}

/* ===== v2 layout: game column + rail ===== */
/* Only the game page widens to the v2 wrap; .col-game keeps the old 560px
   column so every board metric below (--cell-size, overlays, numpad) is
   untouched. The landing pages (/legkie/, /slozhnye/, /pravila/) share this
   stylesheet and #app, and must stay a single narrow reading column. */
#app.app--wide {
  max-width: calc(var(--container-wide) + 2 * var(--page-gutter));
}

.layout {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr));
  gap: var(--grid-gutter);
  align-items: start;
}

.col-game {
  grid-column: span 8;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  min-width: 0;
}

.rail {
  grid-column: span 4;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.rail-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
}

.rail-card__title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  margin-bottom: 12px;
}

.rail-card__more {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-primary);
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  transition: background var(--transition);
}

.rail-card__more:hover {
  background: var(--color-primary-light);
}

.rail-card__sub {
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

/* rail leaderboard */
.rail-lb__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.875rem;
}

.rail-lb__row:last-child {
  border-bottom: none;
}

.rail-lb__rank {
  width: 22px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
}

.rail-lb__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rail-lb__time {
  font-variant-numeric: tabular-nums;
  color: var(--color-text-secondary);
  font-size: 0.8125rem;
}

.rail-lb__row--me {
  background: var(--color-primary-light);
  border-bottom: none;
  border-radius: var(--radius-md);
  margin: 4px -10px 0;
  padding: 8px 10px;
}

.rail-lb__row--me .rail-lb__rank,
.rail-lb__row--me .rail-lb__name {
  color: var(--color-primary);
  font-weight: 600;
}

.rail-lb__note {
  font-size: 0.75rem;
  color: var(--color-text-secondary);
  text-align: center;
  margin-top: 10px;
}

.rail-lb__empty {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  text-align: center;
  padding: 14px 0;
}

/* level + streak */
.xp-bar {
  height: 9px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  overflow: hidden;
  margin: 8px 0;
}

.xp-bar__fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--color-primary), var(--color-accent));
  border-radius: 999px;
  transition: width var(--transition);
}

.streak-days {
  display: flex;
  gap: 5px;
  margin-top: 10px;
}

.streak-days__day {
  flex: 1;
  aspect-ratio: 1;
  border-radius: 8px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  display: grid;
  place-items: center;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.streak-days__day--on {
  background: color-mix(in srgb, var(--color-warning) 18%, transparent);
  border-color: color-mix(in srgb, var(--color-warning) 40%, transparent);
}

/* header level chip (streak-chip sibling) */
.level-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8125rem;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--color-primary-light);
  color: var(--color-primary);
  white-space: nowrap;
}

/* daily hero card */
.daily-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  margin-bottom: 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: linear-gradient(135deg, var(--color-primary-light), transparent);
}

.daily-card__icon {
  font-size: 1.375rem;
  line-height: 1;
}

.daily-card__body {
  flex: 1;
  min-width: 0;
}

.daily-card__title {
  display: block;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
}

.daily-card__sub {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

.daily-card .btn--sm {
  padding: 7px 12px;
  font-size: 0.8125rem;
  white-space: nowrap;
}

body.is-daily .daily-card {
  border-color: var(--color-primary);
}

/* growth strip */
.growth {
  padding: var(--space-6) 0 var(--space-1);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-6);
}

.growth__title {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: var(--space-4);
}

.growth__tiles {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--grid-gutter);
}

.growth-tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition), transform var(--transition);
}

.growth-tile:hover {
  border-color: var(--color-primary);
  transform: translateY(-2px);
}

.growth-tile__ic {
  font-size: 1.375rem;
  margin-bottom: 4px;
}

.growth-tile b {
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
}

.growth-tile span:not(.growth-tile__ic) {
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  line-height: 1.45;
}

/* the SEO prose was written for a 560px column — keep it readable at 1180px */
.seo-content,
.footer {
  max-width: var(--container-content);
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 1000px) {
  .layout {
    grid-template-columns: 1fr;
  }
  .col-game,
  .rail {
    grid-column: 1;
  }
  .rail {
    width: 100%;
    max-width: 560px;
    margin: 0 auto;
  }
  .growth__tiles {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .level-chip {
    display: none;
  }
  .daily-card {
    flex-wrap: wrap;
  }
  .daily-card .btn--sm {
    width: 100%;
    justify-content: center;
  }
}

@media (max-width: 460px) {
  .growth__tiles {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  /* .header__actions had no rule of its own, so its seven inline-flex children simply
     wrapped: measured at 390px they occupied FIVE rows and made the header 107px tall,
     a quarter of a phone screen spent before the game begins. Flex keeps them on one row.

     Tap targets go to 44px, the floor Apple and Google both publish. An earlier attempt
     bought the room for that by hiding the language button, which was wrong: this class is
     shared with duel.html and /obuchenie/, and on the duel page the button re-renders the
     page in place mid-duel and has no footer alternative. Nothing is hidden here; the
     header just stops being a block container. */
  .header {
    padding: 10px 0;
  }

  .header__actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 2px;
    flex-wrap: nowrap;
  }

  .header__actions .btn,
  .header__actions .btn--lang {
    /* .btn--lang carries its own min-width: 36px, and naming it here rather than relying
       on specificity is the difference between 36px and 44px in practice. */
    min-width: 44px;
    min-height: 44px;
    padding: 8px;
  }

  /* Same treatment the duel button already gets at 620px: keep the mark, drop the word. */
  .btn--rules .btn__label {
    display: none;
  }

  /* Every pixel above the board is a pixel of game the player has to scroll to find. */
  .game-stats {
    margin-bottom: 10px;
  }
}

/* ===== Duel promotion: header CTA + rail card ===== */
/* Duel is the differentiator, so it gets a permanent header slot instead of
   competing with «Новая игра» for room in the game bar. */
.btn--duel-header {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.8125rem;
  white-space: nowrap;
  text-decoration: none;
  color: #fff;
  background: linear-gradient(135deg, var(--color-duel-opponent), var(--color-primary));
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition);
}

.btn--duel-header:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
  color: #fff;
}

.rail-duel {
  display: block;
  text-decoration: none;
  color: inherit;
  background: linear-gradient(150deg,
      color-mix(in srgb, var(--color-duel-opponent) 12%, var(--color-surface)),
      var(--color-surface));
  border-color: color-mix(in srgb, var(--color-duel-opponent) 35%, var(--color-border));
  transition: border-color var(--transition), transform var(--transition);
}

.rail-duel:hover {
  border-color: var(--color-duel-opponent);
  transform: translateY(-2px);
}

.rail-duel__ic {
  display: block;
  color: var(--color-duel-opponent);
}

.rail-duel__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  margin: 6px 0 4px;
}

.rail-duel__text {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  line-height: 1.45;
}

.rail-duel__cta {
  display: inline-block;
  margin-top: 12px;
  padding: 8px 14px;
  border-radius: var(--radius-md);
  background: var(--color-duel-opponent);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 600;
}

@media (max-width: 620px) {
  /* Header runs out of room before the game bar does: drop the label, keep the mark. */
  .btn--duel-header .btn__label {
    display: none;
  }
  .btn--duel-header {
    padding: 7px 9px;
  }
}

/* ===== Duel: cells-left readout ===== */
.duel-player__left {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

.duel-player__leftlabel {
  margin-left: 4px;
  font-family: var(--font-body);
  font-size: 0.68rem;
  font-weight: 500;
  color: var(--color-text-muted);
  text-transform: lowercase;
}

/* Opponent closing in: amber, then red. Your own run at the same distance is
   green, so a glance never confuses "about to win" with "about to lose". */
.duel-player--warn {
  border-color: var(--color-warning);
}

.duel-player--warn .duel-player__left {
  color: var(--color-warning);
}

.duel-player--danger {
  border-color: var(--color-error);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 18%, transparent);
}

.duel-player--danger .duel-player__left {
  color: var(--color-error);
  animation: duel-left-pulse 1s ease-in-out infinite;
}

.duel-player--danger .duel-bar__fill {
  background: var(--color-error);
}

.duel-player--almost {
  border-color: var(--color-success);
}

.duel-player--almost .duel-player__left {
  color: var(--color-success);
}

@keyframes duel-left-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.65; transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
  .duel-player--danger .duel-player__left { animation: none; }
}

/* ===== Game feel (shared by the board on both pages) =====
   Your side and the opponent's side must never read the same way. Yours pops in
   the indigo-violet the rest of the site is built from; theirs washes in rose
   without moving, so it registers as a threat rather than as your own reward.
   No sound: duels are played in the same quiet places as everything else. */

:root {
  --fx-violet: #7c3aed;
  --fx-indigo: #4f46e5;
}

[data-theme="dark"] {
  --fx-violet: #a78bfa;
  --fx-indigo: #818cf8;
}

/* your digit lands */
.cell--pop {
  animation: fxPop 0.34s cubic-bezier(0.2, 1.4, 0.4, 1);
}

@keyframes fxPop {
  0% { transform: scale(0.5); opacity: 0.3; }
  60% { transform: scale(1.16); }
  100% { transform: scale(1); }
}

/* the opponent closes a cell: colour only, no movement */
.cell--duel-theirs-in {
  animation: duelTheirsIn 0.5s ease;
}

@keyframes duelTheirsIn {
  0% { background: var(--color-duel-opponent); }
  100% { background: var(--color-duel-opponent-bg); }
}

/* a wrong digit */
.cell--shake {
  animation: fxShake 0.38s ease;
}

@keyframes fxShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-5px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(3px); }
}

/* a row, column or box you completed rolls through */
.cell--sweep {
  animation: fxSweep 0.62s ease both;
}

@keyframes fxSweep {
  0% { background: transparent; }
  35% { background: var(--fx-violet); color: #fff; transform: scale(1.1); }
  100% { background: transparent; transform: scale(1); }
}

/* the win */
.cell--win {
  animation: fxWin 0.9s ease both;
}

@keyframes fxWin {
  0% { transform: scale(1); }
  30% { transform: scale(1.14); background: var(--fx-indigo); color: #fff; }
  100% { transform: scale(1); }
}

.fx-confetti {
  position: absolute;
  top: 0;
  left: 0;
  width: 9px;
  height: 13px;
  border-radius: 2px;
  z-index: 6;
  pointer-events: none;
  animation: fxFall 1.6s ease-in forwards;
}

@keyframes fxFall {
  0% { opacity: 1; transform: translateY(-10px) rotate(0); }
  100% { opacity: 0; transform: translateY(460px) rotate(540deg); }
}

/* combo: a flourish for a run of correct digits. A duel has no score, so this
   is feel only and never touches the result. */
.fx-combo {
  min-height: 20px;
  margin: 2px 0 6px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--fx-violet);
  opacity: 0;
  transition: opacity var(--transition);
}

.fx-combo--on {
  opacity: 1;
  animation: fxComboIn 0.3s ease;
}

@keyframes fxComboIn {
  0% { transform: scale(0.8); }
  55% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .cell--pop,
  .cell--duel-theirs-in,
  .cell--shake,
  .cell--sweep,
  .cell--win,
  .fx-confetti,
  .fx-combo--on {
    animation: none;
  }
}

/* ===== Путь: the learning campaign at /obuchenie/ ===== */
.path-main {
  max-width: var(--container-content);
  margin: 0 auto;
  width: 100%;
}

.path-title {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.25;
  margin-bottom: var(--space-2);
}

.path-lead {
  color: var(--color-text-secondary);
  font-size: 0.9375rem;
  margin-bottom: var(--space-5);
}

.path-progress {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  flex-wrap: wrap;
}

.path-progress__bar {
  flex: 1;
  min-width: 140px;
  height: 8px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  overflow: hidden;
}

.path-progress__fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--fx-indigo), var(--fx-violet));
  transition: width var(--transition);
}

.path-progress__label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.path-reset {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  padding: 4px 8px;
  border-radius: var(--radius-sm);
}

.path-reset:hover {
  color: var(--color-text);
  background: var(--color-surface-alt);
}

/* the map */
.path-stages {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: 0;
  margin: 0 0 var(--space-6);
}

.path-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color var(--transition), transform var(--transition);
}

.path-card:hover {
  border-color: var(--color-primary);
  transform: translateY(-2px);
}

/* Nothing is locked any more; the suggested next step just gets a quiet nudge. */
.path-card--suggested {
  border-color: var(--color-primary);
}

.path-card--suggested .path-card__action {
  color: var(--color-primary);
}

.path-card--done {
  border-color: color-mix(in srgb, var(--fx-violet) 45%, var(--color-border));
}

.path-card__num {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9375rem;
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.path-card--done .path-card__num {
  background: var(--fx-violet);
  color: #fff;
}

.path-card__body {
  flex: 1;
  min-width: 0;
}

.path-card__name {
  display: block;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
}

.path-card__short {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  line-height: 1.45;
}

.path-card__action {
  flex: none;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-primary);
  white-space: nowrap;
}


/* a stage */
.path-back {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-primary);
  padding: 6px 0;
  margin-bottom: 6px;
}

.path-stage__title {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 700;
  margin-bottom: 10px;
}

.path-teach {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--fx-violet);
  border-radius: var(--radius-lg);
  padding: 16px 18px;
  margin-bottom: 20px;
}

.path-teach p {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--color-text-secondary);
}

.path-teach p + p {
  margin-top: 10px;
}

.path-teach strong {
  color: var(--color-text);
}

.path-play__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.path-remaining {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-secondary);
}

.path-hint {
  min-height: 20px;
  margin: 8px 0 12px;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

@media (max-width: 480px) {
  .path-title { font-size: 1.3rem; }
  .path-card { padding: 12px; gap: 10px; }
  .path-teach { padding: 14px; }
}

/* ===== Explainable hints =====
   Two strengths on purpose: the unit is the area to think about, the focus cells are
   the pattern itself. A player should be able to act on the first without reading. */
.cell--hint-unit {
  background: color-mix(in srgb, var(--fx-indigo) 12%, transparent) !important;
}

.cell--hint-focus {
  background: color-mix(in srgb, var(--fx-violet) 28%, transparent) !important;
  box-shadow: inset 0 0 0 2px var(--fx-violet);
  animation: hintPulse 1.4s ease-in-out infinite;
}

@keyframes hintPulse {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--fx-violet); }
  50% { box-shadow: inset 0 0 0 3px var(--fx-violet); }
}

.hint-explain {
  margin: 8px auto 4px;
  max-width: var(--board-size, 468px);
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--fx-violet) 8%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--fx-violet) 30%, var(--color-border));
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--color-text);
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .cell--hint-focus { animation: none; }
}

/* ===== Technique pages (spokes off /obuchenie/) ===== */
.spoke-crumbs {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-bottom: 8px;
}

.spoke-crumbs a {
  color: var(--color-primary);
  text-decoration: none;
  font-weight: 600;
}

.spoke-article h3 {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  margin: 26px 0 10px;
}

.spoke-article p {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-text-secondary);
  margin-bottom: 10px;
}

.spoke-article strong,
.spoke-article em {
  color: var(--color-text);
}

.spoke-article a {
  color: var(--color-primary);
}

.spoke-list {
  margin: 0 0 12px 18px;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-text-secondary);
}

.spoke-list li {
  margin-bottom: 4px;
}

/* the read-only demo board */
.spoke-example {
  margin: 16px 0 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The board is a block-level grid with fixed columns, so on its own it stretches to the
   container and draws a border around empty space. The game page hides this by centring
   it in a flex row; do the same here. */
.board--example {
  width: max-content;
  max-width: 100%;
  cursor: default;
  pointer-events: none;
}

.board--example .cell {
  cursor: default;
}

.spoke-example__bar {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-top: 12px;
}

.spoke-example__text {
  min-height: 22px;
  margin-top: 10px;
  text-align: center;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--color-text);
}

/* a candidate ruled out by the technique */
.cell--hint-strike {
  position: relative;
  background: color-mix(in srgb, var(--color-error) 14%, transparent) !important;
}

.cell--hint-strike::after {
  content: '';
  position: absolute;
  inset: 22%;
  border-top: 2px solid var(--color-error);
  transform: rotate(-45deg);
}

.spoke-practice {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid var(--color-border);
}

.spoke-practice h3 {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  margin-bottom: 6px;
}

.spoke-nav {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 28px 0 8px;
  font-size: 0.875rem;
  font-weight: 600;
}

.spoke-nav a {
  color: var(--color-primary);
  text-decoration: none;
}

.spoke-nav a:hover {
  text-decoration: underline;
}

/* FAQ on the technique pages */
.spoke-faq__item {
  border-bottom: 1px solid var(--color-border);
  padding: 10px 0;
}

.spoke-faq__item summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--color-text);
  list-style: none;
}

.spoke-faq__item summary::-webkit-details-marker {
  display: none;
}

.spoke-faq__item summary::before {
  content: '+ ';
  color: var(--color-primary);
  font-weight: 700;
}

.spoke-faq__item[open] summary::before {
  content: '− ';
}

.spoke-faq__item p {
  margin: 8px 0 2px;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--color-text-secondary);
}

/* the hub cards are links now */
.path-card__link {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-decoration: none;
  color: inherit;
}

/* The rules button was a bare question mark, which reads as decoration rather than an
   offer. It carries its label on desktop and collapses to the icon where the header
   runs out of room, same rule as the duel pill. */
.btn--rules {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.btn--rules .btn__label {
  font-size: 0.8125rem;
  font-weight: 600;
}

@media (max-width: 760px) {
  .btn--rules .btn__label {
    display: none;
  }
}

/* Depth without a wall of text: the page reads short, the full argument is one click
   away, and every word is in the HTML for a crawler either way. */
.spoke-deep {
  margin: 14px 0;
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--fx-indigo);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: 12px 16px;
}

.spoke-deep summary {
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-text);
  list-style: none;
}

.spoke-deep summary::-webkit-details-marker {
  display: none;
}

.spoke-deep summary::after {
  content: ' ▾';
  color: var(--color-primary);
}

.spoke-deep[open] summary::after {
  content: ' ▴';
}

.spoke-deep p {
  margin-top: 10px;
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--color-text-secondary);
}

.spoke-example__count {
  display: block;
  margin-bottom: 8px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  text-align: center;
}

/* ===== "Найдите сами": the drill ===== */
.spoke-drill-section {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid var(--color-border);
}

.spoke-drill-section h3 {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  margin-bottom: 6px;
}

.spoke-drill {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 14px;
}

/* Unlike the worked example this board is meant to be clicked. */
.board--drill {
  width: max-content;
  max-width: 100%;
  cursor: pointer;
}

.spoke-drill__prompt {
  min-height: 22px;
  margin-top: 12px;
  text-align: center;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-text-secondary);
}

.spoke-drill__prompt--good {
  color: var(--fx-violet);
}

.spoke-drill__prompt--bad {
  color: var(--color-error);
}

.spoke-drill__pad {
  margin-top: 10px;
  width: min(var(--board-size, 468px), 100%);
}

.spoke-drill__bar {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-top: 12px;
}

/* ===== Задачи дня: the daily trainer ===== */
.trainer-intro,
.trainer-result {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: 22px;
  text-align: center;
  margin-bottom: 24px;
}

.trainer-intro__text {
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--color-text-secondary);
  margin-bottom: 16px;
}

.trainer-intro__note {
  margin-top: 12px;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.trainer-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}

.trainer-progress__bar {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  overflow: hidden;
}

.trainer-progress__fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--fx-indigo), var(--fx-violet));
  transition: width var(--transition);
}

.trainer-progress__label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.trainer-actions {
  display: flex;
  justify-content: center;
  margin-top: 14px;
}

.trainer-result__icon {
  font-size: 2.25rem;
}

.trainer-result__title {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  margin: 6px 0 10px;
}

.trainer-result__score {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--fx-violet);
}

.trainer-result__streak {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-text);
  margin-top: 4px;
}

/* The countdown is the point of the whole screen: it says come back. */
.trainer-result__countdown {
  margin-top: 10px;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--color-primary);
  font-variant-numeric: tabular-nums;
}

.trainer-result__text {
  margin-top: 10px;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.trainer-result__actions {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 16px;
}

.trainer-cost {
  margin-top: 6px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-warning);
}

.trainer-result__breakdown {
  margin-top: 6px;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
}

.trainer-result__best {
  margin-top: 4px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-muted);
}

.trainer-result__best--new {
  color: var(--fx-violet);
}

/* The trainer promo, same shape as the duel card but in the learning palette. */
.rail-trainer {
  display: block;
  text-decoration: none;
  color: inherit;
  background: linear-gradient(150deg,
      color-mix(in srgb, var(--fx-violet) 12%, var(--color-surface)),
      var(--color-surface));
  border-color: color-mix(in srgb, var(--fx-violet) 35%, var(--color-border));
  transition: border-color var(--transition), transform var(--transition);
}

.rail-trainer:hover {
  border-color: var(--fx-violet);
  transform: translateY(-2px);
}

.rail-trainer__ic {
  font-size: 1.5rem;
  line-height: 1;
}

.rail-trainer__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 600;
  margin: 6px 0 4px;
}

.rail-trainer__text {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  line-height: 1.45;
}

.rail-trainer__cta {
  display: inline-block;
  margin-top: 12px;
  padding: 8px 14px;
  border-radius: var(--radius-md);
  background: var(--fx-violet);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 600;
}

/* ===== Судоку для печати (/pechat/) =====
   The controls follow the theme like everything else. The sheets do not: a sheet is a
   preview of paper, and paper is white in both themes. Making it follow the dark theme
   would mean showing the reader something the printer will never produce. */

.print-controls {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: var(--shadow-sm);
  margin-bottom: 18px;
}

.print-control {
  margin-bottom: 16px;
}

.print-control__label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  margin-bottom: 8px;
}

.print-control .difficulty-selector {
  flex-wrap: wrap;
}

.print-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9375rem;
  cursor: pointer;
  margin-bottom: 18px;
}

.print-check input {
  width: 18px;
  height: 18px;
  accent-color: var(--color-primary);
  cursor: pointer;
}

.print-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.print-status {
  margin-top: 14px;
  font-size: 0.9375rem;
  color: var(--color-text-secondary);
  min-height: 1.4em;
}

.print-progress {
  margin-top: 10px;
  height: 6px;
  border-radius: 999px;
  background: var(--color-surface-alt);
  overflow: hidden;
}

.print-progress__fill {
  height: 100%;
  width: 0;
  background: var(--color-primary);
  border-radius: 999px;
  transition: width 0.25s ease;
}

.print-slow {
  margin-top: 10px;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  line-height: 1.45;
}

.print-tip {
  max-width: 780px;
  margin: 0 auto 18px;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  background: var(--color-primary-light);
  border-radius: var(--radius-md);
  padding: 12px 14px;
}

/* ===== The sheets ===== */

.print-preview {
  max-width: 780px;
  margin: 0 auto;
  padding: 0 16px 32px;
  width: 100%;
}

.sheet {
  background: #fff;
  color: #111;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 22px;
  margin-bottom: 20px;
}

.sheet__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 14px;
  font-size: 0.8125rem;
  color: #666;
}

.sheet__title {
  font-family: var(--font-display);
  font-weight: 600;
  color: #111;
}

.sheet__grids {
  display: grid;
  gap: 18px;
  justify-items: center;
}

.sheet--4 .sheet__grids,
.sheet--answers .sheet__grids {
  grid-template-columns: 1fr 1fr;
}

.pboard {
  width: 100%;
}

.pboard__label {
  font-size: 0.75rem;
  color: #666;
  margin-bottom: 5px;
}

/* One grid. Borders only, never a fill: most printers drop background colours unless the
   reader turns them on, and a grid whose 3x3 boxes are marked by shading would come out
   as an undivided 9x9. cqw keeps the digits proportional to the grid at any size, so the
   same rule serves the screen preview and every paper layout. */
.pgrid {
  /* Two line weights, two variables. They have to be variables: the print block below
     darkens the thin lines, and as a plain `.pcell { border-color }` override it also
     recoloured the 2px box separators, which have the same specificity and lose on order.
     The boxes came out grey, which on paper is most of what makes a grid readable. */
  --pline: #b0b0b0;
  --pbox: #111;
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  aspect-ratio: 1;
  width: 100%;
  border: 2px solid var(--pbox);
  container-type: inline-size;
}

.pcell {
  border-right: 1px solid var(--pline);
  border-bottom: 1px solid var(--pline);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 500;
  color: #111;
  font-size: 1rem;
  font-size: 5.6cqw;
  line-height: 1;
}

.pcell:nth-child(9n) { border-right: 0; }
.pcell:nth-child(n+73) { border-bottom: 0; }
.pcell--rt { border-right: 2px solid var(--pbox); }
.pcell--bt { border-bottom: 2px solid var(--pbox); }

.pgrid--small .pcell {
  font-weight: 400;
  font-size: 5.2cqw;
}

@media (max-width: 640px) {
  .sheet {
    padding: 14px;
  }
  .sheet--4 .sheet__grids,
  .sheet--answers .sheet__grids {
    grid-template-columns: 1fr;
  }
}

/* ===== Paper =====
   The screen preview above is responsive so it reads on a phone; here the same markup is
   pinned to real millimetres, because a printed cell has to be a size a person can write
   in. One card on screen is one page on paper, so what you scrolled through is what comes
   out of the printer. */
@media print {
  /* `portrait` rather than `A4`: naming a paper size makes the browser print that size
     whatever is in the tray, and the English page at /en/printable/ is read by people on
     US Letter. Letter is 6mm wider and 18mm shorter than A4, so the shorter one governs
     every height below. */
  @page {
    size: portrait;
    margin: 12mm;
  }

  html, body {
    background: #fff !important;
    color: #000;
  }

  /* Scoped to a class the page only gets once a sheet has been built. Unscoped, pressing
     Ctrl+P before pressing «Подготовить» hid the entire page and printed one blank sheet,
     which is a worse answer than printing the page as it stands. */
  body.print-ready .no-print,
  body.print-ready .header,
  body.print-ready .footer,
  body.print-ready #print-result {
    display: none !important;
  }

  .print-preview {
    max-width: none;
    padding: 0;
    margin: 0;
  }

  .sheet {
    box-shadow: none;
    border-radius: 0;
    padding: 0;
    margin: 0;
    break-after: page;
    page-break-after: always;
  }

  .sheet:last-child {
    break-after: auto;
    page-break-after: auto;
  }

  .sheet__head {
    margin-bottom: 6mm;
  }

  .sheet__grids {
    gap: 8mm;
  }

  .pboard {
    width: auto;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  /* Sized with headroom, not to the millimetre the page allows, and sized for the smaller
     of the two papers. Measured in a browser with these rules forced on: an answer sheet at
     78mm came to 279mm against the 273mm A4 leaves after margins, so its last row silently
     became an extra page, and the 2-per-page sheet landed on exactly 273.1mm. Fixing that
     for A4 still left only 4mm on US Letter, which has 255mm of height rather than 273.
     These now clear Letter by about 20mm. tests/print.test.mjs holds the numbers. */
  .sheet--1 .pgrid { width: 160mm; }
  .sheet--2 .pgrid { width: 102mm; }
  .sheet--4 .pgrid { width: 83mm; }
  .sheet--answers .pgrid { width: 63mm; }

  /* Pale grey survives on some printers and vanishes on others, so the thin lines go
     darker. The box separators stay black: that contrast is the whole grid. */
  .pgrid {
    --pline: #777;
  }
}

/* ===== Решить судоку (/reshit/) ===== */

.solver-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 24px;
  align-items: start;
  margin-bottom: 28px;
}

/* `--board-size` is defined against the viewport (`min(480px, 100vw - 32px)`), which is
   right for the game, where the board owns the page. Here it sits in a grid column beside
   a 300px panel, so the viewport says nothing useful and the board overflowed its column
   and was clipped on the right. Rebasing it on the column keeps every derived metric,
   including `--cell-size`, correct. */
.solver-board {
  min-width: 0;
  --board-size: min(480px, 100%);
}

.solver-board .board {
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(9, 1fr);
  width: var(--board-size);
  aspect-ratio: 1;
  margin: 0 auto;
}

.solver-pad {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  margin-top: 14px;
}

.solver-pad button {
  padding: 12px 0;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--color-text);
  transition: all var(--transition);
}

.solver-pad button:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.solver-pad__erase {
  font-size: 1rem !important;
  color: var(--color-text-secondary) !important;
}

.solver-status {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-border-thick);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--color-text-secondary);
  margin-bottom: 16px;
  min-height: 3.4em;
}

.solver-status--good { border-left-color: var(--color-success); color: var(--color-text); }
.solver-status--warn { border-left-color: var(--color-warning); color: var(--color-text); }
.solver-status--bad { border-left-color: var(--color-error); color: var(--color-text); }

.solver-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.solver-actions .btn {
  width: 100%;
}

.solver-actions .btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.solver-chain {
  margin-top: 20px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
}

.solver-chain__title {
  display: block;
  font-size: 0.875rem;
  margin-bottom: 10px;
}

.solver-chain__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.solver-chain__list li {
  display: flex;
  justify-content: space-between;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}

.solver-chain__list b {
  color: var(--color-text);
  font-weight: 500;
}

@media (max-width: 900px) {
  .solver-layout {
    grid-template-columns: 1fr;
  }
  .solver-actions {
    flex-direction: row;
    flex-wrap: wrap;
  }
  .solver-actions .btn {
    width: auto;
    flex: 1 1 140px;
  }
}
