/*
  Тема BestTests.ru. Задача 0.10, разделы 3 и 29.1 ТЗ.

  Раздел 3 требует Bootstrap с оформлением по образцу Paper Dashboard:
  его цвета, отступы, радиусы, размеры и шрифты. Тема сделана слоем
  поверх собранного Bootstrap, а не пересборкой из Sass: пересборка
  притащила бы в проект Node и сборочный конвейер ради десятка
  переменных, а обновление Bootstrap перестало бы быть заменой одного
  файла.

  Bootstrap 5.3 генерирует цвета компонентов литералами, а не через
  --bs-primary, поэтому мало переопределить палитру в :root — цвет
  задаётся ещё и переменными самих компонентов (--bs-btn-bg и подобные).
*/

/* --------------------------------------------------------------------
   Шрифт. Раздел 3: локально с сервера, без обращения к внешним CDN;
   кириллица обязательна. Montserrat — шрифт Paper Dashboard.
   Файл переменный, одним начертанием закрывает весь диапазон
   насыщенности, поэтому его хватает одного на подмножество символов.
   -------------------------------------------------------------------- */

@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/montserrat-cyrillic.6fd02dd74afd.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Montserrat";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/montserrat-latin.311d352d9323.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
    U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------
   Палитра раздела 29.1 и базовые токены
   -------------------------------------------------------------------- */

:root {
  /* Основной цвет действия — оранжевый из логотипа. Раньше здесь был
     голубой Paper Dashboard; он остался в рисунках раздела 29 (ленты
     свитков, снежинка заморозки, само название сайта), но интерфейс
     красится тем же цветом, что «.ru» в логотипе.

     Оттенка два, и второй — не украшение. Белым по #FF4400 контраст
     3,46:1 при норме 4,5:1: для заливки кнопки это терпимо и принято,
     для текста — нет. Поэтому #FF4400 берут заливки и рамки, а всё,
     что читается буквами на белом — ссылка, надпись outline-кнопки,
     .text-primary, — берёт #D93800 с его 4,57:1. Третий оттенок нужен
     наведению на ссылку: подсветка обязана отличаться от исходного
     цвета, а не только от фона. */
  --bt-orange: #ff4400;
  --bt-orange-dark: #d93800;
  --bt-orange-darker: #b32e00;

  /* Голубой остаётся в палитре, хотя интерфейс им больше ничего
     не красит: он цвет нарисованной графики, и если оранжевый
     с ней не уживётся, вернуть его ссылкам — одна строка. */
  --bt-blue: #51bcda;
  --bt-blue-dark: #3d9fba;
  --bt-green: #6bd098;
  --bt-green-dark: #55b47e;
  --bt-yellow: #fbc658;
  --bt-yellow-dark: #e0a938;
  --bt-red: #f5593d;
  --bt-red-dark: #d4432a;
  --bt-dark: #66615b;
  --bt-grey: #b9c2cc;
  --bt-light: #f4f3ef;

  /* Серый неработающей кнопки. Решение заказчика от 06.09.2026:
     «сделаем неактивные кнопки серыми» — на всём сайте, вместо
     оранжевого оттенка, о котором договаривались в правке 1.

     Причина видна на скриншоте гостя: Bootstrap гасит нажатую кнопку
     прозрачностью 65%, и на плотном оранжевом это почти незаметно —
     заказчик принял отключённую «Проверить себя» за рабочую. Серый
     от оранжевого отличается не яркостью, а цветом, и спутать их
     нельзя ни на каком экране.

     Заливка тёмная настолько, чтобы белая подпись на ней читалась
     (3,1:1). Неактивные элементы управления от нормы контраста
     освобождены, но нечитаемая кнопка — это не «выключено»,
     это «сломано». */
  --bt-off: #8a929b;
  --bt-off-line: #c3c9d0;

  /* Paper Dashboard: почти круглые кнопки, мягкие тени, тонкие линии. */
  --bt-radius: 0.75rem;
  --bt-radius-pill: 30px;
  --bt-shadow: 0 1px 15px 1px rgba(39, 39, 39, 0.08);
  --bt-shadow-hover: 0 12px 20px -10px rgba(39, 39, 39, 0.16);

  /* Тёмный оттенок, а не заливочный: --bs-primary и --bs-primary-rgb
     раздают цвет утилитам .text-primary и .border-primary, то есть
     буквам на белом. */
  --bs-primary: var(--bt-orange-dark);
  --bs-success: #6bd098;
  --bs-warning: #fbc658;
  --bs-danger: #f5593d;
  --bs-primary-rgb: 217, 56, 0;
  --bs-body-color: #66615b;
  --bs-body-color-rgb: 102, 97, 91;
  --bs-body-font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;
  --bs-body-font-size: 0.95rem;
  --bs-body-font-weight: 400;
  --bs-link-color: var(--bt-orange-dark);
  --bs-link-color-rgb: 217, 56, 0;
  --bs-link-hover-color: var(--bt-orange-darker);
  --bs-border-color: #ddd8d0;
  --bs-border-radius: var(--bt-radius);
  --bs-border-radius-sm: 0.5rem;
  --bs-border-radius-lg: 1rem;
  --bs-focus-ring-color: rgba(255, 68, 0, 0.25);

  /* Bootstrap задаёт цвет вторичной кнопки литералом внутри самого
     компонента, а не через --bs-secondary. Поэтому переопределение
     палитры его не касается, и на странице появляется чужой синий
     #0d6efd рядом с нашим цветом — это видно сразу и выглядит
     как недоделка. */
  --bs-secondary: #66615b;
  --bs-secondary-rgb: 102, 97, 91;

  /* Дорожка полос и колец. Светло-серый Bootstrap (#e9ecef) на нашем
     сером фоне почти не виден: полоса без начала выглядит не пустой,
     а отсутствующей. */
  --bt-track: #e3e0d8;

  /* Лестница «плохо → хорошо», пять ступеней. Решение заказчика
     от 06.09.2026: «В восприятии человека красный — плохо, зелёный —
     хорошо. Середина — это жёлтый. Соответственно прогресс бар должен
     по мере улучшения его показателей эволюционировать от красного
     к зелёному через жёлтый и оттенки соответствующих цветов».

     Фирменного оранжевого в лестнице нет, и это тоже его слово:
     «после жёлтого и перед зелёным вставлять здесь фирменный
     оранжевый не к месту». Между жёлтым и зелёным лежит жёлто-зелёный;
     оранжевый стоит до жёлтого, а не после, — ступень 1.

     Лестницей уже красится тепловая карта класса (16.3) с границами
     20/40/60/80. Цвета вынесены сюда, чтобы карта и полосы брали их
     из одного места: две лестницы означали бы, что одно и то же число
     на двух экранах выглядит по-разному. */
  --bt-scale-0: var(--bt-red);
  --bt-scale-1: #f2874f;
  --bt-scale-2: var(--bt-yellow);
  --bt-scale-3: #a9d17c;
  --bt-scale-4: var(--bt-green);
}

/* Цвет полосы задаётся здесь, а не в :root, и это не стилистика.
   Bootstrap объявляет --bs-progress-bar-bg: #0d6efd прямо в правиле
   `.progress`, а класс сильнее псевдокласса `:root` — объявление
   в палитре до полосы просто не доходит. Полоса владения предметом
   на главной из-за этого была бутстраповской синей всё это время,
   а не нашей: два разных синих на одном экране никто не различал.
   Та же ловушка ждёт всякий компонент со своими переменными, поэтому
   вкладки, пагинация, список и выпадающее меню ниже перекрашены
   тоже по своим селекторам. */
.progress {
  background-color: var(--bt-track);
  --bs-progress-bar-bg: var(--bt-orange);
}

/* Ступени полосы. Класс раздают фильтры `цвет_оценки` (все пять
   ступеней, от красной к зелёной) и `цвет_хода` (только две верхние).

   Селектор из двух классов, потому что Bootstrap красит `.progress-bar`
   собственной переменной, и одноклассовое правило до неё не дотянется. */
.progress-bar.bt-bar--0 { background-color: var(--bt-scale-0); }
.progress-bar.bt-bar--1 { background-color: var(--bt-scale-1); }
.progress-bar.bt-bar--2 { background-color: var(--bt-scale-2); }
.progress-bar.bt-bar--3 { background-color: var(--bt-scale-3); }
.progress-bar.bt-bar--4 { background-color: var(--bt-scale-4); }

body {
  /* Paper Dashboard: страница серая, карточки на ней белые. Белое
     на белом лишает карточку края — она перестаёт читаться как
     отдельный объект, и экран превращается в сплошной список. */
  background: var(--bt-light);
  /* Футер прижат книзу и на короткой странице: раздел 5.4 требует его
     на всех страницах, а «висящий» посередине футер выглядит поломкой. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Карточка остаётся белой независимо от фона страницы: Bootstrap
   берёт её цвет из --bs-body-bg, а тот менять нельзя — от него
   зависят поля ввода, выпадающие списки и модальные окна. */
.card,
.modal-content,
.list-group-item {
  --bs-card-bg: #fff;
  background-color: #fff;
}

/* Прокручиваемое окно, у которого содержимое обёрнуто формой.
   Правка 6, пункт 8: «модальное окно „начать интеллектуальную битву"
   не прокручивается вниз. Из-за этого при появлении тем после выбора
   предмета часть управляющих кнопок уезжает вниз и становится
   недоступной».

   Дело не в прокрутке как таковой, а в разрыве флекс-цепочки.
   `modal-dialog-scrollable` держится на том, что `.modal-content` —
   колонка флексов с ограниченной высотой, а `.modal-body` внутри неё
   растягивается и прокручивается сам. Когда шапка, тело и подвал
   завёрнуты в `<form>` (иначе поля не отправить одним запросом),
   между ними встаёт обычный блок: он не наследует ни направление
   колонки, ни ограничение по высоте, вырастает под содержимое
   и обрезается по `overflow: hidden` родителя — вместе с подвалом,
   в котором лежит кнопка отправки.

   Правило общее, а не для окна битвы: так же устроено окно «свой
   тест», и следующая форма в окне сломалась бы ровно тем же
   способом. */
.modal-dialog-scrollable .modal-content > form {
  display: flex;
  flex-direction: column;
  max-height: 100%;
  overflow: hidden;
}

.bt-page {
  flex: 1 0 auto;
  padding-top: 2rem;
  padding-bottom: 3rem;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: 600;
  color: var(--bt-dark);
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.4rem; }
h3 { font-size: 1.2rem; }

/* Название страницы — по центру. Правка 1, пункт 3.

   Правило общее, а не класс на каждом заголовке: страниц под восемь
   десятков, и класс, который нужно не забыть поставить, однажды
   забудут — новая страница выйдет с заголовком не как у всех. Обратный
   порядок надёжнее: по центру по умолчанию, а те немногие заголовки,
   которые стоят в ряду с чем-то ещё (приветствие рядом с кольцом цели,
   заглавие витрины рядом с картинкой), помечены `text-start` явно. */
.bt-page h1 { text-align: center; }

/* --------------------------------------------------------------------
   Кнопки и поля в стиле Paper Dashboard
   -------------------------------------------------------------------- */

.btn {
  --bs-btn-border-radius: var(--bt-radius-pill);
  --bs-btn-padding-x: 1.4rem;
  --bs-btn-padding-y: 0.5rem;
  --bs-btn-font-weight: 600;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.btn:hover { box-shadow: var(--bt-shadow-hover); }
.btn:active { transform: translateY(1px); }

/* КАКУЮ КНОПКУ КОГДА РИСОВАТЬ
   ===========================

   Правило записано здесь по просьбе заказчика от 09.09.2026 (правка 5,
   пункт 3): «есть какой-то принцип, когда мы ставим кнопки с -outline-,
   а когда без него? Я что-то не улавливаю логики». Логика была,
   но нигде не записана, а незаписанное правило нельзя ни проверить,
   ни соблюсти.

   Правка 6, пункт 3 разделила два признака, которые до неё были
   слиты в один: «насколько действие важное» и «можно ли его вообще
   нажать». Заказчик: «давай сделаем так, чтобы в серый цвет были
   окрашены только неактивные кнопки. Кликабельные кнопки серыми быть
   не должны. Это касается всех кнопок на сайте. Соответственно, если
   кнопка — outline, то её обод и текст должен быть не серым, а
   оранжевым (или другим, в зависимости от ситуации)». Отсюда:
   **важность показывает форма (сплошная или контурная), смысл
   показывает цвет, а серый означает ровно одно — «нажать нельзя»**.

   1. **В одной карточке ровно одно главное действие — сплошной
      оранжевой кнопкой.** Главное — то, ради чего человек пришёл
      на этот экран: «Сохранить», «Отправить заявку», «Начать».
      Карточек на странице бывает несколько, и у каждой своё главное
      действие: на «Профиле» это «Загрузить» у аватарки и «Сохранить»
      у ника — они не спорят, потому что стоят в разных карточках
      и относятся к разным вещам.

   2. **Всё остальное — контурное, но того же цвета.** Переходы
      в соседний раздел, вторые пути к тому же результату, «Показать
      ещё», «Найти», «Закрыть», четыре режима теста, из которых один
      главный, а три рядом. Контурная кнопка не «слабее» — она просто
      не первая, и серым её красить не за что: нажимается она так же.

   3. **Разрушающее действие — красное**, и только оно: удаление
      аккаунта, удаление картинки. Оранжевым его красить нельзя —
      оранжевый на сайте означает «делай это».

   4. **Погашенная кнопка — не действие, и только она серая.** Пока
      «Сохранить» не зажглась (строка не менялась), самой заметной
      на экране оказывается контурная «Добавить новую…» — и это верно:
      в эту секунду завести новую строку и есть единственное, что
      можно сделать.

   Проверка простая: если на видимой части экрана две сплошные
   оранжевые кнопки в одной карточке — одна из них не главная;
   если серая кнопка нажимается — она покрашена неверно. */
.btn-primary {
  /* Ореол вокруг кнопки при переходе клавишей — тоже синий литерал
     Bootstrap. Без него оранжевая кнопка светилась бы синим, и заметно
     это только с клавиатуры: мышью в это состояние не попасть. */
  --bs-btn-focus-shadow-rgb: 255, 68, 0;
  --bs-btn-bg: var(--bt-orange);
  --bs-btn-border-color: var(--bt-orange);
  --bs-btn-hover-bg: var(--bt-orange-dark);
  --bs-btn-hover-border-color: var(--bt-orange-dark);
  --bs-btn-active-bg: var(--bt-orange-dark);
  --bs-btn-active-border-color: var(--bt-orange-dark);
}

.btn-success {
  --bs-btn-bg: var(--bt-green);
  --bs-btn-border-color: var(--bt-green);
  --bs-btn-hover-bg: var(--bt-green-dark);
  --bs-btn-hover-border-color: var(--bt-green-dark);
  --bs-btn-active-bg: var(--bt-green-dark);
  --bs-btn-active-border-color: var(--bt-green-dark);
}

.btn-warning {
  --bs-btn-bg: var(--bt-yellow);
  --bs-btn-border-color: var(--bt-yellow);
  --bs-btn-color: #fff;
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--bt-yellow-dark);
  --bs-btn-hover-border-color: var(--bt-yellow-dark);
}

.btn-danger {
  --bs-btn-bg: var(--bt-red);
  --bs-btn-border-color: var(--bt-red);
  --bs-btn-hover-bg: var(--bt-red-dark);
  --bs-btn-hover-border-color: var(--bt-red-dark);
}

/* Надпись на невыделенной кнопке — это буквы на белом, поэтому цвет
   у неё тёмный (4,57:1), а рамка и заливка при наведении остаются
   заливочными: на них норма другая, 3:1 как для элемента управления.

   `btn-outline-secondary` красится тем же самым и намеренно: правка 6
   отменила серую контурную кнопку как приём, а в шаблонах таких кнопок
   тридцать пять — «Найти», «Открыть», «Показать ещё», «Закрыть»,
   переходы в соседние разделы. Перебирать их по одной значило бы
   тридцать пять раз принять одно и то же решение и один раз ошибиться;
   вдобавок серая контурная кнопка вернулась бы в первом же новом
   шаблоне, написанном по памяти. Класс остаётся в разметке, но больше
   ничего не значит: обе контурные кнопки — одна кнопка. */
.btn-outline-primary,
.btn-outline-secondary {
  --bs-btn-focus-shadow-rgb: 255, 68, 0;
  --bs-btn-color: var(--bt-orange-dark);
  --bs-btn-border-color: var(--bt-orange);
  --bs-btn-hover-bg: var(--bt-orange);
  --bs-btn-hover-border-color: var(--bt-orange);
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--bt-orange-dark);
  --bs-btn-active-border-color: var(--bt-orange-dark);
  --bs-btn-active-color: #fff;
}

/* Неактивная кнопка — серая, какого бы вида она ни была.

   Правило общее, а не по кнопке: неработающих кнопок на сайте
   десятки — «Работа над ошибками» без ошибок, «Ещё тест по слабой
   теме» без слабых тем, все четыре кнопки «Моих тестов» у гостя, —
   и каждая, покрашенная отдельно, однажды разошлась бы с остальными.

   Прозрачность снята: серого достаточно, а полупрозрачная серая
   подпись на светлом фоне уже не читается. */
.btn-primary:disabled, .btn-primary.disabled,
.btn-secondary:disabled, .btn-secondary.disabled,
.btn-success:disabled, .btn-success.disabled,
.btn-danger:disabled, .btn-danger.disabled,
.btn-warning:disabled, .btn-warning.disabled,
.btn-info:disabled, .btn-info.disabled {
  --bs-btn-disabled-bg: var(--bt-off);
  --bs-btn-disabled-border-color: var(--bt-off);
  --bs-btn-disabled-color: #fff;
  --bs-btn-disabled-opacity: 1;
}

[class*="btn-outline-"]:disabled,
[class*="btn-outline-"].disabled {
  --bs-btn-disabled-color: var(--bt-off);
  --bs-btn-disabled-border-color: var(--bt-off-line);
  --bs-btn-disabled-opacity: 1;
}

/* Тень и сдвиг — признаки нажимаемости. У неработающей кнопки
   их быть не должно: рука тянется именно к тому, что откликается. */
.btn:disabled:hover, .btn.disabled:hover { box-shadow: none; }
.btn:disabled:active, .btn.disabled:active { transform: none; }

.form-control, .form-select {
  border-radius: var(--bt-radius);
  padding: 0.55rem 0.9rem;
}

/* Скругления по краям полосы «поле + кнопка».

   Bootstrap оставляет крайним элементам группы их собственный радиус,
   а он у поля и у кнопки разный: поле берёт 0,75rem, кнопка —
   таблетку в 30 точек. У одной и той же полосы получались разные углы
   слева и справа, и это видно на глаз — поиск по нику и поле личной
   ссылки на странице «Друзья» (замечание заказчика 05.09.2026).

   Внутри группы кнопка берёт радиус поля: скругление принадлежит
   полосе целиком, а не тому, из чего она собрана. */
.input-group > .btn {
  --bs-btn-border-radius: var(--bt-radius);
}

.input-group-sm > .btn {
  --bs-btn-border-radius: var(--bs-border-radius-sm);
}

/* Кнопка «Скопировать» рядом с полем ссылки. Правка 1, пункт 6.

   Подпись на узком экране съедала полосу: на 360 точках от самого
   адреса оставалось «https://besttests.r». Ниже 440 точек от кнопки
   остаётся значок, а подпись прячется — но остаётся в разметке:
   читалке с экрана значок не говорит ничего.

   Значок при этом не украшение, а единственный ответ на нажатие.
   Пока подпись видна, об удаче сообщает она — «Скопировано»; когда
   её нет, сказать может только значок, и скрипт подменяет его
   галочкой. Без этого нажатие на телефоне выглядело бы так, будто
   ничего не произошло, — ровно та ошибка, из-за которой скрипт
   копирования вообще появился (задача 3.1). */
.bt-copy__icon {
  display: none;
}

@media (max-width: 440px) {
  .bt-copy__icon { display: inline-block; }

  /* Подпись убирается с глаз, но не из разметки: `display: none`
     выкинул бы её и из читалки с экрана, и кнопка осталась бы
     безымянной. */
  .bt-copy__label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}

.form-control:focus, .form-select:focus {
  border-color: var(--bt-orange);
  box-shadow: 0 0 0 0.2rem var(--bs-focus-ring-color);
}

/* Флажки, радио и переключатели.

   Тот же случай, что у полосы прогресса выше, только хуже: Bootstrap
   пишет здесь #0d6efd литералом, и это даже не наш прежний голубой,
   а чужой бутстраповский синий. Переопределение палитры до него
   не доставало, поэтому переключатели в уведомлениях светились цветом,
   которого больше нигде на сайте нет.

   Кружок переключателя приходит картинкой в data-URI, и цвет в ней
   тоже зашит. Заменяется целиком: в состоянии фокуса Bootstrap красит
   кружок в голубой #86b7fe, и на оранжевой дорожке он выглядел бы
   случайной синей точкой. Знак «решётка» в адресе картинки обязан
   быть записан как %23 — иначе браузер прочтёт его как начало якоря
   и картинку не загрузит. */
.form-check-input:checked {
  background-color: var(--bt-orange);
  border-color: var(--bt-orange);
}

.form-check-input:focus {
  border-color: var(--bt-orange);
  box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
}

.form-switch .form-check-input:focus:not(:checked) {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ff4400'/%3e%3c/svg%3e");
}

.form-check-input[type="checkbox"]:indeterminate {
  background-color: var(--bt-orange);
  border-color: var(--bt-orange);
}

.form-range::-webkit-slider-thumb { background-color: var(--bt-orange); }
.form-range::-moz-range-thumb { background-color: var(--bt-orange); }

/* Компоненты, которых на страницах пока нет, но цвет в них зашит тем же
   литералом. Красятся здесь, а не когда понадобятся: первым признаком
   пропуска будет чужой синий на готовой странице. */
.nav-pills { --bs-nav-pills-link-active-bg: var(--bt-orange); }

.pagination {
  --bs-pagination-active-bg: var(--bt-orange);
  --bs-pagination-active-border-color: var(--bt-orange);
  --bs-pagination-focus-box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
}

.list-group {
  --bs-list-group-active-bg: var(--bt-orange);
  --bs-list-group-active-border-color: var(--bt-orange);
}

.dropdown-menu { --bs-dropdown-link-active-bg: var(--bt-orange); }

.card {
  border: 0;
  border-radius: var(--bt-radius);
  box-shadow: var(--bt-shadow);
}

/* Кнопка, стоящая в карточке сама по себе.

   `.card` — флекс-колонка, поэтому всякий её прямой ребёнок и есть
   «кнопка одна в ряду» из правки 1, пункт 3: она ставится по центру,
   а на экране 440 точек и уже растягивается во всю ширину.

   Во всю ширину — только на маленьком экране, и это важно. Раньше
   кнопка тянулась на всю ширину карточки везде: «Я учитель» выходила
   на семьсот пикселей и читалась как баннер (скриншоты заказчика
   01.09.2026). Оттуда и взялось `align-self`, оно и осталось —
   поменялась только выключка, с левой на центральную.

   Кнопке, которой ширина нужна всегда, её задают явно — обёрткой
   `d-grid` или классом `w-100`, и оба сильнее этого правила. */
.card > .btn {
  align-self: center;
}

@media (max-width: 440px) {
  .card > .btn { width: 100%; }
}

/* Таблица — такая же карточка, как всё остальное.

   `.table` в Bootstrap рисует себе белый фон, а прямых углов у нас
   нигде больше нет: на светло-сером фоне страницы голая таблица
   выглядела белым прямоугольником с острыми углами посреди
   скруглённых карточек — тепловая карта, список классов и список
   учеников (скриншоты заказчика 02.09.2026). Скругление ставится
   на обёртку `.table-responsive`, потому что она и так обрезает
   содержимое по горизонтали, а не на саму таблицу: у таблицы углы
   принадлежат крайним ячейкам и скругляются по одной.

   Внутри карточки оформление снимается: две тени одна в другой
   дают ободок, которого никто не рисовал. */
.table-responsive {
  background: #fff;
  border-radius: var(--bt-radius);
  box-shadow: var(--bt-shadow);
  padding: 0.35rem 0.75rem;
}

.table-responsive > .table:last-child {
  margin-bottom: 0;
}

.card .table-responsive {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}

/* Полоса действий над вкладками карточки класса (16.3).

   Кнопки шли простым текстовым потоком, и на 360 точках вставали
   как придётся: одна в первой строке, две во второй, две в третьей,
   все разной ширины — «сбились в кучу» на скриншотах заказчика
   02.09.2026. Флекс с явным зазором держит их в сетке, а на узком
   экране каждая занимает половину ширины, и получается ровно 2 × 2. */
.bt-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Ряд, в котором кнопка одна. Правка 1, пункт 3: такая кнопка стоит
   по центру, а на маленьком экране растягивается во всю ширину.

   Отдельный класс, а не общее правило для всякой кнопки-одиночки.
   Одиночки попадаются и в ячейке таблицы, и посреди карточки с текстом,
   и там растянутая во всю ширину кнопка читается баннером — ровно та
   ошибка, которую заказчик нашёл 01.09.2026 на кнопке «Я учитель».
   Класс ставится там, где кнопка завершает страницу или форму.

   Маленький экран здесь — 440 точек и уже, как задано правкой 1.
   Это шире самого узкого телефона, на который мы смотрим (360),
   и уже той ширины, где кнопке уже хватает места стоять по себе.

   Имя `bt-main-action`, а не `bt-actions`: последнее уже занято парой
   равных по ширине кнопок у слабой темы (9.1), и одинаковые имена
   у соседних по смыслу, но противоположных по поведению классов —
   верный способ однажды поставить не тот. */
.bt-main-action {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

@media (max-width: 440px) {
  .bt-main-action > .btn,
  .bt-main-action > form,
  .bt-main-action > form > .btn {
    width: 100%;
  }
}

@media (max-width: 575.98px) {
  .bt-toolbar > .btn,
  .bt-toolbar > form {
    /* `min-content`, а не `0` и не «по умолчанию».

       По умолчанию флекс-элемент не сжимается уже своего содержимого,
       и одна длинная подпись выталкивала пару в две строки, пока
       соседняя пара стояла в одну: список предметов выглядел
       свёрстанным по двум разным правилам. Полный ноль — другая
       крайность: кнопка ужимается уже самого длинного слова, и
       «Приостановить» ломалось на «Приостанови/ть» — та же ошибка,
       что заказчик нашёл на 360 точках 01.09.2026.

       `min-content` — ширина самого длинного слова: ряд делится
       пополам, пока слова помещаются, и переносится целиком, когда
       уже нет. */
    flex: 1 1 calc(50% - 0.25rem);
    min-width: min-content;
  }
  /* Перенос между словами остаётся, разрыв внутри слова запрещён. */
  .bt-toolbar .btn {
    overflow-wrap: normal;
    word-break: keep-all;
  }
  .bt-toolbar > form > .btn {
    width: 100%;
  }
  /* Боковые поля у кнопки-таблетки щедрые, и в половине от 360 точек
     на подпись остаётся меньше, чем она занимает: «Выдать задание»
     и «Ссылка на битву» разъезжались на две строки, а соседние
     по ряду — нет. Поля ужимаются только здесь и только на телефоне. */
  .bt-toolbar > .btn {
    padding-left: 0.6rem;
    padding-right: 0.6rem;
  }
}

/* --------------------------------------------------------------------
   Вкладки. Правка 1, пункт 5
   -------------------------------------------------------------------- */

/* Строка названий с чертой под активным, вместо бутстраповских язычков.

   Язычки `nav-tabs` рисуют вокруг активной вкладки рамку и заливают её
   белым. На светло-сером фоне страницы это выглядело наклейкой поверх
   вёрстки — «устарело и чужеродно» (правка 1). Здесь остаётся только
   то, что и должна нести вкладка: жирная надпись активной и жирная
   черта под ней.

   Черта рисуется рамкой у каждой вкладки, а не подчёркиванием текста:
   подчёркивание идёт по буквам и обрывается вместе со словом, а полоса
   обязана тянуться на всю ширину вкладки — так на образце. Прозрачная
   рамка стоит и у неактивных: без неё активная вкладка становилась бы
   на три точки выше соседних, и вся строка дёргалась при переключении.

   Ряд не переносится, а прокручивается вбок. Перенос ломает саму
   метафору: у папки не бывает второго ряда язычков, и на 360 точках
   пять вкладок карточки класса разъезжались в две неровные строки,
   где активная стояла в первой, а соседняя по смыслу — во второй.
   Обрезанный край следующей вкладки и есть подсказка, что справа
   есть ещё; никакой карусели для этого не нужно — ни своей, ни чужой.
   Прокрутку по точкам (`scroll-snap`) намеренно не включаем: она
   довернула бы ленту так, чтобы вкладка встала ровно по краю, и
   торчащий кусочек — единственный признак прокрутки — пропал бы.

   Полосу прокрутки прячем: на узком экране она заняла бы столько же
   места, сколько сами вкладки. */
.bt-tabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  gap: 1.25rem;
  border-bottom: 1px solid var(--bs-border-color);
}

.bt-tabs::-webkit-scrollbar {
  display: none;
}

.bt-tabs .nav-item {
  flex: 0 0 auto;
}

.bt-tabs .nav-link {
  white-space: nowrap;
  padding: 0.5rem 0;
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--bt-dark);
}

.bt-tabs .nav-link:hover {
  color: var(--bt-orange-dark);
  border-bottom-color: var(--bs-border-color);
}

/* Активная вкладка отличается насыщенностью и чертой, а не цветом:
   приглушить неактивные до серого значило бы опустить их контраст
   ниже нормы 4,5:1 — надпись вкладки это обычный текст, и читать её
   должно быть так же легко, как всё остальное на странице. */
.bt-tabs .nav-link.active {
  color: var(--bt-dark);
  font-weight: 700;
  background: transparent;
  border-bottom-color: var(--bt-orange);
}

/* Область для перетаскивания файла — аватарка в настройках (20).

   Само поле файла внутри неё обычное и работает без всякого скрипта:
   перетаскивание добавляет удобство, а не заменяет выбор кнопкой.
   Поэтому и разметка — `label` с полем внутри: нажатие в любом месте
   области открывает обычный диалог выбора файла, даже если скрипт
   не загрузился. */
.bt-drop {
  display: block;
  padding: 1.25rem;
  border: 2px dashed var(--bt-track);
  border-radius: var(--bt-radius);
  text-align: center;
  cursor: pointer;
  color: var(--bt-grey);
  transition: border-color 0.15s, background-color 0.15s;
}

.bt-drop:hover,
.bt-drop--over {
  border-color: var(--bt-orange);
  background: rgba(255, 68, 0, 0.06);
  color: var(--bt-dark);
}

/* Поле не прячется `display: none`: скрытое так поле выпадает
   из обхода клавиатурой, и до загрузки аватарки нельзя добраться
   без мыши. Оно остаётся в потоке, но не занимает места. */
.bt-drop__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* Табло битвы класс на класс (16.4): класс — счёт — класс. */
.bt-scoreline {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

@media (max-width: 575.98px) {
  .bt-scoreline {
    flex-direction: column;
    gap: 0.35rem;
  }
  .bt-scoreline > * {
    text-align: center !important;
  }
}

/* --------------------------------------------------------------------
   Шапка. Раздел 5.1: название сайта и мини-аватарка на всех страницах.
   -------------------------------------------------------------------- */

.bt-header {
  background: #fff;
  box-shadow: var(--bt-shadow);
}

/* Отступ шапки от краёв экрана. Раздел 5.1: аватарка стоит в одном ряду
   с логотипом, и ряд обязан отступать от края так же, как карточки
   на странице.

   Возвращать отступ приходится руками, потому что класс `container`
   висит на самом `.navbar`, а `.navbar` задаёт поля сокращённой
   записью `padding: <y> <x>` со своим `--bs-navbar-padding-x: 0`.
   Сокращённая запись перекрывает `padding-left`/`padding-right`
   контейнера целиком, и горизонтальный отступ обнуляется. Внешне это
   выглядело так: в 360 точках аватарка стояла в двух точках от края,
   а карточки — в четырнадцати (замер по снимку 05.09.2026), и шапка
   казалась съехавшей вправо.

   Значение берётся из той же переменной, что у контейнера: если
   в Bootstrap изменится размер отступа, шапка поедет вместе
   со страницей, а не останется с прежним числом. */
.bt-header .navbar {
  --bs-navbar-padding-x: calc(var(--bs-gutter-x) * 0.5);
}

.bt-header .navbar-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 700;
  color: var(--bt-dark);
}

.bt-header .navbar-brand:hover { color: var(--bt-orange-dark); }
.bt-logo { height: 34px; width: auto; }

/* Раздел 5.2: три индикатора слева от аватарки. На мобильных они
   сжимаются до иконки с числом — за это отвечает .bt-indicator__label,
   которая прячется на узком экране. Сами величины появятся вместе
   со стриком, дневной целью и лигой (очередь 2). */
.bt-indicators {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.bt-indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--bt-radius-pill);
  background: var(--bt-light);
  color: var(--bt-dark);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.bt-indicator:hover { background: #ebe9e3; color: var(--bt-dark); }
.bt-indicator--streak i { color: var(--bt-red); }
.bt-indicator--goal i { color: var(--bt-green); }
.bt-indicator--league i { color: var(--bt-yellow); }

.bt-indicator__icon { width: 1.05rem; height: 1.05rem; object-fit: contain; }
.bt-indicator__value { font-variant-numeric: tabular-nums; }

/* Индикатор без величины: стрик ещё не начат или раздел не написан.
   Гасится, но с места не уходит — раздел 5.2 задаёт три индикатора,
   и шапка, в которой их становится три позже, переедет у всех
   на глазах. */
.bt-indicator--off { opacity: 0.45; }
.bt-indicator--off:hover { background: var(--bt-light); }

/* Раздел 5.2: «на мобильных они сжимаются до иконки с числом».
   Прячется подпись, число остаётся: индикатор без числа
   не индикатор. */
@media (max-width: 575.98px) {
  .bt-indicator { padding: 0.25rem 0.45rem; gap: 0.25rem; font-size: 0.8rem; }
  .bt-indicator__label { display: none; }
  .bt-indicators { gap: 0.25rem; }
}

.bt-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid transparent;
}

/* Раздел 5.1: аватарка незалогиненного — неактивная. */
.bt-avatar--guest { opacity: 0.55; }
.dropdown-toggle.bt-avatar-toggle::after { display: none; }
.bt-header .dropdown-menu { border: 0; box-shadow: var(--bt-shadow); border-radius: var(--bt-radius); }
.bt-header .dropdown-item.active,
.bt-header .dropdown-item:active { background: var(--bt-orange); }

/* Пункт меню, раздел которого ещё не написан. Показывается серым
   и не кликается: раздел 5.1 задаёт состав меню целиком, и прятать
   половину пунктов — значит потерять из виду, что осталось сделать. */
.dropdown-item.disabled .bt-soon {
  font-size: 0.75rem;
  color: var(--bt-grey);
  margin-left: 0.35rem;
}

/* Полоса «Подтвердите e-mail» — раздел 6.3. Жёлтая, а не красная:
   аккаунт работает, ограничение касается только покупок и
   восстановления пароля. */
.bt-confirm-bar {
  background: var(--bt-yellow);
  color: #5a4a1f;
  font-size: 0.9rem;
  padding: 0.5rem 0;
}

.bt-confirm-bar .btn-warning {
  --bs-btn-bg: #fff;
  --bs-btn-border-color: #fff;
  --bs-btn-color: #5a4a1f;
  --bs-btn-hover-bg: #fdf6e6;
  --bs-btn-hover-border-color: #fdf6e6;
  --bs-btn-hover-color: #5a4a1f;
}

/* На узком экране полоса переносится в три строки, и прижатая вправо
   кнопка оказывается висящей в углу. Центр её возвращает на место.
   Правило живёт здесь, рядом с самой полосой, а не в разделе футера,
   где стояло раньше: имя, описанное в двух разных разделах таблицы
   стилей, — первый признак того, что его заняли дважды, и проверка
   блока 8.1 на это смотрит. */
@media (max-width: 575.98px) {
  .bt-confirm-bar { text-align: center; }
  .bt-confirm-bar .container { justify-content: center; }
  .bt-confirm-bar form.ms-auto { margin-left: 0 !important; }
}

/* Уведомления — полоса под навбаром. Правка 6, пункт 9.

   Полоса, а не карточка: примыкает вплотную, идёт во всю ширину
   и углов не скругляет. Boostrap задаёт `.alert` и радиус, и отступы,
   и рамку — снимаются все три: рамка на полосе во всю ширину рисует
   лишнюю линию вдоль экрана, а нижняя граница у неё и так есть,
   потому что дальше начинается серый фон страницы.

   Несколько сообщений подряд ложатся полосами встык, без просветов:
   просвет между ними читался бы как конец блока, и второе сообщение
   выглядело бы относящимся уже к странице. */
.bt-alerts .alert {
  margin-bottom: 0;
  padding: 0.6rem 0;
  border: 0;
  border-radius: 0;
}

/* --------------------------------------------------------------------
   Футер и полоса cookie — разделы 5.3 и 5.4
   -------------------------------------------------------------------- */

.bt-footer {
  flex-shrink: 0;
  padding: 1.5rem 0;
  border-top: 1px solid var(--bs-border-color);
  font-size: 0.85rem;
  color: var(--bt-dark);
  /* Своей заливки нет: страница уже серая, и вторая такая же полоса
     внизу только рисовала бы лишнюю границу. */
  background: transparent;
  /* По центру — текст футера короткий и служебный; выключка влево
     оставляет справа рваный край во всю ширину экрана. */
  text-align: center;
}

/* Ширину строки ограничиваем: центрированный текст на 1280 растянут
   в одну длинную строку и читается хуже, чем в две коротких. */
.bt-footer .container { max-width: 46rem; }

.bt-footer a {
  color: var(--bt-orange-dark);
  text-decoration: underline;
}

/* Полоса не перекрывает контент (5.3): она в потоке, а не поверх него. */
.bt-cookie-bar {
  position: sticky;
  bottom: 0;
  z-index: 1030;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--bt-dark);
  color: #fff;
  font-size: 0.85rem;
}

.bt-cookie-bar a { color: var(--bt-yellow); }
.bt-cookie-bar .btn { margin-left: auto; }

/* На узком экране полоса переносится в три строки, и прижатая вправо
   кнопка оказывается висящей в углу. Центр её возвращает на место. */
@media (max-width: 575.98px) {
  .bt-cookie-bar { justify-content: center; text-align: center; }
  .bt-cookie-bar .btn { margin-left: 0; }
}

/* Строка выбора предмета для работы над ошибками в «Моей статистике».
   Правка 9, пункт 22: список растягивается на свободное место
   и прижимает кнопку к правому краю карточки. `min-width: 0` обязателен
   — без него флекс не даёт элементу стать уже содержимого, и на узком
   экране список вылез бы за карточку вместо переноса. */
.bt-mistakes-pick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.bt-mistakes-pick .form-select {
  flex: 1 1 12rem;
  min-width: 0;
}

/* Строка «Сложность — Максимальный балл» на карточке вопроса.
   Правка 9, пункт 13: левое к левому краю, правое к правому.
   На узком экране числа переносятся под подписи, а не режутся:
   названия сложностей длинные («средняя», «сложный»), и в 360 точек
   обе половины в одну строку не помещаются. */
.bt-qmeta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  margin-bottom: 0.75rem;
  font-size: 0.85rem;
  color: var(--bt-grey);
}

/* Экран вопроса — раздел 12.1. */
.bt-timer {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.7rem;
  border-radius: var(--bt-radius-pill);
  background: var(--bt-light);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Последние секунды — красным: ноль не должен наступать внезапно. */
.bt-timer--low { background: var(--bt-red); color: #fff; }

/* Вариант ответа — рамка, внутри флажок и подпись.

   Раскладка своя, а не бутстраповская: `.form-check` отодвигает
   подпись отступом слева и вытаскивает флажок наружу отрицательным
   margin. Внутри рамки это давало флажок, сидящий **на** границе
   наполовину снаружи. Флекс ставит их в ряд честно.

   Подпись растянута на всю строку намеренно: попасть пальцем
   в флажок 16 на 16 точек трудно, а в строку целиком — легко. */
.bt-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bt-radius);
  margin-bottom: 0.5rem;
  background: #fff;
}

.bt-option .form-check-input {
  margin: 0;
  float: none;
  flex: 0 0 auto;
}

.bt-option .form-check-label {
  margin: 0;
  flex: 1 1 auto;
  cursor: pointer;
}

.bt-option:hover { border-color: var(--bt-orange); }
.bt-option:has(.form-check-input:checked) {
  border-color: var(--bt-orange);
  background: rgba(255, 68, 0, 0.07);
}

/* --------------------------------------------------------------------
   Отдельные страницы
   -------------------------------------------------------------------- */

/* Вход и восстановление пароля — разделы 6.1 и 6.5. */
.bt-auth { max-width: 26rem; margin: 0 auto; }

/* Юридический документ: узкая колонка, читаемая длина строки. */
.bt-legal { max-width: 46rem; }
.bt-legal p { line-height: 1.7; }
.bt-legal h1 { font-size: 1.6rem; }
.bt-legal h2 { font-size: 1.2rem; margin-top: 1.5rem; }
.bt-legal ul { line-height: 1.7; padding-left: 1.4rem; }
.bt-legal li { margin-bottom: 0.3rem; }

/* Редакция и дата под заголовком документа. */
.bt-legal__meta { color: var(--bs-secondary-color, #66615b); font-size: 0.9rem; }

/* Таблица «Цели обработки» в политике конфиденциальности — раздел 5.4.

   Ячейки широкие и текст в них длинный, поэтому на узком экране
   таблица прокручивается внутри себя, а не растягивает страницу:
   горизонтальная прокрутка всей страницы ломает чтение остального
   документа. Верхнее выравнивание обязательно — в объединённой
   ячейке перечень данных вчетверо длиннее соседних, и по центру
   он оторвался бы от строки, к которой относится. */
.bt-legal table {
  display: block;
  overflow-x: auto;
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0;
  font-size: 0.95rem;
}
.bt-legal th,
.bt-legal td {
  border: 1px solid var(--bs-border-color, #dee2e6);
  padding: 0.5rem 0.7rem;
  vertical-align: top;
  min-width: 14rem;
}
.bt-legal th { background: #ebe9e3; text-align: left; }

/* Изображение раздела 29, для которого файла ещё нет: заглушка того же
   размера. Раздел 29.1 требует, чтобы отсутствие файла не ломало
   вёрстку, — рамка показывает, что место занято черновиком. */
.bt-img--placeholder {
  border: 1px dashed var(--bt-grey);
  border-radius: var(--bt-radius);
  opacity: 0.75;
}

/* Панель математических символов над полем ответа — раздел 23.3.
   Кнопки мелкие и плотные: их двадцать семь, и на телефоне они должны
   уместиться в две-три строки, не оттеснив само поле ввода за экран. */
.bt-symbols {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem;
}

.bt-symbols .btn {
  min-width: 2.25rem;
  padding: .15rem .35rem;
  font-size: 1rem;
  line-height: 1.4;
}

/* Кольцевой индикатор дневной цели — раздел 9.1.
   Рисуется conic-gradient, а не скриптом: кольцо меняется на каждом
   ответе, а везти ради одной дуги библиотеку при запрете CDN
   (раздел 3) не стоит того. Доля приходит переменной --доля. */
.bt-ring {
  --доля: 0%;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: conic-gradient(var(--bt-orange) var(--доля), var(--bt-track) 0);
}
/* Кольцо дневной цели живёт по тому же правилу, что и полосы: под ним
   на той же странице стоит полоса той же цели, и зелёная полоса рядом
   с красным кольцом означала бы, что показатели разные. Кольцо
   показывает ход, поэтому ступеней у него две — как у полосы хода. */
.bt-ring--3 {
  background: conic-gradient(var(--bt-scale-3) var(--доля), var(--bt-track) 0);
}
.bt-ring--4 {
  background: conic-gradient(var(--bt-scale-4) var(--доля), var(--bt-track) 0);
}
.bt-ring__text {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--bs-body-bg, #fff);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .7rem;
  font-weight: 600;
  color: var(--bs-body-color, #66615B);
}

/* Строка «Другие режимы» (9.1). На узком экране четыре ссылки
   переносятся в две строки, и выключка влево оставляет вторую строку
   с рваным правым краем под первой. */
@media (max-width: 575.98px) {
  .bt-modes { justify-content: center; }
}

/* Пара действий у слабой темы (9.1). Обе кнопки одной ширины и одной
   высоты: длинная подпись переносится в две строки, и без выравнивания
   соседняя однострочная кнопка выглядит случайно уменьшенной. */
.bt-actions {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
}
.bt-actions > form,
.bt-actions > .btn {
  flex: 1 1 0;
  min-width: 0;
}
.bt-actions > form > .btn { width: 100%; height: 100%; }
/* Слово в кнопке не разрывается посреди себя. `min-width: 0` выше
   разрешает флекс-элементу сжаться уже содержимого, и на 360 px
   «Тренировать» ломалось на «Трениров/ать» (скриншоты заказчика
   01.09.2026). Перенос по словам остаётся — запрещён только разрыв
   внутри слова. */
.bt-actions .btn { overflow-wrap: normal; word-break: keep-all; }

/* Кольцо в шапке — то же самое кольцо, что на главной, только меньше.
   Общие правила лежат в .bt-ring, здесь только размеры: два разных
   кольца одной величины на одном экране читались бы как два разных
   показателя. */
.bt-ring--mini {
  width: 1.4rem;
  height: 1.4rem;
}
.bt-ring--mini .bt-ring__text {
  width: 1.05rem;
  height: 1.05rem;
  font-size: 0.6rem;
  background: var(--bt-light);
}
.bt-indicator:hover .bt-ring--mini .bt-ring__text { background: #ebe9e3; }

/* Баннер «Установить приложение» — раздел 5.5.

   Липнет к низу и не перекрывает содержимое, как и полоса cookie
   (5.3): предложение установить приложение не должно мешать решать
   вопросы — иначе оно работает против того, ради чего показано. */
.bt-install {
  position: sticky;
  bottom: 0;
  z-index: 1029;
  padding: 0.6rem 0;
  background: #fff;
  border-top: 1px solid var(--bs-border-color);
  box-shadow: 0 -2px 12px rgba(39, 39, 39, 0.06);
}

.bt-install__icon {
  width: 40px;
  height: 40px;
  border-radius: 0.6rem;
  object-fit: cover;
  flex: 0 0 auto;
}

@media (max-width: 575.98px) {
  .bt-install .container { text-align: center; justify-content: center; }
  .bt-install__icon { display: none; }
}

/* ------------------------------------------------------------------
   Лига — раздел 15.
   ------------------------------------------------------------------ */

/* Иконка дивизиона в шапке раздела (29.4) и мелкая аватарка в таблице
   группы. Размеры заданы здесь, а не в разметке: одна и та же таблица
   рисуется на трёх страницах, и три разных размера одной аватарки
   читаются как три разных элемента. */
.bt-division { width: 64px; height: 64px; object-fit: contain; }
.bt-badge { width: 48px; height: 48px; object-fit: contain; }
.bt-empty { width: 120px; height: 120px; object-fit: contain; }
.bt-avatar--sm { width: 24px; height: 24px; margin-right: 0.35rem; }

/* Зоны повышения и понижения (15.2). Цвет фона, а не значок сбоку:
   человек ищет в таблице себя, а не легенду, и граница зоны должна
   читаться боковым зрением. Полоса слева нужна тем, кто не различает
   зелёный и красный, — одного цвета для такого разделения мало. */
   Фон задаётся ячейкам, а не строке. Bootstrap красит каждую `td`
   в `--bs-table-bg`, то есть в белый, и заливка строки оказывалась
   ровно под этим белым: в разметке семь строк зоны повышения были,
   а на экране — ни одной подсвеченной, при том что подпись под
   таблицей обещает «зелёные строки». Найдено собственными снимками
   02.09.2026; ровно так же пряталась серая клетка тепловой карты. */
.bt-league tbody tr { border-left: 3px solid transparent; }
.bt-zone-up { border-left-color: #6BD098; }
.bt-zone-down { border-left-color: #EF8157; }
.bt-league tbody tr.bt-zone-up > * { background-color: rgba(107, 208, 152, 0.16); }
.bt-league tbody tr.bt-zone-down > * { background-color: rgba(239, 132, 87, 0.16); }
.bt-me td { font-weight: 600; }

/* Тостер начисления очков — раздел 15.1.

   «Держится 2 секунды, не перекрывает кнопку „Ответить"». Отсюда
   позиция сверху: кнопка ответа стоит внизу карточки вопроса,
   и плашка над содержимым была бы ровно тем, что ТЗ запрещает. */
.bt-xp-toast {
  position: fixed;
  top: 4.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1080;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  align-items: center;
  pointer-events: none;
}
.bt-xp-toast__item {
  background: #6BD098;
  color: #fff;
  border-radius: 2rem;
  padding: 0.35rem 1rem;
  font-weight: 600;
  box-shadow: 0 4px 14px rgba(39, 39, 39, 0.18);
  animation: bt-xp-fade 2s ease-out forwards;
}
@keyframes bt-xp-fade {
  0%   { opacity: 0; transform: translateY(-0.5rem); }
  15%  { opacity: 1; transform: translateY(0); }
  80%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-0.5rem); }
}

/* Столбики очков по дням (18.3). График рисуется разметкой, а не
   библиотекой: девяносто столбиков — это девяносто div-ов, а любая
   библиотека графиков весит больше, чем весь остальной JS сайта,
   и её пришлось бы поставлять локально (раздел 3). */
.bt-chart {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  height: 6rem;
  padding: 0.25rem 0;
}
.bt-chart__bar {
  flex: 1 1 0;
  min-width: 2px;
  background: var(--bt-track);
  border-radius: 1px 1px 0 0;
}
.bt-chart__bar--active { background: var(--bt-orange); }

/* Подпись на значке сезона — раздел 29.8.

   «Лента или медаль с местом для подписи „Алмаз, сезон 3" — подпись
   накладывается кодом, на изображении её нет». На рисунке две кремовые
   плашки одна под другой; координаты ниже измерены по самому файлу
   badge-season.png (256×256) и переведены в проценты, чтобы подпись
   ехала вместе с картинкой на любом её размере.

   Измерено по гарантированно кремовому прямоугольнику — тому, который
   остаётся кремовым во всех строках плашки. У плашки скруглённые
   концы, и прямоугольник по её крайним точкам вывел бы текст
   на золотую рамку. */
.bt-badge-box { text-align: center; width: 5rem; }
.bt-badge-art {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  container-type: inline-size;
}
.bt-badge-art .bt-badge { width: 100%; height: 100%; }

.bt-badge-line {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  white-space: nowrap;
  color: #2c3e6b;
  font-weight: 700;
  line-height: 1;
  /* Запасной размер для браузеров без единиц контейнера: лучше мелко,
     чем во всю карточку. Ниже он перекрывается расчётом от ширины. */
  font-size: 0.5rem;
  font-size: 7.2cqw;
}

/* Верхняя плашка — дивизион. Кремовая середина в файле: x 76–179,
   y 105–123 из 256, отступ по 2 px с каждой стороны от края кремового.
   Кегль подобран по худшим словам «Платина» и «Серебро»: они длиннее
   всех прочих названий дивизионов и при 7,2% ширины значка занимают
   93 px из 99 доступных. Мерилось шрифтом шире Montserrat, так что
   в браузере запас ещё больше. */
.bt-badge-line--1 { left: 30.5%; top: 41%; width: 38.7%; height: 7.4%; }

/* Нижняя плашка — номер сезона. Кремовая середина: x 87–167,
   y 137–154. Кегль меньше верхнего: плашка уже, а строка длиннее.
   Проверено на «сезон 100» — это пятнадцать лет работы продукта,
   и подпись не должна сломаться раньше, чем он до них доживёт. */
.bt-badge-line--2 {
  left: 34.8%; top: 53.5%; width: 29.7%; height: 7%;
  font-size: 0.42rem;
  font-size: 5.8cqw;
}

/* ------------------------------------------------------------------ */
/* Друзья и профиль — раздел 14.1                                      */
/* ------------------------------------------------------------------ */

/* Строка человека — не таблица. Раздел 14.1 перечисляет семь колонок,
   и на 360 точках таблица из семи колонок либо уезжает в горизонтальную
   прокрутку, либо сжимает ник до двух букв. Здесь показатели переносятся
   на вторую строку и остаются читаемыми. */
.bt-person {
  display: flex;
  /* Перенос обязателен. Без него кнопки «Вызвать» и «…» отбирают
     у ника двести точек, и на экране в 360 точек ему остаётся полоса
     в две буквы: «Хит/ры/й ен/от 741» столбиком. Теперь кнопки уезжают
     на свою строку, а ник получает всю ширину. Найдено на скриншотах
     29.08.2026 — на широком экране этого не видно вовсе. */
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid #ebe9e3;
}
.bt-person:last-child { border-bottom: 0; }

.bt-person__face { flex: 0 0 auto; }

/* Базис в 12 рем — это и есть порог переноса: пока нику хватает
   двенадцати рем, кнопки стоят справа от него; как только перестаёт
   хватать, они переходят на следующую строку целиком. */
.bt-person__main { min-width: 0; flex: 1 1 12rem; }

.bt-person__nick {
  font-weight: 600;
  color: var(--bt-dark);
  text-decoration: none;
  /* `break-word`, а не `anywhere`: второй разрешает браузеру считать
     минимальной шириной блока одну букву, и flex этим пользуется —
     колонка схлопывается ещё до того, как что-то не поместилось.
     `break-word` рвёт слово только тогда, когда оно и правда не влезло. */
  overflow-wrap: break-word;
}
.bt-person__nick:hover { color: var(--bt-orange-dark); }

.bt-person__link {
  font-size: 0.8rem;
  color: var(--bt-grey);
  margin-left: 0.4rem;
}

.bt-person__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.15rem;
  font-size: 0.85rem;
  color: var(--bs-secondary-color, #66615b);
  font-variant-numeric: tabular-nums;
}
.bt-person__stats i { margin-right: 0.2rem; }
.bt-person__stats .bi-fire { color: var(--bt-red); }
.bt-person__stats .bi-lightning-charge { color: var(--bt-yellow); }

.bt-person__division {
  width: 1.1rem;
  height: 1.1rem;
  object-fit: contain;
  vertical-align: -0.2rem;
}

.bt-person__actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  /* Прижимает кнопки к правому краю и на своей строке тоже: перенос
     оставил бы их под аватаркой, где они читались бы как продолжение
     показателей. */
  margin-left: auto;
}

/* «Друг» — взаимная подписка (14.1). Отдельный вид у значка, а не
   просто текст: взаимные связи выводятся наверх обеих вкладок, и глаз
   должен различать их до чтения. */
.bt-badge-friend {
  background: var(--bt-green);
  color: #fff;
  font-weight: 600;
  vertical-align: 0.05rem;
}

/* QR личной ссылки. Размер и вид определились правкой 1, пункт 7.

   Было 180 точек и `image-rendering: pixelated` — оба под голый чёрный
   квадрат: он состоит из прямых углов, и «пиксельная» отрисовка
   держала их резкими. Пергамент под кодом рисованный, со сглаженными
   краями и скруглениями, и такая отрисовка превратила бы его
   в лесенку.

   320 точек, а не 180, потому что сам код занимает теперь чуть больше
   трети стороны картинки — остальное свиток. На 180 точках от кода
   осталось бы шестьдесят пять, и камера через стол его бы не взяла. */
.bt-invite-qr {
  width: 320px;
  max-width: 100%;
  height: auto;
}

/* Аватар профиля. 96 точек, а не 72: он стоит по центру карточки
   отдельной строкой, и в этой роли меньший размер читается как
   иконка рядом с заголовком, а не как портрет человека. */
.bt-profile__avatar {
  display: block;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bt-light);
  margin-left: auto;
  margin-right: auto;
}

.bt-profile__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.bt-profile__value {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.bt-profile__value .bi-fire { color: var(--bt-red); }

.bt-profile__label {
  font-size: 0.8rem;
  color: var(--bs-secondary-color, #66615b);
}

.bt-profile__division {
  width: 1.6rem;
  height: 1.6rem;
  object-fit: contain;
  vertical-align: -0.3rem;
}

/* Картинка внутри карточки с `text-center`.

   `.card` в Bootstrap — колоночный flex-контейнер, а `text-align`
   до flex-элемента не дотягивается: изображение прижимается к левому
   краю, хотя текст под ним честно центрируется. Лечится автоотступами —
   в flex они работают. Найдено на скриншотах 29.08.2026; касалось
   пяти мест сразу: пустых состояний раздела «Друзья» и лиги, карточки
   диагностики на главной и заглушки офлайна. */
.card.text-center > img {
  margin-left: auto;
  margin-right: auto;
}

/* Показатели профиля — по центру карточки. Ряд коротких чисел,
   прижатый к левому краю, на широком экране висит в пустоте:
   справа от него полкарточки воздуха. По центру он читается
   как одна группа, а не как начало таблицы. */
.bt-profile__facts {
  justify-content: center;
}

/* QR личной ссылки — по центру: он квадратный и заметно уже карточки,
   и слева от него иначе остаётся пустая половина. Размеры заданы
   выше, вместе с остальным его видом. */
.bt-invite-qr {
  display: block;
  margin: 0.5rem auto 0;
}

/* Наш рисунок вместо фотографии — аватарка животного из ника (6.6)
   или общая по умолчанию.

   Круглая маска ему не нужна: он уже нарисован круглым. Хуже того,
   она вредна — часть рисунка намеренно выходит за круг: шапочка
   выпускника, кисточка, посох. У барсука за кругом два процента
   изображения, и это ровно те два процента, ради которых рисунок
   делали. Измерено по самим файлам 29.08.2026.

   `contain` вместо `cover`: обрезать нечего, рисунок квадратный
   и должен помещаться целиком. */
.bt-avatar--art,
.bt-profile__avatar.bt-avatar--art {
  border-radius: 0;
  object-fit: contain;
  background: transparent;
}

/* Нарисованные иконки геймификации — раздел 29.4: пламя стрика,
   снежинка заморозки, кольцо выполненной цели.

   Размер в `em`, а не в точках: одна и та же иконка встречается при
   разных кеглях — 0,85 rem в шапке и в строке списка друзей, 1,25 rem
   в профиле, 2 rem в карточке «Прогресса». Единый размер в точках
   сделал бы её крупной в одном месте и мелкой в другом; в `em` она
   всегда одной величины с соседним числом. 1,25 em при кегле шапки
   даёт те же 1,05 rem, что были у прежней иконки, — шапка не переехала.

   Заводятся взамен служебной иконки Bootstrap `bi-fire` и эмодзи
   «🔥» и «❄». Эмодзи рисует шрифт операционной системы: на телефоне
   заказчика это одна картинка, на школьном компьютере другая,
   а рядом в шапке — наш собственный рисунок. Заметил заказчик
   29.08.2026 по разным огням на одном экране. */
.bt-gicon {
  width: 1.25em;
  height: 1.25em;
  object-fit: contain;
  vertical-align: -0.2em;
}

/* Погасший стрик нарисован серым отдельным файлом, поэтому гасить его
   ещё и прозрачностью не нужно: два способа сказать одно и то же
   складываются, и пламя становится едва различимым. Остальная часть
   индикатора приглушается по-прежнему. */
.bt-indicator--off .bt-gicon { opacity: 1; }

/* Снежинка в клетке календаря активности (10.2). Клетка маленькая,
   и число дня в ней прячется — вместо него стоит снежинка, потому что
   день заморозки узнаётся именно по ней. Размер в процентах от клетки:
   клетка задана через aspect-ratio и меняется вместе с шириной экрана.
   Картинка идёт через тег `{% img %}`, как и вся графика раздела 29,
   поэтому фоном её задать нельзя — фон не умеет подставлять заглушку. */
.bt-day__freeze {
  width: 70%;
  height: 70%;
  object-fit: contain;
}

/* Кольцо выполненной дневной цели — раздел 29.4, 128×128.
   Показывается на экране «Сегодня закрыто» (10.1: «при выполнении
   цели — анимация»). */
.bt-goal-done {
  width: 96px;
  height: 96px;
  object-fit: contain;
  animation: bt-goal-done 0.6s ease-out both;
}

@keyframes bt-goal-done {
  from { transform: scale(0.4); opacity: 0; }
  60%  { transform: scale(1.08); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

/* Человеку, который просил систему не двигать картинки, её и не двигаем.
   Само кольцо остаётся: оно несёт смысл, а не украшает. */
@media (prefers-reduced-motion: reduce) {
  .bt-goal-done { animation: none; }
}

/* Тепловая карта класса (16.3). Пять ступеней от красного к зелёному
   и отдельный серый для «данных нет»: ноль здесь означал бы «решал
   и не решил», а это противоположное утверждение. Цвет не остаётся
   единственным носителем смысла — в клетке стоит число, а в подсказке
   ступень названа словом. */
.bt-heat { border-collapse: separate; border-spacing: 2px; }
.bt-heat th { font-weight: 500; font-size: 0.8rem; white-space: nowrap; }
.bt-heat td.bt-heat__cell {
  width: 2.6rem;
  min-width: 2.6rem;
  text-align: center;
  font-size: 0.8rem;
  border-radius: 0.35rem;
  color: #fff;
}
.bt-heat__cell.bt-heat--0 { background: var(--bt-scale-0); }
.bt-heat__cell.bt-heat--1 { background: var(--bt-scale-1); }
.bt-heat__cell.bt-heat--2 { background: var(--bt-scale-2); color: var(--bt-dark); }
.bt-heat__cell.bt-heat--3 { background: var(--bt-scale-3); color: var(--bt-dark); }
.bt-heat__cell.bt-heat--4 { background: var(--bt-scale-4); color: var(--bt-dark); }
/* «Данных нет» — именно серая клетка, как обещает подпись под картой.
   Была `--bt-light` (#f4f3ef) — тот же цвет, что фон страницы, поэтому
   на светлой теме клетка выглядела просто пустым местом, и карта
   врала: подпись говорит «серая клетка — данных нет», а серых клеток
   на экране не было ни одной. Найдено на скриншотах заказчика
   01.09.2026. */
.bt-heat__cell.bt-heat--none {
  background: #dcdcd8;
  color: var(--bt-dark);
}
.bt-heat__topic {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  /* Названия тем бывают длинными («Число, большее или меньшее данного
     числа на заданное число разрядных единиц…»), и обрезать их
     приходится. Но 9rem обрезали даже короткие: высота считается
     по самому длинному названию, а не по каждому. 16rem — предел,
     после которого шапка перестаёт помещаться в экран ноутбука. */
  max-height: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bt-heat__average td { font-weight: 600; }

/* Таблица, которая на телефоне становится списком карточек.

   Появилась 01.09.2026 для кабинета учителя: у тех таблиц по пять
   колонок, и на 360 px `.table-responsive` уводил последнюю — с кнопкой
   «Пригласить учеников», «Исключить», «Открыть» — за правый край,
   не показав ни намёка на прокрутку. 06.09.2026 заказчик нашёл ту же
   беду в рейтинге школ и в «Моей статистике», и класс распространён
   на все таблицы продукта.

   Тогда же он описал, как строка должна выглядеть: «шапки нет, каждое
   поле подписано мелким шрифтом, в первом ряду дата и тест, во втором —
   верно и баллы, а под ними на всю ширину — кнопка». Отсюда сетка в две
   колонки: ячейки текут по две в ряд в том порядке, в каком стоят
   в разметке, а ячейка с действием помечается `bt-cards__wide`
   и занимает всю ширину.

   Первая колонка — `auto`: в ней стоят короткие значения (место, дата,
   счёт), и отдавать им половину строки незачем, длинному названию
   в соседней ячейке эта половина нужнее. Сетка своя у каждой строки,
   поэтому колонки соседних карточек могут не совпасть по ширине —
   так и задумано: на телефоне это уже не таблица, а список карточек,
   и выравнивать их между собой не по чему.

   Порог — 576 px, а не 440 px, которыми в остальном продукте меряется
   «маленький экран». Пять колонок разъезжаются гораздо раньше: рейтинг
   школ перестаёт помещаться уже около 700 px, и ждать 440 значило бы
   оставить сломанным весь диапазон телефона в альбомной ориентации. */
@media (max-width: 575.98px) {
  .bt-cards thead {
    display: none;
  }
  .bt-cards,
  .bt-cards tbody {
    display: block;
    width: auto;
  }
  .bt-cards tr {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.35rem 0.9rem;
    align-items: start;
    padding: 0.7rem 0.5rem;
    border-bottom: 1px solid var(--bt-track);
    /* Выделенную строку — «моя школа» в рейтинге, «мой результат»
       в битве — закрашиваем целиком по строке, а не по ячейкам.
       Bootstrap красит ячейки, и в сетке между ними оставались
       незакрашенные просветы: строка выглядела не выделенной,
       а составленной из отдельных серых плашек. Переменную объявляет
       сам Bootstrap на строке, так что имена классов состояния
       перечислять не нужно. */
    background-color: var(--bs-table-bg-state, transparent);
    border-radius: var(--bt-radius);
  }
  .bt-cards tr:last-child {
    border-bottom: 0;
  }
  .bt-cards th,
  .bt-cards td {
    display: block;
    width: auto;
    padding: 0;
    border: 0;
    /* Закраска ушла на строку — снимаем её с ячеек, иначе они
       нарисуют её поверх второй раз и по своим границам. Bootstrap
       красит выделенную ячейку не фоном, а внутренней тенью
       в девять тысяч пикселей, поэтому снимать нужно и то, и другое. */
    background-color: transparent;
    box-shadow: none;
    /* Выравнивание по правому краю осмысленно в колонке чисел
       и бессмысленно в карточке: `!important` здесь перебивает
       `text-end`, у которого он свой. */
    text-align: left !important;
    overflow-wrap: anywhere;
  }
  .bt-cards td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.75rem;
    line-height: 1.2;
    color: var(--bt-grey);
  }
  .bt-cards td:empty {
    display: none;
  }
  /* Ячейка во всю ширину карточки — обычно с кнопкой действия.
     Кнопка в ней растягивается по тому же правилу, по которому
     растягиваются одиночные кнопки на маленьком экране. */
  .bt-cards .bt-cards__wide {
    grid-column: 1 / -1;
  }
  .bt-cards .bt-cards__wide > .btn,
  .bt-cards .bt-cards__wide > form > .btn {
    width: 100%;
  }
}

/* Код приглашения в класс (16.2). Его диктуют вслух и переписывают
   с доски, поэтому он крупный, моноширинный и с разрядкой: восемь
   знаков подряд мелким шрифтом читаются с ошибками именно так, как
   и задумано алфавитом кода — без нуля и единицы. */
.bt-invite-code {
  font-family: var(--bs-font-monospace, monospace);
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--bt-dark);
}

/* Строка «название темы — счёт» над полоской прогресса.

   Правка 2, пункт 19 (06.09.2026). Стояла на голых утилитах flex,
   и правая часть сжималась наравне с левой: у темы «Преобразование
   рациональных выражений и действия со степенями» счёт «1 из 1»
   вставал тремя строками — «1», «из», «1», — а сама полоска уезжала
   вниз. Здесь три правила, и каждое лечит свою половину беды:
   `min-width: 0` разрешает названию переноситься (без него flex
   не даёт элементу стать уже своего содержимого), `flex: 0 0 auto`
   запрещает сжимать счёт, `white-space: nowrap` — рвать его. */
.bt-topic-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.bt-topic-line > :first-child {
  min-width: 0;
  overflow-wrap: anywhere;
}

.bt-topic-line > :last-child {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* Страница результатов (12.3). Ширина стояла здесь же, но в атрибуте
   `style` прямо в шаблоне; вынесена, чтобы низ страницы и колонка
   мерились одним правилом. */
.bt-results {
  max-width: 46rem;
  margin: 0 auto;
}

/* Низ страницы результатов — правка 9, пункт 16.

   «На узком экране на результатах криво расположены кнопки… давай
   кнопки растянем на всю ширину узкого экрана, а ссылку расположим
   под кнопками. На широком экране все кнопки можно расположить
   в один ряд, а ссылку сделать ниже». Кнопки лежат в формах (тест
   заводится POST-ом), поэтому ширину задаём и форме, и кнопке:
   растянуть одну кнопку внутри неразтянутой формы нельзя. */
.bt-results__buttons {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.bt-results__buttons > form {
  width: 100%;
}

.bt-results__buttons .btn {
  width: 100%;
}

/* Правка 12, пункт 12: на широком экране кнопки по центру —
   так же, как ссылка «На главную» под ними (правка 10, пункт 5). */
@media (min-width: 576px) {
  .bt-results__buttons {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
  }

  .bt-results__buttons > form,
  .bt-results__buttons .btn {
    width: auto;
  }
}

/* Заголовок модального окна с длинным названием темы. Крестик закрытия
   сжимался вместе с заголовком и превращался в щель: имя темы в разборе
   бывает в десять слов (снимок окна разбора 06.09.2026). */
.modal-header .btn-close {
  flex: 0 0 auto;
}

.modal-title {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Раскрывающийся блок, заголовок которого выглядит ссылкой.

   Стрелку `<summary>` рисует браузер, и по умолчанию он ставит её
   маркером списка — со своим отступом, который не совпадает ни с чем
   вокруг. Здесь она заменена на своё изображение, чтобы блок вставал
   в один ряд с остальным текстом карточки. */
.bt-summary-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  color: var(--bs-link-color);
  list-style: none;
}

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

.bt-summary-link::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg) translate(-0.1em, 0.1em);
  transition: transform 0.15s ease;
}

details[open] > .bt-summary-link::before {
  transform: rotate(45deg) translate(-0.05em, -0.05em);
}

.bt-summary-link:hover {
  color: var(--bs-link-hover-color);
}

/* Кнопка, которой на самом деле служит `<summary>` раскрывающегося
   блока («Подать заявку» на странице «Я учитель»).

   Браузер по умолчанию делает `<summary>` элементом списка — со своим
   маркером-треугольником и своим отступом. Из-за этого он не слушался
   центрующей обёртки и стоял левее всех остальных кнопок страницы
   (правка 2, пункт 7). */
.bt-summary-btn {
  display: inline-block;
  list-style: none;
}

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

/* QR-код, который открывается во весь экран по клику.
   Правка 2, пункт 11 (06.09.2026). */
/* По центру своего блока — правка 6, пункт 10: «давай центровать их
   (здесь и в других местах)». Правило одно на все четыре кода сайта
   (личная ссылка, битва, приглашение в класс, бот МАКСа), а не отступ
   на том экране, с которого пришло замечание: `inline-block` внутри
   выключенного влево текста прижимал свиток к левому краю карточки,
   и на широком экране рядом с ним оставалось полкарточки пустоты. */
.bt-qr {
  display: block;
  width: fit-content;
  margin-inline: auto;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: none;
  text-align: center;
  cursor: zoom-in;
}

.bt-qr__img {
  display: block;
  width: 320px;
  max-width: 100%;
  height: auto;
  border-radius: var(--bt-radius);
}

/* Подпись под кодом: без неё непонятно, что пергамент нажимается.
   Курсор-лупа виден только мышью, а код чаще всего смотрят
   с телефона, где курсора нет вовсе. */
.bt-qr__hint {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.85rem;
  color: var(--bt-dark);
}

.bt-qr:hover .bt-qr__hint {
  color: var(--bt-orange-dark);
}

/* Само окно. Фон снят: на просвет виден затемнённый экран, и пергамент
   лежит на нём как лист на столе — своя рамка ему только мешала бы. */
.bt-qr-full {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: transparent;
  border: 0;
}

.bt-qr-full__img {
  /* Квадрат: сторона ограничена и шириной, и высотой экрана, иначе
     на узком телефоне в альбомной ориентации код вылезет за нижний
     край, а на широком мониторе растянется до нечитаемой каши. */
  width: min(100%, 88vh, 40rem);
  height: auto;
  border-radius: var(--bt-radius);
}

.bt-qr-full__close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  padding: 0.75rem;
  background-color: #fff;
  border-radius: 50%;
  opacity: 0.9;
}

/* --------------------------------------------------------------------------
   Дуэль: предложение и приглашение (правка 8, блок 7.7)
   --------------------------------------------------------------------------
   Обоим экранам разметку написали, а оформление — нет: имён
   `bt-duel-offer`, `bt-duel-offer__art` и `bt-duel-invite` в таблице
   стилей не было вовсе. Поэтому картинка выводилась в свои 800 точек
   в столбец, а текст и кнопки растягивались во всю ширину монитора
   (правка 9, пункты 9 и 11 — это одна поломка, а не две). */
.bt-duel-offer {
  max-width: 34rem;
  margin: 0 auto;
}

/* Приглашение шире: в нём два столбца — код слева, друзья справа. */
.bt-duel-invite {
  max-width: 52rem;
  margin: 0 auto;
}

/* Экран ожидания генерации (блок 7.9) — та же беда, найденная
   проверкой ниже, а не снимком: класс был, правила не было, и строка
   про «модель пишет вопросы» растягивалась во всю ширину монитора. */
.bt-generating {
  max-width: 34rem;
  margin: 0 auto;
}

/* Картинка «staredown» квадратная. Ширина задаётся долей колонки,
   а не пикселями: на телефоне занимает её целиком, на мониторе
   останавливается, не доходя до краёв. */
.bt-duel-offer__art {
  display: block;
  width: min(100%, 20rem);
  height: auto;
  /* Картинка квадратная, и заглушка на её месте должна быть такой же:
     без этого пунктирная рамка вытягивалась в столбец (снимок 1). */
  aspect-ratio: 1;
  object-fit: contain;
  margin: 1rem auto 0;
  border-radius: var(--bt-radius);
}

/* --------------------------------------------------------------------------
   Страница «Вопросы» — рабочее место автора вопросов (правка 4, задача 6.2)
   --------------------------------------------------------------------------
   Список здесь сам является формой: у каждой строки свои поля и своя
   кнопка «Сохранить». Заказчик нарисовал две раскладки — 900 px и шире
   и 360 px, — и рубеж между ними стоит именно на 900: в макетах при
   этой ширине кнопка «Сохранить» уходит вправо отдельным столбцом,
   а ниже ложится под поля во всю ширину.

   Ширины полей внутри строки задаёт вкладка: у предмета их три,
   у вопроса полтора десятка. Здесь только общая рамка — сама строка,
   колонка действий и одно поле.
   -------------------------------------------------------------------------- */

.bt-content-page {
  max-width: 64rem;
  margin: 0 auto;
}

.bt-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.bt-list__add {
  margin-top: 0.75rem;
}

.bt-list__add--top {
  margin-top: 0;
  margin-bottom: 0.75rem;
}

.bt-row {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0.75rem;
  background-color: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bt-radius);
}

/* Незаведённая строка помечена рамкой: пока её не сохранили, она
   существует только в браузере, и перезагрузка страницы её потеряет.
   Без пометки это выглядело бы как потеря данных. */
.bt-row--new {
  border-color: var(--bt-orange);
}

.bt-row__fields {
  /* Гибкая строка, а не сетка из двух колонок. Сетка держала бы место
     под иконку и там, где иконки нет: на вкладке «Темы» поля занимали
     две трети ширины, а справа оставалась пустота. Гибкая строка
     подстраивается под то, что в ней есть, — иконка занимает своё,
     колонка полей забирает остальное.

     Иконка при этом стоит слева от полей на всех ширинах, включая 360:
     так нарисовано в макете 1, и так строка остаётся строкой,
     а не разваливается на два этажа.

     Перенос разрешён ради одной вещи — подсказки к иконке в новой
     строке: она уходит на собственную строку во всю ширину
     (`.bt-icon__note`). Больше переносить здесь нечему: иконка
     и колонка полей помещаются рядом на любой ширине. */
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  align-items: flex-start;
}

.bt-row__actions {
  /* Промежуток колонки назван переменной: на него же опирается распорка
     `.bt-row__spacer`, которая выравнивает первую кнопку с полями. */
  --bt-actions-gap: 0.25rem;

  display: flex;
  flex-direction: column;
  gap: var(--bt-actions-gap);
}

.bt-row__note:empty {
  display: none;
}

.bt-field {
  min-width: 0;
}

/* Подпись поля и подсказка мелким шрифтом — выбор заказчика из двух
   предложенных способов (правка 4): «либо вместо всплывающих подсказок
   можно сделать обычные подсказки под полями мелким шрифтом». */
.bt-field .form-label {
  margin-bottom: 0.125rem;
  font-size: 0.8125rem;
  color: var(--bs-secondary-color);
}

.bt-field .form-text {
  margin-top: 0.125rem;
  font-size: 0.75rem;
}

/* У флажка подпись стоит справа от квадратика, поэтому собственная
   надпись поля ему не нужна — иначе она читалась бы заголовком
   соседнего поля. */
.bt-field--check {
  align-self: center;
  padding-top: 1.125rem;
}

@media (min-width: 900px) {
  .bt-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 10rem;
    align-items: start;
  }

  .bt-row__actions {
    /* Кнопка выравнивается по верху строки, как в макетах: у длинной
       строки с полем «что должен освоить ученик» она иначе уезжала бы
       к её низу и терялась из виду. */
    align-items: stretch;
  }
}

/* Колонка полей внутри строки: у предмета это название и «Активен»,
   у темы — четыре поля и описание. Отдельный класс нужен затем, чтобы
   вкладка могла разложить свои поля, не переопределяя саму строку. */
.bt-row__col {
  display: grid;
  gap: 0.25rem 0.75rem;
  grid-template-columns: 1fr;
  align-content: start;
  /* Забирает всю ширину, оставшуюся от иконки. `min-width: 0` —
     чтобы длинное название темы сжимало поле, а не растягивало строку
     за край экрана.

     Основа — ноль, а не `auto`: с тех пор как строке разрешён перенос
     (ради подсказки к иконке, правка 5), колонка с основой по
     содержимому просила бы ширину своих самых длинных подсказок
     и уезжала бы под иконку целиком вместо того, чтобы встать рядом
     с ней и сжаться. */
  flex: 1 1 0;
  min-width: 0;
}

/* --- иконка строки (задача 6.3) --------------------------------------- */

.bt-icon {
  position: relative;
  flex: 0 0 auto;
  /* Ширина — та же пропорция 2:3, что и у самого файла (512×768).
     Рамка держит размер и в пустом состоянии: иначе строка прыгала бы
     по высоте в тот момент, когда картинку бросают. */
  width: 5rem;
}

.bt-icon__box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 5rem;
  height: 7.5rem;
  overflow: hidden;
  cursor: pointer;
  background-color: var(--bt-track);
  border: 1px dashed var(--bs-border-color);
  border-radius: var(--bt-radius);
}

.bt-icon--over .bt-icon__box {
  border-color: var(--bt-orange);
  border-style: solid;
}

.bt-icon__img {
  width: 100%;
  height: 100%;
  /* Вписывание, а не обрезка: тем же правилом файл обрабатывается
     на сервере, и показывать его иначе, чем он сохранён, нельзя. */
  object-fit: contain;
}

.bt-icon__hint {
  display: none;
  padding: 0.25rem;
  font-size: 0.6875rem;
  line-height: 1.2;
  color: var(--bs-secondary-color);
  text-align: center;
}

.bt-icon--empty .bt-icon__img { display: none; }
.bt-icon--empty .bt-icon__hint { display: block; }

/* Заполненная рамка сплошная: пунктир означает «сюда можно бросить»,
   и оставлять его под готовой картинкой значило бы звать бросить
   ещё раз. Бросить, впрочем, по-прежнему можно — на саму картинку. */
.bt-icon:not(.bt-icon--empty) .bt-icon__box {
  border-style: solid;
}

/* «Кнопка „Удалить" при наведении курсора на неё» — правка 4, п. 2.1.
   Показывается только у своей загруженной картинки: у нарисованного
   значка из static удалять нечего, и кнопка, которая ничего не делает,
   хуже отсутствующей. */
.bt-icon__remove {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
  display: none;
  padding: 0.125rem 0.375rem;
  font-size: 0.75rem;
  background-color: var(--bs-body-bg);
}

.bt-icon--own:hover .bt-icon__remove,
.bt-icon--own:focus-within .bt-icon__remove {
  display: block;
}

/* Подсказка к иконке — отдельная строка во всю ширину, под иконкой
   и полями сразу. Выводится только в новой строке (см.
   `content/_icon.html`).

   Прежде она лежала внутри колонки иконки и получала ширину в 12rem
   при колонке в 5rem: текст вылезал из колонки и ложился поверх полей
   соседней — на узком экране это было видно сразу (правка 5, пункт 1).
   Ширина в процентах, а не в rem: строка сама знает, сколько у неё
   места, а подобранное число разъедется при первой смене раскладки. */
.bt-icon__note {
  flex: 1 0 100%;
  /* Последней в строке, хотя в разметке она сразу за иконкой: там ей
     место по смыслу (это подсказка к полю файла и часть его блока),
     а на экране она обязана стоять под всей строкой. Без этого
     подсказка переносила строку сама и уводила колонку полей
     на третий этаж — иконка оставалась одна наверху, чего макет 1
     не предполагает. */
  order: 1;
  margin-top: 0;
  font-size: 0.6875rem;
}


/* --- вкладка «Темы» (задача 6.4) -------------------------------------- */

/* Выпадающие списки «Предмет» и «Класс» над списком тем. Они и фильтр,
   и значение для новых строк, поэтому стоят отдельной полосой, а не
   внутри строки. */
.bt-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  align-items: end;
  margin-bottom: 0.75rem;
}

/* `min-width: 0` — не украшение, а починка боковой прокрутки, найденной
   на айфоне 09.09.2026: «на вкладке „Вопросы" появилась длинная боковая
   прокрутка, ни один элемент вбок не торчит».

   Торчать и правда было нечему. У элемента флекса ширина по умолчанию
   не может стать меньше содержимого (`min-width: auto`), а минимальная
   ширина `<select>` в WebKit считается по самому длинному пункту
   списка. Пункты фильтра «Тема» — это полные названия тем, и одно
   из них («Числа в пределах миллиона и больше: классы и разряды,
   чтение, запись, сравнение, разрядные слагаемые») задавало полю
   ширину в полторы тысячи точек. Само поле при этом рисовалось
   обрезанным по экрану — видна была только прокрутка, а причина нет.
   В Chrome этого не видно: там у `<select>` своя, маленькая
   минимальная ширина, поэтому дефект дожил до боевого сервера.

   Правило общее для всех полей отбора, а не для одной «Темы»: длинный
   пункт может завестись в любом списке, и ловить его по одному
   значило бы ждать следующего айфона. */
.bt-picker .bt-field {
  flex: 1 1 10rem;
  min-width: 0;
}

.bt-picker .bt-field .form-select,
.bt-picker .bt-field .form-control {
  max-width: 100%;
}

/* Поле, чья подпись длиннее прочих, берёт себе больше свободного места
   вместо того, чтобы обрезать её многоточием: самая длинная подпись
   статуса — «Только активные и черновики». */
.bt-picker .bt-field--status {
  flex: 1.4 1 14rem;
}

/* Порядок фильтров вкладки «Вопросы» — решение заказчика от 09.09.2026:
   «на широких экранах поставить фильтры „Предмет", „Класс" и „Статус"
   в верхнем ряду, а фильтр „Тема" — на ряд ниже. Тема потенциально
   самая длинная, ей нужно больше места».

   «Ряд ниже» получается не переносом строки, а полной шириной у самой
   «Темы»: ряд бы «поехал» при любой смене числа фильтров, а поле,
   занимающее строку целиком, остаётся на своей строке всегда.

   Порядок задан по именам полей, а не по их номеру в разметке: правка 6
   уже показала, чем плох `nth-child` — добавленный четвёртым фильтр
   сдвинул нумерацию, и «Статус» уехал в начало строки. */
.bt-picker .bt-field--subject { order: 1; }
.bt-picker .bt-field--class { order: 2; }
.bt-picker .bt-field--status { order: 3; }
.bt-picker .bt-field--topic { order: 4; flex-basis: 100%; }
.bt-picker .bt-picker__row { order: 5; }
.bt-picker .bt-picker__go { order: 6; }

.bt-topic {
  gap: 0.25rem;
}

/* Номер, «Активна», четверть и порядок стоят в ряд под названием
   (макет 2). Сетка, а не перенос по минимальной ширине: заказчик
   10.10.2026 попросил, чтобы четыре поля занимали строку целиком —
   по четверти на широком экране и по половине, в две строки,
   на узком. У новой строки номера нет, и полей три — сетка
   оставляет четвёртую клетку пустой, а не растягивает соседей. */
.bt-topic__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.25rem 0.75rem;
  align-items: start;
}

@media (min-width: 768px) {
  .bt-topic__meta {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Флажку подпись поля не нужна (она справа от квадратика), поэтому
   он опущен на высоту подписи соседей и стоит вровень с их полями.
   `min-width: 0` — чтобы длинная подсказка новой строки переносилась,
   а не выдавливала сетку за край карточки (правка 5, пункт 1). */
/* В половине узкого экрана «Все четверти» подлезало под стрелку:
   стрелке оставлено ровно её место, а не бутстраповский запас. */
.bt-topic__meta .form-select {
  padding-left: 0.625rem;
  padding-right: 1.5rem;
  background-position: right 0.375rem center;
}

/* На самых узких телефонах (360 px) и этого не хватает на одну букву. */
@media (max-width: 400px) {
  .bt-topic__meta .form-select {
    font-size: 0.9375rem;
  }
}

.bt-topic__meta .bt-field--check {
  align-self: start;
  min-width: 0;
  padding-top: 2.25rem;
}

.bt-topic__outcome textarea {
  min-height: 4.5rem;
}

/* Кнопка «Показать» нужна только там, где скрипт не выполнился:
   со скриптом список переключается сам при смене предмета или класса.
   Класс ставит `content-rows.js`, поэтому без скрипта кнопка остаётся
   видимой и страница работает целиком. */
.bt-picker--auto .bt-picker__go {
  display: none;
}

/* Название темы — поле в две строки (решение заказчика 08.09.2026).
   Настоящие названия длинные, и в одну строку человек правит текст,
   видя от него треть. Растягивать поле мышью незачем: две строки —
   это ровно то, что попросили, и одинаково на всех ширинах. */
.bt-topic__name textarea {
  min-height: 3.75rem;
  resize: none;
}

/* --- загрузка файла с темами (задача 6.5) ----------------------------- */

/* «Для широких экранов на вкладке есть поле для перетаскивания xlsx
   файлов с темами» — правка 4, макет 2. На узком экране области нет:
   файл с телефона не перетащишь, а место она заняла бы у всех.
   Кнопка «Скачать образец» остаётся везде — образец нужен и тому,
   кто заполнит его на компьютере позже. */
.bt-upload {
  display: none;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.75rem;
}

.bt-upload__box {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  min-height: 4rem;
  padding: 0.75rem;
  color: var(--bs-secondary-color);
  text-align: center;
  cursor: pointer;
  background-color: var(--bt-track);
  border: 2px dashed var(--bs-border-color);
  border-radius: var(--bt-radius);
}

.bt-upload--over .bt-upload__box {
  color: var(--bt-orange-dark);
  border-color: var(--bt-orange);
}

@media (min-width: 900px) {
  .bt-upload {
    display: flex;
  }
}

/* --- вкладка «Подборки» (задача 6.6) ---------------------------------- */

/* Макет 3: кнопки «Вопросы в подборке» и «Сохранить» идут во всю ширину
   строки, под полями, а не отдельной колонкой справа. Строка подборки
   ниже строки предмета, и узкая колонка кнопок оставляла бы справа
   пустой столб в половину высоты. */
.bt-row--wide {
  display: flex;
  flex-direction: column;
  /* Явно, а не по умолчанию: на широком экране сама `.bt-row` — сетка
     с `align-items: start`, и это правило досталось бы столбцу
     в наследство. Кнопки тогда сжимаются до своего текста вместо
     того, чтобы занять ширину строки, — ровно это и было видно
     на первом снимке вкладки. */
  align-items: stretch;
}

.bt-row--wide .bt-row__actions {
  gap: 0.5rem;
}

/* Правка 19, пункт 1: на широком экране кнопки подборки встают в один
   ряд равной ширины во всю строку; на узком остаются столбиком. */
@media (min-width: 900px) {
  .bt-row--wide .bt-row__actions {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .bt-row--wide .bt-row__actions > .btn {
    flex: 1 1 0;
    min-width: 0;
  }

  .bt-row--wide .bt-row__note {
    flex-basis: 100%;
  }
}

.bt-collection {
  gap: 0.25rem;
}

.bt-collection__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  align-items: start;
}

/* Предмету места больше, чем классу: «Обществознание» в списке
   на 10rem не помещается и наезжает на стрелку, а «5 класс»
   помещается с запасом. */
.bt-collection__meta .bt-field {
  flex: 2 1 12rem;
}

.bt-collection__meta .bt-field:nth-child(2) {
  flex: 1 1 8rem;
}

/* Тот же случай, что у флажка темы: ширина по длинной подсказке
   уводила строку за правый край (правка 5, пункт 1). Правило стоит
   здесь, а не рядом с темами: оно должно идти после
   `.bt-collection__meta .bt-field` — сила у них одинаковая,
   и решает порядок. */
.bt-collection__meta .bt-field--check {
  flex: 0 1 auto;
  min-width: 0;
}

.bt-collection__name textarea {
  min-height: 3.75rem;
  resize: none;
}

/* Пометка «задача N» у кнопки, которую ещё пишет своя задача. Тем же
   способом помечены ненаписанные пункты выпадающего меню. Правило
   общее для всех кнопок страницы: у отдельного `.bt-row__extra`
   пометка на кнопке «Добавить вопрос» осталась без отступа
   и слиплась с подписью — это было видно на первом снимке вкладки. */
.bt-soon {
  margin-left: 0.5rem;
  font-size: 0.75rem;
  color: var(--bt-grey);
  white-space: nowrap;
}

/* В узкой колонке действий пометка не помещается рядом с подписью
   и вылезает за кнопку — уходит под неё отдельной строкой. */
.bt-row__extra .bt-soon {
  display: block;
  margin-left: 0;
}

/* --- окно «Вопросы в подборке» (задача 6.7) --------------------------- */

/* Поиск и два фильтра одной полосой. На узком экране переносятся сами:
   расположение элементов окна одинаковое для всех разрешений (макет 4),
   меняется только число полос. */
.bt-items__search {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.bt-items__search input {
  flex: 3 1 14rem;
}

.bt-items__search select {
  flex: 1 1 8rem;
}

/* Черта между найденным и тем, что уже в подборке (макет 4). Заметная,
   а не волосок: она разделяет два списка одинаковых на вид строк,
   и спутать их нельзя. */
.bt-items__line {
  margin: 1rem 0;
  border-top: 2px solid var(--bt-orange);
  opacity: 1;
}

.bt-items__found,
.bt-items__chosen {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.bt-item {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  padding: 0.375rem 0.5rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bt-radius);
}

.bt-item__id {
  flex: 0 0 auto;
  min-width: 2.5rem;
  padding: 0.125rem 0.375rem;
  font-size: 0.8125rem;
  color: var(--bs-secondary-color);
  text-align: center;
  border: 1px solid var(--bs-border-color);
  border-radius: 0.5rem;
}

.bt-item__text {
  flex: 1 1 auto;
  min-width: 0;
  /* Две строки и многоточие: тексты вопросов бывают в абзац, и полный
     текст растянул бы список из десяти строк на два экрана. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.bt-item__action {
  flex: 0 0 auto;
}

/* «На узких экранах надпись „Удалить" на кнопке заменяется
   на пиктограмму урны» — правка 4, пункт 2.3. Оба варианта лежат
   в разметке, показывает нужный CSS: подменять текст скриптом значит
   держать ширину экрана в двух местах сразу. */
.bt-item__sign {
  display: inline;
}

.bt-item__word {
  display: none;
}

@media (min-width: 576px) {
  .bt-item__sign {
    display: none;
  }

  .bt-item__word {
    display: inline;
  }
}

/* --- вкладка «Вопросы» (задача 6.8) ----------------------------------- */

/* Поиск с кнопкой — отдельной строкой во всю ширину (макет 5).
   В поле вводят и «1042», и «нахождение доли числа», и узкое поле
   в 8rem годится только для первого. */
.bt-picker__row {
  display: flex;
  flex: 1 1 100%;
  gap: 0.5rem 0.75rem;
  align-items: end;
}

.bt-picker__row .bt-field {
  flex: 1 1 auto;
}

.bt-question {
  gap: 0.25rem;
}

/* По верху, а не по низу: поля теперь одной высоты, и выравнивание
   по верхнему краю совпадает с подписями. */
.bt-question__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  align-items: start;
}

.bt-question__meta .bt-field {
  flex: 1 1 12rem;
}

/* Номер вопроса — не поле ввода: он чёрный на макете 5, то есть
   неизменяемый. По нему вопрос ищут и на него ссылаются отчёты
   импорта, и правка номера означала бы правку всех этих ссылок. */
.bt-field--flat {
  flex: 0 0 auto;
}

/* Серый фон, а не белый: поле выглядит как поле ввода, и без отличия
   его пробуют править. Номер вопроса не меняется никогда. Всё
   остальное — отступы, рамка, высота — достаётся ему от Bootstrap
   вместе с классом `form-control`, поэтому оно точно совпадает
   со «Статусом» рядом. */
.bt-question__id {
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
  background-color: var(--bt-track);
}

.bt-field--id {
  flex: 0 1 8rem;
}

.bt-question__body textarea {
  min-height: 5rem;
}

/* --- окно вопроса целиком (задача 6.9) -------------------------------- */

/* Пары полей в ряд: тип и сложность, время и балл. На узком экране
   переносятся сами — минимальная ширина, а не доля. */
.bt-card__pair {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
}

/* `min-width: 0` — по той же причине, что и у полей отбора: в списках
   «Тема 1/2/3» лежат полные названия тем, а минимальная ширина
   `<select>` в WebKit считается по самому длинному пункту. Без этого
   окно вопроса на айфоне обзаводилось бы собственной боковой
   прокруткой. Здесь правило поставлено на будущее, а не по жалобе:
   дефект тот же самый, и ждать второго айфона незачем. */
.bt-card__pair .bt-field {
  flex: 1 1 12rem;
  min-width: 0;
}

[data-bt-card] .form-select,
[data-bt-card] .form-control {
  max-width: 100%;
}

/* Строка варианта в редакторе вопроса. Называлась `.bt-option` —
   третье столкновение имён за две недели, найденное уже не снимком
   заказчика, а проверкой (правка 9, блок 8.1). Так же называется
   вариант ответа на экране теста, и редактор молча получал от него
   рамку, белый фон, отступ в 0,6 rem, оранжевую подсветку по наведению
   и заливку выбранного варианта. */
.bt-card__option {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.5rem;
  align-items: center;
  margin-bottom: 0.375rem;
}

.bt-card__option input[type="text"] {
  flex: 1 1 12rem;
}

.bt-card__option-check {
  display: flex;
  flex: 0 0 auto;
  gap: 0.375rem;
  align-items: center;
  font-size: 0.8125rem;
  white-space: nowrap;
  cursor: pointer;
}

.bt-card__answers,
.bt-card__open {
  margin-bottom: 0.75rem;
}

.bt-attach {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  justify-content: space-between;
  padding: 0.375rem 0.5rem;
  margin-bottom: 0.375rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bt-radius);
}

/* Область перетаскивания внутри окна — та же, что на вкладке «Темы»,
   но видна на всех ширинах: файл к вопросу прикладывают и с телефона,
   а кнопка выбора работает везде. */
.bt-card__drop {
  display: flex;
  width: 100%;
  min-height: 3.5rem;
}

/* Превью вложения в окне вопроса — правка 13, пункт 5: видно, что
   загрузилось именно то, а не только тип файла. */
/* Правка 14, пункт 4: строка с картинкой встаёт столбцом — превью
   на всю ширину, втрое выше прежнего квадрата 4rem, целиком и без
   обрезки; «Убрать» под ним по центру. */
.bt-attach:has(.bt-attach__preview) {
  flex-direction: column;
  align-items: center;
}

.bt-attach__preview {
  width: 100%;
  height: 12rem;
  object-fit: contain;
  border-radius: var(--bt-radius);
}

/* Подпись «Картинка» под самой картинкой ничего не добавляет. */
.bt-attach:has(.bt-attach__preview) .bt-attach__label {
  display: none;
}

.bt-attach__audio {
  max-width: 14rem;
  height: 2rem;
}

.bt-attach__label {
  flex: 1 1 auto;
}

.bt-card__drop.bt-upload--over {
  color: var(--bt-orange-dark);
  border-color: var(--bt-orange);
}

/* Подвал окна вопроса — правка 6, пункт 5.

   На широком экране один ряд: навигация слева, состояние посередине,
   «Закрыть» и «Сохранить» справа. Строка состояния распирает ряд
   (`flex: 1`), и от этого две группы кнопок расходятся по краям сами,
   без утилиты `me-auto` на одной из них. */
.bt-card__foot {
  gap: 0.5rem;
  flex-wrap: nowrap;
  align-items: center;
}

.bt-card__nav,
.bt-card__acts {
  display: flex;
  flex: 0 0 auto;
  gap: 0.5rem;
}

.bt-card__foot .bt-card__note {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
}

/* На узком экране — два ряда, как просил заказчик: «в верхнем ряду
   кнопки навигации (их следует растянуть так, чтобы они занимали всю
   ширину), внизу — кнопки закрыть и сохранить (также на всю ширину).
   Между рядами кнопок должно быть некоторое расстояние, чтобы случайно
   не нажать на „сохранить"».

   Рубеж 992 px, а не общие для страницы 900 и не «узкий экран»
   на глаз: считать надо ширину окна, а не экрана. `modal-lg`
   разворачивается до 800 px только с 992 px, а до этого держит 500 —
   и четыре кнопки в 500 не помещаются. Снимок в 768 показал ровно
   это: «Назад» уехала за левый край окна.

   Промежуток между рядами задан отдельной величиной и намеренно
   крупнее обычного зазора: он здесь не для красоты, а чтобы палец,
   промахнувшийся мимо «Вперёд», не попал в «Сохранить». */
@media (max-width: 991.98px) {
  .bt-card__foot {
    flex-direction: column;
    align-items: stretch;
    gap: 1.25rem;
  }

  .bt-card__nav > .btn,
  .bt-card__acts > .btn {
    flex: 1 1 0;
  }

  /* Состояние прижимается к своему ряду кнопок, а не висит посередине
     промежутка: иначе разрыв, отделяющий «Сохранить», зрительно
     схлопывается обратно. */
  .bt-card__foot .bt-card__note {
    order: -1;
    margin-bottom: -0.75rem;
  }

  .bt-card__foot .bt-card__note:empty {
    display: none;
  }
}

/* --- выравнивание строки и порядок фильтров (правка заказчика 08.09.2026) --- */

/* «Верхний край кнопки „Открыть" должен быть в одну линию с верхним
   краем полей» — просьба заказчика от 08.09.2026. Выравнивает распорка
   в колонке действий (см. `content/_row.html`): это такая же подпись
   поля, только с неразрывным пробелом вместо текста, поэтому её высота
   равна высоте настоящей подписи и меняется вместе со шрифтом,
   а не подобранным числом. Отрицательный отступ снизу гасит
   промежуток колонки — иначе кнопка опустилась бы на него ниже полей.
   В узком экране распорка не нужна: кнопки идут под полями отдельной
   строкой, и выравнивать их не с чем. */
.bt-row__spacer {
  display: none;
  margin-bottom: calc(-1 * var(--bt-actions-gap));
}

/* Настоящая подпись — это `<label>`, а он у Bootstrap `inline-block`;
   у распорки внутри `<span>`, и без этой строки её строка вышла бы
   на неполный пиксель ниже. */
.bt-row__spacer .form-label {
  display: inline-block;
}

@media (min-width: 900px) {
  .bt-row:not(.bt-row--wide) .bt-row__spacer {
    display: block;
  }
}

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

   09.09.2026 заказчик поменял местами «Статус» и «Тему» на узком
   экране: до этого парой стояли «Класс» и «Тема», и длинному названию
   темы доставалась половина строки.

   Рубеж 992, а не общие для страницы 900: между 900 и 991 ширина
   колонки — 720 точек, и три поля в ряд с подписью «Только активные
   и черновики» в неё не помещаются. Это не вкус, а арифметика ширин,
   и совпадать с рубежом строки списка она не обязана. */
@media (max-width: 991.98px) {
  .bt-picker .bt-field--subject { flex-basis: 100%; }
}

/* ------------------------------------------------------------------
   Витрина главной. Правка 8 заказчика от 15.09.2026.

   Строки карточек, которые «пролистываются вбок», и вкладки предметов
   над ними. Прокрутка сделана самим списком — `overflow-x` плюс
   `scroll-snap`, — а не скриптом: браузер умеет это сам, инерцию
   на телефоне даёт из коробки, и карусель на скриптах была бы лишними
   килобайтами и сломанной прокруткой на половине устройств.
   ------------------------------------------------------------------ */
.bt-home {
  max-width: 62rem;
  margin: 0 auto;
}

/* Полка — заголовок, кнопка «все» и лента карточек. Названа полкой,
   а не строкой: класс `.bt-row` занят строкой справочника на странице
   «Вопросы», и витрина, взявшая его, приезжала бы с чужой рамкой
   и чужим `display: flex` (поймано снимком экрана 16.09.2026). */
.bt-shelf {
  display: block;
}

/* Вкладки предметов (скриншот 2 заказчика): подчёркивание активной,
   без рамок и заливок. Сами вкладки тоже прокручиваются вбок —
   предметов бывает тринадцать, а экран один. */
.bt-subjects {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.bt-subjects::-webkit-scrollbar { display: none; }

.bt-subjects__tab {
  flex: 0 0 auto;
  padding: 0.5rem 0;
  color: var(--bt-dark);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}

.bt-subjects__tab:hover { color: var(--bt-orange); }

.bt-subjects__tab--on {
  color: var(--bt-orange);
  font-weight: 600;
  border-bottom-color: var(--bt-orange);
}

/* Лента карточек внутри полки.

   Называлась `.bt-cards` и тем самым во второй раз повторила историю
   `.bt-row`: это имя с 01.09.2026 занято таблицами, которые на телефоне
   становятся списком карточек. Витрина объявила ему `display: flex`
   без медиазапроса — и все двенадцать таких таблиц (история покупок,
   рейтинг школ, статистика, лига, лидерборд битвы, нехватка вопросов,
   приватность и пять таблиц кабинета учителя) на любой ширине
   раскладывались флексом: шапка одним столбцом слева, строки другим
   справа. Заказчик прислал снимки статистики и лиги (правка 9,
   пункты 21 и 25), до остальных десяти просто не дошёл. */
.bt-shelf__lane {
  display: flex;
  gap: 0.75rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  /* Место под тень карточки: без него нижний край тени срезается
     прокруткой. */
  padding-bottom: 0.5rem;
  scrollbar-width: none;
}

.bt-shelf__lane::-webkit-scrollbar { display: none; }

/* Правка 16: на широком экране лента — сетка по пять в ряд, без
   прокрутки. Мышью ленту не протянуть (полоса скрыта, колесо листает
   вниз), а стрелки заказчику не понравились. На главной в строке
   не больше десяти карточек (`В_СТРОКЕ`), остальное — «все», так что
   рядов не больше двух. Узкий тачскрин остаётся с лентой. */
@media (min-width: 768px) {
  .bt-shelf__lane {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    overflow-x: visible;
    scroll-snap-type: none;
    row-gap: 1.25rem;
  }

  .bt-shelf__lane .bt-card {
    width: auto;
  }
}

/* Страница «все»: те же карточки, но переносятся, а не прокручиваются
   — их там может быть полсотни. */
.bt-shelf__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 0.75rem;
}

.bt-card {
  flex: 0 0 auto;
  width: 8.5rem;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  text-decoration: none;
}

.bt-shelf__grid .bt-card { width: auto; }

.bt-card:hover .bt-card__cover { transform: translateY(-2px); }
.bt-card:hover .bt-card__title { color: var(--bt-orange); }

/* Знак поверх картинки предмета — правка 9, пункт 2.

   «На всех карточках предметов нарисована книга и на ней в центре есть
   свободное место. На это свободное место можно что-то наложить».
   Отсюда размер: круг в 40% ширины карточки.

   Положение — 53% по ширине и 59% по высоте, а не середина карточки.
   Геометрический центр приходится на название предмета: у книги есть
   корешок слева и плашка с надписью сверху, и свободное место лежит
   ниже и правее середины. Заказчик увидел это на первом же снимке
   с настоящими картинками («знак наезжает на надпись „Математика"»)
   и предложил сместить знак; числа подобраны измерением, а не на глаз
   — по всем шести нарисованным картинкам предметов искалась самая
   однородная, то есть пустая, область под круг такого размера. Разброс
   между предметами вышел от 49% до 56% по ширине и от 58% до 63%
   по высоте.

   Измерение дало 53% и 61%; высоту заказчик поправил на 59% глазами
   (20.09.2026). Разница — две сотых высоты карточки, около шести точек
   на телефоне: измерение искало самое пустое место, а он смотрел,
   как знак стоит относительно книги целиком. Здесь его правка сильнее
   расчёта, и мерить заново не нужно.

   Картинка предмета и карточка — обе 2:3, поэтому доли по одной
   и другой совпадают: `object-fit: cover` здесь ничего не обрезает.

   Круг белый с цветной иконкой, а не цветной с белой: обложки предметов
   яркие и разноцветные, и сплошная цветная заливка спорила бы с ними
   на каждой второй. Белый круг одинаково читается на любой.

   Иконка берётся из подключённого набора и стоит до тех пор, пока
   художник не нарисует собственную обложку карточки: как только файл
   появится, знак исчезнет сам (см. `_карточка` в `dashboard.home`). */
.bt-card__sign {
  position: absolute;
  top: 59%;
  left: 53%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--bt-dark);
}

/* Нарисованный знак вместо иконки. Подложку он несёт свою, поэтому
   белый круг и тень снимаются: рисунок может быть любой формы. */
.bt-card__sign--drawn {
  background: none;
  box-shadow: none;
  /* Правка 12, пункт 2: скругление в круг резало углы у нарисованных
     знаков. У знака-иконки оно остаётся: белый круг — его подложка. */
  border-radius: 0;
  object-fit: contain;
}

.bt-card__sign--orange { color: var(--bt-orange); }
.bt-card__sign--blue { color: var(--bt-blue-dark); }
.bt-card__sign--green { color: var(--bt-green-dark); }
.bt-card__sign--yellow { color: var(--bt-yellow-dark); }
.bt-card__sign--red { color: var(--bt-red-dark); }
.bt-card__sign--dark { color: var(--bt-dark); }

/* Соотношение 1:1,5 — требование заказчика. Держится `aspect-ratio`,
   а не подобранной высотой: карточка растягивается по ширине экрана,
   и высота обязана следовать за ней сама. */
.bt-card__cover {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1.5;
  border-radius: 0.75rem;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.05);
  transition: transform 0.15s ease;
}

/* Только сама обложка, а не всё, что лежит поверх неё.

   Поверх обложки лежат ещё две картинки — аватарка вызвавшего и знак
   теста, — и у обеих свой размер в долях карточки. Правило вида
   `.bt-card__cover img` весомее одного класса (`.bt-card__sign`):
   селектор с классом и тегом выигрывает у селектора с одним классом.
   Растянутым на всю карточку оказывался не только фон, но и знак,
   и он закрывал собой предмет целиком (19.09.2026, первый заход
   с нарисованными знаками).

   Отсюда `:not([class])`: обложка — единственная картинка внутри без
   класса, а любое наложение класс имеет по определению — им он нужен,
   чтобы задать себе место. Правило потому и не придётся править,
   когда наложений станет три. */
.bt-card__cover img:not([class]) {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Пунктира вокруг обложек нет — решение заказчика 16.09.2026: «давай
   уберём красную пунктирную рамку вокруг карточек на главной».

   Правило 29.1 («заметная заглушка не даёт принять черновик за готовое
   оформление») отменено здесь по существу, а не по вкусу: на витрине
   ненарисованных обложек не бывает вовсе — карточка теста подставляет
   картинку предмета, а она нарисована. Пунктир обводил бы готовое
   оформление, то есть говорил бы неправду. В остальном продукте
   он остаётся: там заглушка и правда заглушка. Сам признак
   `черновик` жив и выбирает запасную обложку.

   Класс оставлен без оформления нарочно: по нему написан тест,
   и он же отмечает в разметке, что настоящей обложки ещё нет. */
.bt-card__cover--draft { /* без рамки, см. выше */ }

.bt-card__badge {
  position: absolute;
  top: 0.35rem;
  left: 0.35rem;
  padding: 0.1rem 0.4rem;
  border-radius: 0.5rem;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 0.75rem;
}

/* Аватарка, наложенная на обложку (7.8): круг в нижнем углу, как
   у зовущего на дуэль. Белая обводка — чтобы тёмная аватарка
   не сливалась с тёмной обложкой. */
.bt-card__avatar {
  position: absolute;
  left: 0.4rem;
  bottom: 0.4rem;
  width: 38%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid #fff;
  object-fit: cover;
  background: #fff;
}

/* Длинное слово («пропорциональное») в узкой колонке сетки вылезало
   в соседнюю карточку. Переносим по слогам, где браузер умеет,
   и в любом месте, где не умеет. */
.bt-card__title,
.bt-card__note {
  hyphens: auto;
  overflow-wrap: anywhere;
}

.bt-card__title {
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.2;
}

.bt-card__note {
  font-size: 0.8rem;
  color: var(--bt-dark);
  opacity: 0.75;
  line-height: 1.2;
}

/* Карточка-форма: сама форма и есть карточка, а кнопка внутри неё
   растягивается на всю площадь. Иначе нажималась бы только подпись. */
.bt-card__press {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
}

.bt-card__timer {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--bt-dark);
}

/* Последний час: тот самый случай, ради которого таймер и ставили. */
.bt-card__timer--soon { color: var(--bt-red); }

/* Счётчик вопросов в окне повторения четверти (7.5): после мягкого
   предела краснеет — заказчик просил именно «загорается красным». */
.bt-quarter__count { font-weight: 600; }
.bt-quarter__count--many { color: var(--bt-red); }
.bt-quarter__warn { color: var(--bt-red); }

.bt-welcome__logo { max-width: 12rem; width: 60%; }

@media (min-width: 576px) {
  .bt-card { width: 10rem; }
}

/* Оформление разбора темы — правка 10, пункт 2.

   «Много текста без выделения жирным и абзацев читаются тяжело даже
   взрослым». Абзацы и жирный рисуются обычными тегами и своих правил
   не требуют; списку правило нужно: у Bootstrap отступ слева около
   двух ремов, и в модальном окне телефона маркированный список уезжал
   бы от левого края дальше, чем соседние абзацы. */
#bt-analysis-body ul {
  margin-bottom: 1rem;
  padding-left: 1.25rem;
}

#bt-analysis-body ul li + li { margin-top: 0.25rem; }

/* Последний абзац не отталкивает подвал окна: у окна свой отступ. */
#bt-analysis-body > p:last-child,
#bt-analysis-body > ul:last-child { margin-bottom: 0; }

/* Двухслойная карточка быстрой дуэли — правка 10, 20.09.2026.

   «Соберём из duel-staredown (она квадратная, поместим её в верхней
   части прямоугольной карточки), а ниже по центру поместим карточку
   предмета… Получится будто звери держат в лапах учебник».

   Числа подобраны по самой картинке: у зверей лапы вытянуты к середине
   на высоте примерно двух третей, и учебник шириной в 62% карточки,
   начинающийся с 40% её высоты, ложится верхними углами прямо в лапы.
   Низом он уходит за край — так и было задумано: «пускай даже она
   влезет не полностью».

   Порядок слоёв важен: учебник под зверями, иначе он их заслоняет
   и держать его становится некому. */
.bt-card__under {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translateX(-50%);
  width: 62%;
  height: auto;
  object-fit: contain;
}

.bt-card__over {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 1;
  height: auto;
  object-fit: contain;
}

/* Подпись полосы владения — правка 12, снимок 2. Раскрывается нажатием
   на «Владение темой N%»; значок «?» подсказывает, что там есть
   пояснение, а стандартный треугольник убран, чтобы подпись не
   выглядела пунктом списка. */
.bt-mastery-hint > summary {
  cursor: pointer;
  list-style: none;
  display: inline;
}
.bt-mastery-hint > summary::-webkit-details-marker { display: none; }
.bt-mastery-hint > summary::after {
  content: "?";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1em;
  height: 1.1em;
  margin-left: .35em;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-size: .8em;
}
.bt-mastery-hint[open] > summary { margin-bottom: .25rem; display: block; }

/* --- выпадающий список тем (правка 17, пункт 1) ------------------------
   «Ширина выпавшего списка не больше, чем ширина поля, значения
   переносятся по словам, соседние значения визуально разделяются».
   Браузерный <select> этого не умеет, поэтому поверх него — свой
   список (topic-select.js), а сам <select> спрятан и только хранит
   значение для формы. */
.bt-topics {
  position: relative;
}

.bt-topics__native {
  display: none;
}

.bt-topics__button {
  text-align: left;
  white-space: normal;
  overflow-wrap: anywhere;
  /* Подпись в несколько строк не должна заходить под стрелку:
     с номером темы (10.10.2026) она стала длиннее и заходила. */
  padding-right: 2.5rem;
  min-height: calc(1.5em + 0.75rem + 2px);
}

.bt-topics__panel {
  position: absolute;
  z-index: 1060;
  top: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  padding: 0.375rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bt-radius);
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
}

.bt-topics__search {
  margin-bottom: 0.375rem;
}

.bt-topics__list {
  max-height: 18rem;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bt-topics__item {
  padding: 0.5rem 0.625rem;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.3;
  cursor: pointer;
  border-radius: 0.5rem;
}

.bt-topics__item + .bt-topics__item {
  border-top: 1px solid var(--bs-border-color);
}

.bt-topics__item:hover,
.bt-topics__item:focus {
  background: var(--bs-tertiary-bg);
  outline: none;
}

.bt-topics__item--chosen {
  font-weight: 600;
  color: var(--bs-primary);
}

.bt-topics__empty {
  padding: 0.5rem 0.625rem;
  color: var(--bs-secondary-color);
}

/* Темы «Своего теста» — список галочек, а не выпадающий, но жалоба
   та же: длинные названия сливаются. Разделители между темами. */
.bt-topic-checks .form-check {
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
  overflow-wrap: anywhere;
}

.bt-topic-checks .form-check + .form-check {
  border-top: 1px solid var(--bs-border-color);
}

/* Поиск тем (правка 18, пункт 2) прилипает к верху прокручиваемого
   списка: искать приходится как раз тогда, когда список длинный.
   Отступ сверху — минус внутреннее поле блока (`p-2`). */
.bt-topic-search {
  position: sticky;
  top: -0.5rem;
  z-index: 1;
  margin: 0.25rem -0.5rem 0;
  padding: 0.5rem;
  background: var(--bs-body-bg);
  border-bottom: 1px solid var(--bs-border-color);
}

/* --- подсказка новичку (правка 17, пункт 5) ---------------------------
   Затемнение — тень рамки вокруг карточки: так «окно» в затемнении
   совпадает с карточкой без вырезов и масок. Сам заслон прозрачный
   и только ловит щелчки, чтобы страница под ним не нажималась. */
.bt-tour {
  position: fixed;
  inset: 0;
  z-index: 1080;
}

.bt-tour__spot {
  position: fixed;
  border-radius: var(--bt-radius);
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.62);
  outline: 3px solid var(--bs-primary);
  pointer-events: none;
  transition: left 0.2s, top 0.2s, width 0.2s, height 0.2s;
}

.bt-tour__note {
  position: fixed;
  padding: 0.875rem 1rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  border-radius: var(--bt-radius);
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.3);
}

/* --- «За неделю» (правка 18, пункт 3.1) ------------------------------- */
.bt-weekly__weeks {
  flex-wrap: wrap;
  gap: 0.25rem;
}

.bt-weekly__result {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  padding: 0.25rem 0;
}

.bt-weekly__rec {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.75rem;
  align-items: center;
  padding: 0.5rem 0;
}

.bt-weekly__rec + .bt-weekly__rec {
  border-top: 1px solid var(--bs-border-color);
}

.bt-weekly__rec-topic {
  flex: 1 1 12rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.bt-weekly__offer {
  padding: 0.75rem 1rem;
  border-radius: var(--bs-border-radius-lg);
  background: var(--bs-primary-bg-subtle);
}

/* Условия бонуса за дуэли на странице быстрой дуэли (правка 19):
   узкой колонкой, чтобы мелкий текст читался строками разумной длины. */
.bt-duel-bonus {
  max-width: 28rem;
  margin-inline: auto;
}
