/* ===== Базовые стили ===== */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Палитра — пастель. Все цвета живут здесь, в правилах ниже стоят только
   их имена: менять оттенок можно в одном месте. Значения и роли описаны
   в прототипе: notes/редизайн/прототип-пастель v4.html, раздел 1.

   В скобках у каждого цвета — контраст к белой карточке: 4.5:1 нужно
   мелкому тексту, 3:1 — границам и графике. */
:root {
  /* фон приложения: градиент «небо — рассвет», лежит под всеми блоками */
  --g1: #c9defb;
  --g2: #e3dceb;
  --g3: #fddbdb;

  --card: #ffffff;        /* все блоки */
  --ink: #16182a;         /* основной текст          17.5:1 */
  --muted: #5f6474;       /* подписи                  5.9:1 */
  --muted-soft: #6f7488;  /* самая тихая подпись       4.6:1 */
  --ground-ink: #4c5161;  /* текст поверх градиента    5.9:1 */

  --accent: #4e47e4;      /* главные кнопки, активный пункт меню */
  --accent-ink: #3b34c9;  /* акцентный текст           8.3:1 */
  --accent-soft: #e6e4fb; /* мягкая подложка акцента */
  --accent-ring: #8b86ee; /* осветлённый акцент: обводка дня «сегодня» */

  --track: #eeeff8;       /* дорожка полос, подложка плиток */
  --hair: #e8e9f2;        /* волосяная граница */
  --ghost-line: #dcdff0;  /* кольцо пустого слота ответа (см. .option .mk) */

  --sky: #8dd9f7;         /* «верно», день занятия, выученное слово */
  --sky-soft: #eaf7fd;
  --sky-ink: #0f6b8a;     /* текст на небесном         5.5:1 на --sky-soft */
  --sky-cap: #376f88;     /* подписи в плитке          5.1:1 */

  --lilac: #9b7fd4;       /* доля «выучил новых»       3.3:1 */
  --lilac-soft: #f0ecfb;
  --lilac-ink: #5b3f9e;   /*                           6.8:1 */
  --lilac-cap: #6a5695;   /*                           5.4:1 */

  --pink-soft: #fdeaf2;
  --pink-mid: #f0b6d6;    /* заливка кружка «не знаю» в «последних ответах» */
  --pink-ink: #b23a6b;    /* «не знаю», ошибка         4.9:1 */
  --pink-cap: #9d4d68;    /*                           4.6:1 */
  --pink-deep: #a5375c;   /* обводки, знак «✗»         6.4:1 */

  --gold: #f1b76e;        /* заливка «звание», медаль, искры */
  --gold-deep: #4a2c05;   /* текст на золоте           7.1:1 */
  --gold-soft: #fdf3df;
  --gold-ink: #8a5a12;    /*                           5.4:1 */
  --gold-cap: #8f6530;    /*                           4.7:1 */
  --gold-ring: #a06a1f;   /* обводка золота            4.6:1 */

  --violet: #a858d0;      /* полосы в «Прогрессе по категориям» */

  /* формы и тени */
  --r-card: 26px;         /* блоки и поздравление */
  --r-tile: 18px;         /* плитки цифр, варианты ответа, режимы */
  --r-btn: 16px;          /* кнопки, поля выбора */
  --r-pill: 999px;        /* счётчики, полоски, точки */
  --sh-card: 0 10px 30px rgba(78, 71, 228, 0.10);
  --sh-btn: 0 6px 16px rgba(78, 71, 228, 0.30);
  --sh-soft: 0 2px 8px rgba(22, 24, 42, 0.06);
}

/* Страница — сетка из двух колонок: слева меню, справа экран. Виден всегда
   один экран из шести (остальные прячет атрибут hidden), поэтому все они
   стоят во второй колонке друг под другом, а меню — первое и одно на всех.
   align-items: start — колонка меню не растягивается на всю высоту. */
body {
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: linear-gradient(165deg, var(--g1) 0%, var(--g2) 55%, var(--g3) 100%);
  background-attachment: fixed;
  color: var(--ink);
  font-size: 15px;
  line-height: 1.5;
  min-height: 100vh;
  padding: 16px;
  display: grid;
  grid-template-columns: 212px minmax(0, 1fr);
  align-items: start;
  /* align-content: start — ряды не растягиваются на всю высоту окна.
     Без него (по умолчанию stretch) на узком экране, где меню и экран
     стоят друг под другом, ряд меню-полосы раздувался до трети экрана:
     меню высотой 54px висело сверху, а под ним зияла пустота. */
  align-content: start;
  gap: 14px;
  max-width: 1180px;
  margin: 0 auto;
}

h1 {
  font-size: 23px;
  letter-spacing: -0.015em;
  line-height: 1.15;
}

h2 {
  font-size: 17px;
  margin-bottom: 12px;
  letter-spacing: -0.01em;
}

/* ===== Меню слева ===== */
/* Полупрозрачная карточка: сквозь неё видно фон, поэтому меню читается как
   часть страницы, а не как ещё один блок. */
.rail {
  position: sticky;
  top: 16px;
  /* Панель меню — на всю высоту экрана: короткая панель обрывалась на
     середине страницы и выглядела недорисованной. Считаем высоту окна минус
     отступы body (16px сверху и снизу). Именно min-height, а не height: на
     низком окне меню имеет право вырасти, а не обрезаться. position: sticky
     при этом никуда не девается — на длинном списке слов меню остаётся на
     виду, поэтому панель всегда занимает левый край целиком. */
  min-height: calc(100vh - 32px);
  background: rgba(255, 255, 255, 0.55);
  border-radius: 22px;
  padding: 14px 12px;
}

.brand {
  margin: 0 0 14px;
  padding: 0 8px;
  font-size: 15px;
  font-weight: 800;
}

/* Название группы пунктов: «Учёба», «Словари», «Служебное».
   Шрифт с засечками — тот же, что у кнопки «i». Так заголовок не путается
   с пунктами меню: пункты набраны основным шрифтом, заголовок — другим,
   и видно, что это не ссылка, а надпись над группой.
   Цвет — тише пунктов: это самый спокойный токен палитры. В :root у него
   посчитано 4.6:1, но это к белой карточке, а панель меню полупрозрачная.
   Замер по снимку: фон под заголовком #cedef8, живой контраст 3.41:1 —
   ниже нормы 4.5:1 для мелкого текста, так решил Александр ради вида.
   В норму возвращает --muted (#5f6474): на этом же фоне 4.33:1. */
.rail-group {
  margin: 14px 0 6px;
  padding: 0 8px;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-soft);
}

.rail-group:first-of-type { margin-top: 0; }

.rail nav {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.rail a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: 14px;
  color: var(--ground-ink);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  /* Подпись не переносится: иначе «Выученные» уезжает на вторую строку,
     а счётчик остаётся висеть справа на первой. */
  white-space: nowrap;
}

.rail a:hover { background: rgba(255, 255, 255, 0.7); }

/* Открытый экран в меню — белая карточка: видно, где ты находишься */
.rail a.active {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 4px 12px rgba(78, 71, 228, 0.12);
}

/* Счётчик слов у пунктов «Выученные» и «Сложные» */
.rail a .cnt {
  margin-left: auto;
  font-size: 12px;
  font-weight: 700;
  background: rgba(255, 255, 255, 0.75);
  border-radius: var(--r-pill);
  padding: 2px 8px;
  color: var(--ground-ink);
  font-variant-numeric: tabular-nums;
}

.rail a.active .cnt {
  background: var(--accent-soft);
  color: var(--accent-ink);
}

/* ===== Шапка экрана ===== */
/* Название экрана и дата слева, талисман прижат к правому краю */
.app-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
  padding: 4px 6px 14px;
}

.app-head h1 { margin: 0; }

.app-date {
  margin: 3px 0 0;
  font-size: 13px;
  color: var(--ground-ink);
}

.mascot {
  height: 78px;
  width: auto;
  flex: none;
  display: block;
}

/* Экраны: ширина по колонке сетки, внутренние отступы не нужны —
   расстояние до меню даёт gap */
main { min-width: 0; }

/* ===== Блоки ===== */
/* Белая карточка с мягкой тенью. Рамки нет: глубину даёт тень, поэтому
   блоки не выглядят «в клеточку». */
.panel {
  background: var(--card);
  border-radius: var(--r-card);
  padding: 20px 22px;
  box-shadow: var(--sh-card);
}

.panel + .panel { margin-top: 14px; }

/* ===== Главная: две колонки в верхней части =====
   Идут после блока «Общий прогресс»: слева звание, справа календарь
   занятий. Расстояние между блоками внутри столбцов даёт gap сетки,
   поэтому обычный отступ «блок + блок» внутри столбца выключаем —
   иначе он сложился бы с gap. */
/* Отступ от блока выше: правило «блок + блок» тут не срабатывает — .top
   не блок, а сетка. Без этой строки колонки прилипли бы к прогрессу. */
.panel + .top { margin-top: 14px; }

.top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 342px;
  gap: 14px;
  align-items: start;
  margin-bottom: 14px;
}

.top-l,
.top-r {
  display: grid;
  gap: 14px;
  align-content: start;
}

.top .panel + .panel { margin-top: 0; }

/* ===== Поздравление с новым званием =====
   Первый блок главной, во всю ширину. Не белая карточка, а мягкий
   рассветный градиент: событие редкое, ему идёт выделение. Медаль —
   шестиугольник из золота палитры, от неё по всей плашке расходятся лучи.
   Отступ снизу — как у блоков между собой (14 px), и он уходит вместе с
   плашкой: когда поздравления нет, атрибут `hidden` убирает и отступ,
   поэтому страница начинается с «Общего прогресса» без лишней дыры. */
.hello {
  position: relative;
  overflow: hidden;
  margin-bottom: 14px;
  /* Свой контекст наложения — он нужен лучам (`.hello::before` с
     `z-index: -1`): без `isolation` такой слой ушёл бы ПОД фон плашки и
     лучей не было бы видно вовсе, а со `z-index: 0` он накрыл бы текст.
     Слои в CSS считаются не по порядку в разметке, а по типу слоя:
     позиционированный слой рисуется выше обычного текста. */
  isolation: isolate;
  /* Запасное значение угла веера — для браузеров, которые не знают
     `@property` (там переменная обычная и наследуется вниз, к лучам):
     без него `var(--spin)` сделал бы негодным всё объявление `background`
     и лучей в таком браузере не стало бы вовсе. В умеющих браузерах это
     значение до лучей не доходит: у свойства стоит `inherits: false`. */
  --spin: 0deg;
  background: linear-gradient(150deg, #fff8ea 0%, #fdf1fb 55%, #eef6ff 100%);
  border-radius: var(--r-card);
  box-shadow: var(--sh-card);
  padding: 24px 22px 22px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

/* Без этой строки `display: flex` перебил бы служебный атрибут `hidden`
   (стили страницы сильнее встроенных стилей браузера) — и поздравление
   висело бы на экране всегда, даже когда его нет. */
.hello[hidden] { display: none; }

/* Лучи — как на праздничных экранах тренажёров: расходятся из-за медали
   по всей плашке. Центр конуса и центр гашения — середина медали:
   24 px верхнего поля плюс половина её высоты (60 / 2 = 30). Меняешь
   размер медали или верхнее поле — поменяй и эти два числа.
   Один луч — 10°, промежуток 16°: 360 / 26 = 14 лучей.
   Цвет — золото палитры `--gold` (#f1b76e) с прозрачностью.
   `mask-image` гасит лучи к краям: у медали они плотные, к подписи и
   углам сходят на нет. Это не украшение, а необходимость: `--muted`
   на нетронутом луче 55 % даёт 4,1:1 вместо 5,4:1 — подпись перестала
   бы проходить норму 4.5:1. С гашением замер по снимку — 5,3:1.
   Гашение задано эллипсом, а не кругом: по ширине он тянется вместе с
   плашкой (46 % ширины), поэтому на широкой колонке главной лучи
   достают до боков, а по высоте стоит твёрдые 300 px — подпись не
   зависит от того, какая колонка ей досталась.

   Веер медленно поворачивается по часовой стрелке: полный круг за 60 с.
   Угол конуса (`from`) читается из переменной `--spin`, а чтобы браузер
   умел её плавно менять, свойство зарегистрировано через `@property`
   ниже — обычную переменную он анимировать не станет, и лучи стояли бы
   на месте. 60 с — это 6°/с: заметно, что карточка живая, но глаз не
   следит за движением, как за вертушкой. Число живёт в одном месте —
   в `animation` у `.hello::before`. В макете-сравнении
   (`notes/редизайн/Сравнение вариантов движения.html`) стояло 45 с, в
   тренажёре — 60 с: он и есть верное значение. */
@property --spin {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
.hello::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: repeating-conic-gradient(from var(--spin) at 50% 54px,
    rgba(241, 183, 110, .55) 0deg 10deg, transparent 10deg 26deg);
  -webkit-mask-image: radial-gradient(ellipse 46% 300px at 50% 54px,
    #000 0, rgba(0, 0, 0, .45) 40%, transparent 100%);
  mask-image: radial-gradient(ellipse 46% 300px at 50% 54px,
    #000 0, rgba(0, 0, 0, .45) 40%, transparent 100%);
  animation: rays-spin 60s linear infinite;
}
/* Кадр один — «довернуть до конца круга»: браузер сам считает
   промежуточные углы (анимация линейная, то есть равномерная). */
@keyframes rays-spin {
  to { --spin: 360deg; }
}

/* Второй вид поздравления — россыпь звёзд на нечётных ступенях (чётные
   остаются с лучами, класс `is-stars` гасит веер ниже). Звезда — обычный
   текст: знак ✦ в <i>, размер задаётся шрифтом. Слой уведён под содержимое
   (`z-index: -1`), как и лучи: попав под медаль или строку, звезда
   пропадает — и текст читается всегда. Раскладку считает app.js и передаёт
   переменными: --x, --y, --sz, --o, --d, --t, --ph и --xmax. */
.hello .stars {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.hello .stars i {
  position: absolute;
  /* Звезда не заходит под кнопку «Закрыть»: --xmax — граница слева от неё,
     её ставит app.js тем звёздам, что стоят на высоте кнопки. `min` берёт
     меньшее из двух: пока места хватает, граница правее звезды и не мешает.
     Первая строка — запасная, для браузера без `min`. */
  left: var(--x);
  left: min(var(--x), var(--xmax, 100%));
  top: var(--y);
  font-style: normal;
  font-size: calc(var(--sz) * var(--k, 1.35));
  line-height: 1;
  color: var(--gold);
  opacity: var(--o, 1);
  transform: translate(-50%, -50%);
  text-shadow: 0 0 10px rgba(241, 183, 110, .55);
  /* Влёт со своей задержкой (--d), потом мерцание (--t). Задержка мерцания
     отрицательная: она ставит звезду сразу в нужную фазу, поэтому звёзды
     горят вразнобой с первой секунды, а не вспыхивают вместе. В самой
     тёмной точке звезда гаснет до 10 % своей яркости (--low). */
  animation:
    star-pop .55s cubic-bezier(.2, 1.5, .4, 1) var(--d, 0s) 1 backwards,
    star-twinkle var(--t, 3s) ease-in-out calc(var(--d, 0s) + .55s + var(--ph, 0s)) infinite;
}

@keyframes star-pop {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.2); }
  60%  { opacity: calc(var(--o, 1) * 1.2); }
  to   { opacity: var(--o, 1); transform: translate(-50%, -50%) scale(1); }
}

@keyframes star-twinkle {
  0%, 100% { opacity: var(--o, 1); }
  50%      { opacity: calc(var(--o, 1) * var(--low, .1)); }
}

/* Звёздный вид — без лучей: это два разных вида, а не два слоя. */
.hello.is-stars::before { display: none; }

/* Медаль — шестиугольник из золота палитры. Обводку рисует сам
   шестиугольник: .medal залит тёмным золотом (--gold-ring), а поверх
   лежит .medal-face — та же фигура, вписанная на 2 px внутрь.
   Толщина обводки — выбор Александра из трёх показанных вариантов
   (3 px — как было в прототипе, 2 px — мягче, без обводки — золото
   растворяется в светлом фоне поздравления: контраст всего 1,6:1).
   Рамкой или `box-shadow: inset` обводку делать нельзя: у clip-path
   фигура шестиугольная, а рамка и внутренняя тень живут в обычной
   прямоугольной коробке. Их боковые полосы (x = 0…2 px) срезались
   шестиугольником не целиком — по бокам, где у фигуры вершина-точка на
   середине высоты, из-под среза торчали коричневые клинья. */
.hello .medal {
  position: relative;
  width: 60px;
  height: 60px;
  margin-bottom: 4px;
  background: var(--gold-ring);
  /* шестиугольник: ровно тот же приём, что у текущего звания */
  clip-path: polygon(25% 2%, 75% 2%, 100% 50%, 75% 98%, 25% 98%, 0% 50%);
}

.hello .medal-face {
  position: absolute;
  inset: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  line-height: 1;
  background: var(--gold);
  clip-path: polygon(25% 2%, 75% 2%, 100% 50%, 75% 98%, 25% 98%, 0% 50%);
}

.hello .ttl {
  margin: 0;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.hello .sub { margin: 0; font-size: 13px; color: var(--muted); }

.hello .close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  cursor: pointer;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  font-family: inherit;
  box-shadow: var(--sh-soft);
}

.hello .close:hover { background: #fff; color: var(--ink); }

/* ===== Календарь занятий ===== */
.cal { max-width: 330px; }

/* Шапка календаря: заголовок месяца стоит ровно посередине между
   стрелками. Колонки именно `auto 1fr auto`, а не `1fr auto 1fr`:
   при равных крайних колонках заголовок встаёт в центр всей шапки, а
   середина промежутка между стрелками — левее: справа от «→» стоит
   «Сегодня», и она отжимает стрелку «→» влево. Схема `auto 1fr auto`
   центрирует заголовок в остатке между стрелками — зазоры слева и
   справа от надписи получаются одинаковыми при любой ширине. */
.cal-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

/* Правая группа шапки: стрелка «вперёд» и кнопка возврата к сегодня.
   Прижата к правому краю своей колонки — там же, где раньше стояла
   одинокая стрелка «→». */
.cal-nav {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
}

.cal-head button {
  width: 32px;
  height: 32px;
  border: none;
  cursor: pointer;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.8);
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  font-family: inherit;
  box-shadow: var(--sh-soft);
}

.cal-head button:hover { color: var(--ink); background: #fff; }

/* «Сегодня» — таблетка, а не кружок: так она читается как действие
   («показать этот месяц»), а не как ещё одна стрелка листания. */
.cal-head .cal-today {
  width: auto;
  padding: 0 10px;
  border-radius: 16px;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}

/* Календарь и так стоит на текущем месяце — нажимать некуда. Кнопка
   остаётся на месте (место не резервируем, вёрстка не дёргается),
   но гаснет: цвет приглушён, курсор обычный. */
.cal-head .cal-today.is-now {
  opacity: 0.45;
  cursor: default;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.8);
}

.cal-title { font-size: 14px; font-weight: 800; text-align: center; }

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}

.cal-grid .dow {
  font-size: 11px;
  font-weight: 700;
  color: var(--muted-soft);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.cal-grid .d {
  position: relative;
  aspect-ratio: 1;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* День занятия: небесная заливка с обводкой потемнее — тот же приём,
   что у верного ответа и выученного слова. */
.cal-grid .d.study {
  background: var(--sky);
  color: #0b3a4d;
  font-weight: 700;
}

/* «Сегодня» — пастельная обводка вместо насыщенного акцента: тот же
   индиго, осветлённый до --accent-ring. Обводка идёт снаружи кружка
   (offset 1px), поэтому её видно и в тот день, когда она над голубой
   заливкой «занятие». */
.cal-grid .d.today { outline: 1px solid var(--accent-ring); outline-offset: 2px; }

/* День, когда взято новое звание: кружок залит золотом целиком — тот же
   приём, что у плитки взятого звания на главной. Правило стоит после
   «занятия» намеренно: у дня звания стоят оба класса (это ведь и день
   занятия), а при равной силе правил побеждает нижнее. */
.cal-grid .d.rank {
  background: var(--gold);
  color: var(--gold-deep);
  box-shadow: inset 0 0 0 2px var(--gold-deep);
  font-weight: 700;
}

/* Звёздочка внутри кружка, в правом верхнем углу. Раньше она висела
   снаружи и попадала в щель между своим числом и соседним — звезду
   9-го числа читали как звезду 10-го. Кружки стоят вплотную, поэтому
   внутри своего кружка — единственное однозначное место. Кружка-подложки
   у звезды больше нет: она лежит на золоте, и тёмно-коричневый значок
   даёт на нём 7.1:1 — подложка была нужна только против небесной заливки.
   Отступы подобраны так, чтобы звезда не касалась обводки: иначе два
   тёмно-коричневых пятна сливаются и звезда читается как зазубрина на
   кольце. Кружок дня не всегда одного размера (39 px на широком экране,
   44 px на узком), поэтому отступы взяты с запасом по большему кружку.
   Число при этом остаётся ровно по центру, как у всех дней. */
.cal-grid .d .star {
  position: absolute;
  top: 6px;
  right: 8px;
  font-size: 10px;
  line-height: 1;
  color: var(--gold-deep);
}

.cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 12px 0 0;
  font-size: 12.5px;
  color: var(--muted);
}

.cal-legend .key { display: inline-flex; align-items: center; gap: 6px; }

.cal-legend .sw { width: 14px; height: 14px; border-radius: 50%; flex: none; }

.cal-legend .sw.study {
  background: var(--sky);
}

.cal-legend .sw.today {
  background: #fff;
  box-shadow: inset 0 0 0 1px var(--accent-ring);
}

.cal-legend .sw.star {
  background: var(--gold);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gold-deep);
  font-size: 9px;
  line-height: 1;
  font-weight: 800;
}

.cal-sum { margin: 10px 0 0; font-size: 13px; color: var(--muted); }
.cal-sum b { color: var(--ink); }

/* ===== Звание ===== */
/* Все 11 ступеней видны сразу: пройденные — небесные с «✓», текущая
   залита золотом, будущие — притушённые, «недоступные». Следующую
   ступень отдельно не выделяем: единственная награда в списке — текущее
   звание. Цвет не единственная подсказка: у пройденных стоит «✓», у
   будущих — серая заливка и обесцвеченные смайлики, а сколько слов
   осталось, подписано под полоской. */
.rank-title {
  font-size: 23px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 12px;
  text-align: center;
}

.ranks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
  margin: 0 0 2px;
  padding: 0;
}

.ranks li {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  white-space: nowrap;
  padding: 4px 11px;
  border-radius: var(--r-pill);
  font-size: 12.5px;
}

.ranks li .chk { font-weight: 800; color: var(--sky-ink); }

.ranks li.done {
  background: var(--sky-soft);
  color: var(--sky-ink);
  font-weight: 700;
  box-shadow: inset 0 0 0 1px rgba(15, 107, 138, 0.28);
}

.ranks li.now {
  background: var(--gold);
  color: var(--gold-deep);
  font-weight: 800;
  box-shadow: inset 0 0 0 1px var(--gold-ring);
}

/* Будущие ступени — «недоступные»: плоская серая заливка вместо белой
   пилюли, тихий серый текст, обесцвеченные смайлики. Раньше следующая
   ступень выделялась мягким золотом с пунктиром — теперь её не выдаём:
   список обещал сразу две награды, текущую и следующую, хотя получить
   можно только одну.
   grayscale() гасит цвет, но сохраняет яркость, а с ней и контраст:
   --muted к --track — 5.1:1, текст читается. */
.ranks li.locked {
  background: var(--track);
  color: var(--muted);
  filter: grayscale(1);
}

/* Полоска пути до следующего звания. Показывает НЕ общий прогресс, а
   отрезок от текущего звания до следующего: получил звание — полоска
   пустая, прошёл отрезок — звание сменилось. Поэтому её 100 % и процент
   в круге — про разное, числа не дублируются. Заливка золотая, как у
   текущего звания, и с тёмной обводкой: золото к дорожке даёт 1.9:1,
   без обводки полоску почти не видно. */
.rank-bar {
  position: relative;
  height: 18px;
  margin: 12px 0 0;
  background: var(--track);
  border-radius: var(--r-pill);
}

.rank-fill {
  height: 100%;
  width: 0;
  background: var(--gold);
  border-radius: var(--r-pill);
  transition: width 0.4s ease;
}

.rank-bar .lbl {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 800;
  color: var(--gold-deep);
  font-variant-numeric: tabular-nums;
}

/* Сколько осталось до следующего звания */
.rank-next {
  margin: 8px 0 0;
  font-size: 12.5px;
  color: var(--muted);
}

/* «Лучший результат» — справка о рекорде, а не текущее состояние,
   поэтому отделена чертой. Показывается только при понижении звания. */
.rank-best {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--hair);
  font-size: 13px;
  color: var(--muted);
}

/* ===== Общий прогресс: круг и плитки-расшифровка ===== */
.prog {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 26px;
  align-items: center;
}

.prog-r .last10 { margin: 12px 0 0; }

.ring-wrap {
  position: relative;
  width: 158px;
  height: 158px;
  flex: none;
}

.ring { display: block; width: 100%; height: 100%; }
.ring circle { fill: none; }
.ring-track { stroke: var(--track); stroke-width: 16; }
/* Доли круга: дуга с круглыми концами, толщина — как у дорожки.
   Короткая доля дугой быть не может (у дуги меньше толщины длины не
   выходит), поэтому вместо неё рисуется «зёрнышко» — эллипс, у которого
   поперёк круга ровно ширина дорожки (16), а вдоль — честная длина доли.
   Растёт зёрнышко тоже вдоль круга, как дуга, и на 16 единицах становится
   кругом — ровно тем же, что закруглённый конец дуги. Размеры задаёт
   updateRing(). */
.ring-fill { stroke-width: 16; stroke-linecap: round; }
.ring-fill.sky { stroke: var(--sky); }
.ring-fill.lilac { stroke: var(--lilac); }
.ring-dot { stroke: none; }
.ring-dot.sky { fill: var(--sky); }
.ring-dot.lilac { fill: var(--lilac); }

.ring-mid {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
}

.ring-pct {
  font-size: 29px;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.ring-sub {
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Плитки цифр. Круг мягкий — обводки у долей нет, поэтому подписи
   написаны словами, а цвет плитки лишь напоминает, про какую долю речь:
   цвет не единственная подсказка. */
.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.tile { border-radius: var(--r-tile); padding: 14px 16px; }

.tile .v {
  display: block;
  font-size: 23px;
  font-weight: 800;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

.tile .c { display: block; font-size: 12.5px; margin-top: 2px; }

.tile.t-sky { background: var(--sky-soft); }
.tile.t-sky .v { color: var(--sky-ink); }
.tile.t-sky .c { color: var(--sky-cap); }

.tile.t-lilac { background: var(--lilac-soft); }
.tile.t-lilac .v { color: var(--lilac-ink); }
.tile.t-lilac .c { color: var(--lilac-cap); }

.tile.t-gold { background: var(--gold-soft); }
.tile.t-gold .v { color: var(--gold-ink); }
.tile.t-gold .c { color: var(--gold-cap); }

/* Точка цвета — та же доля на круге: плитки работают расшифровкой. */
.tile .c .lgd {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
  vertical-align: -1px;
  margin-right: 6px;
}

.tile .c .lgd.sky { background: var(--sky); }
.tile .c .lgd.lilac { background: var(--lilac); }

/* Последние 10 ответов: кружки со знаком внутри. Знак нужен потому, что
   цветом «верно» и «ошибку» различать нельзя — дальтоники их не разделят. */
.last10 {
  font-size: 13px;
  color: var(--muted);
}

.dots {
  display: inline-flex;
  gap: 5px;
  vertical-align: middle;
  margin-left: 6px;
}

.dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  vertical-align: middle;
  font-size: 11px;
  font-weight: 800;
  font-style: normal;
  line-height: 1;
}

.dot.yes {
  background: var(--sky);
  color: var(--sky-ink);
}

/* Кружки «последние 10 ответов» на главной: знак «✓» / «✗» на цветной
   заливке. Розовая — на шаг плотнее, чем --pink-soft: на бледной заливке
   кружок не отличался бы от фона карточки. */
.dot.no {
  background: var(--pink-mid);
  color: var(--pink-deep);
}

.dot.empty { background: var(--track); }

/* ===== Резервная копия ===== */
/* Диалог после выбора файла: сравнение чисел и три кнопки. Прогресс
   меняется только по нажатию кнопки, поэтому блок не мешает просто
   посмотреть, что лежит в файле. */
.import-box {
  margin-top: 14px;
  padding: 12px 14px;
  background: var(--track);
  border: none;
  border-radius: var(--r-tile);
}

.import-compare {
  font-size: 14px;
  margin-bottom: 10px;
}

/* Строка-итог: что загрузилось или почему файл не подошёл */
.import-status {
  margin-top: 12px;
  font-size: 13px;
  color: var(--muted);
}

/* Пустая строка не должна оставлять отступ */
.import-status:empty { margin-top: 0; }

.import-status.ok  { color: var(--sky-ink); font-weight: 700; }
.import-status.err { color: var(--pink-deep); font-weight: 700; }

/* ===== Иконка «i» и подсказка в блоке «Общий прогресс» =====
   Заголовок становится флексом: текст слева, иконка справа.
   Обёртка .info-wrap — точка отсчёта для карточки подсказки
   (position: relative), поэтому карточка висит ровно под иконкой. */
.panel-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.info-wrap {
  position: relative;
  flex: none;
}

.info-btn {
  width: 24px;
  height: 24px;
  padding: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 15px;
  font-style: italic;
  line-height: 1;
  color: var(--accent-ink);
  background: var(--track);
  border: 1px solid var(--hair);
  border-radius: 50%;
  cursor: pointer;
}

.info-btn:hover { background: var(--accent-soft); }

/* Иконка открыта — залита синим, как активная кнопка */
.info-btn[aria-expanded="true"] {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}

.info-pop {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 5;
  /* Ширина ограничена: на узком экране карточка не должна
     вылезать за левый край страницы и давать прокрутку */
  width: min(290px, calc(100vw - 80px));
  padding: 12px 14px;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--muted);
  background: var(--card);
  border: 1px solid var(--hair);
  border-radius: var(--r-tile);
  box-shadow: 0 10px 26px rgba(60, 55, 110, 0.14);
}

.info-line { display: block; }
.info-line + .info-line { margin-top: 8px; }
.info-pop b { color: var(--ink); }

/* ===== Экран тренировки: выбор категории и режима ===== */
.field { margin-bottom: 14px; }

.field .lbl {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: 6px;
}

/* Список категорий. Своя стрелка вместо системной: у системной вид
   зависит от браузера, а тут нужен тихий серый уголок в цвет палитры.
   Стрелка нарисована прямо в стилях (data:image), поэтому лишнего файла
   и запроса к серверу не появляется. */
.select {
  width: 100%;
  appearance: none;
  border: none;
  cursor: pointer;
  background: var(--card) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' fill='none' stroke='%235f6474' stroke-width='2' stroke-linecap='round'/></svg>") no-repeat right 16px center;
  color: var(--ink);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  border-radius: var(--r-btn);
  padding: 14px 40px 14px 16px;
  box-shadow: var(--sh-soft);
}

/* Плитки режима: выбранная залита мягким акцентом с обводкой, поэтому
   видно, что сейчас включено. Для читалки с экрана — aria-pressed. */
.modes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.mode {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: flex-start;
  background: var(--card);
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  border-radius: var(--r-tile);
  padding: 16px;
  box-shadow: var(--sh-soft);
}

.mode .ic { font-size: 22px; }
.mode .nm { font-size: 15px; font-weight: 800; color: var(--ink); }
.mode .ds { font-size: 12.5px; color: var(--muted); }

.mode.on {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.mode.on .nm { color: var(--accent-ink); }

/* Кнопка под полями: своя строка с отступом сверху */
.btn-row { margin-top: 18px; }

.mode-buttons {
  display: flex;
  gap: 10px;
}

/* ===== Кнопки =====
   Обычная кнопка — белая карточка с мягкой тенью, главная — залита
   акцентом. «Знаю» и «Не знаю» на карточке — светлые заливки с обводкой:
   они не спорят с главной кнопкой и сразу показывают, где какая. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 20px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  border: none;
  border-radius: var(--r-btn);
  cursor: pointer;
  background: #fff;
  color: var(--ink);
  box-shadow: var(--sh-soft);
  transition: transform 0.08s ease;
}

.btn:active { transform: scale(0.98); }

/* Кнопка, которую прячут атрибутом hidden («Знаю» и «Не знаю» на карточке
   появляются только после переворота). Без этой строки hidden не работает:
   `display: inline-flex` выше сильнее служебных стилей браузера. Такая же
   строка есть у `.hello` и `.session-over` — у любого блока со своим
   `display`, который прячется атрибутом, она обязательна. */
.btn[hidden] { display: none; }

/* Кнопка «Свернуть/Развернуть все», когда сворачивать нечего (пустой список
   или поиск без находок): она остаётся на месте, но нажать её нельзя —
   обычный атрибут disabled. Он же убирает кнопку из обхода Tab и из чтения
   экранным диктором, а нажатие браузер просто не передаёт обработчику.
   Притушённый вид тут обязателен: без него кнопка выглядела бы рабочей.
   Из раскладки кнопка не уходит: пропадая, она укоротила бы шапку экрана
   на свою высоту (41 px) и всё под ней прыгало бы вверх — именно это и
   происходило при вводе слова, которого нет в базе. */
.btn:disabled {
  background: var(--track);
  color: var(--muted);
  box-shadow: none;
  cursor: default;
}

/* У неактивной кнопки нет и «нажатия»: иначе она проседает под курсором
   и снова выглядит живой. */
.btn:disabled:active { transform: none; }

.btn-primary {
  background: var(--accent);
  color: #fff;
  box-shadow: var(--sh-btn);
}

.btn-primary:hover { background: var(--accent-ink); }

.btn-correct {
  background: var(--sky-soft);
  color: var(--sky-ink);
  box-shadow: inset 0 0 0 2px var(--sky-ink);
}

.btn-correct:hover { background: #dcf1fb; }

.btn-wrong {
  background: var(--pink-soft);
  color: var(--pink-ink);
  box-shadow: inset 0 0 0 2px var(--pink-deep);
}

.btn-wrong:hover { background: #fbdfeb; }

.btn-link {
  background: rgba(255, 255, 255, 0.7);
  color: var(--accent-ink);
  padding: 9px 15px;
  font-size: 14px;
}

.hint {
  margin-top: 12px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.5;
}

/* Пояснения к плиткам «Словарного запаса»: список, каждый пункт
   с новой строки. Отступ слева — место для маркеров (сброс стилей
   в начале файла убирает у списка поля и отступы). */
.hint-list { padding-left: 18px; }

.hint-list li + li { margin-top: 4px; }

/* ===== Прогресс по категориям =====
   Строки в один столбец: сверху то, что уже подтянуто. В строке название
   и число выученных, под ними — полоска и процент. */
.cats {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Строка категории — три столбца: название, «выучено из всех», прогресс.
   Ширины заданы так, чтобы столбцы во всех строках совпадали: у числа и
   процента есть наименьшая ширина, а полоса занимает одну и ту же долю
   строки. Без этого «0 / 143» и «10 / 10» получали бы разную ширину, и
   полосы в строках начинались бы с разных мест — сравнивать их нельзя. */
.cat {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) auto minmax(0, 1fr);
  gap: 0 14px;
  align-items: center;
  padding: 9px 4px;
  border-radius: 12px;
}

.cat + .cat { border-top: 1px solid var(--hair); }

/* Подписи столбцов над списком. Сетка и отступы — те же, что у .cat:
   подпись обязана стоять ровно над своим столбцом. */
.cat-head {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) auto minmax(0, 1fr);
  gap: 0 14px;
  padding: 0 4px 8px;
  border-bottom: 1px solid var(--hair);
  font-size: 11.5px;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* «Выучено» стоит над числами и прижато к правому краю, как они. */
.cat-head span:nth-child(2) {
  min-width: 64px;
  text-align: right;
}

.cat .nm {
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Наименьшая ширина: без неё столбец сжимался бы по длине числа, и
   полоса у каждой строки начиналась бы со своего места. */
.cat .val {
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 64px;
  text-align: right;
}

.cat .line {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.cat .track {
  flex: 1;
  min-width: 0;
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--track);
}

.cat .track i {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--violet);
}

.cat .pct {
  font-size: 12px;
  font-weight: 800;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  min-width: 38px;
  text-align: right;
}

/* ===== Экран занятия: карточки и тест ===== */
/* Занятие идёт без меню: слева осталась бы колонка 212px, а карточке
   нужна ширина. Класс `focus` на <body> ставит showScreen, когда открыт
   экран занятия или итогов. */
body.focus { grid-template-columns: minmax(0, 1fr); }
body.focus .rail { display: none; }
body.focus main { max-width: 560px; margin: 0 auto; width: 100%; }

.session-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 0 4px 16px;
}

/* Счётчик слов — пилюля на градиенте: прозрачно-белая подложка нужна,
   иначе тёмный текст на цветном фоне читается хуже. */
.session-count {
  background: rgba(255, 255, 255, 0.8);
  border-radius: var(--r-pill);
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 800;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  box-shadow: var(--sh-soft);
}

/* Статус слова («изучается: 1 из 3 подряд»). На карточке он лежит на
   градиенте, поэтому это пилюля с полупрозрачной подложкой; в тесте —
   внутри белой карточки, и подложка там не нужна. */
.card-status, .quiz-status {
  display: block;
  width: fit-content;
  padding: 5px 13px;
  border-radius: var(--r-pill);
  font-size: 12.5px;
  font-weight: 700;
}

.card-status {
  margin: 0 auto 12px;
  background: rgba(255, 255, 255, 0.78);
  color: var(--ground-ink);
  box-shadow: var(--sh-soft);
}

.quiz-status {
  margin: 0 auto 12px;
  color: var(--muted-soft);
}

/* Категория слова — строка над словом, а не бейдж в углу: в прототипе
   она часть карточки, набранная тихим прописным шрифтом. */
.card-cat {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted-soft);
}

/* Карточка. position: relative нужен слою искр: он растягивается по
   карточке (inset: 0) и вылетает за её края. */
.flashcard {
  position: relative;
  background: var(--card);
  border: none;
  border-radius: var(--r-card);
  padding: 34px 22px;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--sh-card);
  min-height: 230px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}

.card-prompt {
  margin: 0;
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.card-hint {
  font-size: 12.5px;
  color: var(--muted-soft);
  margin-top: 14px;
}

/* Ответ отбит линией от вопроса: так видно, что карточка перевернулась */
.card-answer {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--hair);
  animation: fadein 0.3s ease;
}

.answer-main {
  margin: 0;
  font-size: 24px;
  color: var(--accent-ink);
  font-weight: 800;
}

.answer-sub {
  margin: 4px 0 0;
  font-size: 14px;
  color: var(--muted);
}

@keyframes fadein {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.card-buttons {
  display: flex;
  gap: 10px;
  margin-top: 16px;
}

.card-buttons .btn { flex: 1; padding: 14px; font-size: 16px; }

/* Тест. position: relative — по той же причине, что у карточки:
   слой искр растягивается по блоку теста. */
.quiz-box {
  position: relative;
  background: var(--card);
  border-radius: var(--r-card);
  padding: 24px 22px;
  box-shadow: var(--sh-card);
}

/* В тесте статус лежит внутри белой карточки — подложка не нужна */
.quiz-box .quiz-status { color: var(--muted-soft); }

.quiz-question {
  margin: 0 0 18px;
  text-align: center;
  font-size: 32px;
  font-weight: 800;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.quiz-sub {
  display: block;
  margin-top: 4px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}

/* Четыре варианта в столбик, а не в две колонки: длинные переводы в
   узкой колонке ломаются на строки, и варианты становятся разной высоты. */
.quiz-options {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

/* Вариант ответа: знак «✓» / «✗» стоит СЛЕВА, а место под него отведено
   заранее и одинаковое во всех строках. Без этого в момент ответа текст
   всех четырёх строк прыгнул бы вправо на ширину знака. */
.option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  text-align: left;
  border: none;
  border-radius: var(--r-tile);
  background: var(--card);
  cursor: pointer;
  box-shadow: inset 0 0 0 2px var(--hair);
  transition: box-shadow 0.15s;
}

.option:hover { box-shadow: inset 0 0 0 2px #cdd2ea; }

/* Верный и неверный вариант — светлые заливки с обводкой: так видно
   и цвет, и то, что это ответ, даже если цвет не различается. Знак
   «✓» или «✗» слева добавляет ещё одну подсказку. */
.option.right {
  background: var(--sky-soft);
  color: var(--sky-ink);
  box-shadow: inset 0 0 0 2px var(--sky-ink);
}

.option.mistake {
  background: var(--pink-soft);
  color: var(--pink-ink);
  box-shadow: inset 0 0 0 2px var(--pink-deep);
}

/* Слот под знак ответа. До ответа он не пустует: в нём стоит приглушённый
   кругляшок — прозрачное кольцо, как у невыбранной радиокнопки. От этого
   список вариантов сразу читается как «выбери один», а место перед словом
   не выглядит дырой. Контраст у кольца низкий намеренно: это украшение,
   а не подсказка — несёт её знак. */
.option .mk {
  flex: 0 0 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 13px;
  box-shadow: inset 0 0 0 2px var(--ghost-line);
}

/* Ответ дан: кругляшок уходит, знак встаёт на его место крупнее — иначе
   в кольце он теряется. На неотвеченных строках кругляшки остаются. */
.option.right .mk,
.option.mistake .mk {
  box-shadow: none;
  font-size: 17px;
}

.option:disabled { cursor: default; }

/* ===== Экран итогов ===== */
.results-panel { text-align: center; }

.results-panel h2 {
  font-size: 21px;
  margin-bottom: 6px;
}

/* Итог занятия — не цифра крупнее прочих, а акцентная строка: главное
   здесь список слов под ней. */
.results-summary {
  font-size: 15px;
  font-weight: 700;
  color: var(--accent-ink);
  margin-bottom: 16px;
}

/* Список шире карточки на 12px с каждой стороны: у подсвеченной строки
   появляются поля, а текст остаётся на той же вертикали, что у соседей. */
.results-list {
  list-style: none;
  text-align: left;
  margin: 0 -12px 20px;
}

.results-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 14px;
  border-bottom: 1px solid var(--hair);
  font-size: 14px;
}

/* min-width: 0 — чтобы на узком экране длинная строка переносилась,
   а не вылезала за край карточки */
.result-text { flex: 1; min-width: 0; }

/* Выученное слово подсвечивает ВСЮ строку, а не кружок справа.
   Подпись «выучено» рядом остаётся: цвет — не единственная подсказка. */
.results-list li.learned {
  background: var(--sky-soft);
  box-shadow: inset 0 0 0 1px rgba(15, 107, 138, 0.16);
  border-bottom-color: transparent;
}

/* На небесном фоне серый #6f7488 даёт 4.24:1 — мало. Подпись берёт
   небесные чернила: и контраст выше, и смысл тот же — «выучено». */
.results-list li.learned .result-status {
  color: var(--sky-ink);
  font-weight: 700;
}

.results-list li:last-child { border-bottom: none; }

.results-list .mark-yes { color: var(--sky-ink); font-weight: 800; }
.results-list .mark-no  { color: var(--pink-deep); font-weight: 800; }

.result-status {
  color: var(--muted-soft);
  font-size: 12px;
}

/* Кружок «выучено» у правого края строки словаря. Смысл тот же, что у
   подписи «выучено»: цвет небесный — как у дня занятия. Кольцо, а не
   сплошная заливка: так кружок читается как значок, а не как кнопка. */
.learned-dot {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--sky);
  box-shadow: inset 0 0 0 2px var(--sky-ink);
}

/* ===== Словари ===== */
.dict-row {
  display: flex;
  /* по базовой линии: транскрипция в скобках мельче слова, и по центру
     она «прыгала» бы относительно строки перевода справа */
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 9px 2px;
  border-bottom: 1px solid var(--hair);
  font-size: 14px;
}

.dict-row:last-child { border-bottom: none; }

/* overflow-wrap: длинное английское слово без пробелов иначе вылезает
   за край карточки на узком экране */
.dict-en { font-weight: 700; overflow-wrap: anywhere; }

.dict-tr { font-weight: 400; color: var(--muted-soft); font-size: 13px; }

.dict-ru { color: var(--muted); font-size: 13.5px; }

/* ===== Экран «Все слова» ===== */
/* Поле поиска выглядит как поле выбора категории на экране тренировки
   (.select): та же белая таблетка, тот же радиус и мягкая тень. Отличие
   одно — своя стрелка у select не нужна, а справа в поле место под
   крестик очистки. */
.search { position: relative; }

.search-input {
  width: 100%;
  box-sizing: border-box;
  border: none;
  background: var(--card);
  color: var(--ink);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  border-radius: var(--r-btn);
  padding: 14px 44px 14px 16px;   /* справа место под крестик */
  box-shadow: var(--sh-soft);
}

.search-input::placeholder { color: var(--muted-soft); font-weight: 400; }

/* Крестик очистки стоит внутри поля, у правого края. Отступ у поля справа
   (44px) задан ровно под него — иначе текст запроса уходил бы под крестик. */
.search-clear {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  border: none;
  background: none;
  cursor: pointer;
  color: var(--muted-soft);
  font-family: inherit;
  font-size: 15px;
  line-height: 1;
  padding: 6px 8px;
  border-radius: 50%;
}

.search-clear:hover { color: var(--ink); }

/* Панель с поиском: она держит одно поле, поэтому у .field отступ снизу
   тут лишний — от панели до карточек есть свой. А вот нижний отступ самой
   панели трогать нельзя: при 6 px поле стояло вплотную к нижнему краю, и
   на скруглении 26 px это читалось как «граница закругляется слишком
   рано». Держим те же 20 px, что у .panel, — тогда низ панели выглядит
   так же, как у остальных блоков. */
.search-panel .field { margin-bottom: 0; }

/* Отступ от панели с поиском до первой карточки — тот же 14 px, что между
   карточками. Общее правило «.panel + .panel» тут не работает: сосед
   панели — не карточка, а контейнер списка #allWordsList, а карточки
   лежат уже внутри него, и без этого правила панель поиска прилипала
   к первой карточке. */
.search-panel + #allWordsList { margin-top: 14px; }

/* Карточка категории и её заголовок-кнопка — общие для трёх экранов:
   «Выученные слова», «Все слова» и «Сложные слова». Отступ между
   карточками даёт общее правило «.panel + .panel» — они сёстры внутри
   #learnedList, #allWordsList, #difficultList и #allTimeList.

   Полоски прогресса и «выучено из 143» в заголовке нет намеренно: числа
   по категориям живут в таблице на экране «Тренировка», а одно число
   в двух местах только расходится. Здесь в заголовке только своё —
   сколько слов внутри карточки (у «Выученных» — выучено, у «Всех слов» —
   всего в категории, у «Сложных» — сколько слов и сколько ошибок): это
   видно и когда карточка свёрнута, и меняется вместе с содержимым. */
.dict-card { padding: 12px 18px; }

/* Заголовок-кнопка сворачиваемой карточки — один на все три словаря:
   «Выученные слова», «Все слова» и «Сложные слова». 17 px — как заголовок
   блока (h2): выше строки слова (14 px), ниже заголовка экрана (23 px).
   Цвет — синий акцентный, как в макете редизайна (notes/редизайн/
   прототип-пастель v4.html, раздел 7): название категории отличается от
   слов под ним не только размером, но и цветом.
   По базовой линии — чтобы на узком экране, где название переносится,
   стрелка осталась у первой строки, а не уехала по центру.

   Заголовок липнет к верху окна, пока на экране его карточка: поднимается
   вместе с ней и уступает место следующему. Липнет он в пределах своей
   карточки, поэтому у верха окна стоять может только один заголовок —
   тот, чьи слова под ним.
   Белый фон обязателен: под заголовок уезжают строки слов, и без фона они
   проступали бы сквозь него. Фон тот же, что у карточки, — в покое
   заголовка не видно вовсе.
   Верхний отступ карточки (12 px) заголовок забирает себе: отрицательным
   полем снимает и своим отступом возвращает на место. Так в покое вид
   не меняется ни на пиксель, а прилипший заголовок не липнет к самому
   краю окна — над названием остаётся та же воздушная полоса.
   Боковых полей нет намеренно: коробка заголовка совпадает со строками
   слов, и вбок от него ничего выглядывать не может.
   Верхние углы скруглены — и ровно на столько, на сколько надо: коробка
   заголовка поднята к верхнему краю карточки, и прямыми углами белый фон
   залезал на её скруглённый угол — в углу карточки появлялась ступенька.
   Радиус = радиус карточки (--r-card, 26 px) минус её боковой отступ
   (18 px, см. .dict-card выше): тогда дуга угла заголовка ложится точно на
   дугу угла карточки и ничего не выступает. Меняешь боковой отступ
   карточки — поменяй и это число. */
.dict-toggle {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  margin-top: -12px;
  padding: 12px 0 0;
  border-top-left-radius: calc(var(--r-card) - 18px);
  border-top-right-radius: calc(var(--r-card) - 18px);
  font-family: inherit;
  font-size: 17px;
  font-weight: 800;
  text-align: left;
  color: var(--accent-ink);
  background: var(--card);
  border: none;
  cursor: pointer;
}

/* Наведение: заголовок и так синий, поэтому цветом наведение не покажешь —
   показываем подчёркиванием. Отступ снизу, чтобы линия не липла к буквам.
   Селектор по последнему куску, а не по всей кнопке: у заголовка два куска —
   стрелка и название, и подчёркивание от родителя легло бы ещё и под
   стрелку (в раскрытом виде она повёрнута — выглядело бы неопрятно). */
.dict-toggle:hover > span:last-child {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Раскрыт — стрелка смотрит вниз: поворот задан правилом ниже, на
   .dict-toggle[aria-expanded="true"]. На «Сложных словах» заголовки те же
   самые, поэтому отдельного правила им не нужно. */

/* Слова под заголовком: отступ, когда карточка раскрыта */
.dict-body { padding-top: 10px; }

/* Прилипший заголовок получает низ: полоску своего фона, тонкую линию под
   ней и мягкую тень. Зачем: под полосу уезжают строки, и без границы
   обрыв строки посреди буквы читается не как прокрутка, а как «слова
   потерялись». Линия ставит границу, тень говорит, что полоса лежит
   сверху, а не вклеена в список.
   Класс is-stuck ставит app.js (updateStuckHeaders) и только тогда, когда
   заголовок действительно стоит у края окна, — в покое ни линии, ни тени
   нет, вид не меняется ни на пиксель.
   Оба слоя нарисованы псевдоэлементами с absolute: они ничего не занимают
   в потоке, поэтому появление линии не сдвигает список и не дёргает
   прокрутку. Полоска тянется вниз на 8 px от коробки заголовка — вместе
   она закрывает строку целиком, а не наполовину, а линия ложится ровно на
   её нижний край. Тень — градиент от тёмного к прозрачному под линией:
   так она затемняет верх подъезжающей строки, а не накрывает её плашкой. */
.dict-toggle.is-stuck::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -8px;
  height: 8px;
  background: var(--card);
  border-bottom: 1px solid var(--hair);
}

.dict-toggle.is-stuck::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  /* Тень начинается не «под линией», а на пиксель выше — внахлёст с её
     нижним краем. Полоска с линией кончается на 8 px от коробки заголовка
     (bottom: -8px), и при top: calc(100% + 9px) между линией и тенью
     оставался ровно пиксель белого — на экране с масштабом он виден как
     щель. Внахлёст эту щель закрывает при любом масштабе. */
  top: calc(100% + 7px);
  height: 10px;
  background: linear-gradient(to bottom, rgba(22, 24, 42, 0.1), rgba(22, 24, 42, 0));
  pointer-events: none;
}

/* Экран «Сложные слова»: два блока — «сейчас в работе» и «за всё время».
   Блок — не карточка, а подпись над списком карточек категорий, и это
   важно: карточки внутри блока уже есть, и блок-карточка дал бы карточку
   в карточке.
   Подпись набрана как заголовки групп в меню слева (.rail-group): тот же
   тихий серый капс с разрядкой. Громкий заголовок здесь был бы лишним
   уровнем — рядом, через 14 px, стоит синий заголовок карточки, и два
   спорящих заголовка читались бы плохо.
   Цвет — --ground-ink, а не --muted: это текст поверх градиента, у --muted
   на нём не хватает контраста до 4.5:1 (см. описание палитры выше).
   Подпись — flex из-за кнопки «i» справа, и текст подписи поэтому обёрнут
   в <span>: флекс раскладывает по отдельным коробкам каждый элемент, а
   текст до и после него — отдельными кусками, и «( 34 )» разъезжалось на
   зазоры. Одной обёрткой текст снова течёт как обычная строка, а gap
   работает только между ним и кнопкой. */
.group-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 18px 6px 4px;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ground-ink);
}

/* Первая подпись экрана стоит под шапкой, а та уже дала отступ снизу —
   18 px тут сложились бы с ним в двойной зазор. */
.group-label:first-child { margin-top: 4px; }

/* Пояснение под подписью — тише самой подписи, как .hint в карточках.
   Отступ снизу отделяет текст от первой карточки: у неё своего верхнего
   поля нет (заголовок забирает его себе, см. .dict-toggle). */
.group-hint {
  margin: 0 6px 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ground-ink);
  max-width: 660px;
}

.toggle-arrow {
  font-size: 13px;
  line-height: 1;
  color: var(--accent-ink);
  transition: transform 0.15s;
}

/* Раскрыт — стрелка поворачивается вниз. */
.dict-toggle[aria-expanded="true"] .toggle-arrow { transform: rotate(90deg); }

/* Строка списка сложных слов: справа перевод и число ошибок.
   flex: none — группа не сжимается, сжимается слово слева (оно и
   переносится). text-align: right — на случай, если подписи встанут
   в две строки, ровнять их по правому краю. */
.dict-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  text-align: right;
}

.dict-wrong {
  font-size: 12px;
  font-weight: 700;
  color: var(--pink-ink);
  background: var(--pink-soft);
  border: none;
  border-radius: var(--r-pill);
  padding: 3px 9px;
  white-space: nowrap;
}

/* Кнопки итогов делят строку поровну — как в прототипе */
.results-panel .mode-buttons .btn { flex: 1 1 auto; }

/* ===== Эффект «слово выучено»: искры вокруг карточки =====
   Слой искр создаёт JS (функция showSparks) и сам убирает через 1.1 с.
   Слой растянут по карточке, клики сквозь него проходят, искры вылетают
   за края карточки. Направление полёта каждой искры задаётся переменными
   --dx / --dy из JS. */
.sparks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.sparks i {
  position: absolute;
  left: 50%;
  top: 50%;
  font-size: 18px;
  font-style: normal;
  color: var(--gold);
  animation: spark-fly 0.7s ease-out forwards;
}

@keyframes spark-fly {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
  30%  { opacity: 1; }
  to   {
    opacity: 0;
    transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy)))
               scale(1.1);
  }
}

/* Бейдж статуса в момент, когда слово стало выученным */
.card-status.learned,
.quiz-status.learned {
  color: var(--sky-ink);
  background: var(--sky-soft);
  box-shadow: var(--sh-soft);
}

/* Если в системе включено «Уменьшить движение» — искр не показываем,
   и веер лучей в поздравлении не крутим: он остаётся как был, ровным.
   Звёзды в поздравлении тоже замирают — стоят на своих местах и горят
   ровно. */
@media (prefers-reduced-motion: reduce) {
  .sparks { display: none; }
  .hello::before { animation: none; }
  .hello .stars i { animation: none; }
}

/* ===== Статистика: сегодня, история званий, столбики по дням, рекорды ===== */

/* Плиток в блоке «Сегодня» четыре, а не три, как на главной. Отдельный
   класс, а не правка .tiles: на главной число столбцов менять нечем. */
.tiles-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Плитка без своего цвета: подложка — дорожка, числа обычным цветом.
   Для «верных / ошибок»: это не доля слов, а ответы, свой оттенок врал бы. */
.tile.t-plain { background: var(--track); }
.tile.t-plain .v { color: var(--ink); }
.tile.t-plain .c { color: var(--muted); }

/* Переключатель срока (7 / 14 / 30 дней) и вида истории званий:
   таблетки в ряд, выбранная залита белым и подкрашена акцентом. */
.seg {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 16px;
  background: var(--track);
  border-radius: var(--r-pill);
}

.seg button {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--muted);
  padding: 6px 14px;
  border-radius: var(--r-pill);
  cursor: pointer;
}

.seg button:hover { color: var(--ink); }

.seg button.on {
  background: #fff;
  color: var(--accent-ink);
  box-shadow: var(--sh-soft);
}

/* История званий: слева дата, справа взятые звания */
.hists { display: flex; flex-direction: column; gap: 2px; }

.hist {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 4px;
}

.hist + .hist { border-top: 1px solid var(--hair); }

/* Ширина даты задана, чтобы звания начинались в одном месте во всех
   строках: каждая строка — своя сетка, как и в таблице категорий. */
.hist .hw { flex: 0 0 190px; font-size: 13.5px; font-weight: 600; }
.hist .hr { display: flex; flex-wrap: wrap; gap: 6px; }

.hist .rk {
  font-size: 12.5px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--gold-soft);
  color: var(--gold-ink);
}

/* --- графики по дням --- */
.chart + .chart { margin-top: 22px; }
.chart h3 { font-size: 14.5px; margin: 0 0 2px; }
.chart-total { font-size: 12.5px; color: var(--muted); margin: 0 0 10px; }

/* Столбики стоят на общей линии — она и есть ноль. Без неё высота
   столбика «на глаз» не читается: непонятно, от чего отсчёт. */
.bars {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  border-bottom: 1px solid var(--hair);
}

.bar {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

/* .bc — «стакан» столбика. Внутри две заливки от низа: .all — весь
   столбик, .part — новые слова поверх низа. Абсолютное положение нужно,
   чтобы .part не сдвигал .all, а лёг ровно на его нижнюю часть. */
.bar .bc {
  position: relative;
  width: 100%;
  max-width: 26px;
  height: 96px;
}

.bar .bc i {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 5px;
}

.bar .all { background: var(--sky); }
.bar .part { background: var(--lilac); }

/* Столбики времени — одного цвета: у времени долей нет. */
#timeBars .bar .all { background: var(--violet); }

/* Подпись под столбиком. Наименьшая высота нужна неподписанным дням:
   у пустого <span> строка схлопывается, и столбики встают на разной
   высоте — общая линия под ними перестаёт быть общей. */
.bar .bd {
  min-height: 14px;
  font-size: 10.5px;
  line-height: 14px;
  color: var(--muted-soft);
  font-variant-numeric: tabular-nums;
}

/* Сегодняшний день подписан заметнее: по нему сверяются с блоком
   «Сегодня» выше. */
.bar.today .bd { color: var(--accent-ink); font-weight: 800; }

/* Легенда под столбиками: точка того же цвета, что заливка */
.chart .lgd {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
  vertical-align: -1px;
  margin: 0 4px 0 10px;
}

.chart .lgd.sky { background: var(--sky); }
.chart .lgd.lilac { background: var(--lilac); }

/* --- рекорды: подпись слева, значение справа --- */
.recs { display: flex; flex-direction: column; gap: 2px; }

.rec-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 4px;
}

.rec-row + .rec-row { border-top: 1px solid var(--hair); }
.rec-row .rl { font-size: 13.5px; color: var(--muted); }
.rec-row .rv { font-size: 13.5px; font-weight: 700; text-align: right; }

/* Пустой блок: вместо столбиков или истории — одна строка текста */
.empty-note {
  font-size: 13px;
  color: var(--muted);
  margin: 4px 0 0;
}

/* Четыре плитки в ряд требуют ширины: «12 ч 20 мин» в 23 px — это 128 px
   плюс запас. Ниже 900 px панель уже́, и длинное время ломалось бы на две-
   три строки, раздувая все четыре плитки. Там они встают парами.
   Порог проверен замером: на 900 px текст ещё в одну строку, на 770 — уже
   нет. */
@media (max-width: 900px) {
  .tiles-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ===== Средний экран: главная снова в одну колонку =====
   Правому столбцу (календарь, 342px) на такой ширине уже не хватает
   места, поэтому календарь уходит вниз, под звание. */
@media (max-width: 1150px) {
  .top { grid-template-columns: minmax(0, 1fr); }
}

/* ===== Узкий экран: меню из колонки превращается в полосу сверху =====
   Слева колонка шириной 212px на узком экране съела бы половину места,
   поэтому сетка страницы становится одноколоночной, а меню — полосой
   с горизонтальной прокруткой: пункты не сжимаются, а уезжают вправо. */
@media (max-width: 760px) {
  body {
    grid-template-columns: minmax(0, 1fr);
    padding: 12px;
  }

  .rail {
    position: static;
    /* Здесь меню — горизонтальная полоса сверху, а не колонка слева.
       Высоту в экран брать нельзя: полоса растянулась бы на весь экран. */
    min-height: 0;
    display: flex;
    gap: 6px;
    overflow-x: auto;
    padding: 8px;
    border-radius: 18px;
  }

  /* Название тренажёра и заголовки групп в полосе только мешают —
     остаются одни пункты меню */
  .rail .brand,
  .rail-group { display: none; }

  /* display: contents — обёртка <nav> перестаёт быть отдельной коробкой,
     и её пункты встают в общий ряд полосы */
  .rail nav { display: contents; }

  /* flex: 0 0 auto — иначе браузер сжимает пункты по ширине полосы,
     и подписи наезжают друг на друга. Пусть лучше полоса прокручивается. */
  .rail a { flex: 0 0 auto; padding: 8px 12px; font-size: 13px; }

  .app-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }

  .app-head h1 { font-size: 20px; }
  .mascot { height: 64px; }

  /* Плитки режима встают друг под друга: в две колонки подписи
     «вспоминаешь сам, потом проверяешь» ломаются на три строки. */
  .modes { grid-template-columns: minmax(0, 1fr); }

  /* Строка словаря встаёт столбиком: слово с транскрипцией сверху,
     перевод и число ошибок — под ним. В строку они уже не помещаются. */
  .dict-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
  }

  .dict-right { text-align: left; }

  /* Статистика: дата перестаёт быть колонкой фиксированной ширины —
     190px здесь съели бы половину строки, а звания всё равно уезжали бы
     вниз. Плитки в две пары заданы выше, у 900 px. */
  .hist { flex-direction: column; align-items: flex-start; gap: 6px; }
  .hist .hw { flex: 0 0 auto; }
}

/* ===== Телефон ===== */
@media (max-width: 480px) {
  /* На тесном экране три столбца не помещаются: полоса уходит на вторую
     строку под название и число — как было до перехода на три столбца.
     Подписи шапки прячем: они выравнивались по столбцам, которых здесь
     уже нет, и висели бы над чем попало. */
  .cat {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 4px 10px;
  }

  .cat .line { grid-column: 1 / -1; }
  .cat .val { min-width: 54px; }
  .cat .pct { min-width: 34px; font-size: 11.5px; }
  .cat-head { display: none; }

  .card-prompt { font-size: 26px; }
  .quiz-question { font-size: 24px; }
  .mode-buttons { flex-direction: column; }

  /* Статистика на телефоне: столбиков больше, они тоньше, поэтому и
     расстояние между ними меньше; высоту графика тоже убавляем, иначе
     экран занимает один график. */
  .bars { gap: 2px; }
  .bar .bc { height: 72px; max-width: 20px; }
  .tiles-4 .tile .v { font-size: 19px; }
  .seg button { padding: 6px 10px; font-size: 12.5px; }
}

/* ===== Табличка «Занятие завершено» ===== */
/* Накрывает весь экран, когда сервер остановлен (в приложении нажали
   «Завершить»): продолжать занятие без сервера нельзя — страница не
   обновится и заново не откроется. Пока табличка на экране, все клики
   достаются ей, а не тренажёру. */
.session-over {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(48, 44, 92, 0.45);
}

/* Без этой строки `display: flex` перебил бы служебный атрибут `hidden`
   (стили страницы сильнее встроенных стилей браузера) — и табличка
   висела бы на экране всегда */
.session-over[hidden] {
  display: none;
}

.session-over-card {
  width: 100%;
  max-width: 420px;
  padding: 26px 24px;
  text-align: center;
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: 0 18px 44px rgba(22, 24, 42, 0.32);
}

/* Значок над заголовком: мягкий круг в цвете акцента — тот же приём, что
   у медали в поздравлении. С ним табличка читается как часть тренажёра,
   а не как системное окно. */
.session-over-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  margin-bottom: 12px;
  border-radius: 50%;
  background: var(--accent-soft);
  font-size: 24px;
}

.session-over-title {
  font-size: 20px;
  font-weight: 800;
  margin-bottom: 8px;
}

.session-over-text {
  color: var(--muted);
}