/*
 * Интерактивный тест уровня на /level-test/ — визуальный слой.
 *
 * Подключается УСЛОВНО (inc/enqueue.php → page-level-test) поверх
 * pages/level-test.css. В base.css ничего не дописано: всё здесь заскоуплено
 * префиксами .leveltest-quiz-* / .quiz-* и живёт только на этой странице.
 *
 * DOM-контракт — docs/plan/level-test-spec.md §4: разметку задаёт
 * patterns/leveltest-quiz.php, поведение — assets/js/pages/level-test-quiz.js.
 * Здесь только оформление; ни один селектор не завязан на порядок узлов,
 * который меняет движок (варианты пересоздаются на каждом вопросе).
 *
 * Ключевые дизайн-решения:
 *   1. Тест — «прибор», а не текст: отдельная приподнятая панель на мягком
 *      фиолето-синем поле (тот же акцент знания, что у остальной страницы).
 *   2. Прогресс и навигация НЕ прыгают при смене вопроса: экран вопроса —
 *      flex-колонка фиксированной минимальной высоты, зона вариантов забирает
 *      слабину (flex:1), кнопки прижаты к низу панели.
 *   3. Тач-цели вариантов ≥64px по высоте и во всю ширину строки: 30 вопросов
 *      с телефона — промах по варианту главный источник раздражения.
 *   4. Состояние выбора считывается тремя способами сразу (рамка + заливка +
 *      залитый маркер), а не одним цветом — WCAG 1.4.1.
 *   5. Тёмная тема — через семантические токены; собственных hex нет.
 *
 * @package easy-peasy
 */

/* =========================================================================
   1. Секция и панель
   ====================================================================== */

/* Межсекционный ритм вокруг панели теста.
 *
 * Значения — из шкалы темы, не подобраны на глаз: сверху полный шаг секции
 * (.section → clamp(48px,7vw,88px)), снизу — тот же шаг, что у нижнего паддинга
 * hero (clamp(24px,3.5vw,40px)). Так суммарные зазоры сходятся симметрично:
 *   сверху = hero padding-bottom + этот padding-top = 24+48 (мобайл) / 40+88 (десктоп)
 *   снизу  = этот padding-bottom + padding-top следующей .section = 24+48 / 40+88
 * то есть 72px на мобильных и 128px на десктопе с обеих сторон.
 *
 * Схлопывания margin здесь быть не может: и hero, и секции темы разделены
 * паддингами, а margin-block у них принудительно обнулён в base.css
 * (.hero,.section{margin-block:0} и .wp-site-blocks > *).
 */
.leveltest-quiz-sec {
  padding-block: clamp(48px, 7vw, 88px) clamp(24px, 3.5vw, 40px);
  /* Компенсация собственного верхнего паддинга при переходе по якорю из hero
     (#quiz): целью прокрутки должна стать ПАНЕЛЬ теста, а не пустое поле над
     ней. Величина ровно на паддинг и отрицательная — верх «цели» поднимается
     к верху панели.
     Высоту липкой шапки здесь НЕ учитываем: её держит scroll-padding-top на
     <html> (base.css), посчитанный из фактического замера --eps-header-h. Пока
     та высота дублировалась тут числом 78px, слагаемые складывались и панель
     приезжала на 154px ниже шапки — на 360px это выталкивало кнопку «Далее»
     за экран. */
  scroll-margin-top: calc(-1 * clamp(48px, 7vw, 88px));
}

/* Панель теста.
 *
 * Декор (верхний блик + мягкое свечение в нижнем правом углу) — ФОНОВЫМИ
 * слоями, а не absolute-псевдоэлементом с отрицательным inset. Причина не
 * косметическая: псевдоэлемент выходил за padding-box на 120px вправо и 160px
 * вниз, из-за чего панель с overflow:hidden становилась прокручиваемым боксом
 * (scrollWidth 431 при clientWidth 311). Дальше достаточно было любого
 * .focus() внутри — движок ставит фокус на заголовок подтверждения смены
 * языка — и браузер прокручивал панель по горизонтали, срезая слева ВЕСЬ
 * контент шага: счётчик, поповер, кнопки (BUG-5 приёмки: cardScrollLeft 67 →
 * поповер уезжал в left:-23). Фон scrollable overflow не создаёт, поэтому
 * прокручивать больше нечего.
 *
 * Геометрия свечения сохранена 1:1: круг радиусом ~268px с центром в
 * (100% - 70px, 100% - 30px) — те же координаты, что давал прежний бокс
 * 380×380 со сдвигом -120/-160.
 */
.leveltest-quiz {
  position: relative;
  isolation: isolate;
  padding: clamp(20px, 4vw, 40px);
  border-radius: clamp(20px, 3vw, 32px);
  background:
    radial-gradient(268px circle at calc(100% - 70px) calc(100% - 30px), color-mix(in srgb, var(--violet) 20%, transparent), transparent 68%),
    radial-gradient(120% 80% at 92% 0%, color-mix(in srgb, var(--blue) 10%, transparent), transparent 60%),
    linear-gradient(160deg, var(--surface-violet), var(--surface-blue));
  border: 1px solid color-mix(in srgb, var(--violet) 24%, var(--line));
  box-shadow: var(--sh-lg);
  /* Вторая линия защиты от того же класса дефекта: clip обрезает так же, как
     hidden, но НЕ делает панель скролл-портом — прокрутить её при фокусе
     нельзя даже теоретически. hidden оставлен строкой выше для движков без
     поддержки clip. */
  overflow: hidden;
  overflow: clip;
}

/* Внутренняя «карточка» экрана: белая поверхность на цветном поле. */
.quiz-screen {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: clamp(16px, 2.4vw, 24px);
  box-shadow: var(--sh-md);
  padding: clamp(18px, 3.2vw, 34px);
}

.quiz-screen[hidden] {
  display: none;
}

/* На узких экранах «панель в панели» съедала бы по 38px с каждой стороны и
   загоняла варианты ответа в 250px. Поджимаем обе рамки: контентная ширина
   вырастает на ~24px — на 360px это разница между тремя и двумя строками
   в варианте. */
@media (max-width: 479.98px) {
  .leveltest-quiz {
    padding: 10px;
    border-radius: 22px;
  }

  .quiz-screen {
    padding: 18px 16px;
  }
}

/* =========================================================================
   2. Общие заголовки экранов
   ====================================================================== */

.quiz-screen-title {
  font-size: clamp(1.35rem, 1.05rem + 1.35vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}

.quiz-screen-title:focus-visible {
  box-shadow: var(--ring);
  border-radius: var(--r-sm);
}

.quiz-screen-sub {
  margin: 12px 0 0;
  max-width: 62ch;
  color: var(--text-muted);
  font-size: var(--fs-body);
  line-height: 1.6;
}

/* =========================================================================
   3. Экран 1 — выбор языка обучения
   ====================================================================== */

.quiz-lang-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: clamp(20px, 3vw, 28px);
}

/* flex + basis вместо grid: пять карточек в последнем неполном ряду
   центрируются сами, без «дыры» справа на планшетных ширинах. */
.quiz-lang-card {
  flex: 1 1 100%;
  max-width: 100%;
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 72px;
  padding: 14px 16px;
  text-align: left;
  font-family: var(--font-body);
  color: var(--text);
  background: var(--surface);
  border: 2px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-sm);
  cursor: pointer;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease, background 0.18s ease;
}

/* Монограмма языка вместо флага: не завязана на растровые ассеты, читается
   в обеих темах и держит фирменный градиент. Цвет — на карточке (--lc). */
.quiz-lang-card::before {
  content: attr(data-mono);
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 14px;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  /* Белый текст на фиксированном hex языка: контраст ≥4.5:1 в обеих темах
     (см. комментарий к $eps_lt_marks в patterns/leveltest-quiz.php). Подсветка
     градиентом идёт в тот же тон, а не в сторону синего — иначе жёлтый DE
     уходил в грязно-оливковый. */
  color: #fff;
  background: linear-gradient(150deg, color-mix(in srgb, var(--lc, var(--violet)) 84%, #fff), var(--lc, var(--violet)));
  box-shadow: 0 8px 18px color-mix(in srgb, var(--lc, var(--violet)) 30%, transparent);
}

/* Шеврон-стрелка справа — рисуем бордюрами, без лишнего SVG в разметке. */
.quiz-lang-card::after {
  content: "";
  flex: none;
  width: 9px;
  height: 9px;
  margin-left: auto;
  border-right: 2.5px solid var(--text-muted);
  border-top: 2.5px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform 0.18s ease, border-color 0.18s ease;
}

.quiz-lang-card-name {
  font-weight: 800;
  font-size: 1.02rem;
  line-height: 1.25;
}

@media (hover: hover) {
  .quiz-lang-card:hover {
    border-color: color-mix(in srgb, var(--lc, var(--violet)) 60%, var(--line));
    background: color-mix(in srgb, var(--lc, var(--violet)) 7%, var(--surface));
    box-shadow: var(--sh-md);
    transform: translateY(-2px);
  }

  .quiz-lang-card:hover::after {
    transform: translateX(3px) rotate(45deg);
    border-color: var(--lc, var(--violet));
  }
}

.quiz-lang-card:focus-visible {
  outline: none;
  border-color: var(--lc, var(--violet));
  box-shadow: var(--ring), var(--sh-md);
}

.quiz-lang-card:active {
  transform: translateY(0);
  box-shadow: var(--sh-sm);
}

.quiz-lang-hint {
  margin: clamp(16px, 2.4vw, 22px) 0 0;
  text-align: center;
  font-size: 0.86rem;
  color: var(--text-muted);
}

/* Раскладка карточек языков.
 *
 * До 480px — одна колонка строкой (монограмма | подпись | шеврон): на телефоне
 * это самый компактный и привычный вид списка выбора.
 *
 * От 480px — плитка-колонка: монограмма сверху, подпись под ней, шеврон в
 * правом нижнем углу абсолютом. Строчная раскладка в многоколоночной сетке не
 * годится: в двух колонках на 480px карточке достаётся ~178px, а строка
 * «монограмма 46 + подпись “Английский” ~90 + шеврон + отступы» требует ~193px —
 * шеврон вылезал за рамку карточки. Плитке хватает ширины самой длинной подписи.
 *
 * Число колонок: 2 → 3 (760px) → 5 (1040px). Порог 1040 не круглое число ради
 * красоты: раньше пятая карточка не помещалась и срывалась на отдельную строку
 * во всю ширину — 4+1 читалось как верстальная ошибка. */
@media (min-width: 480px) {
  .quiz-lang-card {
    position: relative;
    flex: 1 1 calc(50% - 6px);
    max-width: calc(50% - 6px);
    min-height: 128px;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 12px;
    padding: 16px 32px 16px 16px;
  }

  .quiz-lang-card::before {
    width: 50px;
    height: 50px;
    font-size: 1rem;
  }

  .quiz-lang-card::after {
    position: absolute;
    right: 15px;
    bottom: 20px;
    margin: 0;
  }

  .quiz-lang-card-name {
    font-size: 1.02rem;
  }
}

@media (min-width: 760px) {
  .quiz-lang-card {
    flex: 1 1 calc(33.333% - 8px);
    max-width: calc(33.333% - 8px);
  }
}

@media (min-width: 1040px) {
  .quiz-lang-grid {
    gap: 12px;
  }

  .quiz-lang-card {
    flex: 1 1 0;
    max-width: none;
  }
}

/* =========================================================================
   4. Экран 2 — вопрос
   ====================================================================== */

/* Каркас «прогресс сверху — варианты в середине — кнопки внизу».
 *
 * Высоту карточки задают НЕ эти значения, а два резерва ниже — .quiz-prompt и
 * .quiz-options (см. их комментарии): на всех ширинах их сумма с постоянной
 * обвязкой карточки больше здешних min-height, поэтому здесь остался только
 * пол — страховка на случай вырожденного банка (короткий тест, ошибка
 * загрузки), чтобы панель не схлопнулась в узкую полоску.
 *
 * Слабину между резервом вариантов и низом карточки забирает .quiz-options
 * (flex:1) — кнопки «Назад/Далее» прижаты к низу и не гуляют при смене вопроса.
 */
.quiz-screen--question {
  display: flex;
  flex-direction: column;
  min-height: 700px;
}

@media (min-width: 420px) {
  .quiz-screen--question { min-height: 580px; }
}

@media (min-width: 600px) {
  .quiz-screen--question { min-height: 540px; }
}

@media (min-width: 1024px) {
  .quiz-screen--question { min-height: 560px; }
}

/* --- Прогресс и выход на смену языка --- */

/* Ряд «Вопрос N из 30 … Сменить язык». position:relative — якорь для поповера
   подтверждения: он открывается абсолютом и не двигает вопрос и кнопки. */
.quiz-progress-row {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
  min-height: 34px;
}

/* Вторичный вес: не заливка и не рамка-кнопка, а компактный «текст с иконкой».
   Рядом внизу карточки живёт «Далее» — главное действие шага, конкурировать с
   ним этот элемент не должен. Тач-цель добирается до 44px псевдоэлементом,
   чтобы визуально кнопка осталась мелкой. */
.quiz-lang-switch {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: 1.5px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-muted);
  cursor: pointer;
  transition: color 0.16s ease, border-color 0.16s ease, background 0.16s ease;
}

.quiz-lang-switch::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 44px;
  transform: translateY(-50%);
}

.quiz-lang-switch svg {
  width: 14px;
  height: 14px;
  flex: none;
}

/* На самых узких «Вопрос N из 30» (широкий Unbounded, ~138px) и кнопка (~118px)
   в одну строку не влезают — счётчик ломался пополам («Вопрос 7 из» / «30»).
   Уводим кнопку на свою строку с прижатием вправо: подпись остаётся видимой
   (§4.1 запрещает прятать её в иконку), счётчик читается целиком, а высота
   ряда постоянна — прогресс-бар не дёргается между вопросами. */
@media (max-width: 419.98px) {
  .quiz-progress-row {
    flex-wrap: wrap;
    row-gap: 8px;
  }

  .quiz-progress {
    flex: 1 1 100%;
  }

  .quiz-lang-switch {
    margin-left: auto;
    gap: 5px;
    padding: 5px 10px;
    font-size: 0.74rem;
  }

  .quiz-lang-switch svg {
    width: 13px;
    height: 13px;
  }
}

@media (hover: hover) {
  .quiz-lang-switch:hover {
    color: var(--violet);
    border-color: color-mix(in srgb, var(--violet) 45%, var(--line));
    background: color-mix(in srgb, var(--violet) 6%, var(--surface));
  }
}

.quiz-lang-switch:focus-visible {
  outline: none;
  color: var(--violet);
  border-color: var(--violet);
  box-shadow: var(--ring);
}

/* Поповер подтверждения смены языка. Абсолютом от .quiz-progress-row: открытие
   не сдвигает ни один элемент шага.
 *
 * Мобильная база — растяжка по обеим сторонам ряда (left:0 + right:0), а не
 * привязка к правому краю кнопки. Так ширина поповера равна ширине контентной
 * колонки шага, и вытолкнуть его за край экрана нечем: geometry не зависит ни
 * от позиции якоря, ни от длины подписи кнопки, ни от переноса ряда на две
 * строки. Тот же приём страхует и от локалей с более длинными строками.
 * С 480px возвращается компактная карточка у правого края (см. ниже). */
.quiz-confirm {
  position: absolute;
  z-index: 5;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  width: auto;
  max-width: 100%;
  padding: 16px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--violet) 30%, var(--line));
  border-radius: var(--r-md);
  box-shadow: var(--sh-lg);
  text-align: left;
}

/* С планшета — компактная карточка, прижатая к кнопке-якорю: на широкой строке
   растянутый на всю ширину диалог читался бы как отдельная секция, а не как
   ответ на нажатие. */
@media (min-width: 480px) {
  .quiz-confirm {
    left: auto;
    width: min(300px, 100%);
  }
}

.quiz-confirm[hidden] {
  display: none;
}

/* «Носик» к кнопке-якорю: без него поповер читается как случайно всплывшая
   карточка поверх вопроса. Ромб стоит под кнопкой «Сменить язык» (она прижата
   вправо на всех ширинах), рамка рисуется двумя сторонами квадрата — так шов
   с рамкой поповера не виден. Декор, из дерева доступности исключён самой
   природой псевдоэлемента. */
.quiz-confirm::after {
  content: "";
  position: absolute;
  top: -7px;
  /* Отступ от правого края: поповер и кнопка прижаты к одной правой границе
     ряда, поэтому 62px ≈ середина кнопки. Значение заведомо меньше её ширины
     в любой локали, так что носик указывает в кнопку, а не в пустоту, даже
     если подпись станет длиннее или короче. */
  right: 62px;
  width: 12px;
  height: 12px;
  background: var(--surface);
  border-left: 1px solid color-mix(in srgb, var(--violet) 30%, var(--line));
  border-top: 1px solid color-mix(in srgb, var(--violet) 30%, var(--line));
  transform: rotate(45deg);
}

/* Пока подтверждение открыто, остальной шаг уходит на второй план.
 *
 * Это ТОЛЬКО визуальная иерархия, не модальность: подтверждение — disclosure
 * (role="group" + aria-expanded на кнопке, см. patterns/leveltest-quiz.php),
 * фокус в нём не запирается, фон не деактивируется. Поэтому приглушаем
 * прозрачностью и НЕ снимаем pointer-events: клик мимо обязан долетать до
 * страницы — по нему движок подтверждение и закрывает.
 *
 * Прозрачность выбрана ещё и потому, что не двигает лейаут: требование
 * «открытие не смещает вопрос, варианты и навигацию» остаётся выполненным.
 * Селектор :has() — прогрессивное улучшение: где он не поддержан, карточка
 * просто остаётся обычным поповером, как раньше. */
.quiz-screen--question > * {
  transition: opacity 0.16s ease;
}

.quiz-screen--question:has(.quiz-confirm:not([hidden])) > *:not(.quiz-progress-row) {
  opacity: 0.32;
}

.quiz-confirm-title {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 0.98rem;
  line-height: 1.3;
  color: var(--text);
}

.quiz-confirm-text {
  margin: 7px 0 0;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.quiz-confirm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}

.quiz-confirm-actions .btn {
  flex: 1 1 auto;
  white-space: normal;
}

/* Мобильная раскладка действий: строго колонкой и во всю ширину поповера.
   Рядом две кнопки на телефоне дали бы по ~120px на цель с подписью в две
   строки — промах пальцем по «Да, сменить язык» стоит двух десятков ответов.
   44px — минимальная тач-цель (WCAG 2.5.5 / HIG), 10px зазор — больше 8px,
   требуемых между соседними целями. Порядок остаётся прежним: безопасное
   «Продолжить тест» сверху и основной заливкой. */
@media (max-width: 479.98px) {
  .quiz-confirm-actions {
    flex-direction: column;
    gap: 10px;
  }

  .quiz-confirm-actions .btn {
    width: 100%;
    min-height: 44px;
  }
}

/* На планшете и телефоне в альбомной ориентации ширина уже «десктопная», а
   палец прежний — поэтому вторая, независимая от ширины проверка: где ввод
   грубый, цель не ниже 44px. На мыши остаётся компактная btn-sm (40px), так
   что вид уже принятых ширин 480+ на десктопе не меняется. */
@media (pointer: coarse) {
  .quiz-confirm-actions .btn {
    min-height: 44px;
  }
}

/* Разрушительное действие — вторичным весом (обводка, приглушённый текст),
   безопасное «Продолжить тест» остаётся залитой primary-кнопкой. */
.quiz-confirm-yes {
  background: var(--surface);
  border-color: var(--line);
  color: var(--text-muted);
}

@media (hover: hover) {
  .quiz-confirm-yes:hover {
    background: color-mix(in srgb, var(--red) 8%, var(--surface));
    border-color: color-mix(in srgb, var(--red) 40%, var(--line));
    color: var(--text);
  }
}

.quiz-progress {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 0.9rem;
  letter-spacing: 0.01em;
  color: var(--text-muted);
  /* моноширинные цифры: 9 → 10 не дёргает строку */
  font-variant-numeric: tabular-nums;
  min-height: 1.3em;
}

.quiz-progress-track {
  position: relative;
  height: 10px;
  border-radius: var(--r-pill);
  /* нейтрально-фиолетовый жёлоб: на тёплом --surface-2 он читался розовым и
     спорил с коралловым CTA */
  background: color-mix(in srgb, var(--violet) 22%, var(--line));
  overflow: hidden;
}

.quiz-progress-bar {
  display: block;
  height: 100%;
  min-width: 10px;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--violet), color-mix(in srgb, var(--blue) 70%, var(--violet)));
  box-shadow: 0 0 12px color-mix(in srgb, var(--violet) 45%, transparent);
  transition: width 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

/* --- Текст вопроса --- */

/* Общая инструкция на языке интерфейса (одна на весь тест, над самим заданием;
   в разметке она aria-describedby для группы вариантов).
   Главное на экране — вопрос, поэтому инструкция приглушена. Но это НЕ та же
   ступень, что мета-строка низа карточки: .quiz-next-hint — исчезающая подсказка
   к кнопке, .quiz-duration — сноска, а здесь постоянное правило задания, которое
   читают перед первым ответом. Отсюда шаг кегля вверх (14px против 13.1px у
   мета-строки) при том же приглушённом цвете: порядок «вопрос → инструкция →
   сноски» считывается размером, а не цветом.
   14px — нижняя граница комфортного вторичного текста; ниже опускать нельзя,
   это единственное место, где сказано, что делать.
   Скрытый абзац (банк инструкции не задал) отступа не занимает: hidden. */
.quiz-instruction {
  margin: clamp(20px, 3vw, 28px) 0 0;
  max-width: 62ch;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text-muted);
}

/* Инструкция уже дала верхний отступ — вопрос прижимается к ней. Селектор
   обязан проверять :not([hidden]): скрытый абзац остаётся соседом в DOM, и без
   проверки вопрос терял бы свой отступ на банках без инструкции.
   10px, а не меньше: у самого длинного вопроса резерв .quiz-prompt выбран
   текстом целиком, внутреннего воздуха не остаётся, и на 6px строки склеивались. */
.quiz-instruction:not([hidden]) + .quiz-prompt {
  margin-top: 10px;
}

/* Текст задания.
 *
 * НАБОР. Вопрос — не заголовок, а материал для чтения: в банках формата
 * «предложение с пропуском» это фраза до 110 знаков на изучаемом языке.
 * Дисплейный Unbounded в 800 на колонке 257px (360px экрана) давал 15–18 знаков
 * в строке — втрое ниже нормы 35–60 для мобильного, и разгонял самый длинный
 * вопрос (pl-c1-6) до 7 строк. Поэтому здесь текстовая гарнитура: те же 700 по
 * весу, нормальный трекинг, интерлиньяж 1.4 — 28–35 знаков в строке и максимум
 * 4 строки. Иерархию против вариантов (Manrope 600/16px в рамке) держат кегль,
 * вес и то, что вопрос — единственный текст в зоне без подложки.
 *
 * РЕЗЕРВ. Высота считается строками: за счёт набора разброс банка уложился в
 * 4/3/2 строки, и резерв закрывает МАКСИМУМ, а не p90, — смена вопроса не двигает
 * варианты вообще. Замеры (max по всем 150 вопросам × 5 языков, ширина панели):
 *   <440px  — 4 строки (pl-c1-6: 97px при 360)
 *   440–719 — 3 строки (pl-c1-6/pl-b1-1: 75px при 480)
 *   ≥720    — 2 строки (pl-b1-1: 58px при 1024)
 * Пороги не из системной шкалы, а из точек, где ломается текст банка: 4→3 строки
 * между 436 и 440, 3→2 между 700 и 710 (взято 720 с запасом).
 *
 * align-content:center — излишек резерва делится поровну над и под текстом.
 * У короткого вопроса (одна строка при резерве в четыре) это ~36px сверху и
 * снизу вместо 73px «дыры» с одной стороны: ни инструкция сверху, ни варианты
 * снизу не отрываются от вопроса.
 */
.quiz-prompt {
  margin: clamp(20px, 3vw, 28px) 0 0;
  display: grid;
  align-content: center;
  /* мера строки: на 1280+ панель даёт колонку 941px — это 84 знака в строке,
     вдвое выше комфортной нормы. Тот же потолок, что у .quiz-screen-sub.
     На высоту не влияет: максимум остаётся 2 строки на всех ширинах ≥720. */
  max-width: 62ch;
  font-family: var(--font-body);
  font-size: clamp(1.0625rem, 0.97rem + 0.5vw, 1.3rem);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0;
  text-wrap: pretty;
  min-height: 5.6em; /* 4 строки × 1.4 */
}

@media (min-width: 440px) {
  .quiz-prompt { min-height: 4.2em; } /* 3 строки */
}

@media (min-width: 720px) {
  .quiz-prompt { min-height: 2.8em; } /* 2 строки */
}

.quiz-prompt:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-sm);
}

/* --- Варианты ответа --- */

/* Резерв блока вариантов. Верх блока держит резерв .quiz-prompt, а этот
 * min-height отвечает за низ карточки: он не даёт ей расти под длинным списком
 * и уводить вниз кнопки, подсказку и сноску.
 *
 * Банки бывают двух форматов, и высоты у них противоположные, поэтому одно
 * значение на всех даёт либо прыжок, либо дыру:
 *   3 варианта — целые предложения, переносятся: 216…398px на 360px экрана;
 *   4 варианта — одно слово в строке: РОВНО 292px (4×64 тач-цель + 3×12 gap)
 *                и на всех ширинах, разброса нет вообще.
 * Отсюда две ветки. Формат ловим не по языку, а по числу вариантов
 * (:has(> :nth-child(4))) — это и есть причина разницы высот, и правило
 * переживёт перевод любого другого банка в тот же формат. Без поддержки :has()
 * применяется базовое значение — карточка просто чуть просторнее, ничего
 * не ломается.
 *
 * Для трёхвариантных банков резерв — p90 ширины (полный максимум означал бы
 * ~180px пустоты на каждом коротком вопросе): 329 / 259 / 216 на <420 / 420–767 /
 * ≥768. Для четырёхвариантных резерв равен факту — ни прыжка, ни пустоты.
 */
.quiz-options {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 12px;
  /* забирает свободную высоту: кнопки остаются прижатыми к низу карточки */
  flex: 1 1 auto;
  /* небольшой: основной воздух под вопросом даёт зарезервированная зона
     .quiz-prompt, дублировать его отступом не нужно */
  margin-top: 10px;
  min-height: 329px;
}

@media (min-width: 420px) {
  .quiz-options { min-height: 259px; }
}

@media (min-width: 768px) {
  .quiz-options { min-height: 216px; }
}

/* 4 варианта в одну строку — высота блока постоянная на любой ширине */
.quiz-options:has(> :nth-child(4)) {
  min-height: calc(4 * 64px + 3 * 12px);
}

.quiz-option {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 14px 18px 14px 16px;
  background: var(--surface);
  border: 2px solid var(--line);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease;
  -webkit-tap-highlight-color: transparent;
}

/* Нативный radio, перерисованный в маркер: клавиатура, скринридер и
   :checked остаются штатными. */
.quiz-option-input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 26px;
  height: 26px;
  margin: 0;
  border: 2px solid color-mix(in srgb, var(--text-muted) 45%, var(--line));
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.16s ease, background 0.16s ease, box-shadow 0.16s ease;
}

.quiz-option-text {
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* hover — только на устройствах с курсором (на тач-экране «залипал» бы) */
@media (hover: hover) {
  .quiz-option:hover {
    border-color: color-mix(in srgb, var(--violet) 55%, var(--line));
    background: color-mix(in srgb, var(--violet) 5%, var(--surface));
  }

  .quiz-option:hover .quiz-option-input {
    border-color: var(--violet);
  }
}

/* Фокус с клавиатуры: кольцо на всей строке, а не на 26-пиксельном кружке. */
.quiz-option:has(.quiz-option-input:focus-visible) {
  border-color: var(--violet);
  box-shadow: var(--ring);
}

/* Выбранный вариант: рамка + заливка + залитый маркер + акцентная полоса
   слева — четыре независимых признака, не только цвет (WCAG 1.4.1). */
.quiz-option:has(.quiz-option-input:checked) {
  border-color: var(--violet);
  background: color-mix(in srgb, var(--violet) 11%, var(--surface));
  box-shadow: 0 6px 18px color-mix(in srgb, var(--violet) 18%, transparent);
}

.quiz-option:has(.quiz-option-input:checked)::before {
  content: "";
  position: absolute;
  left: -2px;
  top: 12px;
  bottom: 12px;
  width: 4px;
  border-radius: var(--r-pill);
  background: var(--violet);
}

.quiz-option:has(.quiz-option-input:checked) .quiz-option-text {
  font-weight: 700;
}

.quiz-option-input:checked {
  border-color: var(--violet);
  background: var(--violet);
  /* внутренняя белая «прокладка» превращает заливку в классическую точку */
  box-shadow: inset 0 0 0 4px var(--surface);
}

.quiz-option:active {
  background: color-mix(in srgb, var(--violet) 14%, var(--surface));
}

/* --- Навигация --- */

.quiz-nav {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: clamp(18px, 2.6vw, 24px);
  padding-top: clamp(16px, 2.4vw, 20px);
  border-top: 1px solid var(--line);
}

.quiz-nav .quiz-back {
  border-color: var(--line);
  border-width: 2px;
  color: var(--text-muted);
}

@media (hover: hover) {
  .quiz-nav .quiz-back:hover {
    background: var(--surface-2);
    color: var(--text);
  }
}

.quiz-nav .quiz-next {
  margin-left: auto;
  min-width: min(58%, 220px);
}

/* Неактивная «Далее» — нейтральная плашка, а не полупрозрачный коралл.
   .btn[disabled] из base.css гасит кнопку до opacity .45: белый текст на
   выцветшем коралле даёт ~2:1 и читается как «сломанная кнопка». Здесь
   состояние показано формой и цветом поверхности, а текст остаётся
   контрастным (--text-muted на --surface-2 ≈ 6.5:1). */
.quiz-nav .quiz-next[disabled] {
  opacity: 1;
  filter: none;
  background: var(--surface-2);
  color: var(--text-muted);
  border-color: var(--line);
  box-shadow: none;
}

/* Подсказка у неактивной «Далее»: место под неё зарезервировано всегда,
   поэтому появление/исчезновение не двигает кнопки. */
.quiz-next-hint {
  margin: 10px 0 0;
  text-align: right;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
  min-height: 1.2em;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.quiz-screen--question:has(.quiz-next[disabled]) .quiz-next-hint {
  opacity: 1;
}

.quiz-duration {
  margin: 14px 0 0;
  font-size: 0.82rem;
  color: var(--text-muted);
  line-height: 1.45;
}

/* --- Ошибка загрузки банка --- */

.quiz-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  margin: 18px 0 0;
  padding: 14px 16px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--red) 32%, var(--line));
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text);
}

.quiz-error[hidden] {
  display: none;
}

.quiz-error-link {
  font-weight: 700;
  color: var(--blue);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* =========================================================================
   5. Экран 3 — форма-гейт
   ====================================================================== */

/* Та же минимальная высота, что у экрана вопроса: переход к форме не
   «схлопывает» панель и страница не подпрыгивает под курсором. */
.quiz-screen--form {
  min-height: 700px;
}

@media (min-width: 420px) {
  .quiz-screen--form { min-height: 580px; }
}

@media (min-width: 600px) {
  .quiz-screen--form { min-height: 540px; }
}

@media (min-width: 1024px) {
  .quiz-screen--form { min-height: 560px; }
}

/* Статичная полоса «30 из 30»: закрывает жест «тест пройден» перед формой.
   Декоративная — из потока анонса скринридера исключена в разметке. */
.quiz-form-done {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: clamp(18px, 2.6vw, 24px);
}

.quiz-form-done-bar {
  flex: 1 1 auto;
  height: 10px;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--violet), color-mix(in srgb, var(--blue) 70%, var(--violet)));
  box-shadow: 0 0 12px color-mix(in srgb, var(--violet) 40%, transparent);
}

.quiz-form-done-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--green);
  color: #fff;
}

.quiz-form-done-mark svg {
  width: 17px;
  height: 17px;
}

.quiz-screen--form .lead-grid--ff {
  margin-top: clamp(20px, 3vw, 26px);
}

/* Гейт — сфокусированный момент: на широких экранах колонка сужается до
   комфортной ширины формы и центрируется. Поле «Имя» шириной в километр
   выглядит неотлаженно и увеличивает путь взгляда от метки к вводу. */
/* Двойной класс в селекторе не декоративный: у .quiz-form-note и
   .quiz-submit-error свои max-width и margin-шорткаты, объявленные ниже по
   файлу, — с одинарной специфичностью они выигрывали бы и выпадали из колонки. */
@media (min-width: 720px) {
  .quiz-screen.quiz-screen--form > * {
    max-width: 36rem;
    margin-inline: auto;
  }
}

/* Общий футнот формы («Без спама. Перезвоним…») дублирует микротекст гейта,
   который говорит то же самое и подробнее. Внутри теста оставляем один. */
.quiz-screen--form .lead-foot-note {
  display: none;
}

/* =========================================================================
   5.1 Гейт на телефонах (<560px) — форма целиком в пределах одного экрана
   ========================================================================
   Диагностика 16.08.2026: человек с рекламы прошёл 30 вопросов (18 минут на
   телефоне) и не тронул ни одного поля гейта. Замер на 393×850 показал два
   независимых дефекта. Первый — вьюпорт не переезжал к панели, и сверху висел
   hero страницы с призывом «Начать тест», уже неуместным (починено в
   assets/js/pages/level-test-quiz.js, revealCardStart). Второй — сам экран
   гейта высокий: даже прижатый к шапке, он держал кнопку отправки на ~210px
   ниже сгиба, то есть человек не видел, чем заканчивается форма.

   Ниже — только плотность: ни одно поле, пояснение или touch-target (≥44px)
   не убрано и не урезано. Состав полей — отдельный разговор с замером
   (пятое поле уже стоит под наблюдением, см. §11), вёрстка его не решает.
   ====================================================================== */
@media (max-width: 559.98px) {
  /* Полоса «пройдено 100%» — жест завершения, но декоративный (aria-hidden):
     тот же смысл несёт подзаголовок. Оставляем, делая тоньше. */
  .quiz-screen--form .quiz-form-done {
    margin-bottom: 12px;
  }

  .quiz-screen--form .quiz-form-done-bar {
    height: 7px;
  }

  /* Подзаголовок гейта («Все 30 вопросов позади…») — 6 строк корпусом.
     Кегль остаётся читаемым, абзац отдаёт ~45px. */
  .quiz-screen--form .quiz-screen-sub {
    margin-top: 10px;
    font-size: 0.9375rem;
    line-height: 1.5;
    text-wrap: pretty;
  }

  .quiz-screen--form .lead-grid--ff {
    margin-top: 16px;
  }

  .quiz-screen--form .eps-qual-option {
    padding: 9px 12px;
    gap: 9px;
  }

  /* В колонке шириной ~165px варианты переносятся; кегль и интерлиньяж ниже
     держат самый длинный вариант в двух строках, а не в трёх — ряды сетки
     выравниваются по высоте и не «лесенкой». 14px — выше минимума для
     подписей, touch-target остаётся ≥44px за счёт min-height опции. */
  .quiz-screen--form .eps-qual-text {
    font-size: 0.875rem;
    line-height: 1.3;
  }

  .quiz-screen--form .eps-qual-legend {
    margin-bottom: 8px;
  }

  .quiz-screen--form .eps-qual-hint {
    margin-top: 8px;
    font-size: 0.8rem;
    line-height: 1.45;
  }
}

/* Квалифицирующий вопрос в две колонки: 4 варианта столбцом занимали ~208px,
   парами — вдвое меньше при тех же строках ≥44px и тех же трёх признаках
   выбранного состояния (рамка, заливка, маркер). До 390px колонка слишком
   узкая для двух колонок — там варианты остаются столбцом (одна строка на
   вариант, ряды по 46px).

   ГЕОМЕТРИЯ ПОРОГА — ПЕРЕСЧИТАНА 16.08.2026 ПО ЧЕСТНОЙ ШИРИНЕ.
   Прежний расчёт шёл по контенту 378px, потому что headless Chrome рисует
   классический скроллбар 15px, а медиазапросы видят полные 393px: замер и
   срабатывание правила расходились на целый шаг. Перемерено с
   html{scrollbar-width:none} (эмуляция телефона, где скроллбар оверлейный).

   Что дают честные 390px при ПРЕЖНИХ отступах: сетка 302px → колонка 147px →
   текстовая ячейка 91px. Самое длинное русское слово «интересуюсь» — 92,2px,
   то есть в ячейку не влезает, и вариант разрывался посреди слова
   («интересуюс|ь»), занимая 3 строки: ряды сетки становились 56,4 и 74,6px —
   лесенка. На 393px ячейка 92,5px против слова 92,2px — запас 0,3px, то есть
   дефект возвращался бы от любой смены отрисовки шрифта.

   Лечим ПРИЧИНУ — ширину ячейки, а не симптом переноса. Горизонтальные
   расходы строки урезаны на 8px без потери сути: маркер 21→18px (признак
   выбора читается так же), внутренний зазор 9→8px, боковой padding 12→10px,
   зазор сетки 8→6px. Итог на 390px: колонки 148/148, текстовая ячейка
   100,0px — запас к «интересуюсь» (92,2px) 7,8px, а не 0,3px. Вертикаль
   (min-height 46px, padding-block 9px) не тронута: touch-target остаётся ≥44px.

   minmax(0, 1fr), А НЕ ГОЛЫЙ 1fr — это доступность, а не косметика.
   У 1fr авто-минимум трека равен min-content содержимого, и при увеличенном
   системном шрифте (эмуляция html{font-size:24px} — 150% масштаб текста)
   колонка распухала под неразрывное слово: треки становились 166,5/186,3px
   вместо 148/148, правый край опции уезжал на 402,8px при вьюпорте 390.
   Прокруткой это НЕ добиралось — document.scrollWidth оставался равен 390,
   то есть контент был обрезан и недостижим: WCAG 2.1 1.4.4 Resize text
   и 1.4.10 Reflow. minmax(0, 1fr) снимает авто-минимум: при 24px треки
   остаются 148/148, правый край 346px, слово переносится (см. overflow-wrap
   у .eps-qual-text). На обычном кегле рендер не меняется ВООБЩЕ — те же
   148/148, та же ячейка 100,0px, тот же ряд 56,4px (замер 16.08.2026,
   ru и uk, 360/375/390/393/412).

   grid-auto-rows:1fr — страховка равной высоты рядов на будущее: если текст
   варианта когда-нибудь снова уйдёт в три строки, ряды останутся ровными,
   а не лесенкой. */
@media (min-width: 390px) and (max-width: 559.98px) {
  .quiz-screen--form .eps-qual-options {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-auto-rows: 1fr;
    gap: 6px;
  }

  .quiz-screen--form .eps-qual-option {
    padding: 9px 10px;
    gap: 8px;
  }

  .quiz-screen--form .eps-qual-mark {
    width: 18px;
    height: 18px;
  }
}

.quiz-form-note {
  margin: 16px 0 0;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 64ch;
}

.quiz-submit-error {
  margin: 14px 0 0;
  padding: 13px 16px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--red) 32%, var(--line));
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--text);
}

.quiz-submit-error[hidden] {
  display: none;
}

/* =========================================================================
   6. Экран 4 — результат
   ====================================================================== */

.quiz-screen--result {
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
}

.quiz-result:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-lg);
}

.quiz-result-card {
  position: relative;
  --pad: clamp(22px, 3.4vw, 38px);
  padding: var(--pad);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: clamp(16px, 2.4vw, 24px);
  box-shadow: var(--sh-md);
}

/* Медальон уровня: код CEFR берём из data-level — он универсален и не
   переводится, поэтому content:attr() здесь безопасен для локалей. */
.quiz-result-card::before {
  content: attr(data-level);
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  margin-bottom: 18px;
  border-radius: 26px;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 1.7rem;
  letter-spacing: 0.01em;
  color: #fff;
  background: linear-gradient(140deg, var(--violet), color-mix(in srgb, var(--blue) 62%, var(--violet)));
  box-shadow: 0 14px 30px color-mix(in srgb, var(--violet) 34%, transparent);
}

/* Старт с нуля (BUG-12): в медальоне НЕ должно быть кода уровня.
 *
 * data-level карточки остаётся «A1» — его читает аналитика, — но показывать
 * его человеку здесь нельзя: заголовок говорит «Вы в самом начале», а плашка
 * над ним объявляла бы уровень, который тест как раз не подтвердил. Ровно то
 * противоречие, ради снятия которого строку уровня и убрали из заголовка.
 * Вместо кода — флажок старта: смысл «отсюда начинают» без единого слова,
 * значит и без локализации. Иконка того же семейства (lucide, stroke 2), что
 * и остальные в тесте. :has() — прогрессивное улучшение: где его нет, увидят
 * прежний медальон с кодом. */
.quiz-result-card:has(.quiz-result-level--zero)::before {
  content: "";
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z'/%3E%3Cpath d='M4 22V3'/%3E%3C/svg%3E"),
    linear-gradient(140deg, var(--violet), color-mix(in srgb, var(--blue) 62%, var(--violet)));
  background-repeat: no-repeat;
  background-position: center;
  background-size: 38px 38px, cover;
}

/* Заголовок-предложение вместо короткой строки уровня.
 *
 * Базовый .quiz-result-level рассчитан на «Предварительно соответствует
 * уровню B1» — плотный кегль с line-height 1.12 там читается как метка. У
 * варианта «zero» заголовок длиннее и по смыслу это уже фраза поддержки: на
 * 360px он занимает четыре строки, и в плотном интерлиньяже слипается в блок.
 * Поэтому кегль на ступень мягче, а строки просторнее. Меру намеренно НЕ
 * ограничиваем: у остальных уровней заголовок тоже идёт во всю ширину
 * карточки, и колонка уже базовой сломала бы общий силуэт экрана результата
 * (балансировку строк делает text-wrap: balance базового класса). */
.quiz-result-level--zero {
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.5rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.quiz-result-eyebrow {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--badge-violet-text);
}

.quiz-result-score {
  margin: 6px 0 0;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: clamp(2.1rem, 1.4rem + 3vw, 3.2rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  background-image: linear-gradient(100deg, var(--violet), var(--blue));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.quiz-result-level {
  margin: 10px 0 0;
  font-size: clamp(1.25rem, 1.05rem + 1vw, 1.75rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.quiz-result-subtitle {
  margin: 12px 0 0;
  font-size: var(--fs-body-lg);
  font-weight: 700;
  line-height: 1.35;
  color: var(--text);
  max-width: 32ch;
}

/* Три части описания — «что это значит / что дальше / что рекомендуем».
   Различаются рельсой и тоном, а не подписью: подпись потребовала бы текста
   в CSS, который нечем локализовать. */
.quiz-result-desc,
.quiz-result-next,
.quiz-result-rec,
.quiz-result-hook {
  position: relative;
  margin: 14px 0 0;
  padding: 14px 16px 14px 18px;
  border-radius: var(--r-md);
  border-top: 1px solid var(--line);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  border-left: 4px solid var(--rail, var(--violet));
  background: color-mix(in srgb, var(--rail, var(--violet)) 6%, var(--surface));
  font-size: 0.96rem;
  line-height: 1.62;
  color: var(--text);
}

.quiz-result-desc {
  --rail: var(--violet);
  margin-top: clamp(18px, 2.6vw, 24px);
}

.quiz-result-next {
  --rail: var(--blue);
}

.quiz-result-rec {
  --rail: var(--green);
}

/* Польская зацепка под легализацию — коралловый акцент школы. */
.quiz-result-hook {
  --rail: var(--primary);
  font-weight: 600;
}

.quiz-result-note {
  margin: clamp(20px, 3vw, 26px) 0 0;
  padding-top: clamp(18px, 2.6vw, 22px);
  border-top: 1px solid var(--line);
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 72ch;
}

.quiz-result-micro {
  margin: 10px 0 0;
  font-size: 0.8rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 72ch;
}

.quiz-result-cta-caption {
  margin: clamp(22px, 3vw, 28px) 0 0;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.quiz-result-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 14px;
}

.quiz-result-actions .btn {
  white-space: normal;
  text-align: center;
}

.quiz-result-actions .btn-ghost {
  border-color: var(--line);
  border-width: 2px;
}

@media (hover: hover) {
  .quiz-result-actions .btn-ghost:hover {
    background: var(--surface-2);
    color: var(--text);
  }
}

.quiz-result-cta-note {
  margin: 12px 0 0;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 60ch;
}

/* Третичное действие — вне белой карточки, на цветном поле панели.
   Центрируем, чтобы не читалось как случайно забытая кнопка в углу. */
.quiz-restart {
  display: flex;
  margin: 18px auto 0;
  background: var(--surface);
  border: 2px solid var(--line);
  color: var(--text-muted);
}

@media (hover: hover) {
  .quiz-restart:hover {
    background: var(--surface);
    color: var(--text);
  }
}

@media (max-width: 419.98px) {
  .quiz-result-actions .btn {
    width: 100%;
  }
}

@media (min-width: 900px) {
  /* Медальон уходит в колонку слева. Абсолютом, а не гридом: в гриде он занимал
     бы первую строку и растягивал её до своей высоты — между «Ваш результат» и
     баллом появлялась стометровая дыра. Здесь он вне потока, а текст просто
     начинается за отступом. */
  /* Ширину меры задаёт сама карточка, а не max-width у абзацев: иначе тонированные
     блоки обрывались бы посреди белого поля рваным правым краем. 50rem ≈ 74 знака
     в строке при 0.96rem — верх комфортной меры для десктопа. */
  .quiz-result-card {
    max-width: 50rem;
    margin-inline: auto;
    padding-left: calc(var(--pad) + 104px + 34px);
  }

  .quiz-result-card::before {
    position: absolute;
    left: var(--pad);
    top: var(--pad);
    width: 104px;
    height: 104px;
    margin: 0;
    font-size: 2.1rem;
  }
}

/* =========================================================================
   7. Фолбэк без JS
   ====================================================================== */

.quiz-fallback {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  padding: clamp(20px, 3.2vw, 30px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: clamp(16px, 2.4vw, 24px);
  box-shadow: var(--sh-md);
}

.quiz-fallback[hidden] {
  display: none;
}

.quiz-fallback-text {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--text);
  max-width: 62ch;
}

/* =========================================================================
   8. Движение
   ====================================================================== */

@media (prefers-reduced-motion: no-preference) {
  /* Варианты пересоздаются движком на каждом вопросе, поэтому CSS-анимация
     появления отрабатывает сама — без единого класса со стороны JS. */
  .quiz-option {
    animation: quiz-option-in 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
  }

  .quiz-option:nth-child(2) {
    animation-delay: 0.05s;
  }

  .quiz-option:nth-child(3) {
    animation-delay: 0.1s;
  }

  @keyframes quiz-option-in {
    from {
      opacity: 0;
      transform: translateY(10px);
    }

    to {
      opacity: 1;
      transform: none;
    }
  }

  .quiz-lang-card {
    animation: quiz-option-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
  }

  .quiz-lang-card:nth-child(2) { animation-delay: 0.05s; }
  .quiz-lang-card:nth-child(3) { animation-delay: 0.1s; }
  .quiz-lang-card:nth-child(4) { animation-delay: 0.15s; }
  .quiz-lang-card:nth-child(5) { animation-delay: 0.2s; }
}

/* =========================================================================
   9. Тёмная тема — точечные правки поверх токенов
   ====================================================================== */

[data-theme="dark"] .leveltest-quiz {
  background:
    radial-gradient(120% 80% at 92% 0%, color-mix(in srgb, var(--blue) 16%, transparent), transparent 62%),
    linear-gradient(160deg, var(--surface-violet), color-mix(in srgb, var(--surface-blue) 80%, var(--bg)));
}

[data-theme="dark"] .quiz-option-input:checked {
  /* прокладка совпадает с фоном строки выбранного варианта, а не с --surface */
  box-shadow: inset 0 0 0 4px color-mix(in srgb, var(--violet) 11%, var(--surface));
}

/* Медальон уровня заливается токенами --violet/--blue, которые в тёмной теме
   светлеют: белый текст на них падает до ~2:1, поэтому здесь тёмная тушь.
   Плитки языков этого не требуют — у них фиксированные hex и всегда белый. */
[data-theme="dark"] .quiz-result-card::before {
  color: #14122b;
}

/* =========================================================================
   10. Крупные экраны: панель не растягивается на всю ширину полосы
   ====================================================================== */

@media (min-width: 1280px) {
  .leveltest-quiz {
    max-width: 1080px;
    margin-inline: auto;
    padding: clamp(28px, 2.6vw, 44px);
  }
}

/* =========================================================================
   11. Квалифицирующий вопрос гейта — «когда планируете начать»
   ========================================================================
   Пятое поле в форме — осознанный риск: сейчас form_start → form_submit даёт
   57%, порог отказа от вопроса — 45% (ads-structure §6.3.2, замер через 30
   дней). Поэтому визуально вопрос стоит дешевле остальных полей: без рамки-
   карточки, компактные строки, микрокопия объясняет, зачем спрашиваем.

   Радио, а не селект: на мобильном селект — лишний тап и системный пикер
   поверх формы. Четыре варианта в столбец, каждая строка ≥44px — touch-target.
   Выбранный вариант помечен тремя независимыми признаками (рамка, заливка,
   залитый маркер), не одним цветом (WCAG 1.4.1). */

.eps-qual {
  margin: 4px 0 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.eps-qual-legend {
  display: block;
  padding: 0;
  margin-bottom: 10px;
  font-family: var(--font-head);
  font-size: 0.88rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--text);
}

.eps-qual-req {
  margin-left: 4px;
  color: var(--accent-strong);
}

.eps-qual-options {
  display: grid;
  gap: 8px;
}

.eps-qual-option {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 46px;
  padding: 10px 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.16s ease, background-color 0.16s ease;
}

/* Нативный input оставлен на месте и лишь обесцвечен: он остаётся носителем
   семантики, required и клавиатурного управления стрелками. */
.eps-qual-option input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  pointer-events: none;
}

.eps-qual-mark {
  flex: none;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--violet) 45%, var(--line));
  background: var(--surface);
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}

/* Перенос: `break-word`, а НЕ `anywhere`.
   Разница практическая, а не вкусовая. `anywhere` разрешает рвать слово даже
   тогда, когда его можно было уместить целиком, и участвует в расчёте
   min-content ширины — из-за него grid-колонка 1fr схлопывалась сильнее, чем
   нужно, и «интересуюсь» рвалось на 390px. `break-word` рвёт слово только
   когда иначе оно вышло бы за границы ячейки, то есть не ломает нормальный
   текст.

   ВАЖНО: страховкой от горизонтального переполнения (WCAG 1.4.10 Reflow,
   крупный системный шрифт) `break-word` работает лишь в паре с ограниченной
   колонкой. Сам по себе он в расчёте min-content НЕ участвует, и при
   `grid-template-columns:1fr` трек просто распухал под неразрывное слово —
   рвать было нечего, ломался лейаут. Поэтому колонки квалифицирующего
   вопроса объявлены `minmax(0, 1fr)` (см. блоки 390–559.98px и ≥560px):
   трек зафиксирован, слово упирается в ячейку, и вот тогда `break-word`
   его переносит. Менять одно без другого нельзя — вернётся обрезанный
   и недостижимый прокруткой контент.

   Здесь ЕДИНСТВЕННОЕ объявление переноса для этого класса. Раньше ниже по
   потоку жила вторая копия правила (`overflow-wrap:normal`) с той же
   специфичностью — и проигрывала этому блоку, потому что стояла выше: страховка
   существовала в коде и не существовала в вычисленных стилях. Дубль удалён;
   если понадобится изменить перенос — правится эта строка, другого места нет.

   min-width:0 — чтобы флекс-элемент внутри опции реально сжимался до ширины
   ячейки, а не держал min-content и не распирал колонку. */
.eps-qual-text {
  min-width: 0;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text);
  overflow-wrap: break-word;
  hyphens: manual;
}

@media (hover: hover) {
  .eps-qual-option:hover {
    border-color: color-mix(in srgb, var(--violet) 55%, var(--line));
    background: color-mix(in srgb, var(--violet) 5%, var(--surface));
  }
}

.eps-qual-option:has(input[type="radio"]:focus-visible) {
  border-color: var(--violet);
  box-shadow: var(--ring);
}

.eps-qual-option:has(input[type="radio"]:checked) {
  border-color: var(--violet);
  background: color-mix(in srgb, var(--violet) 10%, var(--surface));
}

.eps-qual-option:has(input[type="radio"]:checked) .eps-qual-mark {
  border-color: var(--violet);
  box-shadow: inset 0 0 0 4px color-mix(in srgb, var(--violet) 12%, var(--surface));
  background: var(--violet);
}

.eps-qual-option:has(input[type="radio"]:checked) .eps-qual-text {
  font-weight: 700;
}

.eps-qual-hint {
  margin: 10px 0 0;
  font-size: 0.79rem;
  line-height: 1.5;
  color: var(--text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .eps-qual-option,
  .eps-qual-mark { transition: none; }
}

/* Два варианта в ряд, когда ширины хватает: четыре строки подряд удлиняют
   форму ровно там, где мы боремся за её длину. Порог 560px взят по замеру:
   на нём ячейка под текст — 149,2px, а самая длинная украинская подпись
   («Поки що цікавлюся», 137,5px) ещё держит одну строку с запасом 11,7px.
   Русские подписи на 560px уже переносятся во вторую строку, но ряды при
   этом ровные (63,2px), лесенки нет.

   minmax(0, 1fr) — по той же причине, что и в блоке 390–559.98px: у голого
   1fr авто-минимум трека равен min-content, и при крупном системном шрифте
   колонка распухала бы под неразрывное слово, выталкивая правую опцию за
   кромку без возможности доскроллить (WCAG 1.4.4 и 1.4.10). */
@media (min-width: 560px) {
  .eps-qual-options { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
