/* Экран урока и все упражнения */

.lesson {
  min-height: 100vh;
  /* 100dvh учитывает исчезающую адресную строку — иначе внизу остаётся полоса пустоты. */
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  max-width: var(--shell-max);
  margin: 0 auto;
  padding: 16px 20px calc(20px + env(safe-area-inset-bottom));
  gap: 20px;
  /* Никакая анимация появления не должна порождать горизонтальную прокрутку. */
  overflow-x: clip;
}

/* Пробный урок гостя: между шапкой и заданием добавляется сноска, поэтому
   строк три, а не две.

   Правило стоит здесь, сразу за .lesson, и с удвоенным классом сознательно.
   Оно уже жило в styles.css — и не работало: тот файл подключается раньше
   exercises.css, специфичность у .lesson и .lesson--trial одинаковая, и
   двухстрочная сетка ниже по списку молча побеждала. Сноска забирала себе
   растягивающуюся строку (полтысячи пикселей пустоты), а задание уезжало
   в неявную третью строку под ней. */
.lesson.lesson--trial { grid-template-rows: auto auto minmax(0, 1fr); }

/* Тихая сноска: это пояснение, а не сообщение, ради которого стоит
   прерываться. Высота — по содержимому, строка в гриде у неё auto. */
.lesson__note {
  margin: 0 auto;
  max-width: 520px;
  font-size: 12px;
  line-height: 1.3;
  text-align: center;
  color: var(--ink-40);
}

/* ---------- Верхняя полоса ------------------------------------------------ */
/* Отступ сверху с запасом под чёлку и строку состояния телефона. */
.lesson__top {
  display: flex; align-items: center; gap: 14px;
  padding-top: calc(6px + env(safe-area-inset-top));
}
.lesson__quit {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%; font-size: 22px; color: var(--ink-40);
  transition: background var(--dur), color var(--dur);
}
.lesson__quit:hover { background: var(--ink-08); color: var(--ink); }
.lesson__bar { flex: 1; height: 16px; border-radius: var(--r-pill); background: var(--ink-08); overflow: hidden; }
.lesson__fill {
  height: 100%; width: 0;
  border-radius: var(--r-pill);
  background: var(--turquoise);
  transition: width 300ms var(--ease);
}
.lesson__stage {
  font-size: 13px; font-weight: 900; color: var(--ink-40);
  white-space: nowrap;
}

/* Обратный отсчёт в режиме на время. */
.clock {
  flex: none;
  min-width: 62px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: var(--gold-soft);
  color: var(--gold);
  font-size: 14px; font-weight: 900;
  text-align: center;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Цвет часов — это медаль, которая идёт прямо сейчас. Порог пройден —
   цвет меняется, и по нему сразу видно, за что теперь борьба. */
.clock--gold { background: var(--gold-soft); color: var(--gold); }
.clock--silver { background: rgba(140, 152, 164, 0.18); color: #6b7684; }
.clock--bronze { background: rgba(176, 112, 62, 0.16); color: #a4662f; }

/* Последние секунды важнее оттенка медали и перебивают его. */
.clock--low,
.clock--low.clock--gold,
.clock--low.clock--silver,
.clock--low.clock--bronze {
  background: var(--lipstick-soft);
  color: var(--lipstick);
  animation: pulse 900ms ease-in-out infinite;
}
@keyframes pulse { 50% { transform: scale(1.07); } }

/* ---------- Общий контейнер упражнения ------------------------------------ */
.ex {
  display: grid;
  align-content: start;
  gap: 22px;
  animation: exIn 220ms var(--ease);
}
/* Появление снизу, а не сбоку: горизонтальный сдвиг на узком экране
   вылезал за край и на время анимации давал полосу прокрутки. */
@keyframes exIn { from { opacity: 0; transform: translateY(14px) scale(0.985); } }

.ex__prompt {
  text-align: center;
  font-size: 14px; font-weight: 800; color: var(--ink-40);
  text-transform: uppercase; letter-spacing: 1px;
}

.ex__word {
  text-align: center;
  display: grid; gap: 6px;
  padding: 26px 20px;
  background: var(--white);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
/* Слово и динамик рядом. Отступ, уравновешивающий динамик, добавляется
   только когда динамик есть — иначе слово без кнопки съезжало вправо. */
.ex__head {
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.ex__head--voiced { padding-left: 54px; }
.ex__word-main { font-size: clamp(28px, 7vw, 42px); font-weight: 900; letter-spacing: -0.8px; }
.ex__word-tr { color: var(--ink-40); font-size: 15px; font-weight: 700; }

.ex__example {
  margin-top: 12px; padding-top: 12px;
  border-top: 2px solid var(--ink-08);
  display: grid; gap: 3px;
  animation: riseIn 220ms var(--ease);
}
.ex__example-en { font-size: 15px; font-weight: 800; }
.ex__example-ru { font-size: 14px; font-weight: 600; color: var(--ink-60); }

/* ---------- Кнопка озвучки ------------------------------------------------ */
.speaker {
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--turquoise-soft);
  font-size: 19px; line-height: 1;
  transition: background var(--dur), transform 120ms var(--ease);
}
.speaker:hover { background: var(--turquoise); }
.speaker:active { transform: scale(0.9); }
.speaker--playing { animation: speakerPop 420ms var(--ease); }
@keyframes speakerPop {
  30% { transform: scale(1.18); }
  60% { transform: scale(0.96); }
}

/* ---------- Заставка между раундами --------------------------------------- */
.interlude {
  height: 100%;
  display: grid; align-content: center; justify-items: center; gap: 12px;
  text-align: center;
  animation: interludeIn 320ms var(--ease);
}
.interlude--out { animation: interludeOut 260ms ease-in forwards; }
.interlude__title { font-size: 26px; font-weight: 900; letter-spacing: -0.6px; }
.interlude__hint { color: var(--ink-60); font-weight: 700; max-width: 300px; }

@keyframes interludeIn {
  from { opacity: 0; transform: scale(0.9) translateY(14px); }
}
@keyframes interludeOut {
  to { opacity: 0; transform: scale(1.06); }
}

/* ---------- Упражнение: выбор из четырёх ---------------------------------- */
.options { display: grid; gap: 12px; }
@media (min-width: 620px) {
  .options { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

.option {
  display: flex; align-items: center; gap: 12px;
  min-height: 62px;
  padding: 0 18px;
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: 0 var(--lift) 0 var(--ink-15);
  font-weight: 800; font-size: 17px;
  line-height: 1.3;
  overflow-wrap: anywhere;
  text-align: left;
  transition: transform 90ms var(--ease), box-shadow 90ms var(--ease),
              background var(--dur), color var(--dur);
}
.option:active:not(:disabled) { transform: translateY(var(--lift)); box-shadow: 0 0 0 var(--ink-15); }
.option:disabled { cursor: default; }

.option__key {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  border-radius: 8px; background: var(--paper);
  font-size: 12px; font-weight: 900; color: var(--ink-40);
}
@media (max-width: 860px) { .option__key { display: none; } }

.option--right {
  background: var(--turquoise); color: var(--white);
  box-shadow: 0 var(--lift) 0 var(--turquoise-dark);
}
.option--right .option__key { background: rgba(255,255,255,0.25); color: var(--white); }
.option--wrong {
  background: var(--lipstick); color: var(--white);
  box-shadow: 0 var(--lift) 0 var(--lipstick-dark);
  animation: shake 320ms;
}
.option--wrong .option__key { background: rgba(255,255,255,0.25); color: var(--white); }

@keyframes shake {
  10%, 90% { transform: translateX(-3px); }
  20%, 80% { transform: translateX(5px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}

/* ---------- Упражнение: карточка со свайпом ------------------------------- */
.swipe { display: grid; gap: 18px; justify-items: center; }

.swipe__stage {
  position: relative;
  width: 100%; max-width: 400px;
  height: 300px;
  perspective: 1000px;
  touch-action: pan-y;
}

.flashcard {
  position: absolute; inset: 0;
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-md);
  display: grid; place-content: center; justify-items: center; gap: 10px;
  padding: 28px;
  text-align: center;
  cursor: grab;
  user-select: none;
  will-change: transform;
}
.flashcard:active { cursor: grabbing; }
.flashcard--anim { transition: transform 260ms var(--ease), opacity 260ms; }

.flashcard__head { display: flex; align-items: center; gap: 10px; padding-left: 54px; }
.flashcard__word { font-size: clamp(28px, 8vw, 40px); font-weight: 900; letter-spacing: -0.8px; }
.flashcard__tr { color: var(--ink-40); font-weight: 700; }
.flashcard__example {
  max-width: 300px; line-height: 1.4; min-height: 20px;
  display: grid; gap: 2px;
}
.flashcard__example-en { font-size: 14px; font-weight: 800; color: var(--ink-60); }
.flashcard__example-ru { font-size: 13px; font-weight: 600; color: var(--ink-40); }
.flashcard__answer {
  margin-top: 10px;
  font-size: 22px; font-weight: 900; color: var(--turquoise-dark);
  min-height: 30px;
}
.flashcard__hint { font-size: 13px; color: var(--ink-40); font-weight: 700; }

/* Метки «помню» / «не помню», проявляются при свайпе */
.flashcard__mark {
  position: absolute; top: 20px;
  padding: 7px 14px; border-radius: var(--r-pill);
  font-size: 14px; font-weight: 900; color: var(--white);
  opacity: 0;
  transition: opacity 80ms linear;
  pointer-events: none;
}
.flashcard__mark--yes { right: 20px; background: var(--turquoise); }
.flashcard__mark--no  { left: 20px;  background: var(--lipstick); }

.swipe__buttons { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; width: 100%; max-width: 400px; }
.swipe__legend { font-size: 13px; color: var(--ink-40); font-weight: 700; text-align: center; }

/* ---------- Упражнение: соединение столбиков ------------------------------ */
.match { display: grid; gap: 14px; }

/* Доска: проводки лежат отдельным слоем поверх колонок, но кликам не мешают. */
.match__board { position: relative; }
.match__wires {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 2;
}
.match__wire {
  fill: none;
  stroke: var(--turquoise);
  stroke-width: 3;
  stroke-linecap: round;
  transition: stroke-dashoffset 420ms var(--ease);
}
.match__plug { fill: var(--turquoise); }

/* minmax(0, 1fr), иначе длинное слово вроде «достопримечательностей»
   растягивает колонку и ломает раскладку на узком экране.
   Просвет между колонками — это ещё и коридор для проводов: пары стоят
   вразнобой, провода идут наискось, и в узкой щели они слипаются в пучок. */
.match__cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px 72px;
}
.match__col { display: grid; gap: 12px; align-content: start; }

.match__tile {
  min-height: 58px;
  padding: 10px 14px;
  border-radius: var(--r-md);
  background: var(--white);
  box-shadow: 0 var(--lift) 0 var(--ink-15);
  font-weight: 800; font-size: 16px;
  line-height: 1.25;
  overflow-wrap: anywhere;
  display: grid; place-items: center; text-align: center;
  transition: transform 90ms var(--ease), box-shadow 90ms var(--ease),
              background var(--dur), color var(--dur), opacity var(--dur);
}
.match__tile:active:not(:disabled) { transform: translateY(var(--lift)); box-shadow: 0 0 0 var(--ink-15); }
.match__tile--picked {
  background: var(--turquoise-soft); color: var(--turquoise-dark);
  box-shadow: 0 var(--lift) 0 var(--turquoise);
}
.match__tile--wrong {
  background: var(--lipstick); color: var(--white);
  box-shadow: 0 var(--lift) 0 var(--lipstick-dark);
  animation: shake 320ms;
}
/* Соединённая пара: приглушаем, но оставляем читаемой — провод должен
   вести к чему-то видимому, а не к серому пятну. */
.match__tile--done {
  background: var(--turquoise-soft);
  color: var(--turquoise-dark);
  box-shadow: 0 var(--lift) 0 var(--turquoise);
  opacity: 0.72;
  pointer-events: none;
}

/* ---------- Упражнение: слово во фразе ------------------------------------ */
.gap__sentence {
  font-size: clamp(19px, 4.4vw, 25px);
  font-weight: 800;
  line-height: 1.55;
  text-align: center;
}
.gap__slot {
  display: inline-block;
  min-width: 92px;
  margin: 0 4px;
  padding: 2px 10px;
  border-radius: var(--r-sm);
  border-bottom: 3px solid var(--turquoise);
  background: var(--turquoise-soft);
  color: var(--turquoise-dark);
  transition: background var(--dur), color var(--dur), border-color var(--dur);
}
.gap__slot--right {
  background: var(--turquoise); color: var(--white); border-color: var(--turquoise-dark);
}
.gap__slot--wrong {
  background: var(--lipstick); color: var(--white); border-color: var(--lipstick-dark);
  animation: shake 380ms var(--ease);
}
.gap__hint {
  margin-top: 12px;
  font-size: 14px; font-weight: 700; color: var(--ink-40);
}
/* Разбор после ответа: само слово с переводом и перевод всей фразы. */
.gap__word { font-size: 17px; font-weight: 900; }
.gap__voice { display: flex; justify-content: center; margin-top: 10px; }
.speaker--phrase { width: 40px; height: 40px; font-size: 17px; }

/* ---------- Кнопка «Далее» ------------------------------------------------ */
/* Всегда последняя в задании: взгляд идёт сверху вниз и упирается в неё. */
.ex__next {
  display: grid;
  animation: riseIn 220ms var(--ease);
}

/* ---------- Упражнение: ввод перевода ------------------------------------- */
.typing { display: grid; gap: 18px; }
.typing__input {
  width: 100%;
  min-height: 60px;
  padding: 0 20px;
  border-radius: var(--r-md);
  border: 2px solid var(--ink-15);
  background: var(--white);
  font-size: 19px; font-weight: 800;
  text-align: center;
  transition: border-color var(--dur), box-shadow var(--dur);
}
.typing__input:focus {
  outline: none; border-color: var(--turquoise);
  box-shadow: 0 0 0 4px var(--turquoise-soft);
}
.typing__input--right, .typing__input--right:focus {
  border-color: var(--turquoise); background: var(--turquoise-soft);
}
/* Состояние ошибки перечислено вместе с :focus намеренно: после пустого ответа
   фокус возвращается в поле, и без этого правило :focus перекрасило бы рамку. */
.typing__input--wrong, .typing__input--wrong:focus {
  border-color: var(--lipstick);
  background: var(--lipstick-soft);
  box-shadow: 0 0 0 4px var(--lipstick-soft);
  animation: shake 380ms var(--ease);
}

/* Поле и вердикт — одна связка: приговор относится к тому, что человек только
   что набрал, и стоять он должен вплотную, а не в общем ряду с кнопками. */
.typing__field { display: grid; gap: 8px; }

.typing__note {
  text-align: center; font-weight: 800; min-height: 18px;
  display: flex; justify-content: center; align-items: baseline;
  flex-wrap: wrap; gap: 8px;
  font-size: 13px;
}
.typing__note--right { color: var(--turquoise-dark); }
.typing__note--wrong { color: var(--lipstick); }
/* Верное написание крупнее самого вердикта: слово важнее слова «правильный». */
.typing__answer { font-size: 17px; font-weight: 900; letter-spacing: 0.2px; }

/* Шпаргалка: тихая кнопка с ценой, написанной под ней. Подсказка, за которую
   платят молча, обманывает — поэтому цена стоит рядом, а не в справке. */
.typing__peek { display: grid; justify-items: center; gap: 2px; }
.typing__peek-hint { font-size: 11px; font-weight: 700; color: var(--ink-40); }

/* Раскрытое написание. Стоит под русским словом, там же, где потом появится
   разбор: взгляд не мечется между полем и подсказкой. */
.cheat {
  margin-top: 12px;
  background: var(--paper);
  border: 2px dashed var(--ink-15);
  border-radius: var(--r-md);
  padding: 10px 16px;
  display: grid; gap: 2px; justify-items: center;
  animation: riseIn 200ms var(--ease);
}
.cheat__label {
  font-size: 11px; font-weight: 800; color: var(--ink-40);
  text-transform: uppercase; letter-spacing: 0.6px;
}
.cheat__word { font-size: 20px; font-weight: 900; }
.cheat__hint { font-size: 11px; font-weight: 700; color: var(--ink-40); }

/* Запасной выход «Не помню» — появляется только после пустой попытки. */
.typing__skip {
  display: none;
  justify-items: center;
  gap: 6px;
  animation: riseIn 220ms var(--ease);
}
.typing__skip--on { display: grid; }
.typing__or { font-size: 12px; font-weight: 700; color: var(--ink-40); }

/* ---------- Упражнение: прочитать вслух ----------------------------------- */
/* Фраза разложена на слова: после ответа каждое подсвечивается само по себе,
   и видно не «неверно», а какие именно слова не разобрались. */
.saywords {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 8px;
  font-size: 22px; font-weight: 800; line-height: 1.35;
}
.saywords__word {
  padding: 2px 6px; border-radius: var(--r-sm);
  transition: background var(--dur), color var(--dur);
}
.saywords__word--ok { background: var(--turquoise-soft); color: var(--turquoise-dark); }
.saywords__word--miss { background: var(--lipstick-soft); color: var(--lipstick); }

.say__listen { display: grid; justify-items: center; margin-top: 12px; }

.say { display: grid; justify-items: center; gap: 16px; }

/* Кольцо вокруг кнопки: держит свечение и заодно даёт ему место, не раздвигая
   соседей. Отступ снизу — чтобы подпись не липла к кружку. */
.say__ring {
  position: relative;
  display: grid; place-items: center;
  /* Отступ снизу с запасом: подпись должна отойти от кружка, и разросшееся
     свечение не должно ложиться прямо на её строку. */
  margin-bottom: 16px;
}

/* Неоновое свечение. Отдельный слой под кнопкой: анимировать box-shadow по
   сорок раз в секунду дорого, а transform и opacity браузер считает на
   видеокарте и страницу не перерисовывает. */
.say__glow {
  position: absolute;
  width: 84px; height: 84px; border-radius: 50%;
  background: var(--turquoise);
  filter: blur(16px);
  opacity: 0;
  transform: scale(1);
  pointer-events: none;
  /* Разгон и затухание разные: голос должен подхватываться сразу, а гаснуть
     плавно — иначе свечение дёргается на каждой паузе между словами. */
  transition: opacity 90ms linear, transform 90ms ease-out, background var(--dur);
}

/* Круглая кнопка записи — самое крупное на экране: другого действия здесь нет. */
.say__mic {
  position: relative;
  width: 84px; height: 84px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 34px; line-height: 1;
  background: var(--turquoise); color: var(--white);
  box-shadow: 0 8px 20px var(--turquoise-soft);
  transition: transform var(--dur) var(--ease), background var(--dur);
}
.say__mic:hover { transform: scale(1.05); }
.say__mic:active { transform: scale(0.96); }

/* Запись пошла: кнопка краснеет, свечение проступает. */
.say--listening .say__mic { background: var(--lipstick); }
.say--listening .say__glow {
  background: var(--lipstick);
  opacity: 0.4;
  /* Пока замер громкости не подключился, свечение дышит само: застывшее
     кольцо не отличить от «микрофон завис». Размах тот же, что и у голоса, —
     переход с дыхания на голос не должен читаться как скачок. */
  animation: sayBreathe 1.8s ease-in-out infinite;
}
@keyframes sayBreathe {
  0%, 100% { transform: scale(1); opacity: 0.3; }
  50% { transform: scale(1.18); opacity: 0.5; }
}

/* Громкость пошла — свечение слушается голоса, а не таймера. Размер и
   яркость приходят из JS отдельными свойствами (см. Speak.setLevel):
   calc(var()) внутри transform браузер на каждое изменение не пересчитывает,
   и свечение застывало на первом замере. */
.say--live .say__glow { animation: none; }

.say--checking .say__mic { background: var(--ink-40); }
.say--checking .say__glow { opacity: 0; animation: none; }

/* Подпись под кнопкой — то, что читают первым: это единственная инструкция
   на экране, и мелким шрифтом она терялась под крупным кружком. */
.say__hint { font-size: 17px; font-weight: 800; color: var(--ink-60); text-align: center; }
.say__skip { font-size: 16px; font-weight: 800; padding: 8px 4px; }
.say__hint--ok { color: var(--turquoise-dark); }
.say__hint--miss { color: var(--lipstick); }
/* Черновая расшифровка и разбор. Высоту не резервируем: пустая строка под
   кнопкой выглядела бы дырой. */
.say__heard {
  font-size: 13px; font-weight: 600; color: var(--ink-40);
  text-align: center; line-height: 1.5; max-width: 420px;
}

/* Часть речи под русским словом: подсказывает, что именно спрашивают —
   «холод» или «холодный». */
.write__pos {
  font-size: 12px; font-weight: 800; color: var(--ink-40);
  text-transform: lowercase; margin-top: 4px;
}

.verdict {
  border-radius: var(--r-lg);
  padding: 16px 20px;
  /* По центру: строки тут короткие — «Неверно» и одно слово, — и прижатые
     влево они висели у края широкой плашки, будто их забыли доверстать. */
  display: grid; gap: 4px; justify-items: center; text-align: center;
  animation: riseIn 200ms var(--ease);
}
@keyframes riseIn { from { opacity: 0; transform: translateY(12px); } }
.verdict--right { background: var(--turquoise-soft); color: var(--turquoise-dark); }
.verdict--wrong { background: var(--lipstick-soft); color: var(--lipstick); }
.verdict__title { font-size: 17px; font-weight: 900; }
.verdict__text { font-size: 14px; font-weight: 700; }

/* ---------- Экран результата ---------------------------------------------- */
.result {
  position: relative;
  min-height: 100vh;
  display: grid; place-content: center; justify-items: center;
  gap: 18px; text-align: center;
  padding: 40px 24px;
  max-width: var(--shell-max);
  margin: 0 auto;
}
/* Экран результата занимает всю высоту, а содержимое стоит по центру —
   кнопке «назад» нужен свой угол, а не место в потоке под кнопками. */
.result > .backbtn { top: 24px; left: 24px; }
.result__emoji { font-size: 64px; animation: pop 400ms var(--ease); }
@keyframes pop { from { transform: scale(0.5); opacity: 0; } }
.result__title { font-size: 28px; font-weight: 900; letter-spacing: -0.6px; }
.result__text { color: var(--ink-60); max-width: 420px; line-height: 1.55; }
.result__actions { display: grid; gap: 10px; width: 100%; max-width: 340px; margin-top: 10px; }

.misses {
  width: 100%; max-width: 460px;
  display: grid; gap: 8px;
  text-align: left;
  margin-top: 6px;
}
.miss {
  background: var(--white); border-radius: var(--r-md); padding: 12px 16px;
  display: grid; gap: 2px; box-shadow: var(--shadow-sm);
  border-left: 4px solid var(--lipstick);
}
.miss__en { font-weight: 900; }
.miss__ru { font-size: 14px; color: var(--ink-60); font-weight: 700; }
.miss__given { font-size: 13px; color: var(--lipstick); font-weight: 700; }

/* ---------- Заставка перед тестом ----------------------------------------- */
.gate {
  display: grid; gap: 14px; justify-items: center; text-align: center;
  padding: 34px 24px;
  background: var(--white); border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
}
.gate__emoji { font-size: 46px; }
.gate__title { font-size: 22px; font-weight: 900; }
.gate__text { color: var(--ink-60); max-width: 420px; line-height: 1.55; }

/* ---------- Выбор режима проверки ----------------------------------------- */
/* Два варианта карточками, а не тумблером со строчкой подписи: разница между
   ними — в целом абзаце текста, и в подпись к переключателю она не влезает.
   Выбранный виден по рамке и заливке, а не по одной галочке в углу. */
.modes { display: grid; gap: 10px; width: 100%; max-width: 420px; }
.mode {
  display: flex; align-items: flex-start; gap: 14px;
  text-align: left;
  padding: 14px 16px;
  border-radius: var(--r-md);
  border: 2px solid var(--ink-15);
  background: var(--white);
  transition: border-color var(--dur), background var(--dur);
}
.mode:hover { border-color: var(--ink-40); }
.mode--on {
  border-color: var(--turquoise);
  background: var(--turquoise-soft);
}
.mode__emoji { width: 38px; height: 38px; flex: none; }
.mode__body { display: grid; gap: 3px; }
.mode__title { font-size: 16px; font-weight: 900; }
.mode__text { font-size: 13px; font-weight: 600; color: var(--ink-60); line-height: 1.5; }
.mode--on .mode__title { color: var(--turquoise-dark); }

/* ---------- Сборка предложения на слух ------------------------------------ */
/* Задание разложено на три яруса: что слушаем, из чего собираем, что делаем
   дальше. На широком экране они идут обычным столбцом, на телефоне —
   расходятся по высоте: иначе всё собиралось в комок посередине и выглядело
   сплющенным. */
.ex--assemble { gap: 18px; }
.assemble__top { display: grid; gap: 14px; }

/* Русская фраза в режиме перевода — это само задание, поэтому карточкой
   и крупно, как слово в других упражнениях. */
.assemble__source {
  padding: 20px 18px;
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
  text-align: center;
  font-size: clamp(18px, 4.5vw, 24px); font-weight: 900;
  line-height: 1.35; letter-spacing: -0.3px;
}
.assemble__middle { display: grid; gap: 16px; align-content: start; }
/* stretch, а не center: обёртка кнопки «Далее» (.ex__next) при центрировании
   сжималась по содержимому, и после проверки кнопка становилась заметно уже
   той «Проверить», на месте которой появилась. */
.assemble__bottom { display: grid; gap: 10px; justify-items: stretch; }

/* Строка ответа держит высоту, даже когда пуста: иначе при первом же слове
   набор внизу подпрыгивает и палец промахивается. */
/* Кнопка «прослушать» под карточкой с фразой, по центру. Внутри карточки она
   вставала в общий поток текста и уезжала под последнее слово. */
.assemble__listen { display: grid; justify-items: center; }

.assemble__line {
  /* Собранное растёт от середины: весь экран центрирован, и строка,
     начинавшаяся у левого края, выглядела приклеенной не к тому. */
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  justify-content: center;
  min-height: 62px;
  padding: 12px;
  border-radius: var(--r-md);
  background: var(--white);
  border: 2px dashed var(--ink-15);
}
.assemble__empty { color: var(--ink-40); font-weight: 700; font-size: 14px; }

.assemble__bank { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }

.word-chip {
  min-height: 44px;
  padding: 0 16px;
  border-radius: var(--r-md);
  background: var(--white);
  border: 2px solid var(--ink-15);
  font-size: 16px; font-weight: 800;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur), opacity var(--dur), transform 90ms var(--ease);
}
.word-chip:hover:not(:disabled) { border-color: var(--turquoise); }
.word-chip:active:not(:disabled) { transform: scale(0.96); }
/* Использованное слово не убираем из набора, а гасим: набор не должен
   переставляться под пальцем после каждого нажатия. */
.word-chip--used { opacity: 0.25; box-shadow: none; }
.word-chip--placed { border-color: var(--turquoise); background: var(--turquoise-soft); }

.assemble__feedback {
  min-height: 24px;
  text-align: center; font-weight: 800; line-height: 1.45;
}
.assemble__feedback--ok { color: var(--turquoise-dark); }
.assemble__feedback--bad { color: var(--lipstick); }

/* ---------- Телефон ------------------------------------------------------- */
@media (max-width: 860px) {
  .lesson {
    padding: 10px 16px calc(16px + env(safe-area-inset-bottom));
    gap: 14px;
  }
  /* Опускаем полосу прогресса ниже чёлки. env() отдаёт 0, когда сайт открыт
     обычной вкладкой, а не приложением с главного экрана, — но верхняя панель
     браузера никуда не девается. Поэтому к вырезу добавляем собственный
     отступ, а не полагаемся на него одного. */
  .lesson__top { padding-top: max(24px, calc(env(safe-area-inset-top) + 14px)); }

  /* Задание висит по центру экрана, а не прижимается к верху,
     оставляя внизу пустое поле. */
  .ex { align-content: center; height: 100%; }

  .swipe__stage { height: min(300px, 42vh); }
  .match__cols { gap: 10px 52px; }
  .match__tile { font-size: 15px; }

  /* Три яруса держим одной группой чуть выше середины экрана. Разогнать их
     по всей высоте (space-between) — перебор: между подписью и строкой
     ответа появлялась пустота в треть экрана, и задание разваливалось на
     три несвязанных куска. Нижний отступ поднимает группу над центром,
     оставляя место под клавиатуру на телефоне. */
  .ex--assemble {
    align-content: center;
    height: 100%;
    gap: 22px;
    padding-bottom: 12vh;
  }
}
