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

/* === Экран ============================================================ */

.screen {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: calc(env(safe-area-inset-top) + var(--sp-5));
}

.screen__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
}

.screen__title {
  font-size: var(--fs-xl);
  letter-spacing: -0.01em;
}

.screen__lead {
  color: var(--text-2);
  font-size: var(--fs-md);
  max-width: 60ch;
}

/* === Карточка ========================================================
   Лист бумаги на стойке: светлая поверхность, мягкая тень, скругление 16.
   На тёмной теме тень не читается — поверхность держит светлая грань. */

.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--sp-4);
}

.card--quiet {
  background: transparent;
  box-shadow: none;
}

.card--flush {
  padding: 0;
  overflow: hidden;
}

.card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}

.card__title {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
}

/* === Кнопки ==========================================================
   Высота не ниже 56px — палец на ходу. Обратная связь на нажатие:
   заливка и лёгкое проседание, обе быстрее 200 мс. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  padding: var(--sp-3) var(--sp-5);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.btn:active {
  transform: translateY(1px);
}

.btn[disabled],
.btn[aria-disabled="true"] {
  color: var(--ink-quiet);
  background: var(--surface-sunken);
  border-color: var(--hairline);
  box-shadow: none;
  cursor: default;
  transform: none;
}

.btn--primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
  font-weight: var(--fw-semibold);
  box-shadow: var(--shadow-1);
}

.btn--primary:active {
  background: var(--accent-text);
  color: var(--surface);
}

.btn--ghost {
  background: transparent;
  border-color: var(--hairline-strong);
}

.btn--quiet {
  /* Не 44px, как было: этот класс идёт в общий набор кирпичей для всех
     семи экранов, а на нём нет пометки «не тап-цель». Правило раздела —
     не ниже 56px (--tap) — держим без молчаливых исключений; если позже
     появится буквенная второстепенная ссылка, а не кнопка, для неё нужен
     отдельный класс с явной пометкой, а не уменьшенный .btn--quiet. */
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  background: transparent;
  border-color: transparent;
  color: var(--text-2);
  font-size: var(--fs-md);
}

.btn--quiet:active {
  background: var(--surface-sunken);
}

.btn--danger {
  background: transparent;
  border-color: var(--err);
  color: var(--err-text);
}

.btn--block {
  width: 100%;
}

.btn--tall {
  min-height: 72px;
  font-size: var(--fs-lg);
}

.btn-row {
  display: flex;
  gap: var(--sp-3);
}

.btn-row > .btn {
  flex: 1 1 0;
}

/* === Вариант ответа ===================================================
   Выбор из четырёх. Разбор красит выбранное: верное — матча, ошибка —
   облепиха; остальные варианты гаснут, чтобы глаз шёл к правильному. */

.option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  min-height: 64px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-lg);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    opacity var(--dur) var(--ease);
}

.option:active {
  background: var(--accent-soft);
}

.option.is-correct {
  background: var(--ok-soft);
  border-color: var(--ok);
  color: var(--ok-text);
}

.option.is-wrong {
  background: var(--err-soft);
  border-color: var(--err);
  color: var(--err-text);
}

.option.is-dimmed {
  opacity: 0.45;
}

/* Чип-переключатель шага «Что входит» карточки (src/ui/screens/card-check.js):
   отмеченный ингредиент — до проверки просто «выбран» (акцент, не вердикт).
   is-missing красит после «Дальше» ингредиент, который нужно было отметить,
   но не отметили, — пунктирная обводка отличает «пропустили» от is-wrong
   («отметили лишнее»), у обоих смысл «ошибка», но разный. */
.option[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
}

.option.is-missing {
  border-color: var(--err);
  border-style: dashed;
}

.options {
  display: grid;
  gap: var(--sp-3);
}

/* === Числа ===========================================================
   Главный герой тренажёра. Моноширинный шрифт с табличными цифрами:
   в столбце 180 / 250 / 330 разряды стоят ровно друг под другом. */

.num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -0.01em;
}

.num--lg {
  font-size: var(--fs-lg);
}

.num--xl {
  font-size: var(--fs-answer);
  line-height: var(--lh-tight);
  font-weight: var(--fw-semibold);
}

.num__unit {
  margin-left: 0.25em;
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  font-weight: var(--fw-regular);
}

/* === Плашки и источник ================================================ */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 2px var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: var(--fs-sm);
  white-space: nowrap;
}

.chip--ok {
  background: var(--ok-soft);
  color: var(--ok-text);
}

.chip--err {
  background: var(--err-soft);
  color: var(--err-text);
}

/* Ссылка на лист и ячейку: любое число сверяемо с оригиналом. */
.source {
  font-family: var(--font-num);
  font-size: var(--fs-xs);
  color: var(--text-2);
}

/* === Кольцо прогресса =================================================
   Разметку рисует экран (svg 40×40, r=17, круг повёрнут на -90°),
   заливка кольца — единственная анимация списка напитков. */

.ring {
  display: block;
  width: 40px;
  height: 40px;
  flex: none;
  transform: rotate(-90deg);
}

.ring__track {
  fill: none;
  stroke: var(--hairline-strong);
  stroke-width: 4;
}

.ring__value {
  fill: none;
  stroke: var(--accent);
  stroke-width: 4;
  stroke-linecap: round;
  transition: stroke-dasharray var(--dur) var(--ease);
}

.ring--done .ring__value {
  stroke: var(--ok);
}

/* === Точки сессии ===================================================== */

.dots {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--hairline-strong);
  transition: background-color var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.dot.is-ok {
  background: var(--ok);
}

.dot.is-err {
  background: var(--err);
}

.dot.is-current {
  background: var(--accent);
  transform: scale(1.5);
}

/* Ответ засчитан, но не как бодрое «верно»: «не знаю» и истёкший таймер —
   не ошибка (нет is-err), но и не то же самое, что уверенный верный ответ. */
.dot.is-skip {
  background: var(--ink-quiet);
}

/* === Тренировка: таймер и вопрос ======================================
   Тонкая полоска на timed-вопросах, десять секунд без звука и тряски.
   Настоящий отсчёт держит session.js через setTimeout — эта анимация
   только показывает его, поэтому prefers-reduced-motion её не портит. */

.timerbar {
  height: 3px;
  border-radius: var(--radius-pill);
  background: var(--hairline);
  overflow: hidden;
}

.timerbar__fill {
  height: 100%;
  width: 100%;
  background: var(--accent);
  transform-origin: left center;
}

.session__prompt {
  color: var(--text-2);
  font-size: var(--fs-md);
}

.session__question {
  font-size: var(--fs-question);
  line-height: var(--lh-tight);
  font-weight: var(--fw-semibold);
}

/* Раскрывашка источника в разборе: свой треугольник убираем — «Источник»
   уже выглядит как кнопка (.btn--quiet) и не нуждается во втором значке. */
.explain__source summary {
  cursor: pointer;
  list-style: none;
}

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

.explain__source summary::marker {
  content: '';
}

/* === Поле ввода =======================================================
   Ввод числа: моноширинный, крупный, клавиатура цифровая (inputmode). */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.field__label {
  color: var(--text-2);
  font-size: var(--fs-md);
}

.input {
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
}

.input--num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-answer);
  font-weight: var(--fw-semibold);
  text-align: center;
  min-height: 72px;
}

.input.is-wrong {
  border-color: var(--err);
  background: var(--err-soft);
}

/* Проверка карточки целиком (src/ui/screens/card-check.js) — единственное
   место, где поле ввода красится в «верно»: обычная тренировка ввод после
   ответа просто блокирует, не перекрашивая в зелёный. */
.input.is-ok {
  border-color: var(--ok);
  background: var(--ok-soft);
}

/* === Выезжающий разбор ================================================ */

.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  max-height: 80vh;
  max-height: 80svh;
  overflow-y: auto;
  padding: var(--sp-4) max(var(--gutter), env(safe-area-inset-left))
    calc(env(safe-area-inset-bottom) + var(--sp-4))
    max(var(--gutter), env(safe-area-inset-right));
  background: var(--surface);
  border-top: 1px solid var(--hairline);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-2);
  transform: translateY(100%);
  visibility: hidden;
  transition: transform var(--dur) var(--ease), visibility var(--dur);
}

.sheet.is-open {
  transform: translateY(0);
  visibility: visible;
}

.sheet__inner {
  max-width: var(--content-max);
  margin-inline: auto;
}

/* === Таблица ==========================================================
   Сравнение и «Данные»: первый столбец прилипает, числа — моноширинные. */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-size: var(--fs-md);
}

.table th,
.table td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--hairline);
  text-align: right;
  white-space: nowrap;
}

.table th {
  font-weight: var(--fw-medium);
  color: var(--text-2);
}

.table tr:last-child th,
.table tr:last-child td {
  border-bottom: 0;
}

/* Финальное ревью, minor: раньше здесь стояло position: sticky; top: 0 —
   не работает, потому что .table-wrap не имеет своей вертикальной прокрутки
   (нет max-height, скроллится вся страница) — sticky некуда «прилипать»,
   заголовок просто уезжает вместе со страницей. Прилипает по-настоящему
   только первый столбец (.table__key ниже — там прокрутка ГОРИЗОНТАЛЬНАЯ,
   она у .table-wrap есть на самом деле). Обещание "липнет" убрано отсюда,
   а не изображено бутафорски: сделать честную вертикальную липкость значило
   бы завести отдельный скролл-контейнер с ограниченной высотой для каждой
   таблицы «Сравнения»/«Данных» — самостоятельная правка вёрстки, которая
   в объём этой волны фиксов не входила. */
.table__head {
  background: var(--surface);
}

/* Прилипающий первый столбец: строка ингредиента не должна уезжать.
   white-space селектор здесь — .table th.table__key/.table td.table__key
   (не просто .table__key): у общего правила выше специфичность (0,1,1)
   класс+тип, у одного класса .table__key — только (0,1,0), и без этого
   уточнения nowrap всегда побеждал бы независимо от порядка в файле —
   баг был незаметен, пока в первом столбце не встретился длинный текст
   («Сильногазированная вода в роксе» экрана «Сравнение», задача 12). */
.table__key {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--surface);
  text-align: left;
  min-width: 9rem;
  color: var(--text);
  box-shadow: 1px 0 0 var(--hairline);
}

.table th.table__key,
.table td.table__key {
  white-space: normal;
}

.table__num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.table__num.is-max {
  color: var(--accent-text);
  font-weight: var(--fw-semibold);
}

/* Экран «Данные» (src/ui/screens/data.js): шаги и подача бывают длинными
   предложениями — базовое правило выше (white-space: nowrap) держит их
   компактными для таблиц сравнения/состава, но здесь как раз наоборот
   нельзя обрезать текст молча. pre-line, а не normal — переносы внутри
   самого текста подачи (см. .u-prewrap) остаются как в исходной ячейке.
   Специфичность та же, что у базового правила — побеждает по порядку
   каскада, поэтому объявлено ниже него. */
.table--wrap th,
.table--wrap td {
  white-space: pre-line;
}

/* Строка справочника температур, буквально совпавшая с листом карточки
   (src/core/temperature-match.js, Ruling 29). Первый столбец — тоже сплошной
   фон, а не прозрачный: он «прилипающий» (.table__key) со своим фоном,
   который иначе перекрыл бы подсветку строки под собой. */
.table tr.is-match .table__key,
.table tr.is-match .table__num {
  background: var(--accent-soft);
}

/* === Сегмент-переключатель ============================================
   Группы сравнения (src/ui/screens/compare.js): каждая кнопка — тап-цель
   не ниже --tap, aria-pressed отмечает выбранную. Сетка 2×2 вместо ряда
   в одну строку — на 320px четыре подписи в ряд не влезают без переноса. */

.segmented {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
}

.segmented__btn {
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  text-align: center;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.segmented__btn[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-text);
}

.segmented__btn:active {
  background: var(--surface-sunken);
}

/* Длина тренировки (src/ui/screens/settings.js): три значения, в один ряд
   на любой ширине от 320px — в отличие от четырёх групп сравнения выше,
   которым нужна сетка 2×2. */
.segmented--3 {
  grid-template-columns: repeat(3, 1fr);
}

/* === Переключатель (switch) ===========================================
   Настройка таймера (src/ui/screens/settings.js) — родной <input
   type=checkbox>, а не кастомный div с role=switch: клавиатура, Space,
   чтение с экрана и синхронизация состояния работают сами по себе, стиль
   поверх — только внешний вид. .switch — это <label>, целиком кликабельный
   (нативное поведение label→input), поэтому текст можно ставить как угодно
   близко к переключателю, не теряя тап-цель. Сам input — тап-цель шириной
   64×44 (не менее --tap по обеим осям), а не визуально спрятан в 1px: иначе
   аудит контролов по getBoundingClientRect() увидел бы точечный элемент
   вместо реальной тап-цели. */
.switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--tap);
  cursor: pointer;
}

.switch__text {
  flex: 1 1 auto;
  min-width: 0;
}

.switch__control {
  flex-shrink: 0;
  appearance: none;
  -webkit-appearance: none;
  width: 64px;
  height: 44px;
  margin: 0;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  position: relative;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.switch__control::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-fast) var(--ease);
}

.switch__control:checked {
  background: var(--accent);
  border-color: transparent;
}

.switch__control:checked::after {
  transform: translateX(22px);
}

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

/* === Иконка-кнопка (шестерёнка настроек, src/ui/screens/learn.js) ===== */

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  align-self: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: var(--radius);
  color: var(--text);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease);
}

.icon-btn:active {
  background: var(--surface-sunken);
}

.icon-btn__icon {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* === Список строк ===================================================== */

.list {
  display: flex;
  flex-direction: column;
}

.list__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-3) var(--sp-4);
  border: 0;
  border-bottom: 1px solid var(--hairline);
  background: transparent;
  color: inherit;
  font-size: var(--fs-base);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease);
}

.list__item:last-child {
  border-bottom: 0;
}

.list__item:active {
  background: var(--accent-soft);
}

.list__body {
  flex: 1 1 auto;
  min-width: 0;
}

.list__title {
  font-weight: var(--fw-medium);
}

.list__note {
  color: var(--text-2);
  font-size: var(--fs-md);
}

/* Миниатюра строки списка карточек (src/ui/screens/cards.js) — фото
   «с собой» уменьшенное до квадрата; thumb--empty — нейтральная заглушка
   для облепихи и шиповника (на листе фото нет, выдумывать нечего). */
.thumb {
  width: 48px;
  height: 48px;
  flex: none;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--surface-sunken);
}

.thumb--empty {
  border: 1px dashed var(--hairline-strong);
}

/* === Сообщения и пустые состояния ===================================== */

.banner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius);
  background: var(--surface);
}

.banner--error {
  border-color: var(--err);
  background: var(--err-soft);
  color: var(--err-text);
}

.banner__title {
  font-weight: var(--fw-semibold);
}

.empty {
  padding: var(--sp-6) var(--sp-4);
  color: var(--text-2);
  text-align: center;
}

/* === Нижняя панель ====================================================
   Вкладки-закладки: панель темнее страницы, активная вкладка — лист бумаги,
   вытянутый вперёд. Индикатора-подчёркивания нет: вперёд выходит сам лист. */

.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 15;
  background: var(--surface-sunken);
  border-top: 1px solid var(--hairline);
  padding-bottom: env(safe-area-inset-bottom);
}

.tabbar__list {
  display: flex;
  max-width: var(--content-max);
  margin-inline: auto;
  padding: 0 max(var(--sp-1), env(safe-area-inset-left)) 0
    max(var(--sp-1), env(safe-area-inset-right));
}

.tabbar__item {
  display: flex;
  flex: 1 1 0;
}

.tab {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--nav-h);
  padding: var(--sp-2) 2px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  color: var(--text-2);
  font-size: var(--fs-sm);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease),
    color var(--dur-fast) var(--ease);
}

.tab__icon {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tab__label {
  line-height: 1.1;
}

/* На 320px «Сравнение» упирается в края вкладки — подписи чуть мельче. */
@media (max-width: 359px) {
  .tab__label {
    font-size: var(--fs-xs);
  }
}

.tab[aria-current="page"] {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-1);
}

.tab[aria-current="page"] .tab__icon {
  stroke: var(--accent-text);
}

.tab:active {
  background: var(--surface);
}

/* === Утилиты ========================================================== */

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

.between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.u-muted {
  color: var(--text-2);
}

.u-small {
  font-size: var(--fs-md);
}

/* Тексты из таблицы с переносами строк (сноски, «Подача/Описание») —
   переносы сохраняются как в исходной ячейке, а не схлопываются в одну
   строку обычным поведением HTML. */
.u-prewrap {
  white-space: pre-line;
}

/* === Тренировка: порядок шагов =========================================
   Пул шагов вперемешку рисуется обычными .option (см. выше) — тот же
   тап-кирпич, что и в выборе варианта, здесь тоже несёт «нажми, чтобы
   ответить». Собранная цепочка ниже — список подтверждённых шагов,
   подложка и текст — токены «верно» (тот же смысл: шаг встал на место). */

.steps-chain {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.steps-chain__item {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  background: var(--ok-soft);
  color: var(--ok-text);
  font-size: var(--fs-md);
}

.steps-chain__num {
  flex: none;
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
}

/* Цепочка собрана полностью, но не без ошибок по пути (steps-order.js
   ставит этот класс на .steps-chain, когда state.mistakes > 0 в момент
   завершения) — итог не должен выглядеть неотличимо от идеальной сборки,
   поэтому все пункты перекрашиваются в те же err-токены, что и .option.is-wrong
   у обычного выбора варианта. */
.steps-chain.is-wrong .steps-chain__item {
  background: var(--err-soft);
  color: var(--err-text);
}

/* === Тренировка: фото подачи ===========================================
   aspect-ratio резервирует место под фото ДО его загрузки (снимки — родной
   портрет телефона, 2:3), max-height не даёт высокому кадру вытолкнуть
   кнопки ответа за экран на низких телефонах в альбомной ориентации. */

.photo-card {
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface-sunken);
}

.photo-card__img {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  max-height: 46vh;
  object-fit: cover;
}

/* === Карточка справочника: два фото рядом ==============================
   src/ui/screens/cards.js — те же .photo-card, но по два в ряд. На 320px
   пара 2:3 карточек всё ещё влезает без горизонтального скролла страницы,
   max-height ниже, чем у тренировки: фото здесь не единственный элемент
   экрана, ему нельзя отжимать всё остальное содержимое карточки вниз. */
.photo-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}

.photo-pair .photo-card__img {
  max-height: 32vh;
}

/* === Аккаунты ============================================================
   Страница входа (server/public/login.html), плашка несохранённого
   прогресса, смена пароля в настройках и экран «Пользователи». */

.auth {
  padding-top: calc(env(safe-area-inset-top) + var(--sp-5));
}

.sync-status {
  position: sticky;
  top: 0;
  z-index: 20;
  margin: 0 auto;
  max-width: var(--content-max);
  border-radius: 0 0 var(--radius) var(--radius);
  padding-top: calc(env(safe-area-inset-top) + var(--sp-3));
}

summary.btn {
  list-style: none;
  cursor: pointer;
}
summary.btn::-webkit-details-marker {
  display: none;
}
details[open] > summary.btn {
  margin-bottom: var(--sp-3);
}

.admin-user .btn-row {
  flex-wrap: wrap;
}
.admin-user .btn-row > .btn {
  flex: 1 1 8rem;
}

.admin-password {
  user-select: all;
  word-break: break-all;
}

/* === Карточка «Как устроен тренажёр» ======================================
   src/ui/components/intro.js — модальный <dialog> поверх экрана. Лист бумаги
   по центру; текст прокручивается внутри, кнопка «Понятно» всегда видна
   внизу. Пункты нумеруются счётчиком CSS: цифра в кружке — тот же приём
   «плашки», что и .chip, только круглый. */

.intro {
  width: min(100% - 2 * var(--gutter), var(--content-max));
  max-width: none;
  max-height: calc(100svh - 2 * var(--gutter));
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}

.intro[open] {
  display: flex;
  flex-direction: column;
  animation: intro-in var(--dur) var(--ease);
}

.intro::backdrop {
  background: rgba(23, 16, 9, 0.5);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: intro-fade var(--dur) var(--ease);
}

@keyframes intro-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
}

@keyframes intro-fade {
  from { opacity: 0; }
}

.intro__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-2);
  overscroll-behavior: contain;
}

.intro__scroll:focus {
  outline: none;
}

.intro__head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

.intro__icon {
  width: 48px;
  height: 48px;
  margin-bottom: var(--sp-1);
  border-radius: 12px;
  background: var(--accent);
  fill: none;
  stroke: var(--surface);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.intro__title {
  font-size: var(--fs-xl);
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
}

.intro__lead {
  color: var(--text-2);
  font-size: var(--fs-md);
}

.intro__list {
  counter-reset: intro;
}

.intro__item {
  counter-increment: intro;
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-top: 1px solid var(--hairline);
}

.intro__item::before {
  content: counter(intro);
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-family: var(--font-num);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.intro__item-title {
  font-weight: var(--fw-semibold);
  line-height: 28px;
}

.intro__text {
  color: var(--text-2);
  font-size: var(--fs-md);
}

.intro__foot {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5) calc(var(--sp-4) + env(safe-area-inset-bottom));
  border-top: 1px solid var(--hairline);
}

.intro__hint {
  color: var(--text-2);
  font-size: var(--fs-sm);
  text-align: center;
}

/* На 320px поля карточки уже — тексту нужна ширина. */
@media (max-width: 359px) {
  .intro__scroll { padding-inline: var(--sp-4); }
  .intro__foot { padding-inline: var(--sp-4); }
}
