/* ==========================================================================
   Шерлок — современная логическая игра
   Тёмная тема по умолчанию. Картинки-варианты лежат на серых подложках —
   как серые клетки в оригинале; утверждённая картинка и условия цветные.
   ========================================================================== */

:root {
  --bg: #0d1117;
  --bg-2: #141b23;
  --bg-3: #1b232d;
  --line: #263040;
  --line-2: #33405a;
  --fg: #e8eef6;
  --fg-dim: #9fb0c4;
  --fg-mute: #6d7d92;
  --accent: #d8a24a;
  --accent-2: #f0c274;
  --ok: #4ec98a;
  --bad: #e4645c;
  --radius: 14px;
  --radius-sm: 10px;
  --shadow: 0 10px 30px rgba(0, 0, 0, .45);
  --board-bg: #121922;
  --board-line: var(--line);
  --board-fg: #e8eef6;
  --board-fg-dim: #6d7d92;
  --clue-bg: #1b232d;           /* карточка условия на подложке-блоке */
  --pat-line: rgba(126, 162, 224, .05);   /* узор фона между блоками */
  --pat-dot: rgba(216, 162, 74, .17);
  --pat-glow: rgba(216, 162, 74, .05);
  --cell-bg: rgba(255, 255, 255, .05);
  --cell-bg-2: rgba(255, 255, 255, .1);
  --cell-line: var(--line);
  --scrim: rgba(4, 7, 11, .66);
  --sat: 62%;
  --lum: 62%;
  --gap: 6px;
  --pic: 34px;                  /* размер картинки в условии */
  /* Ширина карточки условия — три картинки в ряд плюс поля. По ней считается
     ширина столбца условий на широком экране. */
  --card-w: calc(36px * 3.76 + 2px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

/* светлая тема: тот же тёмно-синий экран поля, но страница светлая */
[data-theme="light"] {
  --bg: #eef1f6;
  --bg-2: #ffffff;
  --bg-3: #e2e6ee;
  --line: #c6cedb;
  --line-2: #9aa6b8;
  --fg: #171b21;
  --fg-dim: #3d4753;
  --fg-mute: #5d6875;
  --accent: #96591a;
  --accent-2: #7a4610;
  --ok: #16794a;
  --bad: #b03028;
  --shadow: 0 10px 24px rgba(23, 27, 33, .18);
  --board-bg: #16204d;
  --board-line: #0e1638;
  --board-fg: #eef2fb;
  --board-fg-dim: #b3c0dd;
  --clue-bg: #e3e8f1;
  --pat-line: rgba(30, 42, 66, .08);
  --pat-dot: rgba(150, 89, 26, .2);
  --pat-glow: rgba(150, 89, 26, .05);
  --cell-bg: rgba(255, 255, 255, .07);
  --cell-bg-2: rgba(255, 255, 255, .14);
  --cell-line: rgba(255, 255, 255, .22);
  --scrim: rgba(30, 35, 42, .5);
  --sat: 58%;
  --lum: 40%;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background-color: var(--bg);
  /* фон между блоками — узор: диагональная решётка с золотыми точками
     в перекрестьях, как обои в кабинете на Бейкер-стрит */
  background-image:
    radial-gradient(circle at 50% 50%, var(--pat-dot) 0 1.3px, transparent 1.4px),
    repeating-linear-gradient(45deg, var(--pat-line) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(-45deg, var(--pat-line) 0 1px, transparent 1px 22px),
    radial-gradient(130% 80% at 50% 0%, var(--pat-glow), transparent 72%);
  background-size: 22px 22px, auto, auto, auto;
  background-repeat: repeat, repeat, repeat, no-repeat;
  color: var(--fg);
  font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}

body { overflow: hidden; }

/* атрибут hidden должен побеждать любые авторские display-правила */
[hidden] { display: none !important; }

svg { display: block; }

/* Картинка-плитка условия и клетки: тот же класс .card, что был у SVG,
   поэтому размеры задаются прежними правилами, а файл просто заполняет
   отведённый квадрат без искажений. */
img.card { display: block; object-fit: contain; -webkit-user-drag: none; }

/* Контурные значки интерфейса. Картинки-карточки (js/art.js) рисуются
   своими цветами и под это правило не попадают. */
.ui-icon, .ui-icon * {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

button { font: inherit; color: inherit; }
h2 { margin: 0; font-size: 1.05rem; }

/* ---------- каркас ---------- */

/* Каркас занимает всё окно. Потолка ширины нет: страницу увеличивает браузер,
   и при уменьшении масштаба окно становится шире в CSS-пикселях — игра должна
   расти вместе с ним, а не упираться в постоянные 1340 px (из-за них при 80 %
   всё оставалось прежнего размера). Высоту доски ограничивает fitBoard, так что
   на очень широком мониторе поле не выйдет за пределы экрана. */
.app {
  display: flex;
  flex-direction: column;
  height: 100%;
  margin: 0 auto;
  padding: 0 8px calc(8px + var(--safe-b));
}

.topbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px 4px;
}

.topbar-title { display: flex; flex-direction: column; line-height: 1.15; flex: 1; min-width: 0; }
.brand { font-weight: 700; letter-spacing: .32px; font-size: 1.04rem; }
.puzzle-no { color: var(--fg-mute); font-size: .76rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-right { display: flex; align-items: center; gap: 6px; }

.timer {
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 5px 9px;
  min-width: 68px;
  text-align: center;
  font-size: .95rem;
}
.timer.is-low { color: var(--bad); border-color: var(--bad); }
/* Пауза на время меню: часы приглушены, чтобы было видно, что время не идёт. */
.timer.is-paused { color: var(--fg-mute); border-style: dashed; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  border: 1px solid var(--line);
  background: var(--bg-2);
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  transition: background .16s, border-color .16s, transform .08s;
}
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn:active { transform: scale(.94); }
.icon-btn:hover { border-color: var(--line-2); }

.main { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 8px; }

.progress { height: 3px; background: var(--bg-3); border-radius: 3px; overflow: hidden; }
.progress > span {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width .25s ease;
}

/* ---------- вкладки ---------- */

.tabs {
  display: flex;
  gap: 4px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 3px;
}
.tab {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--fg-dim);
  padding: 7px 6px;
  border-radius: 9px;
  cursor: pointer;
  font-size: .85rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tab.is-active { background: var(--bg-3); color: var(--fg); font-weight: 600; }

.workspace {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
}

/* На телефоне список условий занимает не больше половины высоты,
   а доска получает остаток места и центрируется по вертикали.
   Активная вкладка всегда идёт первой — над доской. */
.panel {
  display: none;
  flex: 0 1 auto;
  max-height: 48%;
  min-height: 84px;
  flex-direction: column;
  gap: 8px;
  overflow: hidden;
  /* полоса условий — такой же блок, как доска: своя подложка, рамка и тень */
  padding: 8px;
  background: var(--board-bg);
  border: 1px solid var(--board-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.panel.is-active { display: flex; order: 1; }
.board-wrap { display: none; flex: 1 1 auto; min-height: 0; order: 2; }
/* переключатель режима стоит над доской, а не рядом с ней */
.board-wrap.is-active {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* На широком экране — доска слева во всю высоту, справа одним столбцом идут
   условия: сверху горизонтальные, под ними вертикальные. Раньше вертикальные
   занимали полосу во всю ширину внизу и отнимали у доски высоту; теперь они
   стоят в общем столбце, а доска получила освободившуюся высоту.
   Столбец условий прокручивается целиком: если условия не помещаются по
   высоте, уезжает весь столбец, и полосы никогда не наезжают друг на друга. */
@media (min-width: 980px) {
  .tabs { display: none; }
  .workspace {
    display: grid;
    /* Первый столбец — ровно по доске (её ширину считает скрипт и кладёт в
       --fit-w), второй забирает всё оставшееся место. Поэтому доска стоит у
       левого края, а не центрируется с пустой полосой справа, и условия
       получают всю свободную ширину: тогда они укладываются в меньшее число
       рядов и прокрутка не нужна. */
    grid-template-columns:
      minmax(0, var(--fit-w, 1fr))
      minmax(0, 1fr);
    /* Одна строка: доска и столбец условий стоят рядом и оба тянутся на всю
       высоту рабочей области. */
    grid-template-rows: minmax(0, 1fr);
    align-items: stretch;
    gap: 8px 12px;
    overflow: hidden;
  }
  .panel { display: flex; width: auto; flex: 0 0 auto; min-height: 0; max-height: none; }
  .panel-info { display: none; }
  /* вкладок на широком экране нет: «активная» панель порядка больше не задаёт */
  .panel.is-active { order: 0; }
  /* обёртка доски «растворяется»: поле становится частью сетки */
  .workspace .board-wrap,
  .workspace .board-wrap.is-active { display: contents; }
  /* Доска — вся высота рабочей области. */
  .board-scroll { grid-column: 1; grid-row: 1; justify-self: stretch; align-self: stretch; height: 100%; }
  /* Столбец условий: горизонтальные сверху, вертикальные под ними. */
  .clue-stack {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    /* Полосы прижаты к правому краю, поэтому свободное место остаётся между
       доской и условиями, а не справа от них. */
    align-items: flex-end;
  }
  /* Ширина полосы — ровно по целому числу карточек: её считает скрипт и кладёт
     в --clue-panel-w (горизонтальная полоса) и --clue-panel-w-v (вертикальная).
     Полосы прижаты к правому краю, поэтому пустого места справа не остаётся, а
     свободная ширина уходит в зазор между доской и условиями. */
  .clue-stack > .panel { flex: 0 0 auto; width: var(--clue-panel-w, 100%); max-width: 100%; }
  .clue-stack > .panel-vertical { width: var(--clue-panel-w-v, var(--clue-panel-w, 100%)); }
  /* Вертикальные условия идут тесной сеткой от левого края полосы. */
  .panel-vertical .clue-list { justify-content: flex-start; }
  /* Одинокие картинки — не отдельный блок, а те же элементы общего потока:
     иначе они вставали своей строкой и справа от них оставалась пустая полоса
     шириной в полпанели. С display: contents карточки одиноких картинок
     заворачиваются вместе с условиями и заполняют ширину целиком. */
  .panel-vertical .clue-singles { display: contents; }
  /* одинокие картинки стоят в той же строке, за тонкой чертой */
  .panel-vertical .clue-sep {
    flex: 0 0 1px;
    width: 1px;
    height: 24px;
    margin: 0 4px;
    align-self: center;
    background: var(--line);
  }
  /* Картинки условий на широком экране крупные — около половины крупной
     картинки на доске. Размер задаётся списку условий, чтобы образцы в
     правилах и легенде остались прежними. */
  .panel .clue-list { gap: 6px; }
}
/* ---------- увеличение: стандартными средствами браузера ---------- */

/* Своего масштаба у страницы нет: её увеличивает сам браузер, и все блоки
   растут вместе с ней. Раскладка поэтому не должна зависеть от постоянных в
   пикселях: при увеличении окно становится меньше в CSS-пикселях, и такие
   постоянные «съедали» поле — доска ужималась до нескольких сотен пикселей
   вместо того, чтобы расти вместе со всем остальным. Ширина доски считается
   от ширины её колонки, а не от высоты окна; если содержимое перестаёт
   помещаться по высоте, появляется вертикальная прокрутка (она и должна
   появляться), горизонтальной нет никогда. */

/* Размер картинки в условиях растёт вместе с окном: крупная картинка на доске
   занимает всю клетку, а в условии картинка должна быть примерно вдвое меньше
   её, иначе условия выглядят мелкими рядом с полем. Доля от ширины окна и
   потолок подобраны замером: на 1440 px это 66 px при клетке 130, на 1920 —
   78 px при клетке 169. Ширина карточки и столбца условий считаются от этого
   же размера, поэтому они всегда совпадают с настоящими карточками. */
@media (min-width: 980px) {
  :root {
    --pic-base: clamp(46px, 4.6vw, 78px);
    --card-w: calc(var(--pic-base) * 3.76 + 2px);
  }
}

/* Размер картинки в условиях — базовый размер ряда. Своего масштаба у игры
   нет: страницу увеличивает браузер, и условия растут вместе со всем. */
.panel .clue-list {
  --pic: var(--pic-base, 34px);
}

.panel-title { font-size: .8rem; text-transform: uppercase; letter-spacing: .6px; color: var(--fg-mute); display: flex; gap: 8px; align-items: baseline; }
.panel-hint { text-transform: none; letter-spacing: 0; font-size: .72rem; color: var(--fg-mute); opacity: .8; }

/* Условия идут в строчку, сколько поместится, и только потом переносятся на
   следующую строку. Карточка сжимается по размеру самой подсказки. */
.clue-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: flex-start;
  gap: 6px;
  padding-right: 2px;
  -webkit-overflow-scrolling: touch;
}

/* Все карточки условий одной ширины — по самой широкой, где три картинки в ряд
   (3 картинки + два промежутка между ними + поля карточки). Тогда ряд условий
   выстраивается ровной сеткой независимо от вида условия: у «левее» вместо
   средней картинки многоточие той же ширины, а вертикальные условия (две
   картинки в столбик) встают по центру такой же карточки.
   flex: 0 0 auto — карточка держит ровно свою ширину и не сжимается. Без этого
   флекс поджимал их, ширина получалась «плавающей», и подобрать ширину полосы
   под целое число карточек было невозможно: расчёт не сходился с тем, что
   реально рисовалось. */
.clue-list .clue {
  flex: 0 0 auto;
  width: calc(var(--pic) * 3.76 + 2px);
}

/* Карточка вертикального условия — по размеру самого условия, а не шириной в
   столбец доски. Две картинки в столбик занимают меньше места, чем карточка
   горизонтального условия, и растягивать их до чужой ширины незачем: в узком
   столбце условий такие карточки встают тесной сеткой. Одинокие картинки —
   такие же карточки, поэтому тоже по размеру содержимого.
   На телефоне (узкое окно) правило не действует: там своя раскладка. */
@media (min-width: 700px) {
  .panel-vertical .clue,
  .panel-vertical .clue-single { width: auto; }
  .panel-vertical .clue-list,
  .panel-vertical .clue-singles { gap: 6px; }
}

/* ---------- условия: только картинки, как в оригинале ---------- */

/* Карточка условия — только подложка-блок с картинками. Своей рамки у неё нет:
   картинки — готовые плитки со своей рамкой, и рамка карточки давала вид
   «картинка в картинке». Состояния показываются свечением по краю. */
.clue {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--pic) * .18) calc(var(--pic) * .2);
  background: var(--clue-bg);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color .16s, background .16s;
  position: relative;
}
.clue:hover { border-color: var(--line-2); }
.clue.is-done {
  border-color: color-mix(in srgb, var(--ok) 65%, transparent);
  background: color-mix(in srgb, var(--ok) 10%, var(--clue-bg));
}
.clue.is-lit { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.clue:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Условие, которое игрок разобрал и зачеркнул правой кнопкой мыши (на
   телефоне — удержанием). Пометка только визуальная: на проверку решения
   она не влияет. */
.clue.is-crossed { opacity: .5; border-style: dashed; }
.clue.is-crossed .clue-pics { filter: grayscale(.5); }
.clue.is-crossed::after {
  content: '';
  position: absolute;
  left: 4%;
  right: 4%;
  top: 50%;
  height: 2px;
  border-radius: 2px;
  background: var(--bad);
  transform: rotate(-4deg);
  pointer-events: none;
}
.clue.is-crossed.is-lit { opacity: .85; border-style: solid; }

/* одинокие картинки — компактной сеткой в конце блока вертикальных условий */
.clue-sep { flex: 1 0 100%; height: 1px; background: var(--line); margin: 4px 2px; }
.clue-singles { display: flex; flex-wrap: wrap; gap: 6px; }
.clue-single { padding: calc(var(--pic) * .12) calc(var(--pic) * .24); }
.clue-single .clue-pic { width: calc(var(--pic) * .76); height: calc(var(--pic) * .76 * 7 / 8); }

/* образец условия в правилах и в разделе «Обозначения» */
.legend-sample { flex: 0 0 auto; cursor: default; padding: 4px 8px; }
.legend-sample:hover { border-color: var(--line); }

/* Ряд картинок условия. Ширина — по содержимому, иначе стрелка «между»
   растянулась бы на всю строку абзаца в правилах. */
.clue-pics {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(var(--pic) * .18);
  width: fit-content;
  padding: 1px 0;
}
/* вертикальное условие: две картинки стоят в столбик */
.clue-pics.is-vert {
  flex-direction: column;
  gap: calc(var(--pic) * .09);
}
/* Плитка в условии — та же пропорция 8:7, что и на доске (картинки 256×224):
   по ширине --pic, высота на восьмую меньше. Иначе плитка вписывалась бы в
   квадрат и по краям оставались прозрачные полосы. */
.clue-pic {
  position: relative;
  z-index: 1;
  width: var(--pic);
  height: calc(var(--pic) * 7 / 8);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.clue-pic .card { width: 100%; height: 100%; }
.clue-pic.is-out { opacity: .55; }
.clue-pic.is-out::after {
  content: "";
  position: absolute;
  left: -2px; right: -2px;
  top: 50%;
  height: calc(var(--pic) * .074);
  border-radius: 2px;
  background: var(--bad);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .75);
  transform: rotate(-30deg);
}
/* многоточие вместо средней картинки: «левее, на сколько — неизвестно» */
.clue-pic.is-dots { gap: calc(var(--pic) * .09); }
.clue-pic.is-dots i {
  width: calc(var(--pic) * .15);
  height: calc(var(--pic) * .15);
  border-radius: 50%;
  background: var(--fg-dim);
}
/* Стрелка «между» — двойная, поверх верхних краёв трёх картинок, как в
   оригинале. Она нарисована поверх и не участвует в раскладке, поэтому ширина
   карточки от неё не зависит (см. общую ширину карточек ниже). */
.clue-link {
  position: absolute;
  left: calc(var(--pic) / 2);
  right: calc(var(--pic) / 2);
  top: calc(var(--pic) * -.1);
  height: 0;
  border-top: 2px solid var(--fg-dim);
  z-index: 2;
  pointer-events: none;
}
.clue-link::before, .clue-link::after {
  content: "";
  position: absolute;
  top: calc(var(--pic) * -.075);
  width: 0; height: 0;
  border-top: calc(var(--pic) * .075) solid transparent;
  border-bottom: calc(var(--pic) * .075) solid transparent;
}
.clue-link::before { left: 0; border-right: calc(var(--pic) * .12) solid var(--fg-dim); }
.clue-link::after { right: 0; border-left: calc(var(--pic) * .12) solid var(--fg-dim); }

/* ---------- доска: клетка со стопкой картинок ---------- */

/* Прокрутки вбок здесь нет и быть не должно: доска всегда уже своего места.
   overflow-x: hidden, а не auto — иначе под доской появлялась полоса прокрутки
   от пары «лишних» пикселей. min-width: 0 обязателен: иначе широкая доска
   растягивает всю страницу вместо этой области. */
.board-scroll {
  width: 100%;
  min-width: 0;
  max-width: min(680px, 100%);
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

/* На широком экране потолка ширины нет: доска занимает всю свою колонку, а
   размер клетки подбирает fitBoard — он и вписывает доску в место и по ширине,
   и по высоте. Потолок в пикселях только мешал: на большом мониторе вокруг
   доски оставалась пустая полоса. */
@media (min-width: 980px) {
  .board-scroll { max-width: 100%; }
}

/* Узкое и не очень высокое окно (планшет 1024×768): условия в полосах не
   помещаются — нужно больше строк, чем влезает в окно. Там полосы условий
   прокручиваются внутри себя (так же, как на телефоне). Высота списков тоже
   считается от высоты окна, без постоянных в пикселях: иначе при увеличении
   браузера от списков не оставалось бы ничего. */
@media (min-width: 980px) and (max-width: 1200px) and (max-height: 819px) {
  .panel .clue-list { max-height: 55vh; }
  .panel-vertical .clue-list { max-height: 22vh; }
}

/* Поле без подписей: 6×6. Промежутки между столбцами заметно больше, чем между
   строками, — так столбцы читаются как столбцы. (В клетке картинки квадратные,
   поэтому сверху и снизу остаётся немного места: зазор строк выходит примерно
   таким же, как зазор столбцов, но не больше.) */
/* Ширина поля: на телефоне — вписанная (--fit-w) с множителем масштаба, на
   широком экране — не шире отведённого места и не шире --fit-w, чтобы доска
   помещалась по высоте и прокрутки при 100 % не было. */
.board {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  column-gap: 16px;
  row-gap: 2px;
  padding: 8px;
  width: min(100%, var(--fit-w, 100%));
  margin: 0 auto;
  min-width: 0;
  background: var(--board-bg);
  border: 1px solid var(--board-line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  align-content: start;
}

/* клетка. Своей рамки и подложки у клетки нет: картинки — это готовые плитки
   со своей рамкой, и вторая рамка вокруг них давала вид «картинка в картинке».
   Клетка только держит размер и место; подсветка выбора рисуется тенью.

   Пропорция клетки — ровно пропорция плитки: все картинки нарисованы
   256×224, то есть 8:7. Тогда плитка заполняет клетку целиком, без полей
   сверху и снизу, и не приходится ничего вписывать с потерей размера. */
.cell {
  position: relative;
  aspect-ratio: 8 / 7;
  min-width: 0;
  min-height: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 9px;
  overflow: hidden;
}
/* шесть уменьшенных картинок внутри клетки */
.cell .minis {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 1px;
  width: 100%;
  height: 100%;
}
.mini {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  position: relative;
  border-radius: 4px;
  transition: transform .08s ease, background .14s;
}
/* у картинок нет своих размеров, поэтому проценты от клетки
   и явный минимум 0: иначе SVG диктует доске ширину 300 px */
.mini .card, .cell .big .card { min-width: 0; min-height: 0; }
.mini .card { width: 100%; height: 100%; }
.mini:active { transform: scale(.9); }
.mini.is-out { opacity: .35; filter: grayscale(.75); }
.mini.is-out::after {
  content: "";
  position: absolute;
  left: 6%; right: 6%;
  top: 50%;
  height: 2px;
  border-radius: 2px;
  background: var(--bad);
  transform: rotate(-28deg);
}
.mini.is-hint { background: color-mix(in srgb, var(--accent) 45%, transparent); }

/* большая поставленная картинка занимает всю клетку */
.cell .big {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 6px;
}
/* object-fit: contain — картинка вписывается по большей стороне и не
   растягивается: пропорции плитки сохраняются, свободное место по краям
   остаётся прозрачным. */
.cell .big .card { width: 100%; height: 100%; object-fit: contain; }
/* Состояния клетки. Подложки, рамки и обводки у клетки нет: плитка картинки
   уже со своей рамкой и занимает клетку целиком, поэтому любая вторая рамка
   давала вид «картинка в картинке». Открытая заранее клетка отмечена только
   золотой точкой в углу, а не обводкой. */
.cell.is-locked::after {
  content: "";
  position: absolute;
  right: 3px; top: 3px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
}
/* Подсветка — только на время действия: выбранное условие, подсказка, ошибка. */
.cell.is-lit { box-shadow: 0 0 0 2px var(--accent); }
.cell.is-dead { box-shadow: inset 0 0 0 2px var(--bad); }
.cell.is-hint { animation: pulse 1.1s ease-in-out 2; }

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent); }
  50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* на узком экране клетки мельче */
@media (max-width: 560px) {
  :root { --pic: 30px; }
  .panel .clue-list { --pic-base: 30px; }
  .board { grid-template-columns: repeat(6, minmax(34px, 1fr)); column-gap: 8px; row-gap: 2px; padding: 5px; }
  .cell { border-radius: 7px; padding: 1px; }
}
@media (max-width: 400px) {
  .board { grid-template-columns: repeat(6, minmax(32px, 1fr)); }
  :root { --pic: 28px; }
  .panel .clue-list { --pic-base: 28px; }
}

/* ---------- телефон: полоса условий прокручивается, поле стоит на месте ---- */

/* Полоса условий получает постоянную высоту. Раньше она сжималась по своему
   содержимому, и при переключении «Вертикальные»/«Горизонтальные» доска
   прыгала вверх-вниз. Теперь место под условия одно и то же, а условия,
   которым не хватило высоты, прокручиваются внутри полосы. */
@media (max-width: 979px) {
  .workspace { overflow: hidden; }
  .panel {
    flex: 0 0 auto;
    height: 25vh;
    height: clamp(144px, 25vh, 292px);
    max-height: none;
  }
  /* на вкладке «Задача» доски нет: список по-прежнему занимает всё место */
  body[data-tab="info"] .panel { height: auto; flex: 1 1 auto; }
  .board-wrap.is-active { flex: 1 1 auto; min-height: 0; }
  /* Место поля остаётся прежним, а само поле вписывается в него: --fit-w
     считает скрипт (js/ui.js, fitBoard) — это ширина, при которой доска
     целиком помещается и по ширине, и по высоте отведённого места. */
  .board-wrap .board-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; }
  .board {
    width: min(100%, var(--fit-w, 100%));
    margin: 0 auto;
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
  /* Палец на доске и на условиях не должен выделять текст и вызывать меню
     браузера: касание и удержание — это игровые действия. */
  .board, .clue-list {
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
  }
}

/* Короткий экран (небольшие телефоны): полосе условий и строке подсказки
   отдаём меньше высоты, чтобы полю осталось место, на котором клетки ещё
   можно нажимать пальцем. */
@media (max-width: 979px) and (max-height: 700px) {
  .panel { height: clamp(118px, 21vh, 240px); }
  .hintbar { height: 48px; }
}

/* ---------- телефон в альбоме: поле слева, условия справа ---------- */

/* В альбоме вертикально места мало, а по горизонтали много, поэтому раскладка
   меняется: поле стоит слева во всю высоту экрана (и шириной ровно по своим
   клеткам — её считает fitBoard в --board-col), а справа друг под другом идут
   вертикальные условия, горизонтальные, строка подсказки и кнопки. Вкладки
   здесь не нужны: обе полосы условий видны одновременно. */

/* ---------- сведения о задаче ---------- */

/* на вкладке «Задача» доски нет — список занимает всю высоту */
body[data-tab="info"] .panel { flex: 1 1 auto; max-height: none; }

.info-body { overflow-y: auto; font-size: .86rem; color: var(--fg-dim); display: flex; flex-direction: column; gap: 10px; }
.info-row { display: flex; justify-content: space-between; gap: 10px; border-bottom: 1px dashed var(--line); padding-bottom: 6px; }
.info-row b { color: var(--fg); font-weight: 600; }
.info-list { display: flex; flex-wrap: wrap; gap: 5px; }
.info-legend { display: flex; flex-direction: column; gap: 6px; }
.legend-row { display: flex; gap: 8px; align-items: flex-start; }
.legend-row .clue { flex: 0 0 auto; align-self: flex-start; }
.legend-row p { margin: 0; font-size: .8rem; }

/* ---------- строка подсказки ---------- */

/* Строка стоит в разметке всегда и занимает своё место: при нажатии
   «Подсказка» появляется и исчезает только текст, а раскладка не сдвигается.
   Высота фиксированная (две строки на широком экране, больше на узком),
   поэтому длинный текст прокручивается внутри строки, а не растягивает её. */
.hintbar {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 6px;
  padding: 4px 10px;
  height: 44px;
  box-sizing: border-box;
  background: var(--bg-2);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}
/* пустая строка: место занято, но ничего не нарисовано */
.hintbar.is-off {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
.hintbar.is-off > * { visibility: hidden; }
.hint-icon { line-height: 1.3; }
.hint-text {
  margin: 0;
  flex: 1;
  font-size: .82rem;
  line-height: 1.3;
  max-height: 100%;
  overflow-y: auto;
}
.hint-apply {
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--fg);
  border-radius: 9px;
  padding: 4px 9px;
  cursor: pointer;
  font-size: .8rem;
  white-space: nowrap;
}
.hint-close { width: 28px; height: 28px; font-size: 1.05rem; }

/* на узком экране строка выше: текст переносится на большее число строк */
@media (max-width: 979px) {
  .hintbar { height: 54px; }
}
@media (max-width: 560px) {
  .hintbar { height: 66px; }
}

/* ---------- нижняя панель ---------- */

.actionbar {
  display: flex;
  gap: 6px;
  padding: 6px 0 2px;
}
.act {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 8px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  cursor: pointer;
  font-size: .9rem;
  transition: transform .08s, border-color .16s;
}
.act svg { width: 19px; height: 19px; }
.act:active { transform: scale(.97); }
.act:disabled { opacity: .45; cursor: default; }
.act-primary { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--bg-2)); font-weight: 600; }

/* ---------- окна ---------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(78px + var(--safe-b));
  transform: translate(-50%, 8px);
  max-width: min(92vw, 420px);
  padding: 9px 14px;
  background: var(--bg-3);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  box-shadow: var(--shadow);
  font-size: .85rem;
  text-align: center;
  opacity: 0;
  transition: opacity .18s, transform .18s;
  pointer-events: none;
  z-index: 30;
}
.toast.is-open { opacity: 1; transform: translate(-50%, 0); }

.overlay {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 14px;
  background: var(--scrim);
  backdrop-filter: blur(3px);
  z-index: 20;
}
.overlay.is-open { display: flex; }
/* Подтверждение смены сложности показывается поверх меню, из которого его
   вызвали, поэтому у него отдельный, более высокий слой. */
#confirm { z-index: 25; }
.confirm-note { margin: 0; font-size: .9rem; line-height: 1.5; }
.overlay-card {
  width: min(460px, 100%);
  /* Меню подросло (номер, имя, время, подсказки, набор картинок, отметка), и
     на ноутбучных 768 px по высоте кнопки уезжали под низ. Потолок поднят до
     94vh, а отступы внутри уплотнены — теперь меню целиком видно без прокрутки
     даже на 1366×768. */
  max-height: min(94vh, 860px);
  display: flex;
  flex-direction: column;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.overlay-card.wide { width: min(620px, 100%); }
.overlay-card.small { width: min(260px, 100%); align-items: center; padding: 22px; gap: 12px; }
.card-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--line); }
.card-body { padding: 10px 14px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.card-foot { display: flex; justify-content: space-between; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--line); }
.version { color: var(--fg-mute); font-size: .74rem; align-self: center; }

.field { display: flex; flex-direction: column; gap: 5px; font-size: .86rem; color: var(--fg-dim); }
.field small.hint { font-size: .76rem; line-height: 1.3; color: var(--fg-dim); opacity: .85; }
.field-row { display: flex; gap: 6px; }
.field input, .field select {
  width: 100%;
  padding: 8px 10px;
  background: var(--bg-3);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--fg);
  font: inherit;
}
.field input[type="number"] { -moz-appearance: textfield; }
/* Ползунок громкости: строка «ползунок + число».
   Ползунок растягивается, число занимает фиксированную ширину — иначе при
   движении ползунка подпись «100 %» и «0 %» прыгала бы по ширине. */
.field-range .field-row { align-items: center; gap: 10px; }
.field-range input[type="range"] {
  width: auto;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0;
  background: transparent;
  border: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.range-value {
  flex: 0 0 auto;
  min-width: 52px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: .86rem;
  color: var(--fg-dim);
}
/* Ноль — это «без звука»: подпись меняется на «выкл», и она это показывает. */
.range-value.is-off { color: var(--fg-mute); }

.switch { display: flex; align-items: center; gap: 9px; font-size: .86rem; color: var(--fg-dim); }
.switch input { width: 18px; height: 18px; accent-color: var(--accent); }
.menu-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.menu-note { font-size: .78rem; color: var(--fg-mute); margin: 0; }

.btn {
  padding: 10px 12px;
  background: var(--bg-3);
  border: 1px solid var(--line);
  border-radius: 11px;
  cursor: pointer;
  transition: border-color .16s, transform .08s;
}
.btn:active { transform: scale(.98); }
.btn:hover { border-color: var(--line-2); }
.btn-primary { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, var(--bg-2)); font-weight: 600; }
.btn-ghost { background: transparent; color: var(--fg-dim); }

.prose { font-size: .9rem; line-height: 1.5; color: var(--fg-dim); }
.prose h3 { color: var(--fg); font-size: .95rem; margin: 6px 0 0; }
.prose p { margin: 0; }
.prose ul { margin: 0; padding-left: 18px; }
.prose li { margin-bottom: 5px; }
.prose .clue { display: inline-flex; margin: 0 3px; vertical-align: middle; }
.prose .clue-pic { width: 26px; height: 26px; }
.prose .clue-pics { margin: 2px auto; }
.prose b { color: var(--fg); }
.epigraph {
  margin: 0;
  padding: 9px 11px;
  border-left: 3px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-radius: 0 10px 10px 0;
  font-style: italic;
  font-size: .86rem;
}
.epigraph span { font-style: normal; font-size: .78rem; opacity: .8; }

.table-wrap { overflow-x: auto; }
.best-table { width: 100%; border-collapse: collapse; font-size: .84rem; }
.best-table th, .best-table td { text-align: left; padding: 7px 6px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.best-table th { color: var(--fg-mute); font-weight: 600; font-size: .76rem; text-transform: uppercase; letter-spacing: .4px; }
.best-table tr.is-me td { color: var(--accent-2); }

.empty-note { color: var(--fg-mute); font-size: .84rem; margin: 4px 0 0; }

.win-stats { display: flex; flex-direction: column; gap: 8px; }
.win-row { display: flex; justify-content: space-between; font-size: .9rem; }
.win-row b { font-variant-numeric: tabular-nums; }
.win-score { font-size: 1.5rem; font-weight: 700; color: var(--accent-2); text-align: center; }

.spinner {
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ---------- телефон в альбоме: порядок важен ---------- */

/* Этот блок стоит В КОНЦЕ файла намеренно. Медиазапрос не добавляет
   специфичности, поэтому правило внутри него проигрывает любому обычному
   правилу, объявленному НИЖЕ. Пока блок стоял в середине, его настройки
   строки подсказки и кнопок (объявлены ниже) не применялись вовсе —
   в альбоме они оставались прежней высоты и отнимали место у условий. */
@media (max-width: 979px) and (orientation: landscape) {
  /* В альбоме места по вертикали мало, поэтому раскладка такая же, как в
     портрете: поле слева во всю высоту, справа — кнопки выбора условий и
     ОДНА полоса условий под ними. Раньше здесь показывались обе полосы сразу,
     и на низком экране они не помещались: вторая уезжала под край, а первая
     наезжала на строку подсказки и кнопки (замер: полоса 372 px при экране
     390 px, вторая полоса начиналась с 421 px). */
  .app {
    display: grid;
    grid-template-columns: var(--board-col, 46%) minmax(0, 1fr);
    grid-template-rows: auto auto auto minmax(0, 1fr) auto auto;
    column-gap: 8px;
    row-gap: 4px;
  }
  /* обёртки «растворяются»: доска, вкладки и полоса условий становятся
     ячейками сетки. Без этого .clue-stack оставался обычным блоком, полосы
     прокручивались внутри него и вылезали за экран. */
  .main, .workspace, .clue-stack { display: contents; }
  /* Шапка уходит В КОЛОНКУ УСЛОВИЙ, а не во всю ширину: по вертикали в альбоме
     каждый пиксель на счету, и отдельная строка шапки отнимала у полосы
     условий около 50 px — на экране 640x288 полосе оставалось 67 px, то есть
     одна строка карточек. Теперь шапка стоит над вкладками справа, а слева
     доска начинается с самого верха. */
  .topbar { grid-column: 2; grid-row: 1; padding: 0 0 2px; gap: 6px; }
  .progress { grid-column: 1 / -1; grid-row: 2; }
  .board-wrap { grid-column: 1; grid-row: 1 / 7; display: flex; min-height: 0; }
  /* Поле по ширине ограничено долей экрана, поэтому по высоте его остаётся
     больше, чем оно занимает. Прижимаем его к середине отведённого места:
     иначе доска льнёт кверху, а под ней остаётся пустая полоса. */
  .board-wrap .board-scroll {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .tabs { grid-column: 2; grid-row: 3; }
  /* Компактнее: на низком экране вкладки и кнопки не должны съедать место
     у условий. */
  .tab { padding: 5px 6px; font-size: .8rem; }
  .icon-btn { width: 32px; height: 32px; border-radius: 9px; }
  .brand { font-size: .95rem; }
  /* Показываем только выбранную полосу: обе сразу на низком экране не
     помещаются. */
  .panel { display: none; height: auto; max-height: none; min-height: 0; padding: 6px; }
  /* В альбоме картинки условий мельче, чем в портрете: это единственный способ
     уложить ТРИ колонки карточек по ширине экрана и при этом не завести
     горизонтальный скролл. Поле от этого не страдает — оно ограничено высотой
     экрана, а не шириной полосы условий. */
  .panel.is-active {
    display: flex;
    grid-column: 2;
    grid-row: 4;
    max-width: none;
  }
  .panel .clue-list { --pic: var(--pic-land, calc(var(--pic-base, 34px) * .74)); }
  .panel .clue { width: calc(var(--pic) * 3.76 + 2px); }
  .hintbar { grid-column: 2; grid-row: 5; margin: 0; height: 40px; padding: 2px 8px; }
  .actionbar { grid-column: 2; grid-row: 6; padding: 2px 0 0; gap: 4px; min-width: 0; }
  .actionbar .btn { padding-top: 7px; padding-bottom: 7px; }
  /* Кнопки обязаны влезать в узкую колонку условий: подписи сжимаются с
     многоточием, а не вылезают за экран (замер: «Начать задачу» доходила до
     857 px при экране 844 — из-за этого появлялся горизонтальный скролл). */
  .actionbar .act { min-width: 0; }
  .actionbar .act span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .actionbar .btn { font-size: .78rem; padding-left: 4px; padding-right: 4px; }
  .panel .clue-list { max-height: none; }
  /* Карточки условий здесь обычной ширины: столбец поля в альбоме узкий, и
     карточка «в столбец доски» стала бы меньше двух картинок. */
  .panel .clue { width: calc(var(--pic) * 3.76 + 2px); }
  /* Вкладка «Задача»: доски нет, сведения занимают всю ширину. */
  body[data-tab="info"] .board-wrap { display: none; }
  body[data-tab="info"] .panel.is-active { grid-column: 1 / -1; grid-row: 3 / 6; }
}

/* Узкий альбом: подписи вкладок не влезают целиком и обрезаются
   многоточием («Вертикальн…»). Уменьшаем шрифт и отступы, чтобы слова
   читались полностью. */
@media (max-width: 720px) and (orientation: landscape) {
  .tab { font-size: .68rem; padding: 4px 2px; }
  /* Карточки условий ещё мельче: на 640x288 три колонки иначе не встают, и
     полоса условий показывает по две карточки в ряд. */
  .panel .clue-list { --pic: var(--pic-land, calc(var(--pic-base, 34px) * .55)); }
  .panel .clue { width: calc(var(--pic) * 3.76 + 2px); }
  .panel { padding: 4px; }
}
