/* Стили платформы Lessona.
   Принцип палитры: хром нейтральный (чернила), единственный яркий цвет —
   жёлтый маркер — закреплён строго за заметками и выделениями. Тема урока
   красит только область урока (см. applyTheme в core.js), но не хром. */
:root{
  /* Палитра платформы под именами --c-*. Тема урока их не переопределяет —
     благодаря этому класс .unthemed возвращает платформенные цвета внутри
     оформленного урока (поля редактора не должны краситься темой). */
  --c-ink:#171A21; --c-ink-2:#3A3F4A; --c-muted:#7C7A72;
  --c-paper:#FBFAF7; --c-surface:#FFFFFF; --c-surface-2:#F1EFEA;
  --c-line:#E6E4DE; --c-line-2:#D2CFC6;
  --c-marker:#E8A317; --c-marker-soft:#FBEBC4; --c-marker-ink:#7A5406;
  --c-ok:#2E7D4F; --c-ok-bg:#E7F2EB; --c-err:#C33A2B; --c-err-bg:#F8E5E1; --c-err-line:#F0C9A8;

  /* Хром платформы */
  --ink:var(--c-ink); --ink-2:var(--c-ink-2); --muted:var(--c-muted);
  --marker:var(--c-marker); --marker-soft:var(--c-marker-soft); --marker-ink:var(--c-marker-ink);
  --paper:var(--c-paper); --surface:var(--c-surface);
  --line:var(--c-line); --line-2:var(--c-line-2);
  --ok:var(--c-ok); --ok-bg:var(--c-ok-bg);
  --err:var(--c-err); --err-bg:var(--c-err-bg); --err-line:var(--c-err-line);
  /* Форма (хендофф v3). Четыре радиуса вместо двух и правило вложенности:
     внутренний радиус равен внешнему минус отступ. Панель 22 → лист 16 →
     плашка 10 при отступе 6 дают концентрические углы, и вложенность видна
     без единой рамки. Ушли 9 и 12. */
  --r-1:10px;   /* плашка, кнопка, поле, чип   */
  --r-2:16px;   /* карточка, лист, обложка     */
  --r-3:22px;   /* панель, модальное, окно ИИ  */
  --r-pill:99px;
  /* Старые имена остаются ссылками: три тысячи строк стилей не переписываются
     в один день, а форма при этом меняется на всех экранах сразу. */
  --radius:var(--r-2); --radius-sm:var(--r-1);
  /* Глубина (хендофф v3). Три поверхности: бумага — фон, лист — карточка и
     панель, плашка — строка внутри листа. Правило, которое легко проверить
     глазами: рамка или тень, но не оба сразу. Лист держится тенью, плашка —
     заливкой, рамка остаётся там, где элемент должен читаться как поле. */
  --sh-1:0 1px 2px rgba(23,26,33,.05);                                     /* лист лежит */
  --sh-2:0 1px 2px rgba(23,26,33,.05),0 12px 28px -12px rgba(23,26,33,.16); /* поднят    */
  --sh-3:0 2px 6px rgba(23,26,33,.08),0 28px 60px -20px rgba(23,26,33,.28); /* всплыл    */
  /* Кант вместо тени: в тёмном хроме чёрная тень на тёмной бумаге ничего не
     поднимает, и уровни там держатся рамкой с подсветкой сверху. */
  --edge:0 0 0 1px rgba(255,255,255,.09);
  /* Подъём под курсором. Отдельно от --sh-2: наведение поднимает мягче, чем
     «главный объект экрана», и четыре разных литерала по месту давали четыре
     разные глубины на одно и то же движение. */
  --sh-2h:0 1px 2px rgba(23,26,33,.05),0 8px 18px -8px rgba(23,26,33,.28);
  /* Движение (хендофф v3). Три длительности и две кривые вместо девяти разных
     .15s по месту. --ease — всё обычное, --ease-s — то, что въезжает на экран:
     панель, тост, выпадающий список.
     Спека называет их --t-fast / --t-base / --t-slow, но --t-base у платформы
     уже занято четвёртой ступенью кегля: объявление длительности проигрывало
     ей по порядку, и переход получал «13px» вместо «220ms» — то есть молча не
     работал. Здесь --dur-*, чтобы две шкалы не делили одно пространство имён. */
  --dur-fast:120ms;   /* наведение, нажатие, подсветка */
  --dur-base:220ms;   /* появление, раскрытие, переход */
  --dur-slow:340ms;   /* панели, модальные, тосты      */
  --ease:cubic-bezier(.2,.8,.2,1);
  --ease-s:cubic-bezier(.16,1,.3,1);
  /* Шкала отступов (хендофф v2). Двенадцать величин, выбранных по месту,
     сведены к шести ступеням — иначе соседние блоки не выравниваются. */
  --s-1:4px;   /* внутри плашек, значок↔текст */
  --s-2:8px;   /* связанные элементы */
  --s-3:12px;  /* строки списков, gap сеток */
  --s-4:16px;  /* отступ карточки — он же --pad */
  --s-5:24px;  /* между разделами страницы */
  --s-6:32px;  /* поля страницы, крупные развязки */
  /* Шкала кегля ХРОМА — шесть ступеней из хендоффа v2 (раздел «Дизайн-токены»).
     Урочные кегли сюда не входят: они живут в темах оформления, и тема вправе
     набрать инструкцию задания своим размером. Лендинг тоже вне шкалы — у него
     свой типографический ряд с clamp().

     Соответствие уровням спеки:
       t-1 22px Onest 700     → --t-h1    заголовок страницы
       t-2 16px Onest 600     → --t-lg    заголовок карточки или раздела
       t-3 14px Manrope 400   → --t-md    основной текст хрома
       t-4 13px Onest 600     → --t-base  кнопки, меню, вкладки
       t-5 12.5px Manrope 400 → --t-sm    подписи
       t-6 10.5px Manrope 600 → --t-label eyebrow, служебное

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

     Шестая ступень в v3 сменила семейство: JetBrains Mono приносил на страницу
     третье семейство ради номеров блоков и служебных подписей. Его работу
     делает Manrope с font-variant-numeric:tabular-nums — цифры перестают
     выпадать из строки по ширине, а везде, где число меняется на месте
     (счётчики, остаток действий, суммы, время, проценты сборки), столбцы
     больше не дёргаются при обновлении.

     Что осталось мимо шкалы, считает npm run css-scale. */
  --t-label:10.5px;
  --t-sm:12.5px;
  --t-base:13px;
  --t-md:14px;
  --t-lg:16px;
  --t-h1:22px;
  /* Две дисплейные ступени (телефон 640, решение 7a). Шесть ступеней хрома
     считаны под текст и кнопки, и обе величины, ради которых на страницу
     заходят, в них не попадают: время до занятия и сумма за месяц на 22px
     читаются наравне с заголовком раздела. С расстояния вытянутой руки это
     не работает — на телефоне страницу держат в руке, а не рассматривают.

     Разрешены ровно двум смыслам: крупному числу и времени до события. Всё
     остальное остаётся на шести ступенях — иначе это не две ступени, а восемь
     размеров на выбор. */
  --t-d1:26px;   /* время до занятия, цена в предложении тарифа */
  --t-d2:34px;   /* сумма за месяц */
  /* Вне шкалы хрома: заголовок текстового блока и заголовок части урока — это
     содержимое урока, а не платформа вокруг него. Отдельным именем, чтобы
     не читалось как седьмая ступень хрома. */
  --t-lesson-h:19px;

  --font-head:'Onest',system-ui,sans-serif;
  --font-body:'Manrope',system-ui,sans-serif;
  --pad:var(--s-4); --fs:var(--t-md);
  --shadow:var(--sh-2);

  /* Алиасы под старые имена переменных — чтобы существующие компоненты
     взяли палитру Lessona без правок. В контексте урока applyTheme
     переопределяет эти же переменные на палитру темы. */
  --bg:var(--paper);
  --surface-2:var(--c-surface-2);
  --line-strong:var(--line-2);
  --accent:var(--ink); --accent-ink:var(--paper);
  --accent-soft:#F1EFEA; --accent-soft-ink:var(--ink);
  --note:var(--marker); --note-bg:var(--marker-soft); --note-ink:var(--marker-ink);
  /* Рамка и «скотч» заметки — тоже переменные: тема урока красит заметку своим
     акцентом, и жёлтый кант на её фоне выглядел бы чужим. */
  --note-line:#EBD9A0; --note-tape:rgba(232,163,23,.45);
  /* Ступени стопки заметок (решение 14b). Бумага под бумагой — краска, а не
     прозрачность: на светлой это две ступени вниз от #FBEBC4, в тёмной три
     непрозрачные ступени охры. Тень тут не работает ни там, ни там: на охре она
     грязь, а в темноте её просто нет. */
  --note-stack-2:#F6E6BC; --note-stack-3:#F0DCA6;
}

/* Тёмная тема хрома (обязательна по брифу — половина учеников занимается вечером).
   Класс ставится на <html> из core.js. Системную настройку initChromeTheme
   намеренно не читает: умолчание — светлая, выбор человека хранится сам. */
html[data-chrome="dark"]{
  /* Переопределяем только --c-*: остальные имена ссылаются на них, поэтому
     .unthemed в тёмном хроме тоже получает тёмные платформенные цвета. */
  /* Восемь ролей из хендоффа v3: шасси, лист, граница, текст, тихий текст,
     верно, ошибка, акцент. Акцент #E8A317 в тёмной не меняется — маркер
     одинаково читается на обеих бумагах. */
  --c-ink:#F2F1EE; --c-ink-2:#C4C4C0; --c-muted:#83868E;
  --c-paper:#1B1E24; --c-surface:#22262E; --c-surface-2:#2E323B;
  --c-line:#2E323B; --c-line-2:#3A3F4A;
  --c-ok:#4FA772; --c-err:#E2705E; --c-err-line:#5A3A2E;
  /* Подложки данных в тёмной перестают быть плотными: красное и зелёное с
     альфой .16 поверх листа. Плотная заливка на тёмной бумаге читалась
     отдельным прямоугольником, а не подсветкой ответа. */
  --c-ok-bg:rgba(79,167,114,.16); --c-err-bg:rgba(226,112,94,.16);
  --c-marker-soft:#3A3320; --c-marker-ink:#E8C77A;
  --note-line:#5A4A22; --note-tape:rgba(232,199,122,.30);
  /* Три ступени охры: лист заметки, под ним темнее, под ним ещё темнее. Числа
     из спеки (14b): #3D331B — это #E8A317, посаженный на шасси до светлоты
     листа, а ступени под ним отличаются на шаг вниз, как #22262E и #1B1E24 в
     платформенных ролях. */
  --note-stack-2:#332B17; --note-stack-3:#2A2313;
  /* --accent задаём через --ink, а не --paper: в тёмной палитре --paper это цвет
     фона, и текст вроде a{color:var(--accent)} становился невидим. */
  --accent:var(--ink); --accent-ink:var(--paper); --accent-soft:var(--c-surface-2);
  /* Тени в тёмном хроме не работают: тень платформы чёрная, и на тёмной бумаге
     чёрное на почти чёрном ничего не поднимает. Иерархия остаётся та же,
     средство другое — вместо тени кант плюс подсветка сверху. Уровни различает
     сила канта: лежащий лист берёт линию, поднятый — линию сильнее.
     Половина занятий вечерние, поэтому оба режима проверяются на каждом
     экране, а не в конце. */
  --sh-1:0 0 0 1px var(--c-line),inset 0 1px 0 rgba(255,255,255,.04);
  --sh-2:0 0 0 1px var(--c-line-2),inset 0 1px 0 rgba(255,255,255,.06);
  /* Третий уровень всплывает над затемнённым столом — там чёрная тень снова
     что-то значит, но держит форму всё равно кант. */
  --sh-3:0 0 0 1px var(--c-line-2),inset 0 1px 0 rgba(255,255,255,.06),0 24px 56px -18px rgba(0,0,0,.7);
  --shadow:var(--sh-2);
}

/* Повышенный контраст — настройка доступности платформы (Настройки →
   Оформление). Раньше это была седьмая тема урока, то есть включалась там, где
   её почти не видно, и только для одного урока. Переопределяем базовый слой
   --c-*, поэтому контраст доходит и до .unthemed-островков внутри занятия. */
html[data-contrast="high"]{
  --c-ink:#000000; --c-ink-2:#111111; --c-muted:#333333;
  --c-paper:#FFFFFF; --c-surface:#FFFFFF; --c-surface-2:#EDEDED;
  --c-line:#111111; --c-line-2:#000000;
  --c-ok:#12662F; --c-ok-bg:#E4F3E9; --c-err:#B00020; --c-err-bg:#FBE6EA; --c-err-line:#B00020;
  --c-marker-ink:#4A3300;
}
html[data-chrome="dark"][data-contrast="high"]{
  --c-ink:#FFFFFF; --c-ink-2:#F0F0F0; --c-muted:#D0D0D0;
  --c-paper:#000000; --c-surface:#0B0B0B; --c-surface-2:#1C1C1C;
  --c-line:#EDEDED; --c-line-2:#FFFFFF;
  --c-ok:#7BE0A2; --c-ok-bg:#0C2114; --c-err:#FF9C90; --c-err-bg:#2A0F0C; --c-err-line:#FF9C90;
  --c-marker-soft:#4A3300; --c-marker-ink:#FFE9B8;
}

/* Островок платформенной палитры внутри оформленного урока.
   Тема урока пишет свои цвета в контейнер урока (applyTheme), и всё внутри их
   наследует — включая поля редактора, которые темой краситься не должны:
   панель «Стиль» обещает «как урок выглядит у ученика», а не «покрасить
   конструктор». Здесь возвращаем платформенные --c-* обратно. */
.unthemed{
  --ink:var(--c-ink); --ink-2:var(--c-ink-2); --muted:var(--c-muted);
  --paper:var(--c-paper); --surface:var(--c-surface); --surface-2:var(--c-surface-2);
  --line:var(--c-line); --line-2:var(--c-line-2); --line-strong:var(--c-line-2);
  --accent:var(--c-ink); --accent-ink:var(--c-paper);
  --accent-soft:var(--c-surface-2); --accent-soft-ink:var(--c-ink);
  /* Скругления тоже платформенные: тема урока задаёт свои, и хром внутри
     занятия менял форму вместе с уроком — панель хода становилась то острой,
     то круглой, хотя к уроку не относится. */
  --radius:var(--r-2); --radius-sm:var(--r-1);
  /* Зелёное и красное хрома: тема урока переопределяет и их, и «в классе» в
     шапке занятия бралось зелёным темы — на платформенной бумаге оно линяло. */
  --ok:var(--c-ok); --ok-bg:var(--c-ok-bg);
  --err:var(--c-err); --err-bg:var(--c-err-bg); --err-line:var(--c-err-line);
  font-family:var(--font-body);   /* иначе дети наследуют шрифт темы, а не переменную */
  /* маркер тоже возвращаем платформенный: тема урока красит свои заметки своим
     акцентом, но элементов хрома внутри страницы урока это не касается */
  --marker:var(--c-marker); --marker-soft:var(--c-marker-soft); --marker-ink:var(--c-marker-ink);
  --note:var(--marker); --note-bg:var(--marker-soft); --note-ink:var(--marker-ink);
  --font-head:'Onest',system-ui,sans-serif;
  --font-body:'Manrope',system-ui,sans-serif;
  color:var(--ink);
}
/* .btn.primary светлеет сама (background:var(--ink)), но её ховер в светлой теме
   уходит в осветление — на тёмном фоне это нечитаемо, поэтому здесь наоборот. */
html[data-chrome="dark"] .btn.primary:hover{background:#FFFFFF}
html[data-chrome="dark"] .btn.primary:active{background:#D8D8D4}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:var(--font-body);background:var(--bg);color:var(--ink);font-size:var(--fs);line-height:1.55;-webkit-font-smoothing:antialiased}
h1,h2,h3,h4,.head{font-family:var(--font-head)}
button,input,textarea,select{font-family:inherit;color:inherit}
a{color:var(--accent)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}
/* Псевдоэлементы названы явно: «*» их не задевает, и всё, что движется на
   ::before и ::after, — пульс живых меток, блик скелета, заставка занятия,
   заливка сегмента в шагах лендинга — продолжало двигаться у тех, кто просил
   этого не делать. Заставка к тому же так и не показывала свой конечный вид:
   его правило ниже перебивала неснятая анимация. */
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}html{scroll-behavior:auto}}

/* ---------- Раскладка с левым меню ----------
   Меню — на страницах-списках (Сегодня, Уроки, Ученики, кабинет ученика).
   В конструкторе и классе меню нет: там своя левая колонка (рельса структуры,
   панель хода урока), две левые колонки сделали бы экран теснее без пользы. */
.app{display:grid;grid-template-columns:212px minmax(0,1fr);min-height:100vh}
.app-main{min-width:0;display:flex;flex-direction:column}

/* Меню прокручивается только вниз, и это надо сказать вслух. overflow-y:auto в
   одиночку не значит «вертикально»: по правилам CSS, стоит одной оси перестать
   быть visible, как вторая молча становится auto. То есть панель всё это время
   была прокручиваемой и вбок — и стоило любому пункту оказаться шире колонки,
   как под меню появлялась горизонтальная полоса.

   Оказывался знак: он тоже <a> внутри меню, поэтому брал width:100% от
   содержимого колонки, а сверх того имел боковые поля по 4px — восемь лишних
   пикселей ниоткуда. Ширину ему теперь считает сама раскладка (в колонке-флексе
   auto тянется до края за вычетом полей), а полоса выключена явно: следующий
   длинный пункт обрежется, а не заведёт прокрутку. */
.sidebar{background:var(--paper);border-right:1px solid var(--line);padding:var(--s-4) var(--s-3);display:flex;flex-direction:column;gap:2px;position:sticky;top:0;height:100vh;overflow-y:auto;overflow-x:hidden}
.sidebar .brand{margin:0 var(--s-1) var(--s-4);font-size:var(--t-lg);width:auto}
.sidebar a,.sidebar button{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-3);border-radius:var(--r-1);border:none;background:transparent;width:100%;text-align:left;cursor:pointer;font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink-2);text-decoration:none;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.sidebar a:hover,.sidebar button:hover{background:var(--surface-2)}
/* Знак — не пункт меню: подсветка под ним выглядит как выделенный раздел */
.sidebar .brand:hover,.topbar .brand:hover{background:none}
.sidebar a.on,.sidebar button.on{background:var(--ink);color:var(--paper)}
.sidebar .sep{height:1px;background:var(--line);margin:var(--s-3) var(--s-2)}
.sidebar .spacer{flex:1}
/* Счётчик у «Проверки» — единственный элемент меню с цветом маркера. Заливка
   жёлтая всегда, а не только у выбранного пункта: счётчик в меню — одно из
   четырёх значений маркера, и «сколько работ ждёт» не зависит от того, открыт
   ли раздел. Текст задан чёрным буквально: в тёмной теме --ink светлый, а на
   жёлтом читается только тёмное. */
.sidebar .count{margin-left:auto;background:var(--marker);color:#171A21;border-radius:var(--r-pill);font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:600;padding:2px var(--s-2)}
/* Точка вместо числа: у «Оплат» считать нечего — важно, что где-то деньги
   разошлись. Красная потому, что называет данные (долг), а не работу модели:
   жёлтая плашка-счётчик рядом означала бы совсем другое. */
.sidebar .nav-dot{margin-left:auto;width:7px;height:7px;border-radius:var(--r-pill);
  background:var(--err);flex-shrink:0}
.sidebar .count+.nav-dot{margin-left:var(--s-1)}
/* Раздел плана, который ещё не построен — виден, но не ведёт в пустоту */
.sidebar .soon{opacity:.4;cursor:default;pointer-events:none}

/* Шапка — бумага, как и левое меню: белое на платформе значит «содержимое», а
   шапка содержимого не несёт. На занятии это и вовсе обязательно — материал
   урока там единственная белая область, и белая шапка спорила бы с ним.
   Отделяет её линия снизу, а не своя подложка. */
/* Высота 52 везде одинаковая: экран может положить в панель что угодно, но не
   может её вырастить — иначе рабочая область прыгает при переходах. */
.topbar{background:var(--paper);border-bottom:1px solid var(--line);height:52px;display:flex;align-items:center;gap:var(--s-3);padding:0 var(--s-5);position:sticky;top:0;z-index:60}
/* Внутри раскладки с меню лого и навигация живут в меню, а не в топбаре */
.app-main .topbar{justify-content:flex-end}
/* Кроме телефона: там меню спрятано, и знак остаётся единственным, по чему
   видно, где ты находишься (кабинет ученика, хендофф v2, Р-3). */
@media(min-width:641px){.app-main .topbar .brand{display:none}}
/* Лицо в шапке — вся остальная опознавательная часть хрома кабинета */
/* Лицо в шапке: круг 30 на плашке, а не тёмная заливка. Панель не должна
   носить второй чёрный предмет — чёрное в хроме занято главной кнопкой и
   активным пунктом меню. */
.top-ava .stu-ava{width:30px;height:30px;font-size:var(--t-label);
  background:var(--surface-2);color:var(--muted)}

/* На телефоне меню ложится полосой поверх страницы, а шапка встаёт над ним:
   «Выйти» и переключение темы — про вход, а не про раздел, и стоять они должны
   выше навигации, а не между ней и содержимым. Порядок задаём флексом: сама
   шапка лежит внутри .app-main, и без display:contents её из этой обёртки не
   вынуть, не трогая разметку девяти страниц. */
@media(max-width:860px){
  .app{grid-template-columns:minmax(0,1fr);display:flex;flex-direction:column}
  .app-main{display:contents}
  .app-main>*{order:3}
  .app-main>.topbar{order:1}
  .app>.sidebar{order:2}
  /* Полоса меню прокручивается вбок, но не вниз: overflow-x:auto делает
     прокручиваемой и вертикаль, и полосу можно было стянуть на несколько
     пикселей — под ней открывалась щель до всего, что ниже. */
  .sidebar{position:static;height:auto;flex-direction:row;align-items:center;gap:var(--s-1);
    overflow-x:auto;overflow-y:hidden;padding:var(--s-3) var(--s-3);border-right:none;border-bottom:1px solid var(--line)}
  .sidebar .brand,.sidebar .sep,.sidebar .spacer,.sidebar .soon{display:none}
  .sidebar a,.sidebar button{width:auto;white-space:nowrap;padding:var(--s-2) var(--s-3);flex-shrink:0}
}
.brand{display:flex;align-items:center;gap:var(--s-2);font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.01em;flex-shrink:0;color:var(--ink);text-decoration:none}
.brand svg{flex-shrink:0;display:block}
/* контур знака берёт цвет текста — корректно инвертируется в тёмном хроме */
.brand svg .lsn-stroke{stroke:var(--ink)}
.brand svg .lsn-pad{fill:var(--surface);stroke:var(--surface)}
/* Возврат и название открытого — вместо прежних вкладок навигации */
.top-back{display:inline-flex;align-items:center;text-decoration:none;color:var(--muted);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-base);white-space:nowrap;
  padding:var(--s-1) var(--s-3);border-radius:var(--r-1);margin-left:var(--s-1)}
.top-back:hover{color:var(--ink);background:var(--surface-2)}
.top-step{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--muted);white-space:nowrap}
.top-sep{color:var(--line-2);font-size:var(--t-sm)}
.top-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;margin-left:var(--s-1)}
/* Ряд действий сжимается, а не уезжает за край: на занятии в нём набирается
   больше всего — поиск слова, смена материала, домашка, выход. Место отдаёт
   поиск: он всегда под рукой, а кнопки названы глаголами, и резать их нечем.
   Присутствие из этого ряда ушло в панель занятия (см. .tp-live): вопрос
   «здесь ли ученик» был здесь самым тихим элементом строки. */
.top-actions{display:flex;gap:var(--s-2);align-items:center;min-width:0;margin-left:auto}
/* Где мы сейчас — в панели, и только там, где меню спрятано: на широком экране
   раздел назван подсвеченным пунктом слева, и второе имя было бы повтором. */
.top-here{display:none;font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
/* Идущее занятие в панели: точка, время с начала и слово. Жёлтая точка — то же,
   что у плашки «идёт» в расписании: маркер здесь значит «происходит сейчас». */
.cls-live{display:inline-flex;align-items:center;gap:6px;font-size:var(--t-sm);color:var(--muted);
  white-space:nowrap;flex-shrink:0}
.cls-live>i{width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker);flex-shrink:0;
  animation:pulse 1.4s ease-in-out infinite}
.cls-live>b{font-variant-numeric:tabular-nums;font-weight:600;color:var(--ink-2)}
/* Действия занятия сложены в свою обёртку — на телефоне их прячет одна строка
   CSS. Обёртке нужна и раскладка: строчным потоком поле поиска и кнопки
   переносились как слова в абзаце, без промежутка между строками, и ряд
   «Выбрать материал · Под ученика · Домашка» прилипал к словарю снизу.
   Промежутки те же, что в самой панели. */
.cls-acts{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;row-gap:var(--s-2);min-width:0}
/* Поиск слова в панели занятия ужимается первым. По умолчанию у него
   width:100% — он рассчитан на лист, где занимает всю строку, — и в ряду
   действий требовал себе целую строку, выталкивая кнопки под себя. */
.cls-acts .ws{width:auto;flex:0 1 260px;min-width:190px}
/* Подпись над колонкой заметок: колонка появляется только на широком экране,
   и подпись живёт по тем же правилам. */
.notes-label{display:none}
@media(min-width:1300px){
  /* Считаем от ЛЕВОГО края полотна, а не от правого.

     Стикеры стоят абсолютом от своего .margin-slot, то есть отсчитываются от
     правого края листа — а лист не шире 700 (правило ниже). Подпись стояла с
     тем же смещением `right`, но её точка отсчёта другая: .class-canvas, а оно
     шире листа — 998 у преподавателя и 956 у ученика. Подпись уезжала правее
     стикеров на всю эту разницу и вылетала за край страницы, и от неё одной
     страница ехала боком: на 1440 её правый край приходился на 1638-й пиксель.
     Стикеры при этом стояли верно — потому и заметно было только по пустому
     месту справа и по полосе прокрутки.

     700 + 266 − 230 — это правый край листа плюс вылет стикера минус его
     ширина, то есть левый край той же колонки, те же числа, что строкой ниже. */
  .canvas:has(.sticky.aside) .notes-label{display:block;position:absolute;
    left:calc(700px + 266px - 230px);right:auto;width:230px;top:-2px}
}
@media(max-width:640px){.app-main .topbar .top-here{display:block}}
/* Остаток запросов ИИ внизу меню: подпись, число и полоса. Нажатие ведёт туда,
   где действия добавляют. */
.nav-quota{display:block;margin:var(--s-3) var(--s-3) var(--s-2);padding:var(--s-3);
  background:var(--surface);border-radius:var(--r-1);text-decoration:none;
  transition:background var(--dur-fast) var(--ease)}
.nav-quota:hover{background:var(--surface-2)}
.nav-quota .nq-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.nav-quota .nq-head b{font-family:var(--font-body);font-weight:600;font-size:var(--t-sm);
  font-variant-numeric:tabular-nums;color:var(--ink-2)}
.nav-quota .bar{margin-top:6px}
.ws-host{display:flex;min-width:0}
/* Значок в шапке страницы — такой же гость ряда, как кнопка со словом, и рамку
   носит ту же: без неё оформление урока читалось не кнопкой, а иллюстрацией
   между «Предпросмотром» и «Ещё». Отмена (↶) под это правило попадает заодно —
   она в том же ряду и того же веса. */
.top-actions .icon-btn{border-color:var(--line-2);background:var(--surface)}
.top-actions .icon-btn:hover{border-color:var(--ink);color:var(--ink)}
.top-actions .icon-btn[disabled]{opacity:.45;pointer-events:none}
.top-actions .icon-btn svg{width:16px;height:16px}
.top-user{font-size:var(--t-sm);color:var(--muted);white-space:nowrap}
/* На странице без левого меню (занятие, конструктор) шапка несёт сразу и путь,
   и все действия. Своё имя оттуда убираем: кто вошёл — видно по кнопке «Выйти»,
   а место нужнее присутствию и поиску слова. */
body>.topbar .top-user{display:none}

.btn{border:1px solid transparent;background:var(--surface);border-radius:var(--r-1);min-height:34px;
  padding:var(--s-2) var(--s-3);font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
  cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  transition:background var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease),
             color var(--dur-fast) var(--ease),transform 90ms var(--ease);
  white-space:nowrap;text-decoration:none;color:var(--ink);box-shadow:var(--sh-1)}
/* Вторичная — лист с sh-1, без рамки: правило «рамка или тень, но не оба
   сразу». Рамка осталась одному элементу — полю ввода, где она говорит
   «сюда можно писать». */
.btn:hover{box-shadow:var(--sh-2);transform:translateY(-1px)}
.btn:active{transform:translateY(0);background:var(--surface-2)}
/* Кант фокуса — двойной, с зазором цвета бумаги: на чёрной кнопке одинарный
   сливается с заливкой. Глобальный :focus-visible здесь перекрыт. */
.btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--ink)}
/* Нажатие отзывается на всей платформе: до v3 не отзывалось нигде, и от этого
   интерфейс читался картинкой, а не программой. */
.btn.primary{background:var(--ink);color:var(--paper);box-shadow:none}
/* Ховер главной осветляет, а не чернит: чернее чёрного не бывает, и до v3
   нажатие на неё не читалось вовсе. */
.btn.primary:hover{background:#2A2E37;box-shadow:var(--sh-2)}
.btn.primary:active{background:#0F1116;transform:translateY(0)}
/* Опасная набрана красным текстом, а не красным фоном: зелёный и красный на
   платформе означают данные — верно и ошибка, — и заливать ими кнопку значит
   отдать цвету ошибки второе значение. */
.btn.danger{color:var(--err);background:none;box-shadow:none;padding:0 var(--s-3)}
/* Опасная тихая ссылка — в операционке у «удалить». Красная не ради тревоги, а
   потому что соседняя такая же строкой включает Pro: цвет здесь и есть разница
   между «подарил месяц» и «стёр человека». */
.more-link.danger{color:var(--err)}
/* Правая колонка строки в операционке: числа выключены вправо, как в отчёте. */
.adm-side{text-align:right}
@media(max-width:640px){
  /* На телефоне отчётной колонки не бывает: 390 пикселей делить надвое значит
     сложить обе половины в столбики по одному слову. Всё, что было справа,
     встаёт под именем и читается строками слева. */
  .adm-side{text-align:left;width:100%;margin-top:6px}
  .adm-side>div{margin-top:2px}
  /* «включить Pro» и «удалить» — по сорок четыре, иначе в них не попасть. */
  .adm-side .more-link{min-height:36px;display:inline-flex;align-items:center}
}
.more-link.danger:hover{color:var(--err);opacity:.8}
.btn.danger:hover{background:var(--err-bg);color:var(--err);transform:none}
.btn.danger:focus-visible{box-shadow:0 0 0 2px var(--err)}
.btn.danger:disabled{color:#E0B7B0}
/* ---------- Кнопка с ИИ ----------
   Маркер здесь не спорит с правилом «жёлтый только для заметок»: на лендинге
   тем же маркером помечены ровно ИИ-места (плашка «ИИ» с пульсирующей точкой),
   и внутри продукта знак должен быть тот же, что в обещании. Иначе главная
   функция платформы выглядит как пятая кнопка в ряду одинаковых серых.

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

   Чернила текста заданы числом, а не переменной: маркер светлый в обеих темах
   хрома, а --ink в тёмной становится светлым и на жёлтом пропал бы. Так же
   набран счётчик в выбранном пункте меню.

   Правило одно на все экраны: одна такая кнопка на страницу, шире соседних на
   ступень отступа, с искрой слева, и называет она результат («Собрать урок с
   ИИ»), а не средство («ИИ»). Рядом с ней чёрной primary-кнопки не ставим —
   два тяжёлых пятна в одном ряду гасят друг друга. */
.btn.ai{background:var(--marker);border-color:var(--marker);color:#171A21;
  padding-left:var(--s-4);padding-right:var(--s-4)}
.btn.ai:hover{background:var(--marker);border-color:var(--marker);filter:brightness(.93)}
/* Вторая дверь к тому же: перенос учебника делает та же модель, просто материал
   свой, а не придуманный. Без знака он читался как техническое «перенести
   файл» — обычная кнопка рядом с волшебной, — хотя на лендинге именно с него
   начинается рассказ про ИИ. Знак тот же, вес меньше: обычная кнопка с искрой
   маркером. Так на экране видно семью из двух входов и порядок внутри неё. */
.btn.ai-soft .spark{color:var(--marker)}
.btn.ai-soft:hover{border-color:var(--marker)}
.btn .spark{width:15px;height:15px;flex-shrink:0;display:block}
/* Искра на кнопке-значке: правка задания стоит в одном ряду со стрелками и
   удалением, но единственная из них меняет содержание блока, а не его место.
   Отсюда цвет — приглушённый, пока на карточку не навели. */
.icon-btn .spark{width:14px;height:14px;display:block}
.icon-btn.ai-mark{color:var(--line-2)}
.block:hover .icon-btn.ai-mark{color:var(--marker)}
.icon-btn.ai-mark:hover{color:var(--marker);background:var(--marker-soft)}
/* Искра в заголовке окна: та же примета и тот же вес, что у кнопки, которая его
   открыла, — сплошная у сборки с нуля, приглушённая у переноса учебника. */
.head-ai{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;flex-shrink:0;
  border-radius:var(--r-1);background:var(--marker);color:#171A21;margin-right:var(--s-2);vertical-align:-6px}
.head-ai.soft{background:var(--marker-soft);color:var(--marker)}
.head-ai svg{width:16px;height:16px;display:block}
/* Примеры просьб под полем правки. Первая просьба к модели у всех звучит как
   поисковый запрос — «лексика», — и модель делает не то. Готовая фраза
   показывает длину и вид просьбы вернее любого объяснения, поэтому она
   нажимается и подставляется в поле целиком. */
.rv-hints{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-2)}
.rv-hint{border:1px dashed var(--line-2);background:none;border-radius:var(--r-pill);
  padding:var(--s-1) var(--s-3);cursor:pointer;text-align:left;
  font-family:var(--font-body);font-size:var(--t-sm);color:var(--muted)}
.rv-hint:hover{border-style:solid;border-color:var(--marker);color:var(--ink)}
.btn.soft{background:var(--accent-soft);color:var(--accent-soft-ink);box-shadow:none}
/* Тихая: живёт в шапках и в строках списка, где кнопка не должна спорить с
   содержимым. Проявляется фоном по наведению. */
/* Тихая: живёт в шапках и в строках списка, где кнопка не должна спорить с
   содержимым. Проявляется фоном по наведению, не поднимается. */
.btn.ghost,.btn.quiet{background:none;box-shadow:none;color:var(--ink-2);padding:0 var(--s-3)}
.btn.ghost:hover,.btn.quiet:hover{background:var(--surface-2);box-shadow:none;color:var(--ink);transform:none}
.btn.ghost:active,.btn.quiet:active{background:var(--line)}
.btn.ghost:focus-visible,.btn.quiet:focus-visible{box-shadow:0 0 0 2px var(--ink)}
.btn.soft:hover{filter:brightness(.96)}
.btn:disabled{cursor:default;box-shadow:none;background:var(--surface-2);color:#B4B1A8}
.btn:disabled:hover{transform:none;box-shadow:none}
.btn:disabled:active{transform:none}
.btn.primary:disabled{background:var(--line);color:#B4B1A8}
.btn.ghost:disabled,.btn.quiet:disabled{background:none;color:#B4B1A8}
/* Обод занятой кнопки. Цвет обода наследуется от вида: на главной чёрной он
   светлый, на вторичной — линия. */
.btn .btn-spin{width:12px;height:12px;border-radius:var(--r-pill);flex-shrink:0;
  border:2px solid var(--line);border-top-color:var(--muted);
  animation:spin 700ms linear infinite}
.btn.primary .btn-spin{border-color:rgba(251,250,247,.3);border-top-color:#FBFAF7}
.btn.danger .btn-spin{border-color:#F3D9D4;border-top-color:var(--err);opacity:.7}
.btn.sm{min-height:28px;padding:0 var(--s-3);font-size:var(--t-sm)}
/* Крупная — в диалоге и на телефоне, где кнопку жмут пальцем. */
.btn.lg{min-height:40px;padding:0 18px;font-size:var(--t-md)}
.icon-btn{border:none;background:transparent;color:var(--muted);width:28px;height:28px;border-radius:var(--r-1);cursor:pointer;font-size:var(--t-base);display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.icon-btn:hover{background:var(--surface-2);color:var(--ink)}
/* Значок вне строки списка — сам себе плашка. */
.icon-btn.lg{width:34px;height:34px;background:var(--surface);box-shadow:var(--sh-1);color:var(--ink-2)}
.icon-btn.lg:hover{box-shadow:var(--sh-2);transform:translateY(-1px)}
/* Озвучка слова. Значок рисуется кодом, как и все остальные на платформе.
   Пока слово читается, кнопка помечена маркером: нажатие ушло наружу за
   записью, и без отметки это выглядит как «не сработало». Маркер здесь по
   правилу — это выделение, а не заливка объекта. */
.say-btn svg{width:15px;height:15px;display:block}
.say-btn.saying{color:var(--marker)}
/* Озвучка на карточке изучения: в углу, поверх карточки. Внутри текста ей не
   место — карточку нажимают целиком, чтобы перевернуть, и кнопка посреди слова
   ловила бы этот же нажим. */
.flashcard{position:relative}
.flashcard .card-say{position:absolute;top:8px;right:8px}
.say-btn.saying svg{animation:sayPulse 1s ease-in-out infinite}
@keyframes sayPulse{0%,100%{opacity:1}50%{opacity:.45}}
@media (prefers-reduced-motion:reduce){.say-btn.saying svg{animation:none}}

.workspace{display:grid;grid-template-columns:260px minmax(0,1fr);gap:var(--s-5);max-width:1180px;margin:0 auto;padding:var(--s-5) var(--s-5) 120px}
.canvas{min-width:0}
/* Панель «Стиль» не накрывает лист, а становится третьей колонкой: выезжая
   справа, она закрывала правую половину урока — ровно ту часть, ради которой
   оформление и смотрят. Рельса на это время уходит: оглавление и панель нужны
   в разные минуты, а вместе они не оставляют листу ширины. */
.workspace.style-open{grid-template-columns:minmax(0,1fr) 348px}
.workspace.style-open .rail{display:none}
.style-panel{background:var(--surface);border-radius:var(--r-3);padding:var(--s-5);
  box-shadow:var(--sh-2);align-self:start;position:sticky;top:74px;
  max-height:calc(100vh - 96px);overflow:auto}
.style-panel[hidden]{display:none}
.sp-head{display:flex;align-items:flex-start;gap:var(--s-3)}
.sp-head .head{font-size:var(--t-lg)}
.sp-sub{font-size:var(--t-sm);color:var(--muted);line-height:1.5;margin-top:2px}
.sp-x{margin-left:auto;color:var(--muted);flex-shrink:0}
.sp-x:hover{color:var(--ink)}

.rail{position:sticky;top:74px;align-self:start;max-height:calc(100vh - 96px);display:flex;flex-direction:column}
.rail-head{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-label);text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:700;padding:0 var(--s-1) var(--s-2)}
.rail-head>span:first-child{flex:1;min-width:0}
/* «Выделить» — служебная кнопка рельсы: тише блочных, но со своим словом,
   иначе о выборе нескольких блоков узнают только те, кто пробует Ctrl-клик. */
.rail-pick{background:none;border:1px solid var(--line);border-radius:var(--r-1);color:var(--muted);
  font-family:var(--font-head);font-size:10.5px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;padding:3px 7px;cursor:pointer;flex-shrink:0}
.rail-pick:hover{border-color:var(--ink);color:var(--ink)}
.rail-pick.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.rail-list{overflow-y:auto;overflow-x:hidden;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:3px;padding-right:2px}
.rail-item{display:flex;align-items:center;gap:9px;height:34px;padding:0 9px;border-radius:var(--r-1);cursor:pointer;font-size:var(--t-base);font-family:var(--font-head);font-weight:600;color:var(--ink-2);border:1px solid transparent;position:relative;flex-shrink:0}
.rail-item:hover{background:var(--surface-2);color:var(--ink)}
/* Активный пункт больше не чернильный, а поднятый: чёрная строка в оглавлении
   читалась как выбранная пачка, хотя выбор здесь — совсем другое состояние. */
.rail-item.active{background:var(--surface);box-shadow:var(--sh-1);color:var(--ink)}
.rail-item.active .rail-num{color:var(--ink);opacity:1}
/* Иконки блоков рисуются currentColor, поэтому в активном пункте и в тёмной
   теме они перекрашиваются сами — отдельных правил для них больше не нужно. */
.rail-item.is-note{color:var(--marker-ink);padding-left:42px}
.rail-item.is-note .rail-num{display:none}
.rail-item.is-note .rail-ic{width:12px;height:12px;background:var(--marker);
  border-radius:var(--r-1);margin-left:var(--s-2)}
.rail-item.is-note .rail-ic svg{display:none}
.rail-item.is-note .rail-label{font-size:var(--t-sm)}
.rail-item.is-note .rail-dot{display:none}
/* Активный пункт стал белым и поднятым, а не чернильным, — значит и заметка на
   нём набрана своими чернилами, а не бумагой: правило .is-note стоит после
   .active и без этой строки перекрыло бы его цвет. */
.rail-item.active.is-note{color:var(--note-ink)}
.rail-item.dragging{opacity:.4}
/* Черта показывает, куда встанет блок: тянешь вверх — над строкой, вниз — под
   ней. Одна «до» на оба направления врала бы в конце урока: «перед последним»
   это не конец списка. */
.rail-item.drop-before::before,.rail-item.drop-after::after{content:'';position:absolute;
  left:0;right:0;height:2px;background:var(--accent);border-radius:2px}
.rail-item.drop-before::before{top:-3px}
.rail-item.drop-after::after{bottom:-3px}
/* Отмеченный блок: та же роль, что у выделенной строки в списке файлов.
   Активный (тот, на который перешли) при этом остаётся тёмным — это разные вещи,
   и совпадать они не обязаны. */
.rail-item.picked{background:var(--accent-soft);border-color:var(--accent);color:var(--ink)}
.rail-item.picked .rail-num{color:var(--ink);opacity:.55}
.rail-num{width:24px;flex-shrink:0;font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-label);color:var(--muted);text-align:right}
.rail-ic{width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:var(--r-1);background:var(--surface-2)}
.rail-ic svg{width:18px;height:18px}
.rail-item.is-note .rail-ic svg [stroke="#171A21"]{stroke:var(--marker)}
.rail-item.is-note .rail-ic svg [fill="#171A21"]{fill:var(--marker)}
.rail-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}
.rail-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:transparent}
.rail-dot.ok{background:var(--ok)}
.rail-dot.err{background:var(--err)}
.rail-dot.todo{background:transparent;border:1.5px dashed var(--line-strong)}
.rail-add{flex-shrink:0;margin-top:var(--s-2);border:1px dashed var(--line-2);background:transparent;color:var(--muted);border-radius:var(--r-1);padding:var(--s-2);font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);cursor:pointer;width:100%;transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}
.rail-add:hover{background:var(--surface-2);border-color:var(--muted);color:var(--ink)}

.cover{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;margin-bottom:var(--s-3)}
.cover-img{width:100%;height:200px;object-fit:cover;display:block;background:var(--surface-2)}
/* Кнопки лежат поверх картинки, а не строкой под ней: строка кнопок разрывала
   обложку и название, между которыми у ученика ничего нет. */
.cover-pic{position:relative}
.cover-pic .field-cover{height:200px}
.cover-acts{position:absolute;right:var(--s-3);top:var(--s-3);display:flex;gap:var(--s-2)}
/* Поле адреса открывается на самой обложке, под кнопками: адрес вставляют и
   тут же видят, что встало. Полоса поверх картинки, чтобы поле читалось на
   любой обложке — от белой до чёрной. */
.cover-link{position:absolute;left:var(--s-3);right:var(--s-3);bottom:var(--s-3);
  display:flex;gap:var(--s-2);background:var(--paper);border-radius:var(--r-1);
  padding:var(--s-2);box-shadow:var(--sh-2)}
.cover-link input{flex:1;min-width:0;border:1px solid var(--line);border-radius:var(--r-1);
  background:var(--surface);padding:0 var(--s-2);height:32px;font-size:var(--t-sm);
  font-family:var(--font-body);color:var(--ink)}
.cover-link input:focus{outline:none;border-color:var(--accent)}
.cover-body{padding:var(--pad)}
.cover-title{font-family:var(--font-head);font-weight:700;font-size:28px;letter-spacing:-.025em;line-height:1.2}
.cover-sub{color:var(--muted);margin-top:var(--s-2);font-size:15px}
.cover-meta{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-3)}
.pill{background:var(--surface-2);border-radius:var(--r-pill);padding:6px var(--s-3);font-size:var(--t-sm);color:var(--muted)}
.pill b{color:var(--ink);font-weight:600}
.cover-edit input,.cover-edit textarea{width:100%;border:1px solid transparent;border-radius:var(--radius-sm);padding:var(--s-2) var(--s-2);font-size:var(--t-md);background:transparent;color:var(--ink);transition:background var(--dur-fast) var(--ease)}
.cover-edit input:hover,.cover-edit textarea:hover{background:var(--surface-2)}
.cover-edit input:focus,.cover-edit textarea:focus{outline:none;background:var(--surface-2);border-color:var(--line)}
/* Поле в одну строку, и длинное название обрезалось краем посреди буквы: от
   «Renting an Apartment Abroad: …» на телефоне оставалось «Renting an Apartment /»
   — половина «A» у края читалась поломкой. Многоточие говорит, что текст идёт
   дальше; в фокусе поле, как и прежде, листается к курсору. */
.cover-edit input{text-overflow:ellipsis}
.cover-edit .t{font-family:var(--font-head);font-weight:700;font-size:28px;letter-spacing:-.025em}
.cover-edit .st{font-size:var(--t-md);color:var(--muted)}
/* Девять полей обложки сложились в одну строку сводки: собирают урок не о них,
   а о заданиях, и девять инпутов подряд занимали первый экран целиком.
   Подложку берём --surface-2, а не --paper: внутри оформленного листа --paper
   равен фону самого листа, и плашка на нём была бы не видна. */
.cover-set{display:grid;grid-template-columns:1fr auto;gap:var(--s-3);align-items:center;
  background:var(--surface-2);border-radius:var(--r-1);padding:11px var(--s-3);
  margin-top:var(--s-4);cursor:pointer;transition:background var(--dur-fast) var(--ease)}
.cover-set:hover{background:color-mix(in srgb, var(--ink) 8%, var(--surface))}
.cs-main{min-width:0;display:flex;align-items:center;gap:var(--s-3)}
.cs-eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.1em;color:var(--muted);
  font-variant-numeric:tabular-nums;flex-shrink:0}
.cs-line{font-size:var(--t-sm);color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs-edit{font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--ink);flex-shrink:0}
.cover-fields{margin-top:var(--s-3)}
.cover-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s-1);margin-top:var(--s-2)}
.cover-grid input{font-size:var(--t-base)}

/* Три уровня раскрытия — три поверхности. Свёрнутый блок это плашка на листе,
   без рамки и без тени: видно тип, название и порядок — этого хватает, чтобы
   читать урок оглавлением. Заливки у неё нет вовсе: внутри оформленного листа
   --paper равен фону самого листа, и «бумажная» плашка на нём не читалась бы. */
.block{background:transparent;border:1px solid transparent;border-radius:var(--r-1);margin-bottom:2px;scroll-margin-top:82px;transition:background var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.block:hover{background:var(--surface-2)}
.block.focus{box-shadow:0 0 0 3px var(--accent-soft)}
.block.flash{animation:flash 1.4s ease-out}
.block.is-note{background:var(--note-bg);border-color:#EBD9A0}
/* Раскрытый блок — тот, «в работе»: белая карточка с кольцом чернилами и
   тенью. Потерять место, где остановился, нельзя, поэтому поднятие заметное. */
.block.open{background:var(--surface);box-shadow:0 0 0 2px var(--ink),var(--sh-2)}
.block.open:hover{background:var(--surface)}
.block.is-note.open{background:var(--note-bg)}
/* Предпросмотр — третий уровень: служебного в нём нет совсем, карточка
   становится подложкой под то, что видит ученик. */
.block.preview{background:var(--surface-2);box-shadow:none}
.block.preview:hover{background:var(--surface-2)}
.block.preview>.bhead{display:none}
@keyframes flash{0%{box-shadow:0 0 0 4px var(--accent-soft)}100%{box-shadow:0 0 0 0 transparent}}
.bhead{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3) var(--pad);cursor:pointer;user-select:none}
.bnum{font-variant-numeric:tabular-nums;font-weight:500;font-size:var(--t-label);letter-spacing:.08em;color:var(--muted);background:var(--surface-2);border-radius:var(--r-1);padding:3px var(--s-2);flex-shrink:0;min-width:30px;text-align:center}
.bnum svg{width:16px;height:16px;display:block;margin:0 auto}
/* Значок типа и номер стоят рядом одной плашкой: значок отвечает «что это»,
   номер — «какой он по счёту у ученика». Номер есть не у всякого блока, значок
   есть у всякого, поэтому ширину держит значок, а номер к нему приписывается. */
.bnum{display:inline-flex;align-items:center;gap:5px;min-width:0}
.bnum .bic{display:flex;color:var(--muted)}
.bnum .bn{font-variant-numeric:tabular-nums}
.is-note .bnum{background:#F1E4B5;color:var(--note-ink)}
/* Название блока — его содержимое, а не имя типа: карточка должна называть то
   же, что стоит о ней в рельсе, иначе урок читается на двух языках. */
.bname{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Тип — подписью справа и нажатием. Нужен он дважды: когда пробегаешь урок
   глазами в поисках «где тут тест» — и когда блок открыт на правку, где до сих
   пор он гас совсем (opacity:0) и в редакторе было не разобрать, что за блок
   перед тобой. Нажатие меняет тип: «Пропуски вписать» превращаются в «Пропуски
   из пула», текст — в акцент, и содержимое, которое подходит новому типу,
   переезжает вместе с ним (см. convertBlock в builder.js). */
.btype{color:var(--muted);font-size:var(--t-label);font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;font-variant-numeric:tabular-nums;flex-shrink:0;font-family:var(--font-head);
  border:1px solid transparent;border-radius:var(--r-pill);padding:1px var(--s-2);background:none;
  cursor:pointer;white-space:nowrap;display:inline-flex;align-items:center;gap:3px;
  opacity:0;transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.block:hover .btype,.block.open .btype{opacity:1}
.btype:hover{color:var(--ink);background:var(--surface-2)}
.btype .bt-swap{opacity:0;font-size:var(--t-label);transition:opacity var(--dur-fast) var(--ease)}
.block:hover .btype .bt-swap,.block.open .btype .bt-swap{opacity:.55}
/* На телефоне имя типа уходит: в шапке блока он спорит за ширину со значками
   правки, и они вылезали за край листа. Что это за блок, говорит значок слева. */
@media(max-width:640px){.block .btype{display:none}}
/* «В РАБОТЕ» — янтарём, а не серым: серая на белой карточке читалась как ещё
   одна служебная подпись, хотя говорит она о том, где человек сейчас стоит. */
.bwork{font-size:var(--t-label);font-weight:600;letter-spacing:.08em;font-variant-numeric:tabular-nums;
  color:var(--marker-ink);background:var(--marker-soft);border-radius:var(--r-pill);
  padding:var(--s-1) 9px;flex-shrink:0;white-space:nowrap}
/* ---------- Перенос блока на самом листе ----------

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

   Тянут именно за неё, а не за карточку: у раскрытого блока внутри поля ввода
   и текст, который выделяют мышью. */
.bgrip{flex-shrink:0;width:16px;margin-left:-4px;cursor:grab;color:var(--line-strong);
  font-size:13px;line-height:1;user-select:none;opacity:0;
  transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.block:hover .bgrip,.block.focus .bgrip{opacity:1}
/* В режиме галочек и у отмеченного блока ручка видна постоянно: там её и
   ищут — отметил несколько и тащишь их вместе, а появление по наведению
   заставляет искать наугад. */
.block.picked .bgrip,.workspace:has(.bpick) .block .bgrip{opacity:1}
.bgrip:hover{color:var(--muted)}
.bgrip:active{cursor:grabbing}
.block.dragging{opacity:.4}
/* Черта показывает, куда встанет блок, — та же, что в рельсе: тянешь вверх, она
   над карточкой, вниз — под ней. */
.block.drop-before,.block.drop-after{position:relative}
.block.drop-before::before,.block.drop-after::after{content:'';position:absolute;
  left:0;right:0;height:2px;background:var(--accent);border-radius:2px;z-index:2}
.block.drop-before::before{top:-2px}
.block.drop-after::after{bottom:-2px}

.btools{display:flex;gap:2px;margin-left:var(--s-3);opacity:0;transition:opacity var(--dur-fast) var(--ease)}
/* Искра в ряду инструментов блока — того же роста, что соседние значки, и
   маркерная: это действие модели, а не правка руками. */
.btools .b-ai{color:var(--marker-ink)}
.btools .b-ai .spark{width:15px;height:15px;display:block}
.btools .b-ai:hover{background:var(--marker-soft)}
.block:hover .btools,.block.focus .btools{opacity:1}
.bbody{padding:0 var(--pad) var(--pad)}
.chev{color:var(--muted);font-size:var(--t-label);transition:transform var(--dur-base) var(--ease);flex-shrink:0;width:14px}
.block.open .chev{transform:rotate(90deg)}
/* Тип урока в обложке: подпись, переключатель и «Адаптировать» одним рядом,
   пояснение — строкой под ним во всю ширину. */
.mode-row{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s-2) var(--s-3);margin-top:var(--s-3);
  padding-top:var(--s-3);border-top:1px solid var(--line)}
.mode-row .seg{margin-bottom:0}
.mode-row .mode-lbl{font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--muted)}
.mode-row .hint{flex-basis:100%;margin:0}
/* Переключатель вида. Лист компонентов просил инверсию — чёрную активную
   кнопку на белом ложе, — но все экранные макеты (расписание, просмотр урока,
   конструктор) рисуют обратное: серое ложе и белую активную кнопку с лёгкой
   тенью. Взяли макеты: их три против одного, и переключатель вида не действие,
   чтобы весить как главная кнопка. Заодно ушёл .hdr-seg — он делал ровно это
   же, но только в шапке конструктора. */
.seg{display:inline-flex;background:var(--surface-2);border-radius:var(--r-1);padding:3px;margin-bottom:var(--s-3)}
.seg button{border:none;background:transparent;padding:7px 13px;border-radius:var(--r-1);font-size:var(--t-sm);font-weight:600;font-family:var(--font-head);color:var(--muted);cursor:pointer;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.seg button:hover{color:var(--ink)}
.seg button.on{background:var(--surface);color:var(--ink);box-shadow:var(--sh-1)}

.insert{height:22px;display:flex;align-items:center;justify-content:center;position:relative;opacity:0;transition:opacity var(--dur-fast) var(--ease)}
.insert:hover{opacity:1}
.insert::before{content:'';position:absolute;left:0;right:0;height:1px;background:var(--accent);opacity:.35}
.insert button{position:relative;border:1px solid var(--line);background:var(--surface);color:var(--accent);width:24px;height:24px;border-radius:50%;cursor:pointer;font-size:var(--t-md);line-height:1;display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow)}

.field{margin-bottom:var(--s-3)}
.field label{display:block;font-size:var(--t-sm);color:var(--ink-2);margin-bottom:6px;font-weight:400}
/* Поле — единственное место, где рамка несёт смысл: она говорит «сюда можно
   писать». Всё остальное на платформе держится тенью или заливкой. */
.field input,.field select{width:100%;height:38px;border:1px solid var(--line);border-radius:var(--r-1);padding:0 var(--s-3);font-size:var(--t-md);background:var(--surface);color:var(--ink);transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.field textarea{width:100%;border:1px solid var(--line);border-radius:var(--r-1);padding:10px var(--s-3);font-size:var(--t-md);line-height:1.55;background:var(--surface);color:var(--ink);transition:border-color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.field input:hover,.field textarea:hover,.field select:hover{border-color:var(--line-2)}
.field input:disabled,.field textarea:disabled,.field select:disabled{background:var(--surface-2);color:#B4B1A8}
/* Ошибка объясняет, что делать, и живёт под полем, а не в тосте: тост уезжает
   через четыре секунды, а исправлять поле человек будет дольше. */
.field.bad input,.field.bad textarea,.field.bad select{border-color:var(--err)}
.field-err{font-size:var(--t-sm);line-height:1.45;color:var(--err);margin-top:6px}
.field-count{display:flex;justify-content:flex-end;font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);margin-top:6px}
.field input:focus,.field textarea:focus,.field select:focus{outline:none;border-color:transparent;box-shadow:0 0 0 2px var(--ink)}
/* Поле с ошибкой остаётся красным и под курсором. Проверка сама ставит фокус в
   это поле, а обычное правило фокуса гасило рамку — то есть красной её не
   видел никто: она загоралась и в ту же секунду пропадала. */
.field.bad input:focus,.field.bad textarea:focus,.field.bad select:focus{
  border-color:var(--err);box-shadow:0 0 0 2px var(--err-bg)}
.field textarea{resize:vertical;line-height:1.6}
.md-bar{display:flex;gap:var(--s-1);margin-bottom:var(--s-1)}
.md-btn{border:1px solid var(--line-2);background:var(--surface);color:var(--ink);border-radius:var(--r-1);min-width:30px;height:28px;cursor:pointer;font-size:var(--t-md);line-height:1;display:inline-flex;align-items:center;justify-content:center}
.md-btn:hover{border-color:var(--marker)}
.hint{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-1)}
.ed-row{display:flex;gap:var(--s-2);margin-bottom:var(--s-2);align-items:center}
.ed-row input,.ed-row select{flex:1;border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface-2)}
.ed-row input:focus{outline:none;border-color:var(--accent);background:var(--surface)}
.ed-row select{flex:0 0 78px}
.ed-row .grip{color:var(--muted);font-size:var(--t-sm);width:16px;text-align:center;flex-shrink:0}

/* Вопрос «Теста» в редакторе: текст, варианты, «+ Вариант». Вопросы отбиты друг
   от друга линией — иначе варианты соседних сливаются в один список и непонятно,
   к чему относится галочка «верно». */
.test-ed{margin-bottom:var(--s-3)}
.test-ed+.test-ed{padding-top:var(--s-3);border-top:1px solid var(--line)}
.test-ed textarea{width:100%;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-2) var(--s-3);font-size:var(--t-md);background:var(--surface-2);color:var(--ink);
  resize:vertical;line-height:1.6;margin-bottom:var(--s-2)}
.test-ed textarea:focus{outline:none;border-color:var(--accent);background:var(--surface)}
.test-ed-head{display:flex;align-items:center;gap:var(--s-2)}
.test-ed-head label{flex:1;font-size:var(--t-sm);color:var(--muted);font-weight:600;margin-bottom:var(--s-1)}

/* ---------- Единая строка списка (хендофф v2) ----------
   Одна анатомия вместо четырёх: .day-row, .attn-row, .hw и .stu-row делали одно
   и то же — значок, текст, статус, действие, — но различались историей
   появления, а не смыслом. Четыре слота, разница между вариантами только в
   содержимом:

     [якорь 44px] аватар 40 · время mono · значок
     [основное 1fr] имя 14 Onest 600 + подпись 12.5 Manrope muted
     [статус auto] .tag
     [действие auto] .btn.sm

   Строка живёт на бумаге, а не на листе: карточка белая, список — фон
   страницы, иначе лента из десяти строк читается как десять карточек. */
/* Колонка имени не сжимается до нуля. У «auto»-колонок предел — их содержимое
   целиком, а у minmax(0,1fr) низ нулевой: колонка статуса и кнопок забирала всю
   ширину, и «Petr» превращался в «Pet…» рядом с двумя кнопками во всю строку.
   Нижняя граница переворачивает правило — тесно становится тому, что справа. */
.row{display:grid;grid-template-columns:44px minmax(6rem,1fr) auto auto;align-items:center;
  gap:var(--s-3);background:var(--surface-2);border-radius:var(--r-1);
  padding:10px 14px;margin-bottom:6px;text-decoration:none;color:var(--ink);
  transition:background var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease),
             box-shadow var(--dur-fast) var(--ease)}
/* Плашка светлеет и приподнимается ровно настолько, чтобы стало понятно:
   строка нажимается. Фон в жёлтое не красим и строку не двигаем вбок —
   смещается только содержимое действий. */
.row:hover{background:var(--surface);box-shadow:var(--sh-1);transform:translateY(-1px)}
/* Строка без якоря — когда ни лица, ни времени нет */
.row.bare{grid-template-columns:minmax(6rem,1fr) auto auto}
/* Действие — сама строка: когда вести из неё некуда, кроме одного места,
   кнопка рядом со статусом только отнимает ширину у названия */
.row.act{cursor:pointer}
.row.act:active{transform:scale(.997)}
.row.act:hover{background:var(--surface);box-shadow:var(--sh-1)}
/* Якорь: любой из трёх видов встаёт в одну колонку и центрируется */
.row .r-anchor{display:flex;align-items:center;justify-content:center;min-width:0}
.row .r-time{font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-base);color:var(--ink-2);text-align:center}
/* Занятие не сегодня — той же строкой, но тише: сегодняшнее время читается
   первым, остальное отвечает на «а когда вообще». */
.row .r-time.soft{font-weight:400;color:var(--muted)}
.row .r-main{min-width:0}
/* display:block обязателен: overflow и text-overflow на инлайновом элементе не
   действуют вовсе. Часть строк размечена тегом span (расписание, лента дня), и
   там многоточие молча не работало — длинное имя с названием урока уезжало за
   край экрана и тянуло за собой горизонтальную прокрутку всей страницы. */
.row .r-title{display:block;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.row .r-sub{font-size:var(--t-sm);color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Подпись, которую нельзя обрывать: «занятия кончились · срок кончился» — это и
   есть повод, по которому строка попала в список, а не пояснение к нему. */
.row .r-sub.wrap{white-space:normal;overflow:visible;text-overflow:clip}
/* Подпись может идти в строку с названием — «Weather & Small Talk · сегодня» */
.row .r-title .r-sub{display:inline;font-weight:400}
/* Число справа на линии имени: у строки «Абонементы на исходе» имя и остаток —
   одна мысль «у кого сколько», и стоять они должны на одной строке. */
.row .r-title.with-tag>.r-num{flex-shrink:0;font-variant-numeric:tabular-nums;
  font-family:var(--font-body);font-weight:600;color:var(--ink-2);margin-left:auto}
/* Шеврон рядом с действием строки: пока действия нет, он один отвечает «сюда
   можно зайти», а с действием уступает ему место. */
.row .r-chev{flex-shrink:0}
.row:hover .r-side .r-act{opacity:1}

/* Название с плашкой рядом: обрезается название, а плашка стоит целиком —
   иначе длинный заголовок съедал бы «2 правки», ради которых строку и читают. */
.row .r-title.with-tag{display:flex;align-items:center;gap:var(--s-2);min-width:0}
.row .r-title.with-tag>.r-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.row .r-title.with-tag>.tag{flex-shrink:0}
/* Кнопки переносятся, а не вылезают за край: в узкой колонке пара действий
   («Провести» + «Не состоялось») шире, чем вся колонка, и строка уводила
   страницу в горизонтальную прокрутку. */
.row .r-side{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;justify-content:flex-end}
.row.off{opacity:.55}
.row.off:hover{opacity:1}
/* Действие проявляется по наведению — кроме основного, оно видно всегда.
   На устройствах без мыши показываем сразу: наводить там нечем. */
.row .r-act{transition:opacity var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
@media (hover:hover){
  .row .r-act:not(.always){opacity:0;transform:translateX(4px)}
  .row:hover .r-act,.row:focus-within .r-act{opacity:1;transform:none}
}

.card{background:var(--surface);border-radius:var(--radius);padding:var(--pad);
  margin-bottom:var(--s-3);box-shadow:var(--sh-1)}
.ex-head{display:flex;align-items:flex-start;gap:var(--s-3);margin-bottom:var(--s-3)}
/* «Пройдено» — про ход занятия, а не про правильность: блок могли разобрать и
   с ошибкой. Поэтому приглушённым, а не зелёным: зелёный на платформе значит
   «верно», и здесь он обещал бы то, чего никто не проверял. */
.ex-done{margin-left:auto;flex-shrink:0;white-space:nowrap;
  font-family:var(--font-head);font-weight:600;font-size:11px;color:var(--muted)}
.ex-badge{background:var(--surface-2);color:var(--muted);font-variant-numeric:tabular-nums;font-weight:500;font-size:var(--t-label);letter-spacing:.06em;border-radius:var(--r-1);padding:3px var(--s-2);flex-shrink:0;margin-top:1px}
.ex-badge svg{width:16px;height:16px;display:block}
/* Счёт сложенного — справа в шапке задания, у самого края: он про весь блок,
   а не приписка к его названию. */
.ex-count{margin-left:auto;font-variant-numeric:tabular-nums;font-size:var(--t-sm);
  color:var(--muted);flex-shrink:0}
.ex-instr{font-family:var(--font-head);font-weight:600;font-size:15px;line-height:1.45}
/* ---------- Образец задания ----------
   В учебнике первый пункт сделан за ученика и набран иначе — курсивом, другим
   цветом. Здесь так же: тихая полоса между инструкцией и заданием, чтобы
   образец не читался как ещё одно упражнение, которое надо выполнить. */
.ex-example{display:flex;gap:var(--s-3);align-items:flex-start;margin:0 0 var(--s-3);padding:var(--s-2) var(--s-3);
  border-left:2px solid var(--line-2);background:var(--surface-2);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.ex-example .exe-label{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);padding-top:3px;flex-shrink:0}
.ex-example .exe-text{font-size:var(--t-md);line-height:1.6;color:var(--ink-2);font-style:italic}

/* Картинка при задании (общее поле image, см. blockImageHtml в blocks.js).
   В отличие от .block-img она не тянется во всю ширину и не режется по краям:
   вырезанный из учебника кусок бывает в две ладони, и растянутый до края листа
   он рассыпается в пиксели. Ширина по самой картинке, потолок — чтобы страница
   разворота не заняла экран целиком. */
.ex-image{display:block;max-width:100%;max-height:420px;height:auto;
  margin:0 0 var(--s-3);border-radius:var(--radius-sm)}

.block-img{width:100%;border-radius:var(--radius-sm);display:block;margin-bottom:var(--s-3);max-height:340px;object-fit:cover}
.block-caption{font-size:var(--t-sm);color:var(--muted);text-align:center;margin-bottom:var(--s-3)}
.block-text{font-size:15.5px;line-height:1.75}
.block-text p{margin-bottom:var(--s-3)}
.block-text p:last-child{margin-bottom:0}
.block-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-lesson-h);margin-bottom:var(--s-3)}
.block-text .block-h{font-family:var(--font-head);font-weight:700;font-size:15.5px;margin:var(--s-3) 0 var(--s-1)}
.block-text .block-h:first-child{margin-top:0}
/* Списки задания: пункты, варианты, фразы под одним заголовком. Маркер и номер
   вынесены на поля, чтобы текст пунктов держал общую левую границу с абзацами. */
.block-list{margin:0 0 var(--s-3);padding-left:1.35em}
.block-list:last-child{margin-bottom:0}
.block-list li{margin-bottom:var(--s-1)}
.block-list li:last-child{margin-bottom:0}
.block-list li::marker{color:var(--muted)}
/* Вопрос задания набран как текст, а не одной строкой: в него тоже попадают
   списки и переносы — «Answer the questions» с тремя пунктами это обычный вид. */
.ex-question{font-family:var(--font-head);font-weight:600;font-size:15px;line-height:1.6;margin-bottom:var(--s-3)}
.ex-question p{margin-bottom:var(--s-2)}
.ex-question p:last-child{margin-bottom:0}
.ex-question .block-list{margin-bottom:var(--s-2);font-weight:500}

/* ---------- Диалог ----------
   Реплики в учебнике набраны как «1 A: … / B: …». Номер обмена платформа ставит
   сама на карточке задания, а кто говорит — показывает вёрстка, а не буква в
   тексте: у каждого собеседника своя черта слева, вторая реплика с отступом.
   Между обменами воздух, поэтому пары читаются парами, а не сплошной лентой. */
.dlg{font-size:var(--t-lg)}
.dlg-turn{position:relative;padding:2px 0 2px var(--s-3);margin-bottom:var(--s-1);line-height:2.2;
  border-left:2px solid var(--line-2)}
.dlg-turn.s1{margin-left:var(--s-5);border-left-color:var(--accent)}
.dlg-turn.s2{margin-left:52px;border-left-color:var(--marker)}
.dlg-turn.s3{margin-left:78px;border-left-color:var(--ok)}
.dlg-turn.start{margin-top:var(--s-4)}
.dlg-turn.start:first-child{margin-top:0}
.dlg-who{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);display:block;line-height:1.6;margin-bottom:-2px}
.gap-text{font-size:15.5px;line-height:2.4}

/* ---------- «Слово и картинка» ----------
   Разворот учебника: слева фразы с местом под номер, справа пронумерованные
   фотографии. Фраза выбирается кликом, следом кликают по фотографии — так же,
   как в «По группам». На узком экране колонки встают друг под друга. */
.imgm{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:var(--s-4);align-items:start}
.imgm-list{display:flex;flex-direction:column;gap:var(--s-1)}
.imgm-row{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-2) var(--s-3);border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--surface);cursor:pointer;font-size:14.5px;transition:border-color var(--dur-fast) var(--ease);
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
.imgm-row:hover{border-color:var(--ink-2)}
.imgm-row.selected{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-soft-ink)}
.imgm-row.ok{border-color:var(--ok);background:var(--ok-bg)}
.imgm-row.err{border-color:var(--err);background:var(--err-bg)}
.imgm-slot{flex-shrink:0;width:30px;height:26px;display:inline-flex;align-items:center;justify-content:center;
  border:1.5px dashed var(--line-strong);border-radius:var(--r-1);background:var(--surface-2);
  font-variant-numeric:tabular-nums;font-size:var(--t-sm);font-weight:500}
.imgm-row.selected .imgm-slot,.imgm-row.ok .imgm-slot,.imgm-row.err .imgm-slot{border-style:solid}
.imgm-text{min-width:0}
.imgm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:var(--s-2)}
.imgm-photo{position:relative;padding:0;border:1px solid var(--line);border-radius:var(--radius-sm);
  overflow:hidden;background:var(--surface-2);cursor:pointer;aspect-ratio:1;transition:border-color var(--dur-fast) var(--ease)}
.imgm-photo:hover{border-color:var(--accent)}
.imgm-photo.used{opacity:.4}
.imgm-photo img{width:100%;height:100%;object-fit:cover;display:block}
.imgm-n{position:absolute;left:4px;top:4px;background:var(--ink);color:var(--paper);
  font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:500;border-radius:5px;padding:2px var(--s-1)}
@media(max-width:720px){.imgm{grid-template-columns:1fr}}
/* Строка редактора: миниатюра слева, фраза и ссылка справа */
.imgm-ed{display:flex;align-items:flex-start;gap:var(--s-2);margin-bottom:var(--s-2)}
.imgm-ed-pic{width:56px;height:56px;flex-shrink:0;padding:0;overflow:hidden;cursor:pointer;
  border:1.5px dashed var(--line-strong);border-radius:var(--radius-sm);background:var(--surface-2);
  color:var(--muted);font-size:var(--t-label);font-family:var(--font-head)}
.imgm-ed-pic:hover{border-color:var(--accent);color:var(--ink)}
.imgm-ed-pic img{width:100%;height:100%;object-fit:cover;display:block}
audio{width:100%}
/* Подпись под плеером на занятии: звук общий, и об этом надо сказать — иначе
   неожиданно, что нажатие у себя запускает дорожку у второго. */
.aud-sync{font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.04em;color:var(--muted);margin-top:6px}
.aud-sync.warn{font-family:var(--font-body);font-size:var(--t-sm);letter-spacing:0;color:var(--err)}
.aud-sync.blocked{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-family:var(--font-body);font-size:var(--t-sm);letter-spacing:0}
.embed{position:relative;padding-top:56.25%;border-radius:var(--radius-sm);overflow:hidden;background:var(--surface-2);margin-bottom:var(--s-3)}
.embed iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* Скругление у акцента круговое. Раньше левые углы были острыми — предполагалось,
   что цветная полоса продолжает край листа, а на деле плашка стоит в отступе
   карточки, и два острых угла посреди скруглённого урока читались как обрезок. */
.callout{border-left:3px solid var(--accent);background:var(--accent-soft);border-radius:var(--radius-sm);padding:var(--s-3) var(--s-4)}
.callout.tip{border-color:var(--ok);background:var(--ok-bg)}
.callout.warn{border-color:var(--err);background:var(--err-bg)}
.callout .ct{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);margin-bottom:var(--s-1)}
.callout .block-text{font-size:14.5px}

/* ---------- Конец урока, открытого по ссылке ----------
   Зовём там, где решение созревает: урок дочитан, и человек либо увидел в нём
   свою работу, либо нет. Полоса сверху говорит то же самое, но её читают до
   урока, когда звать ещё нечем. Тёмная плашка — тот же приём, что у последнего
   экрана лендинга: конец страницы, где спрашивают «берём?». */
.share-foot{max-width:760px;margin:var(--s-6) auto 0;padding:var(--s-6);
  border-radius:var(--radius);background:var(--ink);color:var(--paper);text-align:center}
.share-foot .sf-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg)}
.share-foot .sf-d{margin:var(--s-2) auto 0;max-width:52ch;font-size:var(--t-md);
  line-height:1.55;opacity:.8}
.share-foot .sf-act{display:flex;gap:var(--s-3);justify-content:center;flex-wrap:wrap;margin-top:var(--s-4)}
.share-foot .btn{border-color:rgba(255,255,255,.25);color:var(--paper);background:transparent}
.share-foot .btn.primary{background:var(--marker);border-color:var(--marker);color:#171A21}

/* ---------- Лексика урока ----------
   Слова списком, каждое нажимается. Сетка, а не колонка: десяток слов в столбик
   занимает пол-экрана и читается как задание, а в две-три колонки виден весь
   набор разом — то, ради чего блок и нужен.

   Карточка слова не выглядит кнопкой: у неё нет ни заливки, ни рамки, пока на
   неё не навели. Нажимаемость обещает подчёркнутое пунктиром слово — тот же
   приём, что у словарных подсказок в тексте. */
.vocab-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:var(--s-1) var(--s-3)}
.vw{display:flex;flex-direction:column;align-items:flex-start;gap:1px;width:100%;
  border:1px solid transparent;border-radius:var(--radius-sm);background:none;
  padding:6px var(--s-2);text-align:left;cursor:pointer;font-family:inherit}
.vw:hover{background:var(--surface-2);border-color:var(--line)}
.vw b{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink);
  border-bottom:1px dashed var(--line-2)}
.vw:hover b{border-bottom-color:var(--marker)}
.vw span{font-size:var(--t-base);color:var(--muted);line-height:1.35}

/* ---------- Заголовок части урока ----------
   В учебнике части отбиты цветной полосой: SPEAKING, VOCABULARY, GRAMMAR.
   Здесь то же самое чертой акцента темы урока — часть выглядит как в печатном
   оригинале, и видно, где кончилась одна и началась другая. */
/* Подпись части не держится в строке с названием любой ценой. Была nowrap и не
   сжималась, и на телефоне длинная («asking questions & phone inquiries»)
   вылезала за лист и раздвигала окно: просмотр урока на 390 выходил в 408, вид
   «Как у ученика» в конструкторе — в 417, а название рядом с ней ломалось по
   словам («WARM / UP»). Теперь, когда тесно, подпись уходит строкой ниже — к
   правому краю, где и стояла, — а совсем длинная переносится. Где всё
   помещается, раскладка прежняя. */
.sec-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--s-1) var(--s-3);margin:var(--s-6) 0 var(--s-4);padding-bottom:var(--s-2);
  border-bottom:2px solid var(--accent);overflow-wrap:anywhere}
.sec-head .sh-title{font-family:var(--font-head);font-weight:800;font-size:var(--t-lesson-h);
  letter-spacing:-.01em;line-height:1.2}
.sec-head .sh-kicker{margin-left:auto;min-width:0;text-align:right;font-variant-numeric:tabular-nums;font-size:var(--t-label);
  letter-spacing:.1em;color:var(--muted)}

/* В рельсе структуры заголовок набран заголовком: по ней читается устройство урока */
.rail-item.is-head{margin-top:var(--s-2);padding-top:var(--s-2);height:auto;border-radius:0;
  border-top:1px solid var(--line);color:var(--ink);
  font-family:var(--font-head);font-weight:700;font-size:var(--t-sm);letter-spacing:.04em}
.rail-item.is-head:hover{background:none;border-color:var(--line);color:var(--ink)}
.rail-item.is-head.active{background:none;color:var(--accent)}
.rail-item.is-head .rail-dot{display:none}

/* ---------- Таблица: грамматика, парадигмы, фразы ----------
   В учебнике это плашка с сеткой, и на платформе она должна читаться так же
   тихо: тонкие линии, шапка на подложке, первый столбец — заголовочным шрифтом
   (в учебниках слева всегда метка: форма, часть фреймворка, инфинитив).
   Цвета берёт из темы урока, поэтому таблица выглядит частью материала. */
/* Регистр надписи оставляем как написал преподаватель: в учебниках метки плашек
   набраны капсом («THE FRAMEWORK»), а заголовки грамматических таблиц — обычным
   («Past simple»). Переводить всё в капс значит спорить с источником. */
/* .eyebrow ниже в файле переводит текст в капс — здесь перебиваем обоими классами */
.eyebrow.tbl-label{margin-bottom:var(--s-2);text-transform:none;letter-spacing:.08em}
.tbl-wrap{overflow-x:auto;margin-bottom:2px}
.tbl{border-collapse:collapse;width:100%;font-size:var(--t-md);line-height:1.5}
.tbl th,.tbl td{border:1px solid var(--line);padding:var(--s-2) var(--s-3);text-align:left;vertical-align:top}
.tbl th{background:var(--surface-2);font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
.tbl td:first-child{font-family:var(--font-head);font-weight:600}
/* Продолжение строки — метки нет, рамку между ними убираем: читается как список */
.tbl td.tbl-cont{border-top-color:transparent}
.tbl td.tbl-cont:first-child{border-right-color:transparent}
.tbl .tbl-gap{width:96px;margin:0}

.margin-slot{position:relative}
.sticky{background:var(--note-bg);border:1px solid var(--note-line);border-radius:var(--r-1);padding:var(--s-3) var(--s-4);box-shadow:2px 3px 0 rgba(138,106,0,.08);position:relative}
.sticky::before{content:'';position:absolute;top:-6px;left:20px;width:34px;height:12px;background:var(--note-tape);border-radius:2px;transform:rotate(-2deg)}
.sticky .sw{font-family:'Caveat',cursive;font-size:20px;font-weight:600;color:var(--note-ink);line-height:1.3}
.sticky .sw b{font-family:var(--font-head);font-size:15px;font-weight:700;display:block;margin-bottom:2px}
.sticky .stag{position:absolute;top:9px;right:11px;font-size:var(--t-label);font-weight:700;font-family:var(--font-head);color:var(--note-ink);opacity:.55;text-transform:uppercase;letter-spacing:.05em}
.class-canvas{position:relative}
.sticky.aside{width:230px}

/* ---------- Лист урока (хендофф v2) ----------
   Тема красит лист, а не страницу. Раньше applyTheme писал переменные в body,
   кремовый заливал весь вьюпорт до краёв экрана, платформа исчезала — урок
   читался как отдельный сайт, и темами поэтому не пользовались. Теперь урок —
   оформленный документ на платформенном столе: фон страницы, топбар и рельса
   всегда платформенные, а лист виден тенью.
   Шрифт и кегль объявлены здесь: body берёт их у платформы, и лист должен
   назвать свои сам, иначе переменные темы никто не читает. */
.lesson-sheet{background:var(--bg);color:var(--ink);
  font-family:var(--font-body);font-size:var(--fs);
  border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:var(--pad)}
/* В тёмном хроме лист виден кантом, а не тенью: тень платформы там чёрная, и на
   тёмном столе её нет вовсе — а если и урок тёмный, лист сливался со страницей
   (1.05 против 17.9 в светлом хроме) и «документ на столе» переставал читаться.
   Кант — снаружи рамки: рамка принадлежит уроку, кант — столу под ним. */
html[data-chrome="dark"] .lesson-sheet{box-shadow:var(--shadow)}
/* ---------- Стол под уроком ----------
   Тема урока красит лист, хром остаётся выбором человека — правило верное, но
   с ценой: светлый урок у ученика с тёмным хромом лежал на почти чёрном поле, и
   края листа резали глаз. В обратную сторону то же — тёмный урок в белой рамке.

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

   Считает color-mix, а не разметка (--lesson-bg ставит applyTheme в core.js):
   так стол пересчитывается сам, когда хром переключают прямо посреди занятия.
   Браузер постарше правило пропустит и покажет прежнюю бумагу — не поломка. */
html.on-lesson body{
  background:color-mix(in srgb, var(--paper) 79%, var(--lesson-bg, var(--paper)) 21%);
}
/* Лист на подстроенном столе отделяется кантом в обе стороны: разница между
   ними теперь мягче прежней, а «документ на столе» должен читаться. */
html.on-lesson .lesson-sheet{box-shadow:0 0 0 1px color-mix(in srgb, var(--ink) 12%, transparent),var(--shadow)}
/* Заметки на полях лежат снаружи листа — они и в тетради на полях. Считаются
   они от колонки блоков, которая уже листа на его поле, поэтому вылет
   складывается из зазора и этого поля. Зазор — жёлоб, и он не пустой: в нём
   стоит кнопка «✧ заметка», поэтому он шире прежнего на её ширину. Сама
   ширина листа при этом остаётся прежней шириной колонки — иначе занятие с
   заметками перестало бы помещаться на экранах чуть шире 1300px. */
@media(min-width:1300px){
  .lesson-sheet{max-width:700px}
  .sticky.aside{position:absolute;right:calc(-266px - var(--pad));width:230px;margin:0;
    transform:rotate(-1.5deg);transition:top var(--dur-base) var(--ease)}
  /* Наклон чередуется: одинаково наклонённая стопка читается ошибкой вёрстки,
     а не рукой, которая клеила записки по одной. */
  .margin-slot:nth-of-type(even) .sticky.aside{transform:rotate(1deg)}
}
@media(max-width:1299px){.sticky.aside{margin:0 0 var(--s-3);transform:rotate(-.5deg)}}
.sticky .sdel{position:absolute;top:-9px;right:-9px;width:22px;height:22px;border-radius:50%;border:1px solid var(--note-line);background:var(--note-bg);color:var(--note-ink);font-size:11px;cursor:pointer;display:none;align-items:center;justify-content:center;box-shadow:0 1px 3px rgba(0,0,0,.12)}
.sticky:hover .sdel{display:flex}
/* Выключатель «в словарь» на стикере. Строкой внизу, а не значком в углу:
   значок пришлось бы разгадывать, а тут прямо написано, куда уйдёт заметка.
   Выключенный тихий, включённый набран чернилами заметки — разница видна, но
   ни один не спорит с самим словом наверху. */
.sticky .svoc{display:block;width:100%;margin-top:var(--s-2);padding:3px 0;border:none;background:none;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-label);letter-spacing:.04em;
  text-transform:uppercase;text-align:left;cursor:pointer;color:var(--note-ink);opacity:.45}
.sticky .svoc:hover{opacity:.8}
.sticky .svoc.on{opacity:.85}
.sticky .sw[contenteditable]{outline:none;min-width:60px;cursor:text}
.sticky .sw[contenteditable]:empty::before{content:'фраза – перевод';opacity:.45}
.note-hint{font-size:var(--t-label);color:var(--note-ink);opacity:.6;margin-top:var(--s-1);font-family:var(--font-body)}
/* ---------- Кнопка «заметка» ----------
   Стоит на границе перед своим блоком и не двигается: кнопка, уехавшая вниз
   вместе с заметками, зовёт добавить заметку совсем к другому заданию. Чтобы
   не двигаться, ей нужна своя полоса — жёлоб между листом урока и колонкой
   заметок. Там она и живёт, и колонки не пересекаются вовсе.

   Жёлоб узкий, поэтому в нём видна одна метка ✧. Слово кнопка договаривает
   под курсором: пилюля растёт вправо, поверх поля, и это её единственный
   момент, когда она чем-то накрывает заметки. На узких экранах полей нет — там
   она возвращается над блоком целым словом, как была. */
.note-insert{height:0;display:flex;align-items:center;justify-content:flex-end;position:relative;z-index:3}
/* Кнопка видна всегда. По наведению её было не найти: на занятии заметку кидают
   на ходу, и искать невидимую кнопку мышью посреди урока некогда. Приглушена,
   чтобы не спорить с материалом, и наливается цветом под курсором. */
.note-insert button{border:1px dashed var(--note-line);background:var(--note-bg);color:var(--note-ink);border-radius:var(--r-pill);padding:3px var(--s-3);font-size:var(--t-sm);font-weight:700;font-family:var(--font-head);cursor:pointer;opacity:.5;transition:opacity var(--dur-fast) var(--ease);white-space:nowrap}
.note-insert:hover button,.note-insert button:focus-visible{opacity:1}
@media(min-width:1300px){
  .note-insert{margin:0}
  .note-insert button{position:absolute;left:calc(100% + 26px);padding:3px 6px;
    display:inline-flex;align-items:center;gap:0;transition:opacity var(--dur-fast) var(--ease),gap var(--dur-fast) var(--ease)}
  /* Слово ждёт курсора: в покое оно свёрнуто в ноль, поэтому метка занимает
     ровно ширину жёлоба и до колонки заметок не дотягивается. */
  .note-insert .ni-word{display:inline-block;max-width:0;overflow:hidden;transition:max-width var(--dur-fast) var(--ease)}
  .note-insert:hover button .ni-word,.note-insert button:focus-visible .ni-word{max-width:60px}
  .note-insert:hover button,.note-insert button:focus-visible{gap:var(--s-1)}
  /* Полоса наведения — только по жёлобу: раньше она накрывала всё поле, и
     кнопки распахивались от любого движения мыши над заметками. */
  .note-insert::before{content:'';position:absolute;left:100%;width:42px;height:40px;top:-20px}
}
@media(max-width:1299px){
  .note-insert{height:22px;margin-bottom:var(--s-1)}
  .note-insert button{opacity:.75}
  .note-insert .ni-word{margin-left:var(--s-1)}
}
/* Банк — приподнятая карточка на карточке задания, а не вдавленная плита:
   слова из него берут, и лежать они должны сверху. Отношение было обратным —
   серый банк внутри белой карточки. */
.pool{border:none;border-radius:var(--r-2);padding:10px var(--s-3) var(--s-3);
  display:block;min-height:46px;margin-bottom:var(--s-4);
  background:var(--surface);box-shadow:var(--sh-1)}
.pool-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);
  margin-bottom:var(--s-2)}
/* «осталось N» — единственное, что говорит, сколько работы впереди: банк не
   пустеет, использованное в нём остаётся зачёркнутым и его можно забрать назад. */
.pool-left{font-size:var(--t-label);font-weight:600;color:var(--muted);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.pool-row{display:flex;flex-wrap:wrap;gap:var(--s-2)}
/* font/color наследуем явно: плашки-слова ставятся тегом span, а выбор дней в
   расписании ученика — кнопкой, и без этого она бы взяла шрифт браузера */
.chip{font:inherit;font-weight:600;color:inherit;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-1);padding:6px var(--s-3);cursor:pointer;user-select:none}
.chip:hover{border-color:var(--accent)}
.chip.selected{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-soft-ink)}
.chip.used{text-decoration:line-through;text-decoration-thickness:1px;
  background:var(--surface-2);border-color:var(--line);color:var(--muted);font-weight:500}
/* На клетках-буквах зачёркивания нет: линия поверх глифа ломает опознание
   буквы — а опознать её и есть всё задание. Только приглушение. */
.pool-letters .chip.used{text-decoration:none}
/* Буквы в банке — квадраты, как клетки под ними: чип по ширине глифа делал ряд
   рваным, и «l» с «w» переставали читаться одной колодой. */
.pool-letters .chip{width:36px;height:36px;padding:0;display:inline-flex;
  align-items:center;justify-content:center}
/* Плашка после проверки — используется «По группам», где верным/неверным помечена
   не рамка вокруг слота, а сама переносимая плашка */
.chip.ok{border-color:var(--ok);background:var(--ok-bg);color:var(--ok)}
.chip.err{border-color:var(--err);background:var(--err-bg);color:var(--err)}

/* Плашки выбора в панели профиля — цели ученика и дни регулярного расписания.
   Мельче плашек-слов в заданиях: их много, а панель узкая.
   .add — вариант, который ещё не выбран: пунктир и приглушённый цвет, чтобы
   список предложенного не спорил за внимание с уже выбранным.
   .flat — то же, но для чтения: без рамки и без указателя мыши. */
.chip-row{display:flex;flex-wrap:wrap;gap:var(--s-1)}
.chip.sm{padding:5px 10px;font-size:var(--t-sm);border-radius:var(--r-1)}
/* Число в чипе-фильтре: сам счёт, а не подпись к нему. Набран цифрами в ряд,
   чтобы чипы не дёргались при смене чисел. */
.chip b{font-weight:600;font-variant-numeric:tabular-nums;color:var(--muted);margin-left:3px}
.chip.selected b{color:inherit;opacity:.72}
.chip.add{border-style:dashed;color:var(--muted);font-weight:500}
.chip.add:hover{border-style:solid;color:var(--ink)}
.chip.flat{background:var(--surface-2);border-color:transparent;cursor:default;font-weight:500}
.chip.flat:hover{border-color:transparent}
.chip .x{color:var(--muted);margin-left:var(--s-1)}
.chip:hover .x{color:inherit}

/* Отчёт временного переноса из tutorapp — таблица моноширинным шрифтом длиннее
   панели настроек, поэтому скроллится сама и не тянет за собой всю страницу. */
.tutorapp-out{margin-top:var(--s-3);padding:var(--s-3) var(--s-3);background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--radius-sm);font-variant-numeric:tabular-nums;font-size:var(--t-sm);line-height:1.6;
  white-space:pre;overflow-x:auto;max-height:320px;overflow-y:auto}
.slot{display:inline-flex;align-items:center;justify-content:center;min-width:46px;height:36px;border:1.5px dashed var(--line-strong);border-radius:var(--r-1);background:var(--surface-2);cursor:pointer;font-weight:600;padding:0 var(--s-2);vertical-align:middle;margin:0 3px}
/* Поставленное слово — серая плашка со сплошной рамкой. Пустой пропуск при
   этом остаётся пунктирным, и перепутать их нельзя: разница в рамке, а не в
   цвете. Чернильная заливка, стоявшая здесь раньше, делала из собранной фразы
   ряд чёрных блоков — читалось это не как ответ ученика, а как вымаранный
   текст, и на длинном предложении рябило.
   Вердикт .ok/.err стоит ниже и перекрывает заливку: цвет данных сильнее. */
.slot.filled{border-style:solid;border-color:var(--line-2);background:var(--surface-2);color:var(--ink)}
.slot.next{border-color:var(--ink)}
/* Намеченный пропуск — сплошной рамкой: видно, что нажатие услышано и слово
   встанет сюда. Пустые пропуски темнеют, пока в банке ждёт выбранное слово:
   это места, куда его можно положить. Цветом ни то, ни другое не помечаем:
   зелёный и красный на платформе значат «верно» и «ошибка» у ответа, а жёлтый
   занят под работу модели и пометки от преподавателя. */
.slot.aimed{border-color:var(--ink);border-style:solid}
.slot.open{border-color:var(--ink-2)}
/* Палец до пропуска. Слово теперь кладут вторым нажатием, и это нажатие
   приходится на пропуск посреди строки текста — 36 пикселей высоты против
   правила «не ниже 44» (хендофф, раздел телефона). Растим саму цель, а не
   рамку: невидимое поле вокруг не меняет ни высоту строки, ни вид задания.
   По горизонтали прибавка меньше — два пропуска подряд не должны перехватывать
   нажатия друг у друга. */
.slot{position:relative}
@media(max-width:640px){
  .slot::after{content:'';position:absolute;inset:-6px -3px}
}
.sent-slot.next{border-bottom-color:var(--ink)}
.slot.ok{border-color:var(--ok);background:var(--ok-bg);color:var(--ok)}
.slot.err{border-color:var(--err);background:var(--err-bg);color:var(--err)}
.letter-slot{width:40px;height:40px;font-size:17px;min-width:0}

/* ---------- «Собери предложение»: слова встают на строку ----------
   Не сетка клеток, а одна линия письма: собранное должно читаться предложением,
   иначе ученик проверяет порядок клеток, а не слышит фразу. Линия одна на все
   слова и переносится вместе с ними; пустое место — пунктирный прочерк ровно
   под одно слово, так видно, сколько ещё осталось поставить. */
/* Предложения идут одно под другим, каждое со своим номером, линией и банком.
   Номер появляется только когда предложений больше одного: над единственным он
   означал бы, что где-то есть второе. */
.sent-item{display:flex;gap:var(--s-3);align-items:flex-start}
.sent-item+.sent-item{margin-top:var(--s-2)}
.sent-body{flex:1;min-width:0}
.sent-num{flex-shrink:0;margin-top:14px;width:22px;text-align:right;
  font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}
.sent-line{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--s-2) 6px;
  min-height:44px;padding:var(--s-2) 0 var(--s-3);margin-bottom:var(--s-3)}
.sent-line.ok{border-bottom-color:var(--ok)}
.sent-line.err{border-bottom-color:var(--err)}
.sent-slot{display:inline-flex;align-items:center;justify-content:center;
  min-width:52px;height:32px;padding:0 var(--s-2);border-radius:var(--r-1);cursor:pointer;
  font-weight:600;border:1.5px dashed var(--line-strong);background:var(--surface-2)}
.sent-slot.filled{border-style:solid;border-color:var(--line-2);background:var(--surface-2);color:var(--ink);
  padding:0 var(--s-2);min-width:0}
.sent-slot.filled:hover{background:var(--line)}
.sent-line.ok .sent-slot.filled{color:var(--ok)}
.sent-line.err .sent-slot.filled{color:var(--err)}
@media(max-width:560px){.sent-slot{min-width:40px}}
.type-gap{display:inline-block;width:112px;max-width:100%;border:none;border-bottom:2px solid var(--line-strong);background:transparent;font-weight:600;font-size:15px;text-align:center;padding:2px var(--s-1);margin:0 3px}
/* Пропуск длиной в предложение: ширину задаёт разметка (см. gapStyle), а текст
   в нём выравниваем по левому краю — по центру строка читается как заголовок. */
.type-gap.wide{text-align:left}
.type-gap:focus{outline:none;border-bottom-color:var(--accent)}
.type-gap.ok{border-bottom-color:var(--ok);color:var(--ok)}
/* Проверенное верным зафиксировано (lockCheck в blocks.js): поле только для
   чтения, и курсор ввода над ним обещал бы правку, которой не будет. */
.type-gap[readonly]{cursor:default}
.type-gap.err{border-bottom-color:var(--err);color:var(--err)}
/* Ряд кнопок под заданием: проверить · сбросить · результат */
.ex-acts{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-3)}
.check-btn{border:none;background:var(--accent-soft);color:var(--accent-soft-ink);font-family:var(--font-head);font-weight:700;font-size:var(--t-base);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-4);cursor:pointer}
.check-btn:hover{filter:brightness(.96)}
.check-btn:disabled{opacity:.5;cursor:default}
.check-btn.ghost{background:none;color:var(--muted);box-shadow:inset 0 0 0 1px var(--line-2);padding:var(--s-2) var(--s-3)}
.check-btn.ghost:hover{color:var(--ink)}
.result-tag{font-weight:700;font-size:var(--t-base);font-family:var(--font-head)}
.result-tag.ok{color:var(--ok)}
.result-tag.err{color:var(--err)}
/* Ответы к заданию — преподавателю (keysHtml в blocks.js). Отбиты линией и
   подписаны словами «только у вас»: экран на занятии видно и с той стороны
   стола, и строка должна сама сказать, что показывать её не надо. Подпись
   набрана меткой, сами ответы — обычным текстом листа: читают их, а не её. */
.ex-keys{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--line)}
.ek-lab{display:block;font-family:var(--font-body);font-variant-numeric:tabular-nums;
  font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.ek-v{display:block;margin-top:6px;font-size:var(--t-base);line-height:1.55;color:var(--ink)}
.match-cols{display:flex;gap:var(--s-3)}
.match-col{flex:1;display:flex;flex-direction:column;gap:var(--s-2)}
/* Плашка — кнопка, а не текст: нажатие на длинную фразу в две-три строки Safari
   нередко понимает как начало выделения, и до задания клик уже не доходит.
   Слева стоят слова в одну строку, справа — определения в две-три, и выглядело
   это как «правая колонка не работает». */
.match-item{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-sm);padding:var(--s-3);text-align:center;font-weight:600;cursor:pointer;
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
.match-item:hover{border-color:var(--accent)}
/* Выбранное — чернилами, а не мягкой подложкой: между «выбрал» и «не выбрал»
   разница должна быть видна через весь экран, иначе пара собирается наугад. */
.match-item.selected{border-color:var(--ink);background:var(--ink);color:var(--paper)}

/* ---------- Сопоставление: пары вместо нитей ----------
   Холст .match-svg и пересчёт координат ушли. Нити приходилось перемерять на
   каждое изменение ширины, на телефоне они не читались вовсе, а к концу
   задания колонки превращались в клубок из восьми линий. Соответствие
   хранится то же (p.done) — рисуется иначе: сложенная пара покидает колонки и
   встаёт строкой над ними, колонки укорачиваются, и в них остаётся только
   нерешённое. Крестик разбирает пару назад — раньше эту роль играло повторное
   нажатие по нити, которой больше нет. */
/* Съезд пары к середине перед тем, как она встанет строкой. Поднимаем её над
   соседями: иначе едущее слово проезжает под ними и на середине пути пропадает. */
.match-item.joining{transition:transform var(--dur-base) var(--ease);position:relative;z-index:2}
/* ---------- Пропуск глазами проверяющего ----------
   В уроке пропуск — поле, в проверке — уже разбор: что вписал ученик и, если не
   сошлось, что здесь должно стоять. Поля тут нет вовсе: печатать проверяющему
   некуда, а линия поля обещала бы обратное. Зелёный и красный — данные: верно и
   ошибка. */
.gap-v{display:inline-block;border-radius:var(--r-1);padding:1px 7px;margin:0 2px;
  font-weight:600;font-size:15px;line-height:1.5}
.gap-v.ok{background:var(--ok-bg);color:var(--ok)}
.gap-v.err{background:var(--err-bg);color:var(--err);text-decoration:line-through;
  text-decoration-thickness:1px}
.gap-v.right{background:var(--ok-bg);color:var(--ok)}
.gap-v.none{color:var(--muted);box-shadow:inset 0 0 0 1px var(--line);font-weight:400}
/* Свободный пропуск (вписывают своё): ни зелёного, ни красного — сверять не с
   чем, а подложка отделяет вписанное учеником от текста задания. */
.gap-v.said{background:var(--surface-2);color:var(--ink)}
.gap-v-arr{color:var(--muted);font-style:normal;margin:0 1px}

/* Верные пары в проверке свёрнуты одной строкой: разбирают неверные, а
   перечень сошедшегося нужен только чтобы знать, что оно сошлось. */
.match-folded{color:var(--muted);font-size:var(--t-sm);line-height:1.5;margin-bottom:var(--s-3)}
.match-pair.v-err{background:var(--err-bg)}
.match-pair.v-err .match-half.to{color:var(--err);text-decoration:line-through;
  text-decoration-thickness:1px}
.match-pair .match-half.right{font-weight:600;color:var(--ok)}

.match-done{display:flex;flex-direction:column;gap:6px;margin-bottom:var(--s-4)}
/* Сложенная пара — сетка, а не флекс: половины сжимались по содержимому, и
   стрелка у «goodwill» стояла не там, где у «small talk». Колонка стрелок
   выстраивается только при равных долях, и читать столбик сложенного тогда
   можно сверху вниз, а не рыская глазами. Карточка светлее задания: сложенное
   лежит на нём, а не вдавлено в него. */
.match-pair{display:grid;grid-template-columns:1fr 16px 1fr auto;align-items:center;
  gap:var(--s-2);background:var(--surface);box-shadow:var(--sh-1);
  border-radius:var(--r-1);padding:8px var(--s-3);min-width:0}
.match-half{font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis}
.match-half.to{font-weight:400;color:var(--ink-2)}
.match-arrow{color:var(--muted);flex-shrink:0}
.match-x{margin-left:auto;flex-shrink:0;background:none;border:none;color:var(--muted);
  cursor:pointer;font:inherit;font-size:var(--t-sm);line-height:1;padding:var(--s-1);
  border-radius:var(--r-1);transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.match-x:hover{background:var(--surface);color:var(--ink)}
/* Черта между сложенным и оставшимся: без неё пары и колонки читаются одним
   списком, и непонятно, что уже решено. */
.match-split{height:1px;background:var(--line);margin:0 0 var(--s-4)}
/* Подсказка после первого нажатия. До неё выбранное слово подсвечивалось, но
   что делать дальше, нигде не говорилось — и правая колонка выглядела нерабочей. */
.match-hint{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-2)}
/* Подсказка к слову из букв уехала под клетки и погасла: она нужна, когда
   слово не складывается, а не первой строкой задания. */
.spell-hint{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-2)}

/* ---------- «По группам»: слова разложить по колонкам ----------
   Колонки — цель, банк слов ниже, как поднос под корзинами. Выбранное слово
   кладётся кликом по колонке; плашка внутри колонки кликом возвращается в банк. */
.sort-cols{display:flex;gap:var(--s-3);margin-bottom:var(--s-3);flex-wrap:wrap}
.sort-col{flex:1;min-width:120px;border:1.5px dashed var(--line-strong);border-radius:var(--radius-sm);
  padding:var(--s-3);background:var(--surface-2);cursor:pointer}
.sort-col:hover{border-color:var(--accent)}
.sort-head{font-family:var(--font-head);font-weight:700;font-size:var(--t-base);text-align:center;margin-bottom:var(--s-2)}
.sort-items{display:flex;flex-wrap:wrap;gap:var(--s-1);justify-content:center;min-height:30px}

/* ---------- «Опорный план»: подписанные поля своими словами ---------- */
.frame-grid{display:flex;flex-direction:column;gap:var(--s-3);margin-bottom:2px}
.frame-row{display:flex;flex-direction:column;gap:var(--s-1)}
.frame-label{font-family:var(--font-head);font-weight:700;font-size:13.5px}
.frame-area{width:100%;min-height:52px;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-2) var(--s-3);font-size:14.5px;background:var(--surface-2);resize:vertical}
.frame-area:focus{outline:none;border-color:var(--accent);background:var(--surface)}
.frame-area:disabled{opacity:.7}
/* Как и у «Соответствий»: вариант ответа — кнопка, и выделять его текст мышью
   незачем, а Safari на этом теряет клик (см. .match-item). */
/* «Тест» с несколькими вопросами: пункты идут один под другим со своим номером,
   как в учебнике. Номер появляется только когда вопросов больше одного — над
   единственным он означал бы, что где-то есть второй (так же у «Собери
   предложение»). Пункты разделены линией: без неё варианты соседних вопросов
   сливаются в один длинный список. */
.test-q{display:flex;gap:var(--s-3);align-items:flex-start}
.test-q+.test-q{margin-top:var(--s-4);padding-top:var(--s-4);border-top:1px solid var(--line)}
.test-q .tq-body{flex:1;min-width:0}
.test-q .tq-body .opt:last-child{margin-bottom:0}
.tq-num{flex-shrink:0;width:22px;text-align:right;padding-top:2px;
  font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}

.opt{display:flex;align-items:center;gap:var(--s-3);border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3) var(--s-3);margin-bottom:var(--s-2);cursor:pointer;background:var(--surface);
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
.opt:hover{border-color:var(--accent)}
.opt.selected{border-color:var(--accent);background:var(--accent-soft)}
.opt.ok{border-color:var(--ok);background:var(--ok-bg)}
.opt.err{border-color:var(--err);background:var(--err-bg)}
.opt .radio{width:16px;height:16px;border:2px solid var(--line-strong);border-radius:50%;flex-shrink:0}
.opt .box{width:16px;height:16px;border:2px solid var(--line-strong);border-radius:5px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fff}
.opt.selected .radio{border-color:var(--accent);background:radial-gradient(circle,var(--accent) 45%,transparent 50%)}
.opt.selected .box{border-color:var(--accent);background:var(--accent)}
.opt.ok .box{border-color:var(--ok);background:var(--ok)}
.tf-row{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3) 0;border-bottom:1px solid var(--surface-2)}
.tf-row:last-of-type{border:none}
.tf-text{flex:1}
.tf-btn{border:1px solid var(--line);background:var(--surface);border-radius:var(--r-1);padding:6px var(--s-3);font-family:var(--font-head);font-weight:700;font-size:12px;cursor:pointer;color:var(--muted);margin-left:var(--s-1)}
.tf-btn.selected{border-color:var(--accent);background:var(--accent-soft);color:var(--accent-soft-ink)}
.tf-btn.ok{border-color:var(--ok);background:var(--ok-bg);color:var(--ok)}
.tf-btn.err{border-color:var(--err);background:var(--err-bg);color:var(--err)}
.order-item{display:flex;align-items:center;gap:var(--s-3);border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3) var(--s-3);margin-bottom:var(--s-2);cursor:pointer;background:var(--surface);
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation}
.order-item:hover{border-color:var(--accent)}
.order-num{width:26px;height:26px;border-radius:var(--r-1);border:1.5px dashed var(--line-strong);display:flex;align-items:center;justify-content:center;font-family:var(--font-head);font-weight:700;font-size:var(--t-sm);color:var(--muted);flex-shrink:0}
.order-item.numbered .order-num{border-style:solid;border-color:var(--accent);background:var(--accent-soft);color:var(--accent-soft-ink)}
.order-item.ok{border-color:var(--ok);background:var(--ok-bg)}
.order-item.err{border-color:var(--err);background:var(--err-bg)}
.open-area{width:100%;min-height:88px;border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3);font-size:var(--t-md);background:var(--surface-2);resize:vertical}
.open-area:focus{outline:none;border-color:var(--accent);background:var(--surface)}
.open-area[readonly]{color:var(--ink-2)}
/* Отправленный ответ в очереди проверки — текстом, а не полем: читают его
   целиком, и высота должна идти от ответа, а не от вёрстки. Переносы строк
   ученика сохраняем — абзацы его письма это часть работы. */
.open-read{white-space:pre-wrap;word-break:break-word;font-size:var(--t-md);line-height:1.65;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-3);margin-bottom:var(--s-2)}
.sent-tag{color:var(--ok);font-weight:700;font-family:var(--font-head);font-size:var(--t-base)}
.saved-word{border-bottom:2px solid var(--note);border-radius:2px;background:linear-gradient(transparent 60%,var(--note-bg) 60%)}

.class-grid{display:grid;grid-template-columns:250px minmax(0,1fr);gap:var(--s-5);max-width:1180px;margin:0 auto;padding:var(--s-5) var(--s-5) 120px}
/* Шире, когда появляются поля с заметками: им нужно 256px справа от листа.
   Правило стояло выше по файлу, где его перебивала строка над ним, и полосу
   заметок на экранах чуть шире 1300px срезало краем страницы. */
@media(min-width:1300px){.class-grid{max-width:1320px}}
.class-grid.solo{grid-template-columns:minmax(0,1fr)}
.class-grid.solo .tpanel{display:none}
/* Без панели хода (ученик, просмотр) лист встаёт по центру, а место справа
   остаётся заметкам на полях: лист 700 + вылет 26 + стикер 230. */
@media(min-width:1300px){
  .class-grid.solo .class-canvas{max-width:956px;margin:0 auto;width:100%}
  /* Полосу под заметки держим только тогда, когда заметки есть. Без них лист
     уезжал влево на 256px и читался съехавшим, хотя место справа пустое: на
     1440 он стоял в 235 от левого края и в 506 от правого. :has живой — заметка,
     добавленная на занятии, вернёт полосу без перерисовки. */
  .class-grid.solo .class-canvas:not(:has(.sticky)){max-width:700px}
}
@media(max-width:1299px){.class-grid.solo .class-canvas{max-width:700px;margin:0 auto;width:100%}}
/* ---------- «Где мы сейчас» у ученика ----------
   Панель хода — про ведение занятия, и ученику её не дают. Но вопрос «здесь ли
   преподаватель и на том же ли мы задании» принадлежит ему ровно так же, и
   одна строка над листом на него отвечает.

   Строка платформенная, а не урочная: тема красит лист, а не стол под ним. */
.stu-bar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:var(--s-3) var(--s-4);margin-bottom:14px;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink)}
.stu-bar[hidden]{display:none}
.stu-bar .sb-who{display:flex;align-items:center;gap:var(--s-2);min-width:0}
.stu-bar .live{width:8px;height:8px;margin:0;flex-shrink:0;animation-duration:2s}
.stu-bar .sb-sep{width:1px;height:18px;background:var(--line);flex-shrink:0}
/* Что на экране у ученика — урок или домашка к нему. В домашке пометка цветом
   маркера: переход должен бросаться в глаза, а не вычитываться. */
.stu-bar .sb-sec{flex-shrink:0;font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
  padding:2px 10px;border-radius:var(--r-pill);background:var(--surface-2);color:var(--ink-2)}
.stu-bar .sb-sec.hw{background:var(--marker-soft);color:var(--marker-ink)}
.stu-bar .sb-bar{width:120px;height:5px;margin:0;flex-shrink:0}
/* «Задание 3 из 12» — число, которое меняется на месте: табличные цифры, иначе
   строка дёргается при каждом переходе к следующему блоку. */
.stu-bar .sb-at{font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
/* Подпись о том, чего никто не спрашивал вслух: тихая и последняя в строке. */
.stu-bar .sb-same{font-family:var(--font-body);font-weight:400;font-size:var(--t-sm);
  color:var(--muted);margin-left:auto}
/* Ширину держим по листу: лист на широком экране 700 и стоит слева, а строка
   во всю колонку висела бы над ним отдельной полосой. */
@media(min-width:1300px){.stu-bar{max-width:700px}}
/* ---------- Панель занятия ----------
   Не один список, а стопка лотков: присутствие, ход урока, ошибки и домашка
   отвечают на разные вопросы, и в общей плашке читались продолжением друг
   друга. Лоток — тот же .panel, что везде на платформе.

   Поднята ровно одна карточка, и это присутствие: «здесь ли ученик» — первый
   вопрос занятия. Остальные лежат. */
.tpanel{position:sticky;top:74px;align-self:start;max-height:calc(100vh - 96px);overflow:auto;
  display:grid;gap:var(--s-3);align-content:start}
/* Полосу прокрутки в боковых колонках выключаем.

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

   Три записи на три движка: scrollbar-width понимает Firefox, -ms-overflow-style
   остался от старого Edge, остальные слушают ::-webkit-scrollbar. */
.tpanel,.rail-list{scrollbar-width:none;-ms-overflow-style:none}
.tpanel::-webkit-scrollbar,.rail-list::-webkit-scrollbar{width:0;height:0}
/* Гасим сами: .panel — flex, и он перебил бы display:none у [hidden], которым
   прячутся лотки ошибок и домашки. */
.tpanel .panel[hidden]{display:none}
.tpanel .tp-live{padding:var(--s-4);gap:0;box-shadow:var(--sh-2)}
.tpanel .tp-flow{padding:6px}
/* Домашняя работа — свой лоток, последним в панели: сдана ли, проверена ли.
   Геометрия та же, что у ошибок: это лотки одного ряда. Отдельного лотка
   «Домашка» со списком заданий больше нет — её показывает «Ход урока» на
   вкладке «Домашка». */
.tpanel .mis,.tpanel .tp-sent{padding:14px;gap:0}
/* Кто в классе — самая крупная строка панели. */
.tp-live .tl-who{display:flex;align-items:center;gap:9px;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink)}
.tp-live .tl-who .live{width:9px;height:9px;margin:0;flex-shrink:0;animation-duration:2s}
.tp-live .tl-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Где ученик — второй по величине текст экрана: его считывают, не читая. */
.tp-live .tl-at{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.02em;margin-top:var(--s-3)}
.tp-live .tl-typing{display:flex;align-items:center;gap:7px;margin-top:var(--s-1);
  font-size:var(--t-sm);color:var(--marker-ink)}
.tp-live .tl-typing .live{width:6px;height:6px;margin:0;flex-shrink:0;animation-duration:2s}
.tp-live .bar{margin:var(--s-3) 0 0}
.tp-head{padding:5px 6px 2px}
.tp-list{display:flex;flex-direction:column;gap:2px}
.tp-row{display:grid;grid-template-columns:22px minmax(0,1fr) auto;align-items:center;gap:9px;
  padding:var(--s-2) 10px;border:1px solid transparent;border-radius:var(--r-1);
  font-size:var(--t-base);color:var(--muted);cursor:pointer;
  transition:background var(--dur-fast) var(--ease)}
.tp-row:hover{background:var(--paper)}
.tp-num{font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:500;flex-shrink:0}
/* Название блока — то же, что в шапке его карточки: панель работает
   оглавлением, и строка должна называть то, к чему прокручивает. Длинное
   режем: в 250px колонке важнее узнать блок, чем дочитать инструкцию. */
.tp-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-status{margin-left:auto;font-weight:700;font-size:var(--t-sm);font-family:var(--font-head);flex-shrink:0}
.tp-status.ok{color:var(--ok)}
.tp-status.err{color:var(--err)}
/* Открытый ответ отправлен и ждёт преподавателя. Не галочка: галочка здесь
   значит «сошлось», а этот ответ ещё никто не читал. */
.tp-status.sent{color:var(--accent);font-weight:500;font-size:var(--t-label);
  font-variant-numeric:tabular-nums;letter-spacing:.04em}
/* Устный блок платформа не проверяет — вместо галочки словом, чтобы пустой
   статус не читался как «ещё не сделано». В классе это ещё и выключатель:
   разобрали вслух — нажали, и шаг занятия засчитан. */
.tp-status.oral{color:var(--muted);font-weight:500;font-size:var(--t-label);
  font-variant-numeric:tabular-nums;letter-spacing:.04em}
button.tp-status.pick{border:1px dashed var(--line-2);background:none;border-radius:var(--r-pill);
  padding:1px 7px;cursor:pointer;line-height:1.5}
button.tp-status.pick:hover{border-color:var(--ink-2);color:var(--ink)}
button.tp-status.pick.on{border-style:solid;border-color:var(--ok);color:var(--ok)}
/* Ещё не дошли: там пока ничего не случилось, и строка отступает дальше
   сделанных. Ставится только когда известно, где ученик, — иначе «впереди»
   не от чего отсчитывать. */
.tp-row.ahead{opacity:.55}
/* Домашка в панели — своей группой под лентой урока, отбитая чертой. Ход
   занятия ею не меряется: галочек и «где ученик» у этих строк нет, они лежат
   рядом как справка «что задано», и заголовок группы это говорит. */
.tp-part{margin:var(--s-3) var(--s-2) var(--s-1);padding-top:var(--s-3);
  border-top:1px solid var(--line);cursor:pointer;
  font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted)}
.tp-part:hover{color:var(--ink)}

/* ---------- Переключатель «Урок · Домашка» на занятии ----------
   У преподавателя — над «Ходом урока» теми же «пилюлями», что в рельсе
   конструктора (.rail-tabs ниже): без своей карточки и по размеру надписей.
   Сегмент во всю колонку растягивал кнопки, и «Домашка 0/10» ломалась в две
   строки (владелец, 18 сентября). Не влезли — вторая пилюля уходит строкой
   ниже целиком, а не ломается сама. На телефоне панели нет, и переключатель
   стоит над листом сегментом во всю ширину — как у конструктора на телефоне. */
.tpanel .rail-tabs{margin:0;flex-wrap:wrap}
.tpanel .rail-tabs .rt{white-space:nowrap}
.cls-tabs{display:flex;margin:0}
.cls-tabs button{flex:1 1 0;justify-content:center;white-space:nowrap}
.cls-tabs button i{font-style:normal;font-variant-numeric:tabular-nums;color:var(--muted);margin-left:4px}
.cls-tabs button.on i{color:inherit;opacity:.72}
.cls-tabs-top{display:none}
.cls-tabs-top[hidden]{display:none}
@media(max-width:640px){
  .cls-tabs-top:not([hidden]){display:flex;margin:0 0 var(--s-3)}
  .cls-tabs-top .cls-tabs{width:100%}
}

/* ---------- Домашка на листе занятия ----------
   Над заданиями — в каком она состоянии, под каждым — разбор, внизу — итог
   работы с «Проверено». Поля разбора те же, что в очереди проверки (.ws-fix). */
.hw-state{display:flex;align-items:baseline;gap:var(--s-3);flex-wrap:wrap;margin:0 0 var(--s-4)}
.hw-st-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg)}
.hw-st-d{font-size:var(--t-base);color:var(--muted)}
.card .ws-fix{padding-top:var(--s-3);border-top:1px solid var(--line)}
.hw-fix-read:empty{display:none}
.hw-total{margin-top:var(--s-5);padding:var(--s-4);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-2)}
.hw-total:empty{display:none}
.hw-tot-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);flex-wrap:wrap;
  font-family:var(--font-head);font-weight:700;font-size:var(--t-md);margin-bottom:var(--s-2)}
.hw-tot-h span{font-family:var(--font-body);font-weight:400;font-size:var(--t-sm);color:var(--muted)}
.hw-score{display:block;width:100%;resize:none}
.hw-tot-read{display:flex;align-items:baseline;gap:var(--s-3);font-size:var(--t-md);line-height:1.55}
/* Ученик прямо сейчас вводит ответ. Маркерная точка — одна из трёх живых вещей
   на экране, и единственная, что двигается в панели. */
.tp-row .type-dot{margin-left:auto;width:6px;height:6px;border-radius:var(--r-pill);
  background:var(--marker);flex-shrink:0;animation:pulse 2s ease-in-out infinite}
/* ---------- Где второй сейчас ----------
   Язычок на верхней границе блока, снаружи рамки: внутри метка спорила бы с
   самим заданием, а строкой в шапке ничего не говорила о том, к какому блоку
   относится. Точка пульсирует только при живой связи — замершая врала бы, что
   всё в порядке.

   Палитра маркерная, а не зелёная: жёлтый на платформе и значит «идёт прямо
   сейчас, от второго», а зелёным здесь читалось «верно». */
.cls-host{position:relative}
.peer-mark{position:absolute;top:-11px;left:16px;z-index:2;
  display:inline-flex;align-items:center;gap:7px;padding:var(--s-1) 10px;border-radius:var(--r-1);
  border:none;background:var(--marker-soft);color:var(--marker-ink);
  box-shadow:0 2px 6px -2px rgba(138,106,0,.35);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-label);white-space:nowrap;
  max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis}
.peer-mark .live{width:6px;height:6px;margin:0;flex-shrink:0;animation-duration:2s}
/* Кольцо на самом блоке: язычок говорит, кто здесь, кольцо — какой блок он
   читает. Язычок маленький, и на длинном листе взгляд находил его не сразу. */
/* Кольцо там, где сейчас второй. Селектор был написан через .card, а у
   материалов карточки нет вовсе (акцент, заголовок части, справочная таблица) —
   и «Мария здесь» у них не показывалось ничем. */
.cls-host.at-peer{box-shadow:var(--sh-1),0 0 0 2px var(--marker)}
/* У акцента, заголовка части и справочной таблицы карточки нет — они лежат в
   голом .cls-host, у которого ни радиуса, ни отступов. Тень повторяла его форму
   и обводила скруглённое содержимое прямоугольником с острыми углами, впритык.
   Здесь кольцо рисуем контуром с отступом: он повторяет заданный радиус, а
   outline-offset отодвигает его от содержимого, ничего не двигая на листе.
   Карточкам оставляем прежнюю тень — там кольцо обводит саму карточку и по её
   собственному радиусу, то есть уже правильно. */
/* Радиус кольца — радиус самой плашки плюс отступ: кольцо идёт по её форме, а
   не своей. С радиусом карточки (16) вокруг плашки с радиусом 10 углы
   расходились, и кольцо выглядело чужим. */
.cls-host.at-peer:not(.card){box-shadow:none;border-radius:calc(var(--r-1) + 4px);
  outline:2px solid var(--marker);outline-offset:4px}
/* Язычок на наклейке: она узкая и стоит на поле, поэтому справа — слева у неё
   бумажный скотч (.sticky::before), и метка налезала бы прямо на него. В том же
   углу живёт пометка части речи; пока второй здесь, её убираем: «N» — украшение,
   а «кто здесь» — то, ради чего в этот угол смотрят. */
.peer-mark.on-note{left:auto;right:8px;top:-13px}
.sticky:has(.peer-mark) .stag{display:none}

/* ---------- Граница «дальше домашка» на листе занятия ----------
   Домашка лежит на том же листе, ниже урока, и должна быть отделена сильнее,
   чем части урока друг от друга: там граница смысловая («перешли к грамматике»),
   здесь — про принадлежность. Отсюда двойной отступ и подпись о том, что с этим
   разделом делают: смотрят, а не решают. Показывается только преподавателю. */
.hw-part{display:flex;align-items:baseline;gap:var(--s-3);flex-wrap:wrap;
  margin:calc(var(--s-6) + var(--s-3)) 0 var(--s-5);padding-top:var(--s-4);
  border-top:2px solid var(--line-2)}
.hw-part-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg)}
.hw-part-d{font-size:var(--t-base);color:var(--muted)}

/* Строка блока, на котором ученик сейчас, — единственная заметная в панели.
   Кольцо маркером, а не линией: лист и бумага различаются мягко, и в тёмном
   хроме подсвеченная строка переставала быть заметной — обе почти чёрные.
   Жёлтый здесь по правилу «идёт прямо сейчас», а не как акцент. */
.tp-row.here,.tp-row.here:hover{background:var(--paper);border-color:transparent;
  box-shadow:0 0 0 1.5px var(--marker);
  color:var(--ink);font-family:var(--font-head);font-weight:600;font-size:var(--t-base);padding:var(--s-2) 10px}
.tp-row.here .tp-num{color:var(--marker-ink)}

.tp-open{font-size:var(--t-sm);color:var(--muted);background:var(--surface-2);border-radius:var(--radius-sm);padding:var(--s-2);margin:0 0 2px;line-height:1.4}
.bar{height:6px;border-radius:var(--r-pill);background:var(--surface-2);overflow:hidden;margin:var(--s-3) 0 var(--s-1)}
.bar>span{display:block;height:100%;background:var(--marker);border-radius:var(--r-pill);transition:width var(--dur-slow) var(--ease)}
/* Полоса на исходе заполнена целиком и уходит в чернила: красным на платформе
   говорят «ошибка», а «места кончились» — не ошибка, а состояние. Исключение —
   расход запросов ИИ в меню и в карточке тарифа (.bar.spent ниже): его владелец
   15 сентября попросил красить красным. */
.bar.full>span{background:var(--ink)}
html[data-chrome="dark"] .bar{background:var(--line)}
.bar-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);font-size:var(--t-base);color:var(--ink-2)}
.bar-head b{font-size:var(--t-sm);font-weight:600;font-variant-numeric:tabular-nums;color:var(--ink)}
/* Светофор остатка: полная полоса зелёным говорила «всё хорошо» как раз там,
   где занятия кончились. .warn — вот-вот, .low — кончилось или срок прошёл. */
/* Светофор абонемента: запас — маркер, кончился — чернила. Красным на
   платформе говорят «ошибка», а кончившийся абонемент — не ошибка ученика и
   не ошибка преподавателя, а состояние, о котором надо знать. Правило то же,
   что у полосы расхода действий ИИ (.bar.full). */
.bar.warn>span{background:var(--marker)}
/* Кончившийся абонемент — красный целиком, и жёлоб, и заливка: при нулевом
   остатке заливки нет вовсе, и покрасить одну её значило бы не покрасить
   ничего. Решение владельца от 7 сентября: макеты рисуют кончившийся пакет
   красным, и это тот случай, когда красный говорит не «ошибка в ответе», а
   «занятий больше нет» — то есть всё-таки о данных, а не о статусе. */
.bar.low{background:var(--err)}
.bar.low>span{background:var(--err)}
/* Расход запросов ИИ: полоса растёт от работы и краснеет заливкой, когда
   потрачено 80 % (решение владельца 15 сентября). Жёлоб остаётся своим: на 80 %
   красная целиком полоса выглядела бы как 100 %, и не было бы видно, сколько
   ещё можно. */
.bar.spent>span{background:var(--err)}
/* .live — только сама пульсирующая точка. Контейнерам этот класс не давать:
   он задаёт им размер 6×6, и содержимое вываливается наружу. Состояние
   «занятие идёт» у карточки, строки и плашки календаря называется is-live.
   Строки его нарушали: лента дня на главной и строки расписания получали
   .live, и идущее занятие сжималось в жёлтый пульсирующий овал, из которого
   торчали время и «идёт сейчас» (владелец, 15 сентября). */
.live{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--marker);margin-right:var(--s-1);animation:pulse 1.4s ease-in-out infinite}
.live.off{background:var(--line-strong);animation:none}
/* Присутствие человека — зелёная точка (решение владельца 7 сентября).
   Одной и той же точкой платформа говорит две разные вещи: «занятие идёт» —
   это про время, и там маркер; «человек на связи» — это про человека, и здесь
   работает светофор, которому не нужно объяснение. Зелёный по правилу цвета
   держится за данные, и присутствие как раз данные: ученик либо в комнате,
   либо нет. Оценкой это не становится — «в классе» никого не хвалит.

   Погасшая точка остаётся серой: :not(.off) стоит именно за этим. */
.tp-live .live:not(.off),.stu-bar .live:not(.off),.peer-mark .live:not(.off){background:var(--ok)}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.78)}}
.muted{color:var(--muted)}
.small{font-size:var(--t-sm)}

.cab{display:grid;grid-template-columns:200px minmax(0,1fr);gap:var(--s-5);max-width:1180px;margin:0 auto;padding:var(--s-5) var(--s-5) 120px}
.cab-nav{position:sticky;top:74px;align-self:start;display:flex;flex-direction:column;gap:2px}
.cab-nav button{border:none;background:transparent;text-align:left;padding:var(--s-2) var(--s-3);border-radius:var(--radius-sm);font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--muted);cursor:pointer;display:flex;align-items:center;gap:var(--s-2)}
.cab-nav button:hover{background:var(--surface)}
.cab-nav button.on{background:var(--surface);color:var(--ink);box-shadow:var(--shadow)}
.cab-nav .badge{margin-left:auto;background:var(--accent);color:var(--accent-ink);border-radius:var(--r-pill);font-size:var(--t-label);padding:1px var(--s-2);font-weight:700}
.hero{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:var(--pad);margin-bottom:var(--s-3);display:flex;gap:var(--pad);align-items:center;flex-wrap:wrap}
.hero .when{font-family:var(--font-head);font-weight:700;font-size:30px;letter-spacing:-.02em;line-height:1.1}
/* ---------- Показатели: одна карточка крупнее остальных ----------
   Три равные плитки-счётчика («12 · 8 · 40 из 120») не говорят, много это или
   мало. Поэтому главный показатель крупнее и с историей — рядом с соседними
   месяцами или неделями видно, куда всё движется, — а остальные помельче
   рядом. Отсюда ширина 1.6 у первой карточки: в ней живёт график.
   Компонент общий: «Оплаты» у преподавателя и «Прогресс» в кабинете ученика. */
.stats{display:grid;grid-template-columns:1.6fr 1fr 1fr;gap:var(--s-4);margin-bottom:var(--s-4);align-items:stretch}
/* Три равных показателя: график уехал из первой карточки в свою, и держать под
   него полторы ширины больше незачем. Первая всё равно поднята — она главная. */
.stats.stats-3{grid-template-columns:1fr 1fr 1fr;gap:var(--s-3)}
/* Второй показатель — не одна карточка, а две стопкой. Когда у первой есть
   история, а у остальных только число, в ряду их растягивает до её высоты и
   рядом встают ящики с полутора сотнями пикселей пустоты. Стопкой они делят ту
   же высоту пополам и стоят вровень с соседкой. */
.stats.duo{grid-template-columns:1.6fr 1fr}
/* Четыре числа месяца — четырьмя равными плитками: они отвечают на четыре
   разных вопроса, и главного среди них нет. */
.stats.stats-4{grid-template-columns:repeat(4,1fr);gap:var(--s-3)}
.stats-4 .stat{border:none;border-radius:var(--r-2);padding:18px;box-shadow:var(--sh-1)}
@media(max-width:980px){.stats.stats-4{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.stats.stats-4{grid-template-columns:1fr}}
/* Прочерк вместо числа: «считать не из чего» — не то же, что ноль, и весом
   крупной цифры оно быть не должно. */
.stat-none{color:var(--muted)}
/* Шапка вкладки: месяц слева, стрелки справа. Стрелки — значками, а не
   кнопками со словами: их две, они рядом, и слово над ними повторяло бы
   заголовок. */
.prog-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  margin:0 0 var(--s-3)}
.prog-nav{display:flex;gap:var(--s-1)}
.prog-nav .icon-btn{font-size:var(--t-lg);line-height:1}
.prog-nav [disabled]{opacity:.35;pointer-events:none}
.stat-col{display:flex;flex-direction:column;gap:var(--s-4);min-width:0}
.stat-col>.stat{flex:1}
@media(max-width:820px){.stats,.stats.duo,.stats.stats-3{grid-template-columns:1fr}}
.stat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--s-4);display:flex;flex-direction:column;gap:var(--s-2)}
.stats-3 .stat{border:none;border-radius:var(--r-2);padding:22px;box-shadow:var(--sh-1)}
.stats-3 .stat.raised{box-shadow:var(--sh-2)}
.stat-big{font-family:var(--font-head);font-weight:700;font-size:32px;letter-spacing:-.01em;line-height:1.1}
.stat-unit{font-family:var(--font-body);font-weight:400;font-size:var(--t-md);color:var(--muted);margin-left:var(--s-1)}
/* Сноска прижата к низу: у карточек разной высоты подписи иначе висят вразнобой */
.stat-note{font-size:var(--t-sm);color:var(--muted);margin-top:auto}
/* Имена моделей — служебная строка под расходом: набрана моноширинным, чтобы
   читаться именем ключа, а не фразой, и отбита чертой сверху, потому что
   отвечает уже на другой вопрос — не «сколько», а «чем». */

/* Расход по дням: тридцать столбиков в одну строку. Сегодняшний — чернилами,
   самый дорогой — маркером: всплеск и есть то, ради чего график смотрят. */
.adm-chart{display:flex;align-items:flex-end;gap:2px;height:64px;margin:var(--s-3) 0 var(--s-1)}
.adm-chart>i{flex:1;min-width:2px;background:var(--line-2);border-radius:2px 2px 0 0;display:block}
.adm-chart>i.peak{background:var(--marker)}
.adm-chart>i.now{background:var(--ink)}
.adm-chart-x{display:flex;justify-content:space-between;font-size:var(--t-label);color:var(--muted)}
/* Ничего не было — плоская линия вместо пустого места: она отвечает «данные
   пришли, событий нет», а пустое место отвечало бы «что-то сломалось». */
.adm-flat{height:64px;margin:var(--s-3) 0 var(--s-1);position:relative}
.adm-flat::after{content:'';position:absolute;left:0;right:0;bottom:0;height:2px;
  background:var(--line-2);border-radius:2px}
.adm-models{margin-top:var(--s-3);padding-top:var(--s-2);border-top:1px solid var(--line);
  font-variant-numeric:tabular-nums;font-size:var(--t-label);line-height:1.7;word-break:break-all}
/* Строка моделей переехала из плитки расхода в подвал карточки «На что уходят
   деньги»: вопрос «чем потрачено» стоит рядом с «на что». */
.adm-card .adm-models{margin-top:var(--s-4);padding-top:14px;border-top-color:var(--surface-2);color:var(--muted)}

/* ---------- Операционка ----------
   Строка сводки вместо четырёх плиток во весь этаж: по этим числам ничего не
   решают, их читают за секунду и идут к воронке. */
.stat-strip{background:var(--surface);border-radius:var(--r-2);padding:14px 20px;box-shadow:var(--sh-1);
  margin-bottom:20px;display:flex;align-items:center;gap:26px;flex-wrap:wrap}
.stat-strip>i{width:1px;height:18px;background:var(--surface-2);flex-shrink:0}
.stat-strip .spacer{flex:1}
.ss-pair{display:flex;align-items:baseline;gap:7px}
.ss-pair b{font-family:var(--font-body);font-weight:700;font-size:17px;font-variant-numeric:tabular-nums}
.ss-pair span{font-size:var(--t-sm);color:var(--muted)}
.ss-now{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}

.adm-grid{display:grid;grid-template-columns:minmax(0,1fr) 420px;gap:20px;align-items:start}
.adm-side{display:grid;gap:20px;align-content:start}
.adm-card{border-radius:var(--r-2);padding:var(--s-5) 26px;box-shadow:var(--sh-2);margin-bottom:0}
.adm-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3)}
.adm-head h3,.adm-head h4{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);margin:0}
.adm-when{font-size:var(--t-sm);color:var(--muted);white-space:nowrap}

/* Воронка полосами и абсолютными числами. Проценты в строках («48 %») не
   показывали, что между двумя ступенями теряется больше людей, чем на всех
   остальных вместе: одинаковые строки читались как одинаковые потери. */
.funnel{display:grid;gap:var(--s-3);margin-top:22px}
.funnel-step .fs-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s-2);margin-bottom:6px}
.fs-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.fs-side{display:flex;align-items:baseline;gap:var(--s-2);flex-shrink:0}
/* Падение — красным: это данные о потере, а не украшение строки. */
.fs-side i{font-style:normal;font-size:var(--t-sm);color:var(--err);font-variant-numeric:tabular-nums}
.fs-side b{font-family:var(--font-body);font-weight:600;font-size:var(--t-base);
  font-variant-numeric:tabular-nums}
.fs-bar{height:30px;border-radius:var(--r-1);background:var(--ink);min-width:4px}
/* Последняя ступень маркером: ради неё платформа и есть. */
.funnel-step.goal .fs-bar{background:var(--marker)}
.funnel-sum{background:var(--paper);border-radius:var(--r-1);padding:13px 15px;margin-top:20px;
  display:flex;align-items:center;gap:10px}
.funnel-sum b{font-family:var(--font-body);font-weight:700;font-size:20px;color:var(--marker-ink);
  font-variant-numeric:tabular-nums;flex-shrink:0}
.funnel-sum span{font-size:var(--t-base);line-height:1.5;color:var(--ink-2)}

.adm-sep{height:1px;background:var(--surface-2);margin:22px 0 18px}
.adm-tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-3);margin-top:14px}
.adm-tile{background:var(--paper);border-radius:var(--r-1);padding:14px}
.adm-tile b{display:block;font-family:var(--font-body);font-weight:700;font-size:20px;
  font-variant-numeric:tabular-nums}
.adm-tile span{display:block;font-size:var(--t-sm);line-height:1.4;color:var(--ink-2);margin-top:3px}
.adm-note{font-size:var(--t-sm);line-height:1.5;color:var(--muted);margin-top:14px}

.adm-big{display:flex;align-items:baseline;gap:10px;margin-top:var(--s-3);flex-wrap:wrap}
.adm-big b{font-family:var(--font-body);font-weight:700;font-size:32px;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.adm-big span{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}

.kind-rows{display:grid;gap:var(--s-3);margin-top:18px}
.kind-row .kr-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s-2);margin-bottom:5px}
.kr-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.kind-row .kr-head b{font-family:var(--font-body);font-weight:600;font-size:var(--t-sm);
  font-variant-numeric:tabular-nums}
.kind-row .bar{margin:0}
.kr-sub{font-size:var(--t-label);color:var(--muted);margin-top:5px;font-variant-numeric:tabular-nums}

.adm-rows{display:grid;gap:10px;margin-top:14px}
.adm-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);
  font-size:var(--t-base);color:var(--ink-2)}
.adm-row b{font-family:var(--font-body);font-weight:600;font-size:var(--t-base);color:var(--ink);
  font-variant-numeric:tabular-nums}
/* «Данные пока ничего не значат»: числа гаснут, а под ними объяснение почему.
   Прятать их нельзя — тогда непонятно, считаются ли они вообще. */
.adm-card .dim{opacity:.45}
.adm-why{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3) 13px;margin-top:14px;
  font-size:var(--t-sm);line-height:1.5;color:var(--ink-2)}

@media(max-width:1100px){
  .adm-grid{grid-template-columns:minmax(0,1fr)}
  .adm-grid>div{min-width:0}
  .adm-grid .adm-head{flex-wrap:wrap}
  .adm-grid .adm-when{white-space:normal}
}
@media(max-width:640px){
  #adminPage>.seg{max-width:100%;flex-wrap:wrap}
}

/* Полгода дохода столбиками. Маркер тут — цвет данных, а не заметок: урока на
   этом экране нет, спорить не с чем (решение Р-5 хендоффа). Текущий месяц
   маркером, прошлые — маркером по бумаге. */
.mini-chart{display:flex;align-items:flex-end;gap:6px;height:64px;margin-top:auto}
.mini-chart i{flex:1;background:var(--marker-soft);border-radius:3px 3px 0 0;min-height:3px}
.mini-chart i.now{background:var(--marker)}
/* Ряд не про модель и не про преподавателя: жёлтый здесь значил бы одно из
   четырёх своих значений, а это просто занятия по неделям. Нейтральные
   столбики, чернилами — текущая неделя (та же пара, что у .adm-chart). */
.mini-chart.plain i{background:var(--line-2)}
.mini-chart.plain i.now{background:var(--ink)}
.mini-chart-x{display:flex;gap:6px;font-variant-numeric:tabular-nums;font-weight:500;font-size:var(--t-label);
  color:var(--muted);text-transform:uppercase}
.mini-chart-x span{flex:1;text-align:center}
.mini-chart-x span.now{color:var(--marker-ink);font-weight:600}
/* Подпись текущей недели — тем же чернильным, что и её столбик: жёлтая надпись
   под серым рядом обещала бы, что там что-то от модели. */
.mini-chart.plain+.mini-chart-x span.now{color:var(--ink)}
.sec-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);margin:var(--s-5) 0 var(--s-3);display:flex;align-items:center;gap:var(--s-2)}
.sec-title .more{margin-left:auto;font-size:var(--t-sm);font-weight:600;color:var(--accent);cursor:pointer;background:none;border:none}
/* Все таблетки одного роста и на r-pill. Цвет говорит о происхождении:
   серое — служебное, жёлтое — ИИ, идущее занятие или пришедшее от
   преподавателя, зелёное и красное — данные о верном и ошибке. */
.tag{display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 10px;
  border-radius:var(--r-pill);font-family:var(--font-body);font-weight:400;font-size:var(--t-sm);
  white-space:nowrap;background:var(--surface-2);color:var(--ink-2)}
/* Жёлтое: собрано ИИ, идёт сейчас, пришло от преподавателя — три из четырёх
   работ маркера, и все три читаются как «это не ваш ввод». */
.tag.ai,.tag.live,.tag.from{background:var(--marker-soft);color:var(--marker-ink)}
.tag.ai{font-size:var(--t-label);font-weight:600;letter-spacing:.06em;font-variant-numeric:tabular-nums}
.tag.ai::before,.tag.live::before{content:'';width:5px;height:5px;border-radius:var(--r-pill);
  background:var(--marker);flex-shrink:0}
.tag.live::before{animation:pulse 1.4s ease-in-out infinite}
.tag.pro{background:var(--ink);color:var(--paper);font-size:var(--t-label);font-weight:600;
  letter-spacing:.08em;font-variant-numeric:tabular-nums}
/* Метка на бумаге, а не на листе: «Открытый ответ» стоит внутри строки. */
.tag.raised{background:var(--surface);color:var(--ink-2);box-shadow:var(--sh-1)}
.tag.mini{height:auto;padding:2px 7px;font-size:var(--t-label);font-weight:600;letter-spacing:.1em;
  background:var(--marker-soft);color:var(--marker-ink)}
.tag.new{background:var(--accent-soft);color:var(--accent-soft-ink)}
.tag.due{background:var(--err-bg);color:var(--err)}
.tag.sent{background:var(--surface-2);color:var(--muted)}
.tag.done{background:var(--ok-bg);color:var(--ok)}
/* Имена по смыслу рядом с историческими: «верно» и «ошибка» — это про данные,
   и новые места называют их так, а не «done» и «due». */
.tag.ok{background:var(--ok-bg);color:var(--ok)}
.tag.err{background:var(--err-bg);color:var(--err)}
.lib{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:var(--s-3)}
.lib-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;cursor:pointer;transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.lib-card:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
.lib-card img{width:100%;height:106px;object-fit:cover;display:block;background:var(--surface-2)}
.lib-card .b{padding:var(--s-3) var(--s-3)}
.lib-card .t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);line-height:1.35}
/* Поиск по своим словам и отбор по отметке. Двести слов сплошной лентой не
   найти, а строка выше ищет во внешнем словаре — по своим искать было нечем. */
.vocab-tools{display:flex;gap:var(--s-3);align-items:center;flex-wrap:wrap;margin-bottom:var(--s-3)}
.vocab-tools .search-inp{flex:1;min-width:180px;max-width:320px}
.card-acts{display:flex;flex-wrap:wrap;gap:9px;margin:var(--s-3) 0 var(--s-2)}
/* Переносится: три поля в ряд не помещались на телефон и уводили страницу в
   горизонтальную прокрутку — вместе с ней уезжала и нижняя навигация. */
.vocab-add{display:flex;gap:var(--s-2);margin-bottom:var(--s-2);flex-wrap:wrap}
.vocab-add input{flex:1 1 150px;min-width:0;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-md)}
.vocab-add input:focus{outline:none;border-color:var(--accent);background:var(--surface)}
/* Свои слова — сеткой карточек, а не лентой строк. В строке слово, перевод и
   происхождение стояли в одну вертикаль и читались как один хвост; в карточке
   у каждого своя ступень. Лист держится тенью, рамки у него нет — правило
   «рамка или тень, но не оба сразу». */
/* Колонки — minmax(0,1fr): у 1fr нижняя граница — min-content карточки, и
   длинный источник слова в метастроке (nowrap с многоточием) не обрезался, а
   раздвигал колонку — на телефоне вместе с окном, до 598 на названии урока. */
.voc-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
.voc-word{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);padding:var(--s-4)}
.voc-word .w{display:flex;align-items:center;gap:var(--s-2);font-family:var(--font-head);
  font-weight:700;font-size:17px;letter-spacing:-.02em;overflow-wrap:anywhere}
.voc-word .tr{font-size:var(--t-md);color:var(--ink-2);margin-top:5px;overflow-wrap:anywhere}
.voc-word .meta{font-size:var(--t-label);font-weight:600;color:var(--muted);
  font-variant-numeric:tabular-nums;margin-top:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Выученное — на бумаге и рамкой вместо тени: с ним работать больше не надо,
   и лист под него не поднимается. Зелёная точка — единственное место, где
   зелёный на этом экране законен: он значит «выучено», а не «всё хорошо». */
.voc-word.known{background:var(--paper);box-shadow:inset 0 0 0 1px var(--line)}
.voc-word.known .w,.voc-word.known .tr{color:var(--muted)}
.voc-word .dot{flex:0 0 auto;width:7px;height:7px;border-radius:var(--r-pill);background:var(--ok)}
.voc-word .acts{display:flex;align-items:center;gap:var(--s-2);margin-top:10px}
@media(max-width:900px){.voc-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.voc-grid{grid-template-columns:minmax(0,1fr)}}
/* «Мои уроки» и «Прогресс» строками внутри кабинета — только на телефоне:
   нижняя полоса держит четыре пункта, бокового меню там нет, и до этих двух
   вкладок с телефона было не добраться вовсе. На большом экране они в меню. */
.cab-more{display:none}
@media(max-width:640px){.cab-more{display:grid;margin-top:var(--s-4)}}
/* Жалоба в конце обзора — там же и только там, где меню слева нет. Голос тот
   же, что у неё в меню: заметно тому, кто ищет, незаметно тому, кто работает.
   Строка, а не плашка: плашка встала бы четвёртым пунктом списка над ней. */
.cab-report{display:none}
@media(max-width:640px){
  .cab-report{display:block;width:100%;border:none;background:none;cursor:pointer;
    padding:var(--s-5) 2px var(--s-2);text-align:left;font-family:var(--font-head);
    font-weight:500;font-size:var(--t-sm);color:var(--muted)}
  .cab-report:hover{color:var(--ink)}
}
.flashcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:38px var(--pad);text-align:center;cursor:pointer;user-select:none;min-height:168px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-2)}
.flashcard .w{font-family:var(--font-head);font-weight:700;font-size:34px;letter-spacing:-.03em}
@media(max-width:640px){.flashcard .w{font-size:38px}}
/* Строка фактов в кабинете — вместо плиток-счётчиков: цифры полезны, но не
   настолько, чтобы занимать экран выше того, что надо сделать. */
.facts-line{font-size:var(--t-sm);color:var(--muted);margin:0 0 var(--s-1);padding:0 2px}
/* Просроченное — отдельной строкой над списком: срок прошёл, это надо увидеть первым */
.late-line{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3);padding:var(--s-3) var(--s-3);
  border:1px solid var(--err-line);background:var(--err-bg);border-radius:var(--radius-sm);
  cursor:pointer;font-size:var(--t-base)}
.late-line .muted{margin-left:auto}


/* Тултип перевода слова — тёмный (по хендоффу «Выделение слова»): фиксированный
   #171A21 вне зависимости от темы урока, транскрипция mono, «↵ В словарь»
   маркерным цветом. */
.lookup{position:absolute;z-index:90;background:#171A21;color:#EDECE8;border-radius:var(--r-2);box-shadow:var(--sh-3);width:270px;display:none;overflow:hidden}
.lookup.open{display:block}
.lookup .lhead{padding:var(--s-3) var(--s-4) var(--s-2);display:flex;align-items:baseline;gap:var(--s-2);flex-wrap:wrap}
.lookup .lw{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);color:#FBFAF7}
.lookup .ipa{color:#8C8C86;font-size:var(--t-sm);letter-spacing:.03em}
/* Кнопка озвучки в тёмном окошке перевода: своего фона не просит, окошко и так
   тёмное. Прижата к правому краю — слово с транскрипцией читают слева направо,
   и кнопка стоит там, где строка кончается. */
.lookup .say-btn{margin-left:auto;border:none;background:none;color:#8C8C86;cursor:pointer;
  padding:2px;display:inline-flex;align-items:center;flex-shrink:0}
.lookup .say-btn:hover{color:#FBFAF7}
.lookup .lbody{padding:2px var(--s-4) var(--s-3)}
.lookup .tr-chips{display:flex;flex-wrap:wrap;gap:var(--s-1)}
.lookup .tr-chip{border:1px solid #33363D;background:#22252B;color:#EDECE8;border-radius:var(--r-pill);padding:6px var(--s-3);font-size:var(--t-sm);font-weight:600;cursor:pointer}
.lookup .tr-chip:hover{border-color:#4A4E56}
.lookup .tr-chip.on{border-color:var(--marker);background:rgba(232,163,23,.14);color:var(--marker)}
.lookup .ldetail{margin-top:var(--s-2);background:#22252B;border-radius:var(--r-1);padding:var(--s-2) var(--s-3);font-size:var(--t-sm);line-height:1.5;color:#C4C4C0;display:none}
.lookup .ldetail.on{display:block}
.lookup .ldetail .dpos{font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.06em;text-transform:uppercase;color:#8C8C86;margin-bottom:3px}
.lookup .ldetail .dex{margin-top:var(--s-1);color:#9A9A94;font-style:italic}
.lookup .lfoot{padding:0 var(--s-4) var(--s-3)}
.lookup .add-word{background:none;border:none;color:var(--marker);font-family:var(--font-head);font-weight:700;font-size:var(--t-base);cursor:pointer;padding:var(--s-1) 0;display:inline-flex;align-items:center;gap:var(--s-1)}
.lookup .add-word:hover{color:#F4B838}
.lookup .add-word.done{color:#8C8C86;cursor:default}
.lookup .add-word .kbd{font-variant-numeric:tabular-nums;font-size:var(--t-label);opacity:.8}
.lookup .lmsg{font-size:var(--t-sm);color:#9A9A94;padding:2px 0 var(--s-1)}
.lookup .lspin{width:15px;height:15px;border:2px solid #33363D;border-top-color:var(--marker);border-radius:50%;animation:spin .8s linear infinite;margin:var(--s-3) 0}
.lookup .arrow{position:absolute;top:-5px;left:20px;width:11px;height:11px;background:#171A21;transform:rotate(45deg)}

/* Окно всплывает, а не возникает: затемнение набирается, окно приезжает снизу
   по пружинной кривой. display:none этого не позволял — переход с него не
   считается вовсе, — поэтому прячем видимостью, а место окно всё равно не
   занимает: оно вне потока. */
/* Затемнение 55 %, как во всех кадрах хендоффа. На 28 % экран под окном почти
   не гас: окно читалось ещё одной карточкой страницы, а не единственным, с чем
   сейчас разговаривают. */
.scrim{position:fixed;inset:0;background:rgba(23,26,33,.55);display:flex;align-items:center;
  justify-content:center;z-index:100;padding:var(--s-5);
  opacity:0;visibility:hidden;transition:opacity var(--dur-slow) var(--ease-s),visibility 0s var(--dur-slow)}
.scrim.open{opacity:1;visibility:visible;transition:opacity var(--dur-slow) var(--ease-s)}
.scrim>.modal{transform:translateY(12px) scale(.98);transition:transform var(--dur-slow) var(--ease-s)}
.scrim.open>.modal{transform:none}
.modal{background:var(--surface);border-radius:var(--r-3);width:560px;max-width:calc(100vw - 2*var(--s-4));max-height:88vh;overflow:auto;padding:var(--s-5);box-shadow:var(--sh-3)}
.modal h2{font-size:18px;margin-bottom:3px;font-family:var(--font-head);font-weight:700;letter-spacing:-.015em}
.modal .sub{color:var(--ink-2);font-size:var(--t-md);line-height:1.6;margin:var(--s-2) 0 var(--s-4)}
.modal textarea{width:100%;min-height:140px;border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3);font-size:var(--t-md);background:var(--surface-2);resize:vertical}
.modal textarea:focus{outline:none;border-color:var(--accent);background:var(--surface)}
.drop{border:1.5px dashed var(--line-strong);border-radius:var(--radius-sm);padding:var(--s-3);text-align:center;color:var(--muted);font-size:var(--t-base);margin:var(--s-3) 0;cursor:pointer}
.drop:hover{border-color:var(--accent);color:var(--accent)}
.actions{display:flex;gap:var(--s-2);margin-top:18px;justify-content:flex-end;align-items:center}
.spin{width:16px;height:16px;border:2.5px solid var(--line);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite;display:none}
@keyframes spin{to{transform:rotate(360deg)}}
.status{font-size:var(--t-sm);color:var(--muted);margin-right:auto;line-height:1.4}
.status.bad{color:var(--err)}
.file-tag{display:inline-flex;align-items:center;gap:var(--s-2);background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-1);padding:6px var(--s-3);font-size:var(--t-sm);margin-top:var(--s-1);margin-right:var(--s-1)}
/* номер страницы в списке файлов — порядок разбора виден до нажатия «Перенести» */
.file-tag .fnum{font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);background:var(--surface);
  border:1px solid var(--line);border-radius:5px;padding:1px var(--s-1);font-weight:500}
.note-box{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3) 13px;font-size:var(--t-base);color:var(--ink-2);margin-bottom:var(--s-3);line-height:1.5}
.seg-target{display:flex;gap:var(--s-2);margin:var(--s-3) 0}
.seg-target label{flex:1;border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3) var(--s-3);cursor:pointer;font-size:var(--t-base)}
.seg-target label.on{border-color:var(--accent);background:var(--accent-soft)}
.seg-target input{margin-right:var(--s-2)}

/* Уровень и объём в окне сборки урока. Кнопками, а не выпадающим списком:
   вариантов мало, и все они должны быть видны сразу — выбор уровня это
   решение, а не настройка, которую ищут в списке. */
.gen-opts{display:flex;gap:18px;flex-wrap:wrap;margin:var(--s-3) 0 var(--s-1)}
.gen-opts>div{display:flex;flex-direction:column;gap:6px}
.seg-row{display:flex;gap:6px;flex-wrap:wrap}
.seg-row .seg{border:1px solid var(--line);background:var(--surface);border-radius:var(--radius-sm);
  padding:7px var(--s-3);font-size:var(--t-base);font-weight:600;color:var(--ink-2);cursor:pointer}
.seg-row .seg:hover{border-color:var(--line-2);color:var(--ink)}
.seg-row .seg.on{border-color:var(--accent);background:var(--accent-soft);color:var(--ink)}

.pgroup{font-size:var(--t-label);text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:700;margin:var(--s-3) 0 var(--s-2)}
.pitem{display:flex;align-items:center;gap:var(--s-3);width:100%;border:1px solid transparent;background:transparent;border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);cursor:pointer;text-align:left}
.pitem:hover{background:var(--surface-2);border-color:var(--line)}
/* Нынешний тип блока при смене типа: не выбор, а точка отсчёта — от него и
   пляшут, выбирая другой. */
.pitem.on{border-color:var(--line-2);background:var(--surface-2)}
.pitem.on .n{color:var(--ink)}
.pitem .ic{width:34px;height:34px;border-radius:var(--r-1);background:var(--surface-2);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.pitem .ic svg{width:20px;height:20px}
.pitem .n{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.pitem .d{font-size:var(--t-sm);color:var(--muted)}

.style-panel h3{font-size:var(--t-lg);margin-bottom:2px}
.dgroup{margin-top:var(--s-5)}
.dgroup>label{display:block;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.12em;color:var(--muted);font-weight:600;font-variant-numeric:tabular-nums;margin-bottom:var(--s-2)}
.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-2);margin-top:var(--s-3)}
/* Карточка темы — мини-лист урока, а не квадрат с «Aa»: выбирают не шрифт, а
   то, как ляжет урок. Волосок мини-листа приходит переменной --mini-line из
   PRESETS: без него белый лист «Академии» пропадал бы на белой панели. */
.theme-card{border:none;background:none;padding:0;cursor:pointer;text-align:center}
.mini{display:block;border-radius:var(--r-1);padding:9px;box-shadow:inset 0 0 0 1px var(--mini-line,transparent)}
.theme-card.on .mini{box-shadow:inset 0 0 0 1px var(--mini-line,transparent),
  0 0 0 2px var(--ink),0 0 0 4px var(--surface)}
.mini-h{display:block;height:5px;border-radius:2px;width:70%}
.mini-t{display:block;height:3px;border-radius:2px;margin-top:var(--s-2)}
.mini-t.last{margin-top:var(--s-1);width:80%}
.theme-card .sw{height:34px;border-radius:var(--r-1);display:flex;align-items:center;justify-content:center;margin-bottom:var(--s-2);font-weight:700;font-size:var(--t-md)}
.theme-card .nm{font-size:var(--t-sm);color:var(--ink-2);margin-top:var(--s-2);font-family:var(--font-head)}
.theme-card.on .nm{font-weight:600;color:var(--ink)}
.swatches{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:var(--s-3)}
.swatch{width:24px;height:24px;border-radius:var(--r-1);border:none;cursor:pointer}
.swatch.on{box-shadow:0 0 0 2px var(--surface),0 0 0 4px var(--ink)}
/* Что зафиксировано — сказано словами, а не пустой группой с одной кнопкой:
   иначе непонятно, ручку убрали или потеряли. */
.dfix{margin-top:var(--s-5);padding-top:var(--s-3);border-top:1px solid var(--surface-2);
  font-size:var(--t-sm);line-height:1.6;color:var(--muted)}
.opts{display:flex;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-3)}
.opts button{border:none;box-shadow:inset 0 0 0 1px var(--line);background:var(--paper);border-radius:var(--r-1);padding:7px var(--s-3);font-size:var(--t-base);cursor:pointer;font-family:var(--font-head);color:var(--ink-2)}
.opts button.on{background:var(--ink);color:var(--paper);font-weight:600;box-shadow:none}
/* Пустое состояние: глиф «Поле» и слова. Глиф рисуется псевдоэлементами самой
   строки — поэтому он появляется в каждом пустом состоянии платформы сам, и ни
   одно не может обзавестись своим значком. Отступ сверху и положение стикера
   связаны переменной: стикер стоит абсолютом, а линия — в потоке. */
/* Пустое состояние зовёт к действию и не извиняется. Пунктирная рамка на
   290px читалась не как «данных пока нет», а как «здесь не дорисовали»:
   пустота такого размера — сама по себе сообщение, и не то. */
/* Пустое состояние набрано по центру: это не приписка сбоку, а весь ответ
   экрана, и читают его как объявление посреди листа. Прижатое влево на широком
   экране растягивалось на всю строку в 1200 точек, и заголовок с кнопками
   расходились по разным её концам. Строчный вариант (.bare) остаётся слева —
   там это действительно приписка внутри карточки. */
.empty{position:relative;display:flex;flex-direction:column;align-items:center;
  justify-content:center;text-align:center;min-height:250px;
  padding:var(--s-5) var(--s-5);color:var(--muted);border:none;border-radius:var(--r-2)}
.empty p{max-width:46ch}
.empty.bare{align-items:flex-start;text-align:left}
.empty .big{font-size:var(--t-lg);font-family:var(--font-head);font-weight:600;color:var(--ink);margin-bottom:var(--s-1)}
/* Линия поля — в потоке, она же держит место под весь глиф */
/* Глиф «Поле» — четыре столбика вместо серой заглушки. Второй маркерный:
   единственная серия данных на платформе, и здесь она пустая. */
.empty::before{content:'';display:block;width:32px;height:34px;margin:0 0 var(--s-4);
  background:
    linear-gradient(var(--surface-2),var(--surface-2)) no-repeat 0 100%/5px 60%,
    linear-gradient(var(--marker-soft),var(--marker-soft)) no-repeat 9px 100%/5px 100%,
    linear-gradient(var(--surface-2),var(--surface-2)) no-repeat 18px 100%/5px 74%,
    linear-gradient(var(--surface-2),var(--surface-2)) no-repeat 27px 100%/5px 46%}
.empty p{margin:7px 0 14px;font-size:var(--t-base);line-height:1.55;color:var(--ink-2)}
/* «Не найдено» — та же анатомия без глифа: список не пуст, он отфильтрован. */
.empty.none::before{display:none}

/* Скелет загрузки: плашки в форме будущего содержимого, а не спиннер — сетка
   не прыгает при появлении данных. Показывается не раньше 300мс: быстрый
   ответ не должен мигать заглушкой. */
.skel{display:flex;flex-direction:column;gap:6px}
.skel i{display:block;background:var(--paper);border-radius:var(--r-1);padding:13px}
.skel i::before,.skel i::after{content:'';display:block;border-radius:var(--r-pill)}
.skel i::before{height:9px;width:58%;background:linear-gradient(90deg,var(--surface-2) 0%,var(--line) 50%,var(--surface-2) 100%);background-size:300px 100%;animation:skelShine 1.4s linear infinite}
.skel i::after{height:7px;width:82%;background:var(--surface-2);margin-top:9px}
.skel i:nth-child(2)::before{width:44%}
.skel i:nth-child(2)::after{width:70%}
.skel i:nth-child(3)::before{width:52%}
.skel i:nth-child(3)::after{width:76%}
@keyframes skelShine{0%{background-position:-240px 0}100%{background-position:340px 0}}
/* «Пока пусто»: у ученика ещё ничего нет не потому, что сломалось. */
.empty.soft::before{opacity:.45}
/* Ряд действий под объяснением: «Повторить» и выход. Раньше из сорванной
   загрузки не вело ничего, кроме обновления страницы руками. */
.empty-acts{display:flex;gap:var(--s-2);margin-top:var(--s-4);flex-wrap:wrap}
/* Красным — только надстрочник состояния: заголовок говорит, что случилось, и
   чернила для этого достаточно громкие, а красный заголовок читался паникой. */
.eyebrow.err{color:var(--err)}
.empty.error .big{color:var(--ink)}
/* Пустое состояние в строку — короткая приписка внутри карточки, глифу там
   негде развернуться */
.empty.bare{padding:var(--s-4) var(--s-5);align-items:flex-start;text-align:left}
.empty.bare::before{content:none}
/* Тост — речь, а не кнопка: набирается текстом, а не жирным Onest. Обратимое
   действие делается сразу, а возврат живёт здесь. */
/* Тост — плашка со скруглением 22, а не пилюля. Пилюля хороша ровно для одной
   строки: «Сохранено», «Ссылка скопирована». Но тосты бывают и в три строки
   («собрано 15 блоков · проверьте ответы перед занятием»), и на телефоне почти
   любой из них переносится — пилюля превращалась в раздутую лепёшку с
   полукруглыми боками, у которой текст стоит по центру огрызками.

   Ширину ограничиваем, как у тоста-ошибки: без потолка длинная фраза тянулась
   во всю ширину окна и на ноутбуке шла одной строкой через весь экран. */
.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(20px);
  background:var(--ink);color:var(--bg);padding:var(--s-3) 18px;border-radius:var(--r-3);
  max-width:min(420px,calc(100vw - 32px));text-align:left;
  font-size:var(--t-md);font-weight:400;line-height:1.45;font-family:var(--font-body);opacity:0;
  transition:opacity var(--dur-slow) var(--ease-s),transform var(--dur-slow) var(--ease-s);
  z-index:200;pointer-events:none;box-shadow:var(--sh-3)}
/* Ошибка не исчезает сама и разворачивается в прямоугольник: у неё есть что
   сказать и что предложить. */
.toast.bad{border-radius:var(--r-3);padding:14px 18px;flex-direction:column;align-items:flex-start;
  max-width:min(420px,calc(100vw - 32px));white-space:normal;text-align:left}
.toast.bad .tb-lab{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;color:#E88579}
.toast.bad .tb-text{font-size:var(--t-md);line-height:1.55;color:var(--paper);margin-top:7px}
.toast.bad .tb-acts{display:flex;gap:var(--s-2);margin-top:14px}
.toast.on{opacity:1;transform:translateX(-50%)}
/* С действиями тост становится кликабельным — но только пока он виден: класс
   with-acts снимается вместе с on (см. hideToast), и это подстраховано здесь,
   иначе прозрачная полоса внизу экрана глотала бы чужие клики. */
.toast.two{text-align:left;border-radius:var(--r-3)}
.toast.two .toast-sub{display:block;font-style:normal;font-size:var(--t-sm);
  color:rgba(255,255,255,.62);margin-top:3px;white-space:normal}
.toast.with-acts{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-2) var(--s-3) var(--s-2) var(--s-4)}
.toast.with-acts.on{pointer-events:auto}
/* Действие в тосте — жёлтым: отмена массового действия одно из четырёх
   значений маркера, и это единственное место, где он стоит на кнопке. */
.toast-act{border:none;background:none;color:var(--marker);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
  border-radius:var(--r-pill);padding:var(--s-1) var(--s-2);cursor:pointer;white-space:nowrap}
.toast-act:hover{background:rgba(255,255,255,.10)}
.toast.bad .tb-acts .toast-act{height:30px;padding:0 13px;border-radius:var(--r-1);
  background:var(--paper);color:var(--ink)}
.toast.bad .tb-acts .toast-act.quiet{background:none;color:#C4C4C0}

/* ---------- Каталог, ученики ---------- */
/* width:100% обязателен: .app-main — флекс-колонка, а `margin:0 auto` на
   поперечной оси отменяет растягивание, и страница сжималась по содержимому.
   На «Сегодня» это было незаметно (широкие блоки сами держали ширину), а
   кабинет ученика из-за этого выглядел узкой мобильной колонкой. */
.page{max-width:1244px;width:100%;margin:0 auto;padding:var(--s-6) var(--s-6) 120px}
/* Заголовок страницы: подпись и название слева, действие — у правого края и по
   нижней линии заголовка, чтобы кнопка не «висела» рядом с надзаголовком. */
.page-head{display:flex;align-items:flex-end;gap:var(--s-3);margin-bottom:var(--s-5);flex-wrap:wrap}
.page-head h1{font-size:var(--t-h1);letter-spacing:-.015em}
.page-head .spacer{flex:1}
/* Значок лупы — фоном, а не отдельным элементом: поле стоит в шести местах, и
   заводить ради значка обёртку в каждом значило бы править шесть разметок.
   Отступ слева освобождает под него место. */
.search-inp{border:none;border-radius:var(--r-1);height:38px;padding:0 var(--s-3) 0 34px;
  background-repeat:no-repeat;background-position:12px center;background-size:14px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%237C7A72' stroke-width='1.6'><circle cx='7' cy='7' r='4.5'/><path d='M10.5 10.5L14 14' stroke-linecap='round'/></svg>");font-size:var(--t-md);background:var(--surface-2);width:220px;color:var(--ink);transition:background var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.search-inp.wide{width:240px}
.search-inp:hover{background:var(--surface-2)}
.search-inp:focus{outline:none;box-shadow:0 0 0 2px var(--ink)}
.folder-chips{display:flex;gap:var(--s-2);flex-wrap:wrap;margin-bottom:var(--s-4)}
.folder-chip{border:1px solid var(--line);background:var(--surface);border-radius:var(--r-pill);padding:6px var(--s-3);font-size:var(--t-sm);font-weight:600;font-family:var(--font-head);cursor:pointer;color:var(--muted)}
.folder-chip.on{border-color:var(--ink);background:var(--ink);color:var(--paper)}
.folder-chip.on span{opacity:.7}
/* Порядок каталога — выбор, а не подпись: раньше здесь стоял неинтерактивный
   текст, который выглядел переключателем и им не был. */
.cat-sort{border:none;background:none;padding:0;cursor:pointer;font-family:var(--font-body);
  font-size:var(--t-sm);color:var(--muted)}
.cat-sort:hover{color:var(--ink-2)}
.cat-sort .chev{font-size:var(--t-label)}
/* Счёт по языкам под папками: тот же чип, что в фильтрах словаря. */
/* Чип с флагом: три вещи в ряд — флаг, название, число. Без флекса флаг
   ложился на первую букву названия: .flag это inline-block с фиксированным
   размером, и строка обтекала его как картинку. */
.lang-chips{display:flex;flex-wrap:wrap;gap:6px}
.lang-chips .chip{display:inline-flex;align-items:center;gap:6px}
.lang-chips .chip b{font-variant-numeric:tabular-nums;color:var(--muted);margin-left:2px}
.lang-chips .chip.selected b{color:inherit;opacity:.72}
/* Как работают заготовки — нумерованный список в окне. */
.sn-how{margin:0;padding-left:20px;font-size:var(--t-md);line-height:1.6;color:var(--ink-2)}
.sn-how li+li{margin-top:8px}
.sn-how b{color:var(--ink)}

.cat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:var(--s-4)}
.cat-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;display:flex;flex-direction:column;transition:box-shadow var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease);position:relative}
.cat-card:hover{box-shadow:var(--shadow);transform:translateY(-2px)}
.cat-card img{width:100%;height:72px;object-fit:cover;display:block;background:var(--surface-2)}
/* Обложка урока без картинки — мотив «Поле» вместо нейтрального градиента:
   линия поля и стикер с первой буквой темы. Градиент говорил «здесь могла быть
   картинка», а мотив говорит, что это урок Lessona, и по букве урок различим в
   каталоге из тридцати таких же. Две серые полоски за стикером изображали
   текст, которого на обложке нет, — они ушли вместе с ощущением недогрузки. */
.field-cover{position:relative;overflow:hidden;
  background:linear-gradient(135deg,var(--marker-soft) 0%,var(--surface-2) 58%,var(--paper) 100%)}
.field-cover::before{content:'';position:absolute;top:0;bottom:0;left:40px;width:1.5px;background:rgba(23,26,33,.12)}
/* Буква на стикере — не токеном: маркер #E8A317 один и тот же в обеих темах
   хрома, а --marker-ink в тёмной становится светло-золотым (он для текста на
   приглушённой подложке, не на самом маркере) — буква пропадала бы на стикере.
   Пара «яркий маркер + это чернило» постоянна, как и в счётчике меню. */
.field-cover i{position:absolute;left:20px;top:50%;margin-top:-20px;
  width:40px;height:40px;background:var(--marker);border-radius:var(--r-1);transform:rotate(-4deg);
  box-shadow:0 8px 18px -8px rgba(138,106,0,.55);
  display:flex;align-items:center;justify-content:center;font-style:normal;
  font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);color:#7A5406}
.cat-card .field-cover{height:72px}
.lib-card .field-cover{height:106px}
.cat-card .cb{padding:var(--s-3) var(--s-3);flex:1;display:flex;flex-direction:column;gap:var(--s-1)}
.cat-card .ct2{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);line-height:1.3}
/* Подпись слева, действия справа, всегда одной строкой. Ряд иконок не зависит
   от того, насколько длинным вышло название папки: место ему отведено, а
   подпись при нехватке ширины укорачивается многоточием. */
.cat-card .cm{font-size:var(--t-sm);color:var(--muted);display:flex;align-items:center;gap:var(--s-2);min-height:28px}
.cat-card .cm-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cat-card .cm-acts{display:flex;align-items:center;gap:1px;flex-shrink:0;margin-right:-5px}
.cat-card .ca{display:flex;flex-wrap:wrap;gap:var(--s-1);padding:0 var(--s-4) var(--s-3)}
.cat-card .ca .btn{flex:1 1 auto;min-width:66px;justify-content:center;padding:var(--s-2) var(--s-1)}

/* ---------- Каталог уроков: колонка папок и список ----------
   Папки ушли из полосы чипсов в колонку слева. Чипс держал только имя; строка
   колонки держит ещё и число уроков и принимает урок перетаскиванием. Полоса
   чипсов (.folder-chips) осталась в стилях: ею же рисуется выбор папки в окне
   переноса урока (dialog.js). */
.cat-layout{display:grid;grid-template-columns:208px minmax(0,1fr);gap:var(--s-5);align-items:start}
/* Прилипает под панелью, а не под верхним краем окна: панель высотой 52 и
   висит на top:0, поэтому 16px от края — это 36px ПОД ней, и «Все уроки» при
   прокрутке уходили ей за спину. 74 — та же высота, на которой стоят рельса
   конструктора, панель занятия, меню кабинета и рельса расписания. */
.fold-col{position:sticky;top:74px}
.fold-col .fold-head{display:block;margin-bottom:var(--s-2)}
.fold-list{display:flex;flex-direction:column;gap:2px}
/* Геометрия строки — та же, что у пункта левого меню: папки это навигация, и
   вести себя они должны так же. Счётчик серый, а не жёлтой плашкой: жёлтый на
   платформе означает ИИ и отметки преподавателя, а не «сколько всего». */
.fold-row{display:flex;align-items:center;gap:var(--s-2);width:100%;text-align:left;cursor:pointer;
  padding:var(--s-2) var(--s-3);border:1px solid transparent;border-radius:var(--r-1);background:transparent;
  font-family:var(--font-head);font-weight:500;font-size:var(--t-base);color:var(--ink-2);
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.fold-row:hover{background:var(--surface-2)}
.fold-row.on{background:var(--ink);color:var(--paper);font-weight:600}
.fold-row .fr-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fold-row .fr-n{font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:600;color:var(--muted)}
.fold-row.on .fr-n{color:#A8A6A0}
.fold-row .fr-here,.fold-row .fr-drag{display:none}
/* Крестик удаления приходит на наведение: на виду в каждой строке он предлагал
   бы удаление чаще, чем переход в папку. */
.fold-row .fr-x{opacity:0;flex-shrink:0;color:var(--muted);font-size:var(--t-label);padding:0 2px;
  transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.fold-row:hover .fr-x{opacity:1}
.fold-row .fr-x:hover{color:var(--err)}
.fold-row.add{color:var(--muted)}
.fold-row.add:hover{color:var(--ink)}
.fold-note{margin-top:var(--s-3);font-size:var(--t-sm);line-height:1.5;color:var(--muted)}
/* Пока урок в руке: «Все уроки» гаснет — туда не кладут, — остальные строки
   раздвигаются и ждут пунктиром, строка под курсором забирает урок. */
.fold-col.dragging .fold-list{gap:6px}
.fold-col.dragging .fold-row.all{opacity:.45}
.fold-col.dragging .fold-row:not(.all){border:1px dashed var(--line-2);padding:10px var(--s-3)}
.fold-col.dragging .fr-idle{display:none}
.fold-col.dragging .fr-drag{display:block}
.fold-row.drop{background:var(--ink);color:var(--paper);font-weight:600;padding:var(--s-3);
  border-color:transparent;box-shadow:0 8px 18px -10px rgba(23,26,33,.6)}
.fold-row.drop .fr-n,.fold-row.drop .fr-x{display:none}
.fold-row.drop .fr-here{display:block;font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:600;
  letter-spacing:.08em;color:#A8A6A0}

/* Три колонки — только у каталога уроков: тем же .cat-grid рисуются курсы, у
   них своя мера колонки. */
.cat-main .cat-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
/* Полка незаконченного над каталогом. Не карточка и не лист: это строка-повод
   разобраться, и весом она должна быть меньше самих уроков, иначе читается как
   ещё одна группа. */
.draft-shelf{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;
  background:var(--surface-2);border-radius:var(--r-1);
  padding:10px var(--s-3);margin-bottom:var(--s-4)}
.draft-shelf .ds-text{min-width:0;font-size:var(--t-base);color:var(--ink-2)}
.draft-shelf .btn{margin-left:auto}
.draft-shelf .btn+.btn{margin-left:0}
/* Язык — в левом верхнем углу обложки, на белой плашке: обложка бывает и
   картинкой, и глифом, и на обеих код должен читаться. */
.cc-lang{position:absolute;top:var(--s-2);left:var(--s-2);z-index:1;
  background:var(--surface);color:var(--ink-2);border-radius:var(--r-1);
  padding:2px 7px;font-size:var(--t-label);font-weight:600;letter-spacing:.06em;
  box-shadow:var(--sh-1)}
/* Выбор нескольких уроков: галочка приходит на место языка при наведении, а у
   выбранной плитки остаётся видимой — признак выбора, пропадающий вместе с
   курсором, не признак. Рамка чернилами: выбор — состояние, а не подсветка. */
.cc-pick{position:absolute;top:var(--s-2);left:var(--s-2);z-index:2;
  width:22px;height:22px;padding:0;display:none;align-items:center;justify-content:center;
  border:1px solid var(--line-2);border-radius:var(--r-1);background:var(--surface);
  color:var(--ink);font-size:var(--t-sm);line-height:1;cursor:pointer;box-shadow:var(--sh-1)}
.cat-card:hover .cc-pick,.cat-card.picked .cc-pick{display:flex}
.cat-card:hover .cc-lang,.cat-card.picked .cc-lang{display:none}
.cat-card.picked .cc-pick{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.cat-card.picked{box-shadow:0 0 0 2px var(--ink)}

.cat-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);
  padding:0 var(--s-1) 10px}
.cat-group-head.later{padding-top:22px}
.cat-sort{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}

/* Плитка: обложка занимает верх, название уходит под неё, на виду два глагола.
   Пять равновесных кнопок в ряду читались как пять одинаково важных дел. */
.cat-main .cat-card{cursor:pointer}
.cat-main .cat-card img,.cat-main .cat-card .field-cover{height:150px}
.cc-cover{position:relative}
.cc-draft{position:absolute;top:12px;right:12px;background:var(--surface);border-radius:var(--r-1);
  padding:3px var(--s-2);font-family:var(--font-body);font-size:var(--t-label);font-weight:600;letter-spacing:.08em;
  color:var(--muted)}
.cc-body{padding:var(--s-3) 14px 14px;flex:1;display:flex;flex-direction:column}
.cc-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);letter-spacing:-.02em;
  line-height:1.25;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.cc-sub{margin-top:5px;font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cc-acts{position:relative;display:flex;align-items:center;gap:6px;margin-top:13px}
.cc-acts .cc-more{margin-left:auto}
.cc-when{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Черновик: знак приглушён, название тише, а вся пустая заготовка (ноль
   блоков) отступает на второй план целиком. */
.cat-card.draft .field-cover i{opacity:.55;box-shadow:none}
.cat-card.draft .cc-title{color:var(--ink-2)}
.cat-card.empty-draft{opacity:.6}
/* Плитка режет всё, что вылезло за края (обложка), — а меню обязано вылезти. */

/* Пусто и не найдено в каталоге: заголовок крупнее обычного пустого состояния —
   на этом экране он единственный текст. */
.cat-empty{padding:var(--s-5) var(--s-1)}
.cat-empty .big{font-size:var(--t-h1);letter-spacing:-.015em;margin-bottom:var(--s-2)}
.cat-empty.none .big{font-size:var(--t-lg)}
.cat-empty p{max-width:44ch}
.cat-empty-acts{display:flex;gap:9px;flex-wrap:wrap}

/* Ошибка списка живёт карточкой на месте сетки: раньше каталог стирал страницу
   целиком вместе с меню. Красная здесь только рельса слева. */
.cat-error{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  border-left:3px solid var(--err);padding:var(--s-5)}
.cat-error .ce-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);margin-bottom:6px}
.cat-error .ce-text{font-size:var(--t-base);color:var(--ink-2);line-height:1.55;max-width:44ch}
.cat-error .ce-acts{display:flex;align-items:center;gap:var(--s-3);margin-top:var(--s-4);flex-wrap:wrap}
.cat-error .ce-try{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}

/* Скелет каталога: базовый .skel рисует строки списка, каталогу нужны плитки —
   иначе сетка прыгает в момент, когда уроки приходят. */
.skel.tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-4)}
.skel.tiles i{display:block;padding:0;background:var(--surface);border-radius:var(--r-2);overflow:hidden}
.skel.tiles i::before,.skel.tiles i::after{content:none}
/* Рост обложки тот же, что у настоящей плитки каталога (150px): заглушка
   затем и нужна, чтобы сетка не прыгнула, когда обложки приедут. На 88px она
   подпрыгивала на шестьдесят точек — то есть делала ровно то, от чего
   заведена. */
.skel.tiles b{display:block;height:150px;background:var(--surface-2)}
.skel.tiles em{display:block;height:9px;width:76%;margin:var(--s-3) 14px 0;border-radius:var(--r-pill);
  background:linear-gradient(90deg,var(--surface-2) 0%,var(--line) 50%,var(--surface-2) 100%);
  background-size:300px 100%;animation:skelShine 1.4s linear infinite}
.skel.tiles i:nth-child(2) em{width:58%}
.skel.tiles i:nth-child(3) em{width:68%}
.skel.tiles span{display:block;height:26px;margin:var(--s-3) 14px 14px;border-radius:var(--r-1);background:var(--surface-2)}

/* Выбор папки для урока — списком в окне: плашка внутри плитки перекрывала её
   же кнопки. */
.fold-pick{margin-top:var(--s-3);display:flex;flex-direction:column;gap:2px}
.fold-pick .ap-row{display:flex;align-items:center;width:100%;text-align:left;cursor:pointer;
  border:none;background:none;padding:var(--s-2);border-radius:var(--r-1);
  font-family:var(--font-head);font-weight:500;font-size:var(--t-base);color:var(--ink)}
.fold-pick .ap-row:hover{background:var(--surface-2)}

/* Окно «Поделиться уроком». Своей шапки и своей отбивки внизу у него больше
   нет: заголовок с крестиком печатает оболочка, «Закрыть доступ» стоит левым
   действием подвала — там же, где «Удалить» у прочих окон. */
/* Счётчики ссылки — три плитки с крупными числами: числа и есть ответ на
   «дошла ли она», а в сплошной фразе они терялись между словами. */
.sh-tiles{display:flex;gap:var(--s-2);flex-wrap:wrap}
.sh-tile{flex:1 1 110px;background:var(--paper);border-radius:var(--r-1);padding:var(--s-3)}
.sh-tile b{display:block;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;line-height:1.1}
.sh-tile span{display:block;font-size:var(--t-sm);color:var(--muted);margin-top:2px}
.sh-row{display:flex;gap:var(--s-2);margin-top:var(--s-4)}
.sh-url{flex:1;min-width:0;background:var(--paper);border:1px solid var(--line);border-radius:var(--r-1);
  padding:11px 13px;font-family:var(--font-body);font-size:var(--t-base);color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis}

@media (max-width:1180px){
  .cat-main .cat-grid,.skel.tiles{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:760px){
  /* minmax(0,1fr), а не 1fr: у 1fr нижняя граница — самое длинное неразрывное
     содержимое, и название урока в строку («Supercalifragilistic…», «En el
     control de inmigración: frases útiles…») раздвигало колонку шире экрана. На
     телефоне документ становился шириной 656 при любом экране, страница
     листалась вбок, а закреплённые «Собрать урок с ИИ» и нижнее меню уезжали за
     край окна — до них приходилось докручивать. На пробном аккаунте названия
     короткие, и этого не было видно (замечание владельца 14 сентября). */
  .cat-layout{grid-template-columns:minmax(0,1fr)}
  .cat-layout>*{min-width:0}
  .fold-col{position:static}
  .cat-main .cat-grid,.skel.tiles{grid-template-columns:1fr}
  /* Дата правки уступает место названию: на узком экране она первой лишняя. */
  .sn-row{grid-template-columns:34px minmax(0,1fr) auto 30px;gap:10px}
  .sn-row-date{display:none}
}
/* «В домашку» в шапке задания на занятии: тихая, пока на неё не навели, — она
   про после урока, а не про то, что делают сейчас. На устройствах без мыши
   видна всегда: наводить там нечем. */
.card .hw-add-btn{margin-left:auto;flex-shrink:0;border:none;background:none;cursor:pointer;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-label);letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted);padding:2px var(--s-2);border-radius:var(--r-1)}
.card .hw-add-btn:hover{color:var(--ink);background:var(--surface-2)}
.card .hw-add-btn.on{color:var(--accent-soft-ink);background:var(--accent-soft)}
@media (hover:hover){
  .card .hw-add-btn:not(.on){opacity:0;transition:opacity var(--dur-fast) var(--ease)}
  .card:hover .hw-add-btn,.card:focus-within .hw-add-btn{opacity:1}
}

/* ---------- Выбор кадра у картинки ----------
   Рамка ровно тех пропорций, в которых картинка встанет на место, картинка
   внутри двигается мышью. Обрезает не вёрстка, а сам преподаватель — обложка
   узкая, и object-fit:cover резал портрет по центру, оставляя вместо лица
   что придётся. */
.crop-frame{position:relative;overflow:hidden;border-radius:var(--radius-sm);background:var(--surface-2);
  border:1px solid var(--line);cursor:grab;touch-action:none;user-select:none;width:100%}
.crop-frame.grabbing{cursor:grabbing}
.crop-frame img{position:absolute;left:0;top:0;transform-origin:0 0;max-width:none;display:block;pointer-events:none}
.crop-zoom{display:flex;align-items:center;gap:var(--s-3);margin:var(--s-3) 0 var(--s-4)}
.crop-zoom input{flex:1;accent-color:var(--ink)}

/* ---------- Вырезать картинку со страницы учебника ----------
   Страница показана целиком и во всю ширину окна: искать на ней нужную
   фотографию глазами придётся всё равно, и чем крупнее страница, тем точнее
   рамка. Сама рамка рисуется мышью — пропорции у каждой картинки свои. */
.cut-modal{width:min(900px,calc(100vw - 32px))}
.cut-pages{display:flex;gap:var(--s-2);overflow-x:auto;padding-bottom:var(--s-2);margin-bottom:var(--s-3)}
.cut-page{position:relative;width:64px;height:82px;flex-shrink:0;padding:0;overflow:hidden;cursor:pointer;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-1)}
.cut-page.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-soft)}
.cut-page img{width:100%;height:100%;object-fit:cover;display:block}
.cut-page .cut-x{position:absolute;top:2px;right:2px;width:17px;height:17px;line-height:16px;
  font-size:var(--t-label);text-align:center;border-radius:50%;background:var(--surface);border:1px solid var(--line);
  color:var(--muted);opacity:0}
.cut-page:hover .cut-x{opacity:1}
.cut-add{width:64px;height:82px;flex-shrink:0;font-size:var(--t-label);line-height:1.3;color:var(--muted);cursor:pointer;
  background:none;border:1px dashed var(--line-2);border-radius:var(--r-1)}
.cut-add:hover{border-color:var(--accent);color:var(--ink)}
/* Страница приближается, поэтому она в окне прокрутки: при зуме видна её часть,
   и по ней ездят, а не жмурятся. Тень вокруг рамки обрезается этим же окном. */
.cut-scroll{max-height:52vh;overflow:auto;border-radius:var(--radius-sm);background:var(--surface-2)}
.cut-stage{position:relative;width:fit-content;margin:0 auto;cursor:crosshair;
  touch-action:none;user-select:none;line-height:0}
/* Ширину задаёт разметка (cutLayout), поэтому никаких max-width здесь: он бы
   отменял приближение, молча ужимая страницу обратно под окно. */
.cut-stage img{display:block;max-width:none;pointer-events:none}
/* Всё вне рамки притемняем тенью наружу: так видно ровно то, что уедет в
   задание, — а без затемнения рамка теряется среди печатной сетки учебника.
   Саму рамку нажимать можно: за неё её и двигают. */
.cut-rect{position:absolute;border:2px solid var(--accent);cursor:move;
  box-shadow:0 0 0 9999px rgba(23,26,33,.34)}
.cut-h{position:absolute;width:13px;height:13px;background:var(--surface);
  border:2px solid var(--accent);border-radius:3px}
.cut-h[data-h="nw"]{left:-8px;top:-8px;cursor:nwse-resize}
.cut-h[data-h="ne"]{right:-8px;top:-8px;cursor:nesw-resize}
.cut-h[data-h="sw"]{left:-8px;bottom:-8px;cursor:nesw-resize}
.cut-h[data-h="se"]{right:-8px;bottom:-8px;cursor:nwse-resize}

/* Окно выбора ученика: имя целиком, действия справа, длинный список прокручен */
.sp-list{display:flex;flex-direction:column;gap:6px}
.sp-row{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-2) var(--s-2);border-radius:var(--r-1)}
.sp-row:hover{background:var(--surface-2)}
.sp-row .sp-n{flex:1;min-width:0;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sp-row .sp-a{display:flex;gap:var(--s-2);flex-shrink:0}

/* ---------- Окно выбора урока ----------
   Каталог в окне: те же чипы папок, тот же поиск и те же обложки, что во
   вкладке «Уроки». Плоский список названий, который был здесь раньше, годился,
   пока уроков десяток. */
.modal.wide{width:min(720px,calc(100vw - 2*var(--s-4)))}
.lp-search{margin-bottom:var(--s-3)}
.lp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--s-2);
  max-height:min(52vh,440px);overflow:auto;padding:2px}
/* Имя плитки — .lp-pick, а не .lp-card: .lp-card занят карточкой лендинга
   (там lp — landing page, здесь было lesson picker). Правила окна стоят в файле
   выше, и скринам лендинга доставались отсюда и курсор-палец, и обводка по
   наведению — на картинках, которые никуда не ведут. */
.lp-pick{display:flex;flex-direction:column;text-align:left;padding:0;overflow:hidden;cursor:pointer;
  /* Радиус карточки, как у плитки в каталоге: окно показывает те же уроки, и
     скругление у них должно быть то же. Раньше он приезжал сюда случайно —
     из правила лендинга с тем же именем, вместе с его тенью в 50px. */
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-2);position:relative}
.lp-pick:hover{border-color:var(--accent)}
.lp-pick.on{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-soft)}
.lp-pick>img,.lp-pick>.field-cover{width:100%;height:84px;object-fit:cover;display:block;flex-shrink:0}
.lp-pick .lp-b{display:flex;flex-direction:column;gap:2px;padding:var(--s-2) var(--s-3) var(--s-3)}
.lp-pick .lp-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);line-height:1.3}
/* Неверное в разборе — зачёркнутым и цветом ошибки: ученик читает строку
   слева направо и должен сразу видеть, какая половина неправильная. */
.mk-wrong{color:var(--err);text-decoration-thickness:1px}

/* ---------- Ошибки ученика в панели занятия ----------
   Свой лоток панели, а не хвост хода урока: это другой разговор. Черта, что
   отбивала блок раньше, больше не нужна — лотки и так стоят порознь.

   Поле стоит сразу под заголовком, записанное лежит ниже: пишут сюда на слух
   и на ходу, а перечитывают потом. */
/* Счётчик прижат к правому краю: он про весь лоток, а не приписка к слову. */
.mis-head{display:flex;align-items:center;gap:var(--s-2)}
.mis-head .count-pill{margin-left:auto}
/* Строка не зачёркнута: зачёркнутое читается как отменённое, а это то, что
   ученик сказал вслух. Неверное — цветом ошибки, стрелка приглушена, верное —
   чернилами; начертание у обоих обычное, разницу несёт цвет. */
.mis-list{display:flex;flex-direction:column;gap:5px;margin:11px 0 0}
.mis-row{display:flex;align-items:baseline;gap:var(--s-2);font-size:var(--t-sm);line-height:1.45;
  background:var(--paper);border-radius:var(--r-1);padding:var(--s-2) 10px}
.mis-body{min-width:0;flex:1;overflow-wrap:anywhere;color:var(--ink)}
.mis-wrong{color:var(--err)}
.mis-arrow{color:var(--muted)}
.mis-x{margin-left:auto;flex-shrink:0;border:0;background:none;cursor:pointer;
  color:var(--muted);font-size:var(--t-sm);line-height:1;padding:2px 3px}
.mis-x:hover{color:var(--err)}
.mis-empty{font-size:var(--t-label);color:var(--muted);line-height:1.5;margin:var(--s-2) 0 0}
/* Поле без рамки: кольцо внутрь не добавляет линии в и без того плотный лоток.
   В покое кольцо линией, под курсором набора — чернилами: фокус должен быть
   виден, а два одинаковых кольца сказали бы, что поле активно всегда. */
.mis-input{width:100%;border:none;border-radius:var(--r-1);margin-top:10px;
  padding:10px var(--s-3);font-size:var(--t-sm);background:var(--paper);
  box-shadow:inset 0 0 0 1px var(--line-2)}
.mis-input:focus{outline:none;box-shadow:inset 0 0 0 1.5px var(--ink)}
.mis-input::placeholder{color:var(--muted)}
.mis-hint{font-size:var(--t-label);color:var(--muted);margin-top:var(--s-1)}

/* Кто проходит шаг курса своим материалом. Мелкой строкой под правилом
   открытия: это примечание к уроку, а не отдельный список. */
.crs-variants{display:flex;flex-wrap:wrap;gap:var(--s-1) var(--s-2);margin-top:var(--s-1)}
.crs-variant{font-size:var(--t-label);color:var(--accent);white-space:nowrap}
.crs-variant::before{content:'☺ ';opacity:.7}
/* Имена тех, для кого у урока есть личный вариант, — строкой под карточкой в
   каталоге. Раньше карточка говорила только «3 варианта под учеников»: знать,
   что они есть, было можно, а чьи и где — нет. */
.ca-variants{display:flex;flex-wrap:wrap;gap:var(--s-1) var(--s-3);padding:0 var(--s-4) var(--s-3)}
.ca-variants .crs-variant{text-decoration:none}
.ca-variants .crs-variant:hover{text-decoration:underline}

/* Лист урока в режиме чтения: очередь проверки показывает работу ученика
   такой, какой он её оставил. Ответы видны, тронуть их нельзя — иначе
   преподаватель нечаянно перепишет то, что пришёл проверять. Поля не
   выключаем атрибутом: disabled гасит текст, а читать его как раз и нужно. */
.ro [data-body] *{pointer-events:none}
.ro [data-body] input,.ro [data-body] textarea{cursor:default}
.ro .check-btn{display:none}
/* Кроме ссылок и звука: перечитать статью по ссылке и переслушать запись —
   часть проверки, а не правка ответа. */
.ro [data-body] a,.ro [data-body] audio,.ro [data-body] video{pointer-events:auto}

/* Полоса персонального варианта над листом урока. Стоит внутри листа, но
   оформлением от него отделена: это не часть материала, а рамка вокруг него. */
.variant-note{margin:0 0 14px;padding:9px 13px;border-radius:var(--r-1);
  border:1px solid color-mix(in srgb,var(--accent) 35%,transparent);
  background:color-mix(in srgb,var(--accent) 8%,transparent);
  font-size:var(--t-sm);line-height:1.5}
.variant-note a{margin-left:6px;white-space:nowrap}

.lp-pick .lp-m{font-size:var(--t-sm);color:var(--muted)}
/* Урок, уже пройденный с этим учеником: строка говорит не про папку, а про
   прошлое занятие, и цветом отделена от прочих — её читают в первую очередь. */
.lp-pick .lp-m.passed{color:var(--accent)}
.lp-pick .lp-now{position:absolute;top:6px;right:6px;background:var(--ink);color:var(--paper);
  border-radius:var(--r-pill);padding:2px var(--s-2);font-size:var(--t-label);font-family:var(--font-head);font-weight:600}
@media(max-width:560px){.lp-grid{grid-template-columns:1fr;max-height:56vh}
  .lp-pick>img,.lp-pick>.field-cover{height:64px}}

.assign-pop{position:absolute;left:10px;right:10px;bottom:10px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-1);box-shadow:var(--sh-3);padding:var(--s-2);z-index:5}
.assign-pop .ttl{font-size:var(--t-label);text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:700;padding:var(--s-1) var(--s-2)}
.assign-pop .ap-row{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-2);border-radius:var(--r-1);font-size:var(--t-base)}
.assign-pop .ap-row:hover{background:var(--surface-2)}
.assign-pop .ap-row .btn{margin-left:auto}
/* Инициалы лежат в кружке всегда, фото — картинкой поверх них. Не открылось —
   картинка убирает себя, и буквы уже на месте (см. avatar() в core.js). */
.stu-ava{position:relative;overflow:hidden;width:40px;height:40px;border-radius:50%;background:var(--accent-soft);color:var(--accent-soft-ink);display:flex;align-items:center;justify-content:center;font-family:var(--font-head);font-weight:700;font-size:var(--t-md);flex-shrink:0}
.stu-ava img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Имя ученика как ссылка: цвет и вес наследует у строки, подчёркивание — только
   по наведению. Иначе списки занятий и оплат превратились бы в синее полотно. */
.stu-link{color:inherit;text-decoration:none}
.stu-link:hover{text-decoration:underline;text-underline-offset:2px}
.stu-ava.xs{width:26px;height:26px;font-size:var(--t-label)}
.stu-ava.sm{width:28px;height:28px;font-size:var(--t-label)}
.stu-ava.md{width:34px;height:34px;font-size:var(--t-sm);font-weight:600;
  background:var(--surface-2);color:var(--muted)}
.stu-ava.lg{width:64px;height:64px;font-size:var(--t-h1)}
.stu-back{background:none;border:none;color:var(--accent);font-weight:600;font-family:var(--font-head);font-size:var(--t-base);cursor:pointer;padding:0;margin-bottom:var(--s-3)}
.invite-box{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:var(--s-4) var(--s-4);margin-bottom:var(--s-4)}
.invite-url{display:flex;gap:var(--s-2);margin-top:var(--s-3)}
.invite-url input{flex:1;border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface-2);font-family:ui-monospace,Menlo,monospace}

/* ---------- Вход / регистрация ---------- */
.auth-wrap{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:var(--s-5)}
/* Логотип и правовые ссылки — сёстры карточки, а не её дети: карточка держит
   только форму. Ширина строки логотипа равна ширине карточки, иначе знак
   центрируется вместе с обёрткой и уезжает от её левого края. */
.auth-logo{width:396px;max-width:100%;margin-bottom:18px}
.auth-wrap.wide .auth-logo{width:736px}
/* Отступ 26/24 из макета на шкалу не ложится (--s-5 = 24, --s-6 = 32) — берём
   --s-5 по обеим осям, расхождение с макетом в 2 px. */
.auth-card{background:var(--surface);border-radius:var(--r-2);padding:var(--s-5);width:396px;max-width:100%;box-shadow:var(--sh-2)}
/* 28 px вне шкалы хрома намеренно, как у лендинга: это заголовок отдельной
   страницы, а не карточки внутри платформы. npm run css-scale здесь не ошибка. */
.auth-card h1{font-size:28px;letter-spacing:-.03em;margin-bottom:0}
/* Мелкие карточки — запрос смены пароля, подтверждение почты — остаются на --t-h1 */
.auth-card.compact h1{font-size:var(--t-h1);letter-spacing:-.01em}
.auth-card .sub{color:var(--muted);font-size:var(--t-base);margin-top:5px;margin-bottom:0}
/* Подзаголовок-абзац: там, где он объясняет, а не подписывает заголовок,
   он темнее и с разрядкой строк (запрос смены пароля, «письмо отправлено»). */
.auth-card .sub.lead{color:var(--ink-2);font-size:var(--t-md);line-height:1.55}
/* Отступ до первой подписи даёт форма, а не подзаголовок: между полями 16. */
.auth-card form{margin-top:22px}
.auth-card .field{margin-bottom:var(--s-4)}
/* Глобальное .field label держит формы всей платформы — полужирную подпись
   заводим областью, только на карточке входа. */
.auth-card .field label{font-weight:600}
/* Поле на карточке становится на тон темнее самой карточки, а рамка светлее —
   до v3 было наоборот, и поле терялось на белом. */
.auth-card .field input{height:44px;background:var(--paper);border-color:var(--line);padding:0 14px;font-size:var(--t-md)}
/* Строка подписи: слева подпись, справа «Забыли пароль?» или требование к паролю */
.field-top{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);margin-bottom:6px}
.field-top label{margin-bottom:0}
.field-top .pw-forgot{font-size:var(--t-sm);font-weight:600;color:var(--marker-ink);text-decoration:none;transition:color var(--dur-fast) var(--ease)}
.field-top .pw-forgot:hover{color:var(--ink)}
.field-top .req{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted)}
/* Требование выполнено — подсказка гаснет. Зелёным (как .hint.done) не красим:
   зелёный по правилу цвета — только данные, а не «всё хорошо». */
.field-top .req.done{opacity:.45}
.auth-card .btn{width:100%;justify-content:center;padding:14px;font-size:var(--t-md);margin-top:20px}
.auth-sep{height:1px;background:var(--surface-2);margin:20px 0 var(--s-4)}
.auth-card.wide .auth-sep{margin:18px 0 14px}
/* Плашка внутри карточки: почта из приглашения, «отправить ещё раз», подсказки окна оплаты */
.auth-plate{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3) 14px;margin-top:18px}
.auth-plate.split{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3)}
.auth-plate .eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-variant-numeric:tabular-nums}
.auth-plate .val{font-size:var(--t-md);color:var(--ink);margin-top:5px}
/* «Отправить ещё раз» — слово-кнопка в плашке, а не .btn: пока идёт отсчёт,
   нажимать нечего, и полноценная кнопка обещала бы больше, чем может. */
.auth-plate .resend{background:none;border:none;padding:0;font-family:inherit;font-size:var(--t-base);color:var(--muted);cursor:pointer}
.auth-plate .resend:disabled{cursor:default}
.auth-plate .resend:not(:disabled):hover{color:var(--ink)}
.auth-plate .cnt{font-size:var(--t-base);font-weight:600;font-variant-numeric:tabular-nums;color:var(--muted)}
/* Ряд из двух равных кнопок: .actions прижимает вправо и не растягивает */
.auth-row{display:flex;gap:var(--s-2);margin-top:18px}
.auth-card .auth-row .btn{flex:1;width:auto;margin-top:0}
.auth-back{text-align:center;margin-top:var(--s-3)}
.auth-back a{font-size:var(--t-base);font-weight:600;color:var(--marker-ink);text-decoration:none;transition:color var(--dur-fast) var(--ease)}
.auth-back a:hover{color:var(--ink)}
/* Правовые ссылки живут под карточкой, а не в ней */
.auth-foot{display:flex;gap:14px;width:396px;max-width:100%;margin-top:var(--s-4);font-size:var(--t-sm);color:var(--muted)}
.auth-foot a{color:var(--muted);text-decoration:none;transition:color var(--dur-fast) var(--ease)}
.auth-foot a:hover{color:var(--ink)}
/* Точка вместо иконки — тот же приём, что у панели напоминания о почте (.vb-dot).
   Рисуем её псевдоэлементом, а не живым <i>: текст ошибки во всех формах
   ставится через textContent, и настоящего ребёнка он бы стирал. */
.auth-err{background:var(--err-bg);color:var(--err);border-radius:var(--r-1);padding:11px 13px;font-size:var(--t-sm);line-height:1.5;margin-top:10px;display:none;align-items:flex-start;gap:9px}
.auth-err::before{content:'';width:6px;height:6px;border-radius:var(--r-pill);background:var(--err);margin-top:6px;flex:none}
.auth-err.on{display:flex}
/* Погашенные чернила плейсхолдера. Роль занята сырым #B4B1A8 (.btn:disabled,
   .field input:disabled) — нового цвета не заводим. */
.field input::placeholder,.field textarea::placeholder{color:#B4B1A8}

/* Предпросмотр «Как у ученика» внутри карточки: тема урока со своим фоном */
.themed-preview{border-radius:var(--radius-sm);padding:var(--s-3);margin:0 -2px}

/* Панель редактирования внутри оформленной карточки блока: платформенные цвета
   островком, чтобы поля оставались читаемыми в любой теме урока. Отделяем её
   от оформленной части рамкой и фоном — видно, где кончается урок и начинается
   работа с ним. */
.beditor{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-3);margin-top:2px}
/* поля ввода на оформленной подложке: держим контраст за счёт --surface-2 темы */
.beditor .field input,.beditor .field textarea,.beditor .field select,.beditor .row input{
  background:var(--surface-2);border-color:var(--line)}

/* Служебные подписи конструктора — тип блока, переключатель, инструменты —
   набраны шрифтами платформы: тема урока задаёт им цвет, но не типографику,
   иначе serif-тема превращала служебные надписи в текст урока. */
.rail,.block .bhead,.block .seg,.block .btools,.beditor label,.beditor .hint,.beditor .btn,
.tnote-add,.tnote-field label{
  --font-head:'Onest',system-ui,sans-serif;
  --font-body:'Manrope',system-ui,sans-serif;
  font-family:var(--font-body);
}
.beditor .field:last-child,.beditor .row:last-child{margin-bottom:0}
/* Инструменты блока тоже платформенные: иконки не должны тонуть в тёмной теме */
.btools{border-radius:var(--r-1)}

/* Куда девать блок — под раскрытым блоком и словами, а не значками в шапке */
.bfoot{display:flex;gap:var(--s-4);flex-wrap:wrap;margin-top:var(--s-4);padding-top:14px;
  border-top:1px solid var(--line)}
/* Предпросмотр блока: ни номеров-инструментов, ни подписей типа — только то,
   что увидит ученик, и одно слово-выход. */
.bprev{border-radius:var(--r-1);padding:var(--s-4) 0 0}
.bprev-head{display:flex;justify-content:space-between;align-items:center;gap:var(--s-3);margin-bottom:14px}
.bprev-eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);font-variant-numeric:tabular-nums}
.bprev-exit{border:none;background:none;padding:0;cursor:pointer;font-weight:600;font-size:var(--t-sm);
  font-family:'Onest',system-ui,sans-serif;color:var(--ink-2)}
.bprev-exit:hover{color:var(--ink)}
.bprev .themed-preview{background:var(--surface);border-radius:var(--r-1);padding:14px;margin:0}
.bfoot button{border:none;background:none;padding:0;cursor:pointer;color:var(--muted);
  font-family:'Onest',system-ui,sans-serif;font-weight:600;font-size:var(--t-sm)}
.bfoot button:hover{color:var(--ink)}
/* На карточке заметки подложка маркерная, и приглушённый цвет на ней тонет
   (3.8 вместо 4.5): там свои чернила. */
.block.is-note .bfoot button,.block.is-note .btype{color:var(--note-ink)}
.block.is-note .bfoot{border-top-color:var(--note-line)}

/* ---------- Методические заметки преподавателя ----------
   Не маркерные: жёлтый закреплён за заметками на полях, которые видит ученик.
   Здесь наоборот — то, чего ученик не видит, поэтому пунктир и служебное моно. */
.tnote-add{display:inline-flex;align-items:center;gap:var(--s-2);margin-top:var(--s-3);padding:6px var(--s-3);
  border:1px dashed var(--line-2);border-radius:var(--radius-sm);background:none;color:var(--muted);
  font-family:var(--font-head);font-size:var(--t-sm);font-weight:600;cursor:pointer}
.tnote-add:hover{border-color:var(--ink);color:var(--ink)}
.tnote-add svg{width:14px;height:14px;flex-shrink:0}
.tnote-field{margin-top:var(--s-3)}
.tnote-field label{display:flex;align-items:center;gap:var(--s-1)}
.tnote-field label svg{width:13px;height:13px;flex-shrink:0}
.tnote-field textarea{border-style:dashed;background:var(--surface-2);resize:vertical}
.tnote-mark{margin-left:var(--s-1);color:var(--muted);display:inline-flex;align-items:center;flex-shrink:0}
/* «Здесь была картинка» — пометка переноса из учебника. Маркерная, в отличие от
   серой методической: это не запись преподавателя, а незакрытый долг урока. */
.img-mark{margin-left:var(--s-1);color:var(--marker);display:inline-flex;align-items:center;flex-shrink:0}

/* ---------- Разбор преподавателя в проверенной работе ----------
   Голос преподавателя, обращённый к ученику: сплошной кант акцентом темы урока,
   в отличие от пунктирной методической заметки (её ученик не видит вовсе) и от
   жёлтой заметки на полях. Маркер здесь не занимаем — он за заметками. */
.teacher-mark{display:flex;align-items:flex-start;gap:var(--s-3);margin-top:var(--s-3);padding:var(--s-3) var(--s-3);
  border-left:2px solid var(--accent);background:var(--surface-2);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.teacher-mark .tm-tag{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);padding-top:3px;flex-shrink:0}
.teacher-mark .tm-score{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);margin-bottom:3px}
.teacher-mark .tm-text{font-size:var(--t-md);line-height:1.55;color:var(--ink-2)}
/* Исправленный ответ в разборе: подсветка та же, что у преподавателя в очереди
   проверки. Сданный текст рядом не повторяем — он стоит выше, в самом задании,
   и два похожих абзаца подряд читаются как повтор, а не как сравнение. */
.teacher-mark .tm-fix{margin:3px 0 6px;font-size:var(--t-md);line-height:1.6;color:var(--ink)}
.teacher-mark .tm-fix-lab{display:block;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);margin-bottom:2px}

/* Полоса над проверенной работой: статус, оценка целиком, где искать разбор */
.review-bar{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-bottom:var(--s-3);
  padding:var(--s-3) var(--s-4);background:var(--ok-bg);border:1px solid var(--ok);
  border-radius:var(--radius-sm)}
.review-bar .rb-label{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);color:var(--ok)}
.review-bar .rb-score{font-family:var(--font-head);font-weight:700;font-size:var(--t-md)}

/* В классе: полоса поверх блока, только у преподавателя */
/* «ВАМ» — маркером: это то, что видит только преподаватель, одно из четырёх
   значений жёлтого («пришло от преподавателя», здесь — ему самому). Серым она
   читалась служебной сноской урока, которую ученик тоже видит. */
.tnote-live{display:flex;align-items:flex-start;gap:var(--s-2);margin:0 0 var(--s-3);padding:var(--s-2) var(--s-3);
  background:var(--marker-soft);border-radius:var(--radius-sm);
  font-size:var(--t-md);line-height:1.5;color:var(--marker-ink)}
.tnote-live .tl-tag{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.05em;
  color:var(--marker-ink);opacity:.75;padding-top:3px;flex-shrink:0}

/* Поле картинки в конструкторе: файл с компьютера + миниатюра */
.img-field{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-bottom:var(--s-2)}
.img-thumb{width:56px;height:42px;object-fit:cover;border-radius:var(--r-1);border:1px solid var(--line)}

/* ---------- Поиск слова по словарю (ученик) ---------- */
.ws{position:relative;display:flex;align-items:center;gap:var(--s-2);background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--r-pill);padding:var(--s-1) var(--s-3);min-width:220px;max-width:420px;width:100%}
.ws:focus-within{border-color:var(--ink)}
.ws .ws-ic{color:var(--muted);display:flex;flex-shrink:0}
.ws input{flex:1;min-width:0;border:none;background:none;outline:none;font-size:var(--t-base)}
.ws .ws-x{border:none;background:none;color:var(--muted);cursor:pointer;font-size:var(--t-sm);padding:2px var(--s-1)}
.ws .ws-x:hover{color:var(--ink)}
.ws-drop{display:none;position:absolute;top:calc(100% + 7px);left:0;right:0;z-index:60;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:var(--s-2);max-height:60vh;overflow:auto}
.ws-drop.on{display:block}
.ws-sec{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);padding:var(--s-2) var(--s-2) var(--s-1)}
.ws-row{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-2);border-radius:var(--radius-sm);font-size:var(--t-base)}
.ws-row:hover{background:var(--surface-2)}
.ws-row.muted{color:var(--muted)}
.ws-row .ws-en{font-weight:700;font-family:var(--font-head);flex-shrink:0}
.ws-row .ws-ru{color:var(--muted);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ws-row .ws-tag,.ws-sense .ws-tag{font-size:var(--t-label);color:var(--ok);font-weight:700;flex-shrink:0}

/* Карточка слова: заголовок с транскрипцией, значения по одному */
.ws-word{display:flex;align-items:baseline;gap:var(--s-2);padding:var(--s-2) var(--s-2) var(--s-1);border-top:1px solid var(--line);margin-top:var(--s-1)}
.ws-word .ws-en{font-family:var(--font-head);font-weight:700;font-size:var(--t-md)}
.ws-ipa{font-size:var(--t-sm);color:var(--muted)}
.ws-sense{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-1) var(--s-2);border-radius:var(--radius-sm)}
.ws-sense:hover{background:var(--surface-2)}
.ws-sense .ws-ru{font-size:var(--t-md);color:var(--ink);flex-shrink:0;font-weight:600}
.ws-pos{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.04em;
  color:var(--muted);border:1px solid var(--line-2);border-radius:5px;padding:1px var(--s-1);flex-shrink:0}
.ws-near{font-size:var(--t-sm);color:var(--muted);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ws-sense .ws-btn.add{min-width:30px;text-align:center;font-size:var(--t-md);line-height:1;padding:var(--s-1) var(--s-2)}
.ws-ex{font-size:var(--t-sm);color:var(--muted);padding:0 var(--s-2) var(--s-2) var(--s-2);font-style:italic}
.ws-eng{display:flex;gap:var(--s-2);align-items:baseline;padding:var(--s-1) var(--s-2);font-size:var(--t-base);line-height:1.5;color:var(--ink-2)}

/* В занятии строка поиска шире — это рабочий инструмент. Цветом её не выделяем:
   она часть хрома и не должна перекрашиваться темой урока. Ширина желаемая, а не
   обязательная: когда в шапке тесно, поиск уступает место первым (см. .top-actions),
   и нижняя граница здесь оставляет ровно столько, чтобы видеть набранное слово. */
.topbar .ws.big{flex:1 1 300px;min-width:110px;max-width:340px}
.ws-btn{border:1px solid var(--line-2);background:none;color:var(--ink-2);border-radius:var(--r-pill);
  padding:3px var(--s-3);font-size:var(--t-sm);font-weight:600;font-family:var(--font-head);cursor:pointer;flex-shrink:0}
.ws-btn:hover{border-color:var(--ink);color:var(--ink)}
.ws-btn.add{background:var(--marker-soft);border-color:var(--marker-soft);color:var(--marker-ink)}
/* В классе строка поиска стоит в верхней панели и не должна её распирать */
.topbar .ws{max-width:300px;min-width:170px}

/* ---------- Свои диалоги и выпадающие списки ----------
   Системные prompt/confirm и родной <select> открывают окна операционной
   системы — чужой шрифт и чужие кнопки посреди платформы. */
.modal.dlg{width:440px}

/* ---------- Устройство окна: шапка · середина · подвал ----------
   До v3 листалось окно целиком: у длинного списка уезжали и заголовок, и
   кнопки — на пятнадцати учениках «Отмена» оказывалась ниже края экрана, и
   выйти из окна можно было только Esc. Теперь листается одна середина, шапка
   и подвал стоят на месте. Класс .framed — на окнах, собранных modalShell();
   окна со своей разметкой (перенос, доступ) остаются как были,
   пока их не перевели. */
.modal.framed{padding:0;display:flex;flex-direction:column;overflow:hidden}
.modal.framed .mhead{flex-shrink:0;padding:var(--s-5) var(--s-5) 0;margin-bottom:0}
.modal.framed.dlg .mhead{padding:var(--s-4) var(--s-4) 0}
/* Заголовок окна — глагол, и набран как заголовок раздела: до v3 у h3.head
   в окне не было размера вовсе, и он читался вровень с текстом под собой. */
.modal.framed .mhead .head{font-size:var(--t-lg);font-weight:700;letter-spacing:-.02em;line-height:1.3}
/* Подпись под заголовком — одна строка, и только если без неё непонятно. */
.msub{font-size:var(--t-base);color:var(--muted);line-height:1.5;margin-top:5px}
.mbody{flex:1 1 auto;min-height:0;overflow:auto;padding:var(--s-4) var(--s-5) var(--s-5);
  display:grid;align-content:start;gap:var(--s-3)}
.modal.framed.dlg .mbody{padding:var(--s-4) var(--s-4) var(--s-4)}
/* Подвал: слева последствие словами или левое действие, справа «Отмена» и
   глагол. Одной строкой — переносить кнопки вниз некуда, окно и так узкое. */
.mfoot{flex-shrink:0;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
  gap:var(--s-3);padding:var(--s-3) var(--s-5);background:var(--paper);border-top:1px solid var(--line)}
.modal.framed.dlg .mfoot{padding:var(--s-3) var(--s-4)}
.mfoot-note{font-size:var(--t-sm);color:var(--muted);line-height:1.4;font-variant-numeric:tabular-nums}
.mfoot-left{display:flex;align-items:center;gap:var(--s-2);min-width:0}
.mfoot-btns{display:flex;align-items:center;gap:var(--s-2)}
/* Левое действие подвала («Назначить ему урок», «Вся страница», «В архив») —
   не кнопка: оно ведёт в сторону, а не завершает окно. */
.mfoot-act{border:none;background:none;border-radius:var(--r-1);padding:7px 11px;cursor:pointer;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--marker-ink);
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.mfoot-act:hover{background:var(--surface-2)}
a.mfoot-act{display:inline-flex;align-items:center;text-decoration:none}
.mfoot-act.danger{color:var(--err)}
.mfoot-act.danger:hover{background:var(--err-bg)}
/* «Изменения не сохранены» — под кнопками, вместо второго окна с вопросом. */
.mfoot-unsaved{grid-column:1/-1;justify-self:end;display:none;font-size:var(--t-sm);color:var(--muted)}
.mfoot-unsaved.on{display:block}
/* Шаг внутри окна: вместо второго окна поверх первого — «← Назад» в шапке и
   никакого подвала. */
.mhead.step{align-items:center}
.mhead.step>div{flex:1;min-width:0}
.mback{border:none;background:none;padding:0;cursor:pointer;flex-shrink:0;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--marker-ink);
  transition:color var(--dur-fast) var(--ease)}
.mback:hover{color:var(--ink)}
/* Текст подтверждения и плашка-последствие в середине окна. */
.mtext{font-size:var(--t-md);color:var(--ink-2);line-height:1.55}
.mplate{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3);
  font-size:var(--t-sm);color:var(--ink-2);line-height:1.5;font-variant-numeric:tabular-nums}
.mplate.bad{background:var(--err-bg);color:var(--err)}
/* Середина окна раздаёт поля сама, поэтому у вложенных компонентов свои
   нижние отступы и своя прокрутка снимаются: две прокрутки одна в другой
   ловят колесо мыши и не пускают список дальше первой строки. */
.mbody .field{margin-bottom:0}
.mbody .search-inp{width:100%}
.mbody .lp-search,.mbody .folder-chips{margin-bottom:0}
.mbody .lp-grid{max-height:none;overflow:visible;padding:0}
.mbody .empty{min-height:0;padding:var(--s-3) 0}
.mbody .row.tight .stu-ava{width:26px;height:26px;font-size:var(--t-label)}
.mbody .rv-hints,.mbody .mat-zone,.mbody .gen-opts,.mbody .cut-pages,.mbody .crop-zoom{margin:0}
.mbody .ws-sheet{max-height:none;overflow:visible;margin:0}
.mbody .hwp-sec{margin-bottom:0}
.mbody .seg{margin-bottom:0}
.mbody .sl-jump{margin-bottom:0}
/* Подпись-последствие рядом с левым действием подвала: в строке с «Убрать» она
   должна ужиматься, а не выталкивать кнопки окна за край. */
.mfoot-left .mfoot-note{min-width:0}

/* Ответ у утверждения True/False/NG — три кнопки вместо системного списка:
   вариантов всего три, выбирать их кликом быстрее, чем через выпадашку. */
.tf-pick{display:flex;gap:var(--s-1);flex-shrink:0}
.tf-pick .tf-btn{min-width:38px}

.usel{position:relative}
.usel-btn{display:flex;align-items:center;gap:var(--s-3);width:100%;text-align:left;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r-1);background:var(--surface);height:38px;
  padding:0 var(--s-3);font-size:var(--t-md);font-family:inherit;color:var(--ink)}
.usel-btn:hover{border-color:var(--line-2)}
.usel.open .usel-btn{border-color:var(--ink);background:var(--surface)}
.usel-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.usel-chev{color:var(--muted);font-size:var(--t-label);flex-shrink:0}
.usel-list{display:none;position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:70;
  background:var(--surface);border:none;border-radius:var(--r-1);
  box-shadow:var(--sh-3);padding:var(--s-1);max-height:260px;overflow:auto}
.usel.open .usel-list{display:block}
/* Вверх, когда снизу тесно (uselToggle в dialog.js) */
.usel.up .usel-list{top:auto;bottom:calc(100% + 5px)}
.usel-opt{display:flex;align-items:center;gap:var(--s-2);padding:var(--s-2) var(--s-3);border-radius:var(--r-1);cursor:pointer;font-size:var(--t-base)}
.usel-opt:hover{background:var(--surface-2)}
.usel-opt.on{background:var(--accent-soft);color:var(--accent-soft-ink);font-weight:600}

/* ---------- Настройки ----------
   Две колонки вместо сетки равных плиток: карточки читаются сверху вниз в одном
   порядке у всех, а слева стоит колонка разделов — она же показывает, где ты
   сейчас. Плитки на широком мониторе раскладывались в три столбца и меняли
   порядок вместе с шириной окна: «Профиль» оказывался то первым, то третьим. */
.set-grid{display:grid;grid-template-columns:208px minmax(0,1fr);gap:var(--s-5);align-items:start}
/* Лист держится тенью, а не рамкой — правило «рамка или тень, но не оба сразу». */
.set-card{background:var(--surface);border-radius:var(--r-2);padding:var(--s-5) 26px;box-shadow:var(--sh-2)}
.set-card h3{font-size:var(--t-lg);margin-bottom:0}
/* Отступ только у кнопки самой карточки («Сменить пароль»). Кнопки внутри
   строк-плашек стоят в ряду, и общий margin-top ронял их на строку ниже. */
.set-card>.btn{margin-top:var(--s-4)}
/* Строка внутри карточки — плашка на бумаге: r-1 внутри r-2 даёт вложенность
   без второй рамки. */
.set-row{display:flex;align-items:center;gap:var(--s-3);justify-content:space-between;flex-wrap:wrap;
  background:var(--paper);border-radius:var(--r-1);padding:13px 14px}
.set-row .sr-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.set-row .sr-s{font-size:var(--t-sm);color:var(--muted);margin-top:2px}
/* Собственный нижний отступ сегмента рассчитан на форму, а здесь он в строке. */
.set-row .seg{margin-bottom:0}
.set-rows{display:grid;gap:10px;margin-top:18px}

/* ---------- Тариф: карточка, сравнение, оплата, упор учеников ----------
   По макету тарифов (утверждён 3 сентября вместе с сеткой) и телефонному 12h.
   Полоса запросов жёлтая — работа модели; полоса учеников серая — обычный
   счётчик; ни одна не краснеет на исходе. Зелёные «Активен» и «без потолка до
   15 октября», жёлтые «Цена заморожена», «PRO» у имени и «за год −25 %» —
   собственные значения цвета этого макета, утверждённые вместе с ним. */
.plan-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-4)}
.plan-name{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-2)}
.plan-name>b{font-family:var(--font-head);font-size:var(--t-d1);font-weight:700;letter-spacing:-.025em;line-height:1.1}
.plan-pill{display:inline-flex;align-items:center;height:22px;padding:0 var(--s-2);border-radius:var(--r-pill);
  font-size:var(--t-label);font-weight:600;letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}
.plan-pill.ok{background:var(--ok-bg);color:var(--ok)}
.plan-pill.frozen,.plan-pill.hot{background:var(--marker-soft);color:var(--marker-ink)}
.plan-price{text-align:right;flex-shrink:0}
.plan-price b{display:block;font-family:var(--font-head);font-size:var(--t-lg);font-weight:700;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.plan-price span{font-size:var(--t-sm);color:var(--muted)}
.plan-legacy{background:var(--ok-bg);color:var(--ok);border-radius:var(--r-1);padding:var(--s-3) var(--s-3);margin-top:var(--s-4)}
.plan-legacy b{display:block;font-family:var(--font-head);font-size:var(--t-md)}
.plan-legacy p{font-size:var(--t-sm);margin:var(--s-1) 0 0;line-height:1.5}
/* Приём оплаты на паузе. Подложка как у счётчиков ниже: хром нейтральный, а жёлтый
   маркер только для заметок и выделения слов. */
.plan-pause{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3);margin-top:var(--s-3)}
.plan-pause b{display:block;font-family:var(--font-head);font-size:var(--t-lg);font-weight:700;letter-spacing:-.02em}
.plan-pause p{font-size:var(--t-md);margin:var(--s-1) 0 0;line-height:1.5;color:var(--ink-2)}
.plan-meters{display:grid;gap:var(--s-3);margin-top:var(--s-4)}
.plan-meter{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3) var(--s-3)}
.plan-meter-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);
  font-size:var(--t-base);color:var(--ink-2)}
.plan-meter-h b{font-family:var(--font-head);font-size:var(--t-md);color:var(--ink);font-variant-numeric:tabular-nums}
.plan-meter-h b i{font-style:normal;font-weight:500;font-size:var(--t-sm);color:var(--muted);margin-left:var(--s-1)}
.plan-meter .bar{margin:var(--s-2) 0 0}
.plan-meter .bar.open>span{background:linear-gradient(90deg,var(--marker) 0%,var(--marker-soft) 100%)}
.plan-meter-f{display:flex;align-items:center;justify-content:space-between;gap:var(--s-2);flex-wrap:wrap;
  margin-top:var(--s-2);font-size:var(--t-sm);color:var(--muted)}
.plan-warn{color:var(--marker-ink)}
.linkish{border:none;background:none;padding:0;cursor:pointer;font:inherit;color:var(--marker-ink)}
.linkish:hover{color:var(--ink)}
.plan-acts{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-4)}
.plan-when{margin-left:auto;font-size:var(--t-sm);color:var(--muted)}
/* Привязанная карта — строка под действиями: слева состояние, справа отказ от
   него. Черта сверху отделяет её от кнопок, чтобы «Отвязать карту» не читалось
   продолжением ряда кнопок. */
.plan-card-row{display:flex;align-items:center;justify-content:space-between;gap:var(--s-2);flex-wrap:wrap;
  margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--line);
  font-size:var(--t-sm);color:var(--muted)}
.plan-foot{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-3);line-height:1.5}

.plans-head{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3)}
.plans-head .seg{margin:0}
.plans-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-2)}
.plans-col{background:var(--paper);border-radius:var(--r-2);padding:var(--s-4);display:flex;flex-direction:column;min-width:0}
.plans-col.top{box-shadow:0 0 0 2px var(--ink)}
.plans-col-h{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}
.plans-col-h b{font-family:var(--font-head);font-size:var(--t-lg);font-weight:700}
.plans-col .for,.plans-one .for{font-size:var(--t-sm);color:var(--ink-2);margin-top:var(--s-1);line-height:1.45}
.plans-col .price,.plans-one .price{font-family:var(--font-head);font-size:var(--t-d1);font-weight:700;
  letter-spacing:-.025em;font-variant-numeric:tabular-nums}
.plans-col .price{margin-top:var(--s-2)}
.plans-col .price-s,.plans-one .price-s{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-1)}
.plans-btn-wrap{margin-top:auto;padding-top:var(--s-3)}
.plans-btn-wrap .btn{width:100%;justify-content:center}
.plans-rows{display:grid;margin-top:var(--s-3)}
.plans-row{display:grid;grid-template-columns:minmax(0,1.4fr) repeat(3,minmax(0,1fr));gap:var(--s-2);align-items:center;
  padding:var(--s-2) 0;border-top:1px solid var(--line);font-size:var(--t-base)}
.plans-row>span:first-child{color:var(--ink-2)}
.plans-row>span+span{font-weight:600;font-variant-numeric:tabular-nums}
.plans-row .yes{color:var(--ok);font-weight:500}
.plans-note{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-3);line-height:1.5}
.plans-switch{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-2);background:var(--surface-2);
  border-radius:var(--r-1);padding:var(--s-1)}
.plans-switch button{height:44px;border:none;border-radius:8px;background:transparent;font-family:var(--font-head);
  font-size:var(--t-base);font-weight:600;color:var(--ink-2);cursor:pointer}
.plans-switch button.on{background:var(--surface);color:var(--ink);box-shadow:var(--sh-1)}
.plans-one{background:var(--surface);border-radius:var(--r-2);padding:var(--s-4);margin-top:var(--s-2);box-shadow:var(--sh-1)}
.plans-one .plan-name{margin-top:0;align-items:baseline}
.plans-one .diff{display:grid;gap:var(--s-2);margin-top:var(--s-3)}
.plans-one .diff div{display:flex;gap:var(--s-2);align-items:baseline;font-size:var(--t-md);color:var(--ink-2)}
.plans-one .diff b{font-family:var(--font-head);font-size:var(--t-lg);color:var(--ink);min-width:32px}
.plans-one .diff i{font-style:normal;color:var(--muted)}
.plans-pin{margin-top:var(--s-4)}
.plans-pin .btn{width:100%;min-height:52px;justify-content:center;font-size:var(--t-md)}
.plans-pin .plans-note{text-align:center;margin-top:var(--s-2)}

.pay-opts{display:grid;gap:var(--s-2)}
.pay-opt{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:var(--s-3);align-items:center;width:100%;
  text-align:left;background:var(--paper);border:none;border-radius:var(--r-1);padding:var(--s-3);cursor:pointer;
  font:inherit;color:var(--ink)}
.pay-opt.on{box-shadow:0 0 0 2px var(--ink)}
.pay-opt .dot{width:16px;height:16px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--line-2);
  display:flex;align-items:center;justify-content:center}
.pay-opt.on .dot{background:var(--ink);box-shadow:none}
.pay-opt.on .dot::after{content:'';width:6px;height:6px;border-radius:50%;background:var(--surface)}
.pay-opt b{display:block;font-family:var(--font-head);font-size:var(--t-md)}
.pay-opt small{display:block;font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-1)}
.pay-opt strong{font-family:var(--font-head);font-size:var(--t-lg);font-variant-numeric:tabular-nums}
.pay-diff{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3);margin-top:var(--s-3);display:grid;gap:var(--s-2)}
.pay-diff div{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);
  font-size:var(--t-base);color:var(--ink-2)}
.pay-diff b{font-family:var(--font-head);color:var(--ink);font-variant-numeric:tabular-nums}
.pay-note{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-3);line-height:1.5}
.pay-note.warn{color:var(--ink-2)}
/* Про галочку «Запомнить данные карты» — отдельной плашкой, а не подписью:
   человек решает это на следующем экране, у ЮKassa, и слова о ней не должны
   теряться среди условий тарифа. */
.pay-card{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3);margin-top:var(--s-3);
  font-size:var(--t-sm);color:var(--ink-2);line-height:1.5}

.cap-box{background:var(--paper);border-radius:var(--r-1);padding:var(--s-3);margin-top:var(--s-4)}
.cap-list{display:grid;gap:var(--s-2);margin-top:var(--s-2)}
.cap-row{display:grid;grid-template-columns:32px minmax(0,1fr) auto;gap:var(--s-3);align-items:center;
  background:var(--surface);border-radius:var(--r-1);padding:var(--s-2) var(--s-3);box-shadow:var(--sh-1)}
.cap-ava{width:32px;height:32px;border-radius:50%;background:var(--surface-2);display:flex;align-items:center;
  justify-content:center;font-family:var(--font-head);font-size:var(--t-sm);font-weight:600;color:var(--muted)}
.cap-name{font-family:var(--font-head);font-size:var(--t-base);font-weight:600}
.cap-why{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-1)}
.cap-row.done{opacity:.55}
.cap-note{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-2)}
.cap-offer{border-top:1px solid var(--line);margin-top:var(--s-4);padding-top:var(--s-3)}
.cap-offer-t{font-family:var(--font-head);font-size:var(--t-base);font-weight:600}
.cap-offer-s{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-1)}

.plan-tag{display:inline-flex;align-items:center;height:20px;padding:0 var(--s-2);border-radius:var(--r-pill);
  background:var(--marker-soft);color:var(--marker-ink);font-size:var(--t-label);font-weight:600;letter-spacing:.08em}
@media(max-width:640px){
  .plan-when{margin-left:0;width:100%}
  .plans-row{grid-template-columns:minmax(0,1.2fr) repeat(3,minmax(0,1fr));font-size:var(--t-sm)}
}

/* Служебная строка в шапке: «На платформе с … · 134 ученика». Раньше это была
   отдельная карточка «Аккаунт» во весь лист, хотя решить по этим числам нечего. */
.set-since{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums;padding-bottom:var(--s-1)}

/* Колонка разделов. Липнет ниже верхней панели (52 + 20), иначе первый пункт
   уезжает под неё вместе со страницей. */
.set-nav{background:var(--surface);border-radius:var(--r-2);padding:var(--s-3) 10px;box-shadow:var(--sh-1);
  position:sticky;top:72px;display:grid;gap:2px;align-content:start}
/* Седьмой пункт колонки — за чертой и приглушённый: это не раздел настроек. */
.set-nav-sep{height:1px;background:var(--line);margin:var(--s-3) 0}
.set-nav-quiet{border:none;background:none;text-align:left;cursor:pointer;color:var(--muted);
  font-family:var(--font-head);font-size:var(--t-sm);padding:var(--s-2) var(--s-3)}
.set-nav-quiet:hover{color:var(--ink-2)}
.set-nav button{display:flex;align-items:center;gap:var(--s-2);width:100%;text-align:left;border:none;
  background:none;border-radius:var(--r-1);padding:9px var(--s-3);font-family:var(--font-head);font-weight:500;
  font-size:var(--t-base);color:var(--ink-2);cursor:pointer;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.set-nav button>span:first-child{flex:1;min-width:0}
.set-nav button:hover{background:var(--surface-2)}
.set-nav button.on{background:var(--ink);color:var(--paper);font-weight:600}
/* У «Тарифа и оплаты» — название тарифа тихой подписью, а не счётчик: расход и
   так виден в меню слева и в карточке (владелец 15 сентября). На активном пункте
   фон чернильный, и приглушённый цвет на нём пропал бы — берём цвет бумаги. */
.set-nav .set-nav-plan{flex-shrink:0;font-size:var(--t-sm);font-weight:500;color:var(--muted)}
.set-nav button.on .set-nav-plan{color:var(--paper);opacity:.72}

/* Правая колонка. Шире 640 строка настройки читается хуже: глаз теряет, к
   какому полю относится подпись справа. */
.set-body{max-width:640px;display:grid;gap:var(--s-4);align-content:start}
.set-sub{font-size:var(--t-md);line-height:1.55;color:var(--ink-2);margin-top:5px}
.set-tail{font-size:var(--t-sm);line-height:1.5;color:var(--muted);margin-top:var(--s-3)}
/* Поле в настройках выше и на бумаге: карточка теперь белая, и поле цвета
   карточки на ней не читалось как поле. Правка местная — на других экранах
   поле осталось прежним. */
.set-body .field input{height:auto;padding:11px 13px;background:var(--paper)}
.set-body .field label{font-weight:600;color:var(--muted)}
.set-body .field{margin-bottom:0}

/* Профиль: аватар слева, три поля справа. */
.prof-row{display:flex;gap:18px;align-items:flex-start;margin-top:18px}
.prof-photo{display:flex;flex-direction:column;align-items:center;flex-shrink:0}
.prof-photo .stu-ava{width:68px;height:68px;background:var(--surface-2);color:var(--ink-2);
  font-size:24px;font-weight:700}
.prof-photo .quiet-act{margin-top:var(--s-2)}
.prof-fields{flex:1;min-width:0;display:grid;gap:14px}
/* Тихое действие словом: «Фото», «Сделать основным», «Отправить письмо». Кнопкой
   они спорили бы с главным действием карточки, а действий этих по два на лист. */
.quiet-act{border:none;background:none;font-family:var(--font-head);font-weight:600;
  font-size:var(--t-sm);color:var(--muted);cursor:pointer;padding:2px 0;white-space:nowrap;
  transition:color var(--dur-fast) var(--ease)}
.quiet-act:hover{color:var(--ink)}
.quiet-act.mark{color:var(--marker-ink)}
.quiet-act.mark:hover{color:var(--ink)}
/* Плашка внутри поля: «НЕ ПОДТВЕРЖДЕНА» стоит у правого края почты, поэтому
   полю оставлено место под неё. */
.in-wrap{position:relative;display:flex}
.in-wrap>input{flex:1;min-width:0}
.in-wrap .in-tag{position:absolute;right:8px;top:50%;transform:translateY(-50%)}
.in-wrap.tagged>input{padding-right:136px}
.field-note{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-top:var(--s-2);
  font-size:var(--t-sm);line-height:1.45;color:var(--ink-2)}
.two-fields{display:flex;gap:14px;margin-top:18px}
.two-fields .field{flex:1;min-width:0}
.two-fields input{font-variant-numeric:tabular-nums}

/* Плашка с переключателем: «Пропуск списывает занятие с абонемента». */
.set-plate{background:var(--paper);border-radius:var(--r-1);padding:14px;margin-top:14px;
  display:flex;gap:var(--s-3);align-items:flex-start}
.set-plate .sw-pill{margin-top:2px}
.set-plate .sp-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.set-plate .sp-s{font-size:var(--t-sm);line-height:1.55;color:var(--ink-2);margin-top:3px}

/* Переключатель-пилюля. Свой, а не системный чекбокс: системный не красится и
   в тёмной теме остаётся светлым пятном. Имя .sw из спеки занято заметкой на
   полях (.sticky .sw) — голое правило .sw перекрасило бы её текст. */
.sw-pill{position:relative;flex-shrink:0;width:34px;height:20px;padding:2px;border:none;
  border-radius:var(--r-pill);background:var(--line);cursor:pointer;
  transition:background var(--dur-fast) var(--ease)}
.sw-pill>i{display:block;width:16px;height:16px;border-radius:var(--r-pill);background:var(--surface);
  box-shadow:0 1px 2px rgba(23,26,33,.15);transition:transform var(--dur-fast) var(--ease)}
.sw-pill.on{background:var(--ink)}
.sw-pill.on>i{background:var(--paper);box-shadow:none;transform:translateX(14px)}

/* Сегмент с белой активной кнопкой: общий .seg красит активную чернилами, и на
   плашке-строке чёрная кнопка читалась как главное действие карточки. */
.seg.soft{background:var(--surface-2);box-shadow:none}
.seg.soft button{padding:6px var(--s-3)}
.seg.soft button.on{background:var(--surface);color:var(--ink);box-shadow:var(--sh-1)}

/* Полоса сохранения — одна на весь экран. Приходит снизу и называет
   изменённое: три кнопки «Сохранить» по карточкам оставляли половину правок
   несохранёнными, потому что вторая кнопка стояла ниже сгиба. */
/* Полоса сохранения тёмная в обеих темах: это плашка поверх страницы, и
   чернила здесь — заливка, а не текст. От var(--ink) она в тёмной теме
   становилась светлой, а кнопка на ней — белой с белой надписью. */
.save-bar{position:sticky;bottom:20px;z-index:30;margin-top:var(--s-2);background:#171A21;
  border-radius:var(--r-2);padding:14px 18px;box-shadow:var(--sh-3);
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  opacity:0;transform:translateY(14px);
  transition:opacity var(--dur-slow) var(--ease-s),transform var(--dur-slow) var(--ease-s)}
.save-bar.on{opacity:1;transform:none}
.save-bar .sb-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:#F2F1EE}
.save-bar .sb-acts{display:flex;gap:var(--s-2);flex-shrink:0}
.save-bar .sb-quiet{border:none;background:none;color:#8C8C86;font-family:var(--font-head);
  font-weight:600;font-size:var(--t-sm);border-radius:var(--r-1);padding:var(--s-2) 14px;cursor:pointer;
  transition:color var(--dur-fast) var(--ease)}
.save-bar .sb-quiet:hover{color:#E9E9E6}
.save-bar .sb-main{border:none;background:#F2F1EE;color:#171A21;font-family:var(--font-head);
  font-weight:600;font-size:var(--t-sm);border-radius:var(--r-1);padding:var(--s-2) var(--s-4);cursor:pointer}
.save-bar .sb-main:hover{background:#fff}
/* «Вернуть как было» в полосе после сохранения: жёлтым, как всякая отмена
   только что сделанного. */
.save-bar .sb-undo{border:none;background:none;color:var(--marker);font-family:var(--font-head);
  font-weight:600;font-size:var(--t-sm);border-radius:var(--r-1);padding:var(--s-2) 14px;cursor:pointer}
.save-bar .sb-undo:hover{background:rgba(255,255,255,.10)}
/* Ошибка — рельсой, как у поля: красный на платформе значит «ошибка», и это
   единственное, что он значит. Заливку полосы он не трогает. */
.save-bar.bad{border-left:3px solid var(--err);padding-left:15px}
/* После сохранения в полосе остаётся одно действие — «Вернуть как было».
   Прятали весь ряд целиком, и отменить сохранённое было нечем. */
.save-bar.done .sb-acts .sb-quiet,.save-bar.done .sb-acts .sb-main{display:none}
@media (prefers-reduced-motion:reduce){.save-bar{transition:none}}

/* Колонка разделов на узком экране встаёт рядом строкой и перестаёт липнуть:
   липкий блок во всю ширину съедал бы половину видимой страницы. */
@media(max-width:1000px){
  .set-grid{grid-template-columns:1fr}
  .set-nav{position:static;display:flex;flex-wrap:wrap;gap:var(--s-1)}
  .set-nav button{width:auto}
  .set-body{max-width:none}
}

/* Окно сбора домашки: раздел «Домашка» и задания урока в одном списке */
.mhead{display:flex;align-items:flex-start;gap:var(--s-3);margin-bottom:var(--s-4)}
.mhead>div:first-child{flex:1;min-width:0}
.mrow{display:flex;align-items:center;gap:var(--s-2);margin-top:var(--s-4);padding-top:var(--s-3);border-top:1px solid var(--line);flex-wrap:wrap}
.hwp-sec{margin-bottom:var(--s-4)}
.hwp-sec-head{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);padding-bottom:var(--s-1);border-bottom:1px solid var(--line);margin-bottom:var(--s-1)}
.hwp-row{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-2) var(--s-1);border-radius:var(--radius-sm);cursor:pointer}
.hwp-row:hover{background:var(--surface-2)}
.hwp-row.on{background:var(--accent-soft)}
.hwp-row .hwp-ic{color:var(--muted);display:flex;flex-shrink:0}
.hwp-row .hwp-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--t-base)}
.hwp-row .hwp-type{font-size:var(--t-sm);color:var(--muted);flex-shrink:0}
.hw-add{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-bottom:var(--s-3)}
.ap-note{padding:var(--s-2) var(--s-3) 2px;line-height:1.45;border-top:1px solid var(--line);margin-top:var(--s-1)}

/* Переключатель разделов урока в рельсе: занятие и домашка */
.rail-tabs{display:flex;gap:var(--s-1);margin-bottom:var(--s-3)}
.rail-tabs .rt{border:1px solid transparent;background:var(--surface);border-radius:var(--r-pill);
  box-shadow:var(--sh-1);padding:var(--s-2) var(--s-3);font-family:var(--font-head);font-weight:600;
  font-size:var(--t-sm);color:var(--ink-2);cursor:pointer;display:flex;align-items:center;gap:7px;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.rail-tabs .rt:hover{background:var(--surface-2);color:var(--ink)}
.rail-tabs .rt.on{background:var(--ink);color:var(--paper);box-shadow:none}
.rail-tabs .rt-n{font-variant-numeric:tabular-nums;font-size:var(--t-label);opacity:.55}

/* ---------- Черновик урока ---------- */
/* Метка нейтральная, не маркерная: маркер закреплён за заметками. */
.draft-tag{font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:500;text-transform:uppercase;
  letter-spacing:.04em;color:var(--muted);border:1px solid var(--line-2);border-radius:5px;
  padding:1px var(--s-1);vertical-align:middle;white-space:nowrap}
.btn.draft{border-color:var(--line-2);color:var(--ink-2);font-weight:600}
.btn.draft:hover{border-color:var(--ink);color:var(--ink)}

/* ---------- Поле пароля с кнопкой показа ---------- */
.pw-wrap{position:relative;display:flex}
/* Место под слово, а не под значок: глаз читался одинаково и как «показать»,
   и как «скрыть». Отступ считаем по самому длинному из двух слов. */
.pw-wrap input{flex:1;padding-right:74px}
.pw-word{position:absolute;right:10px;top:50%;transform:translateY(-50%);border:none;background:none;
  font-family:var(--font-body);font-size:var(--t-sm);color:var(--muted);cursor:pointer;padding:0;
  transition:color var(--dur-fast) var(--ease)}
.pw-word:hover{color:var(--ink)}
/* Требование выполнено — подсказка гаснет */
.hint.done{color:var(--ok);opacity:.65}

.auth-links{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;font-size:var(--t-base);color:var(--ink-2)}
.auth-links a{font-weight:600;text-decoration:none;color:var(--marker-ink)}
.auth-links a:hover{text-decoration:underline}
/* Строка про учеников под ссылкой «создать аккаунт»: вход у всех общий, и
   отдельной двери для ученика искать не надо. */
.auth-note{margin-top:7px}
.consent{display:flex;align-items:flex-start;gap:var(--s-2);margin:var(--s-1) 0 var(--s-1);cursor:pointer;line-height:1.45}
.consent input{margin-top:2px;flex-shrink:0}
/* На карточке входа галочка своя. Настоящий input не прячем размером и не
   снимаем с потока насовсем: невидимому required-полю браузер не может
   показать своё сообщение и молча отменяет отправку — поэтому он лежит
   поверх коробки в тех же 18×18. */
.auth-card .consent{position:relative;margin:20px 0 0;line-height:1.5}
.auth-card .consent input{position:absolute;left:0;top:1px;width:18px;height:18px;margin:0;opacity:0;cursor:pointer}
/* Радиус 5 на шкалу не ложится (--r-1 = 10 для 18-пиксельной коробки слишком
   круглый) — оставлен сырым как исключение размера. */
.auth-card .consent .box{width:18px;height:18px;flex:none;margin-top:1px;border:1px solid var(--line-2);border-radius:5px;
  background:var(--surface);display:flex;align-items:center;justify-content:center;font-size:var(--t-label);line-height:1;color:transparent;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}
.auth-card .consent .box::before{content:'✓'}
.auth-card .consent input:checked+.box{background:var(--ink);border-color:var(--ink);color:var(--marker)}
.auth-card .consent input:focus-visible+.box{box-shadow:0 0 0 2px var(--ink)}
.auth-card .consent .small{color:var(--ink-2)}
.auth-card .consent a{color:var(--marker-ink)}
/* Между согласием и кнопкой 16: промахнуться мимо галочки и попасть в кнопку
   должно быть труднее, чем раньше. */
.auth-card .consent+.btn{margin-top:var(--s-4)}

/* ---------- Регистрация преподавателя: обещание слева, форма справа ---------- */
.auth-card.wide{width:736px;padding:0;overflow:hidden;display:grid;grid-template-columns:280px 1fr}
.auth-card.wide .auth-form{padding:var(--s-5)}
/* Цвета тёмной половины — лендинговые --lp-dark*: регистрация стоит следующим
   экраном после лендинга, шестую пару чернил заводить незачем. */
.auth-pitch{background:var(--lp-dark);color:var(--lp-dark-ink);padding:var(--s-5);display:flex;flex-direction:column;justify-content:space-between}
.auth-pitch .eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--marker);font-variant-numeric:tabular-nums}
.auth-pitch h2{font-size:var(--t-h1);font-weight:700;line-height:1.2;letter-spacing:-.025em;margin-top:var(--s-3)}
.auth-pitch ul{display:grid;gap:var(--s-3);margin-top:22px;list-style:none}
.auth-pitch li{display:flex;gap:10px;font-size:var(--t-md);line-height:1.5;color:var(--lp-dark-ink-2)}
.auth-pitch li::before{content:'';width:5px;height:5px;flex:none;margin-top:7px;border-radius:var(--r-pill);background:var(--marker)}
/* После шагов лендинга тёмной половины нет, форма стоит одна по центру — как в
   макете шага 6. Довод — в разметке регистрации. Ширина формы та же, что была
   правой колонкой, чтобы поля не поменяли длину между заходами. */
.from-tour .auth-pitch{display:none}
@media(min-width:641px){.from-tour .auth-card.wide{width:456px;grid-template-columns:1fr}}
.auth-pitch .pitch-foot{border-top:1px solid var(--lp-dark-line);padding-top:var(--s-4);margin-top:26px;
  font-size:var(--t-sm);line-height:1.5;color:var(--lp-dark-muted);font-variant-numeric:tabular-nums}
/* На узком экране колонки складываются в одну, но тёмная половина остаётся:
   условия Free нужны как раз тем, кто пришёл с телефона. */
@media(max-width:760px){
  .auth-card.wide{width:396px;grid-template-columns:1fr}
  .auth-wrap.wide .auth-logo{width:396px}
}

/* ---------- Вход и восстановление пароля на телефоне ----------

   Карточка на 390 перестаёт быть карточкой. Тень и скругление вокруг формы,
   которая и так занимает весь экран, обводят рамкой пустоту, а посередине
   экрана остаётся столбик полей с воздухом сверху и снизу. Здесь экран и есть
   форма: знак и заголовок сверху, поля во всю ширину, «Войти» внизу, под
   большим пальцем, а не сразу под последним полем — до верха дотянуться одной
   рукой нельзя.

   Кегль поля 16, а не 14. Ниже шестнадцати Safari на iOS сам приближает
   страницу, когда попадаешь в поле, и обратно уже не отдаляет: пароль
   дописывают в увеличенном и съехавшем вбок экране. Это не про читаемость —
   про то, что из поля нельзя выйти, не потеряв вид страницы.

   Широкую карточку регистрации преподавателя правило не трогает: у неё тёмная
   половина с обещанием и своя разбивка по шагам. */
@media(max-width:640px){
  .auth-wrap:not(.wide){justify-content:flex-start;padding:0;min-height:100dvh}
  .auth-wrap:not(.wide) .auth-logo{width:auto;align-self:stretch;margin:22px 16px 0}
  /* min-height:0 обязателен обоим: без него флексбокс не даёт колонке сжаться
     ниже её собственного содержимого, и экран перерастал видимую высоту на
     два-три пикселя — ровно настолько, чтобы под кнопкой появилась полоса
     прокрутки. Снизу оставляем воздух и место под домашнюю полосу телефона:
     кнопка, прижатая к самому краю, нажимается через раз. */
  .auth-card:not(.wide){width:auto;max-width:none;background:none;box-shadow:none;
    border-radius:0;padding:22px 16px calc(12px + env(safe-area-inset-bottom));
    flex:1;min-height:0;display:flex;flex-direction:column}
  .auth-card:not(.wide):not(.compact) h1{font-size:30px;letter-spacing:-.02em}
  .auth-card:not(.wide) .sub{font-size:var(--t-md);line-height:1.55;color:var(--ink-2)}
  /* Форма забирает остаток экрана — только так кнопка встаёт внизу, а не
     подтягивается вслед за последним полем. */
  .auth-card:not(.wide) form{display:flex;flex-direction:column;flex:1;min-height:0}
  /* Радиус берём из шкалы (16), а не 14 из макета: у платформы радиусов три,
     и четвёртый ради одного экрана — начало расхождения. */
  .auth-card:not(.wide) .field input{height:54px;border-radius:var(--r-2);font-size:var(--t-lg)}
  .auth-card:not(.wide) form .btn{min-height:54px;font-size:var(--t-lg);margin-top:auto}
  /* Разделитель и ссылка «создать аккаунт» остаются под кнопкой: это выход со
     страницы, а не второе главное действие. */
  .auth-card:not(.wide) .auth-sep{margin:18px 0 14px}
  /* Строка «ученик входит здесь же» на телефоне поднимается к заголовку.
     Внизу она стояла бы за кнопкой, ниже сгиба, — а нужна она до того, как
     человек решит, туда ли он попал.

     Двигаем ровно её одну, а порядок задаём всем детям карточки. Ребёнок без
     order у флексбокса идёт ПЕРЕД любым положительным: стоило поднять одну
     строку, как «Вернуться ко входу» и «Ученикам: если почта не подходит»
     уехали выше заголовка на смене пароля. */
  .auth-card:not(.wide)>*{order:2}
  .auth-card:not(.wide)>h1{order:0}
  .auth-card:not(.wide)>.sub,.auth-card:not(.wide)>.auth-note{order:1}
  .auth-card:not(.wide)>.auth-note{margin-top:8px}
  .auth-wrap:not(.wide) .auth-foot{width:auto;align-self:stretch;margin:var(--s-4) 16px 18px}
}

/* ---------- Выбор одним касанием ----------

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

   Имя не .lang-pick: под тем уже живёт выпадающий список языка урока в
   конструкторе (ниже по файлу), и его display:inline-block молча выигрывал у
   здешнего flex — галочка прилипала к слову вместо правого края. */
.onepicks{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:7px}
.onepick{font:inherit;font-weight:600;font-size:var(--t-base);color:var(--ink);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-pill);
  padding:9px 15px;cursor:pointer;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.onepick:hover{border-color:var(--line-2)}
.onepick.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.onepick:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ink)}

/* ---------- Регистрация преподавателя на телефоне: три шага ----------

   Полей на форме пять, и на 390 они выстраиваются в столбик длиной в полтора
   экрана: имя, почта, пароль, пять языков и согласие. Пролистать его можно,
   но ответить на вопрос «сколько ещё осталось» нечем, а первый же отказ формы
   («проверьте почту») случается за пределами видимого.

   Поэтому по одному вопросу на экран, с полосой хода наверху. Форма при этом
   остаётся одна: аккаунт заводится одним запросом, и закрытая на втором шаге
   вкладка не должна оставлять в базе половину человека. */
.reg-top{display:none;align-items:center;gap:var(--s-3);margin:var(--s-3) 0}
.reg-back{width:44px;height:44px;margin-left:-10px;flex:none;border:none;background:none;
  font-size:20px;line-height:1;color:var(--ink);cursor:pointer}
.reg-back[hidden]{display:none}
.reg-bar{flex:1;height:3px;background:var(--line);border-radius:var(--r-pill);overflow:hidden}
.reg-bar i{display:block;height:100%;width:33%;background:var(--ink);border-radius:inherit;
  transition:width var(--dur-base) var(--ease)}
.reg-n{flex:none;font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}

@media(max-width:640px){
  /* Карточка регистрации становится экраном по тем же причинам, что и вход:
     рамка вокруг формы во весь экран обводит пустоту.

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

     Верх ужат до нужного: знак, полоса шагов, заголовок — и сразу поля. */
  .auth-wrap.wide{justify-content:flex-start;padding:0;min-height:100dvh}
  .auth-wrap.wide .auth-logo{width:auto;align-self:stretch;margin:14px 16px 0}
  .auth-card.wide{width:auto;max-width:none;background:none;box-shadow:none;border-radius:0;
    overflow:visible;display:flex;flex-direction:column;flex:1;min-height:0}
  .auth-card.wide .auth-pitch{display:none}
  .auth-card.wide .auth-form{padding:10px 16px calc(12px + env(safe-area-inset-bottom));
    display:flex;flex-direction:column;flex:1;min-height:0}
  .auth-card.wide form{display:flex;flex-direction:column;flex:1;min-height:0}
  .auth-card.wide h1{font-size:24px;letter-spacing:-.02em}
  .auth-card.wide .sub{font-size:var(--t-md);line-height:1.5;color:var(--ink-2)}
  .auth-card.wide .field{margin-bottom:var(--s-3)}
  .auth-card.wide .field input{height:54px;border-radius:var(--r-2);font-size:var(--t-lg)}
  .auth-card.wide form .btn{min-height:54px;font-size:var(--t-lg);margin-top:auto}
  .auth-card.wide .auth-sep{margin:18px 0 14px}
  .reg-top{display:flex}
  .reg-step[hidden]{display:none}
  .auth-card.wide.deep .auth-sep,.auth-card.wide.deep .auth-links{display:none}
  /* Подпись поля и требование к паролю повторяли бы заголовок шага и его
     объяснение слово в слово — на шаге со своим заголовком строку подписи
     убираем целиком. */
  .reg-step[data-title] .field>label,.reg-step[data-title] .field-top{display:none}
  /* Языки на экране-вопросе — строки во всю ширину: пилюли в две неровные
     линии по 44 не набирают, а отмеченное приходится искать по заливке. В окне
     сборки тот же компонент остаётся рядом пилюль: там вариантов три коротких,
     и они встают в строку. */
  /* Пять строк по 54 с промежутками по 8 не оставляли места кнопке: экран
     регистрации перерастал видимую высоту и его приходилось листать. 48 —
     всё ещё выше порога в 44, ниже которого на телефоне не опускаемся. */
  .reg-step .onepicks{display:grid;gap:6px}
  .reg-step .onepick{display:flex;align-items:center;justify-content:space-between;
    min-height:48px;padding:0 16px;border-radius:var(--r-2);font-size:var(--t-lg)}
  .reg-step .onepick.on::after{content:'✓';font-size:var(--t-md)}
}

/* ---------- Конструктор на телефоне ----------

   Урок правят списком. Строка блока называет его содержимым и раскрывается
   нажатием; порядок меняют «Выше» и «Ниже» из меню «⋯» — перетаскивание
   осталось на широком экране, где для него есть рельса.

   Что уходит с экрана: сама рельса (тот же список вторым экземпляром),
   «+» между карточками (вместо них «Добавить блок» в хвосте), имя типа и
   плашка «в работе» (в 296 пикселях строки название блока сжималось до одной
   буквы — «I…», «S…», — и список переставал называть хоть что-нибудь).

   Что приходит: нижняя полоса с «Выдать ученику» и «⋯». Верх остаётся про
   «где я и как выйти», низ — про то, что с уроком сделать. */
.bld-bar{display:none}
.bld-tail{display:none}
/* Выход из конструктора там, где урок кончается. В шапке «Закрыть» стоит
   пятой кнопкой среди значков, и его ищут: конструктор из тех экранов, где
   непонятно, чем работа заканчивается и не потеряется ли она. Строка отвечает
   на оба вопроса сразу. */
.bld-exit{display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);
  flex-wrap:wrap;margin-top:var(--s-5);padding-top:var(--s-4);
  border-top:1px solid var(--line);font-size:var(--t-base);color:var(--muted)}
@media(max-width:640px){
  .bld-exit{margin-top:var(--s-4);gap:var(--s-3)}
  .bld-exit .btn{width:100%;min-height:48px;justify-content:center}
}

@media(max-width:640px){
  /* Вторичная кнопка на телефоне получает контур. По правилу «рамка или тень,
     но не обе» она держится на тени sh-1 — на настольном экране этого хватает,
     а на телефоне мягкая тень в один пиксель не читается вовсе, и белая кнопка
     на бумажном фоне выглядит подписью. Контур внутренний: он не двигает
     геометрию и не спорит с тенью. */
  .btn:not(.primary):not(.ai):not(.ghost){box-shadow:inset 0 0 0 1px var(--line-2),var(--sh-1)}

  .bld-bar{position:fixed;left:0;right:0;bottom:0;z-index:70;
    display:flex;align-items:center;gap:var(--s-2);
    padding:10px var(--s-4) calc(10px + env(safe-area-inset-bottom));
    background:var(--paper);border-top:1px solid var(--line)}
  .bld-bar[hidden]{display:none}
  .bld-bar .btn.primary{flex:1;min-height:52px;justify-content:center;font-size:var(--t-lg)}
  .bld-bar .icon-btn{width:52px;height:52px;flex:none;
    box-shadow:inset 0 0 0 1px var(--line-2);border-radius:var(--r-2)}
  /* Место под полосой: без него последний блок остаётся под ней. */
  .workspace{padding-bottom:120px}

  .bld-tail{display:flex;gap:var(--s-2);margin-top:var(--s-4)}
  .bld-tail .btn{flex:1;min-height:48px;justify-content:center}

  /* Рельса и «+» между карточками уходят: список блоков и есть оглавление. */
  .workspace>.rail{display:none}
  .workspace .insert{display:none}

  /* Шапка конструктора (5a): «←», название с состоянием строкой, «Как у
     ученика» и «⋯» с работой над уроком — отмена, выбор, стиль, тема, «Закрыть
     урок». Кнопки правой зоны широкого экрана на 390 разворачивали панель в
     четыре ряда поверх урока. Плашка «ЧЕРНОВИК» с «Опубликовать», «сохранено»
     и стрелка отмены стояли в одну строку четырьмя кеглями — теперь состояние
     сказано словом под названием, а публикация живёт в нижней полосе и её «⋯».
     Узлы шапки телефона — в конце файла. */
  .bld-top .top-actions{display:none}
  /* Середина не сжимается: «Как у ученика» и «⋯» — цели, а не текст, и место
     уступает название — оно режется многоточием (.bld-ttl). Было flex:0 1 auto
     с min-width:0, а основа левой зоны — всё название в строку. Недостача
     ширины делится по основам, и на длинном названии («Renting an Apartment
     Abroad: Viewings & Landlord Questions») середина сжималась до 89 при
     содержимом в 156: кнопки вылезали из неё, шапка выходила в 453 на экране
     390, и телефонный Chrome раздвигал окно — «Как у ученика» резалось краем,
     «⋯» уезжал за край, страница листалась вбок. На пробном аккаунте названия
     короткие, и сжимать было нечего (найдено 15 сентября на съёмке кадров). */
  .bld-top .top-mid{flex:none}
  .bld-top .hdr-seg button{font-size:var(--t-sm);padding:6px 10px}

  /* Строка блока: номер со значком, название в две строки, одно меню. */
  .bhead{min-height:56px;gap:var(--s-2);padding:var(--s-2) var(--s-3);align-items:flex-start}
  .block .bname{white-space:normal;overflow:hidden;display:-webkit-box;
    -webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.35;padding-top:3px}
  .block .bwork,.block .gen-mark{display:none}
  /* Из трёх значков остаётся один: выбор блоков и дублирование живут в меню и
     в «⋯» нижней полосы, а три кнопки по 44 съедали строку целиком.
     И меню всегда видно: на широком экране оно проявляется при наведении, а
     наведения на телефоне нет — «⋯» просто не существовало бы. */
  .block .btools{opacity:1;margin-left:auto}
  .block .btools>.icon-btn.pick,.block .btools>.icon-btn.b-ai{display:none}
  /* Ручка карточки на телефоне не нужна: блоки здесь — строки (.prow) со своей
     ручкой, которая ведёт палец pointer-событиями (pGripDown в builder.js). */
  .bgrip{display:none}
  .block .chev{padding-top:6px}

  /* Обложка ужимается: на 390 картинка в 200 плюс поля занимали экран целиком,
     и до первого блока приходилось листать. Урок остаётся узнаваемым — это его
     лицо, — но экран начинается с работы. */
  .cover-img,.cover-pic .field-cover{height:120px}
}

/* ---------- «Кто где»: сетка курса ----------

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

   Строки прокручиваются вбок вместе с шапкой, а не по отдельности: на двадцати
   уроках столбцы всё равно не помещаются, а разъехавшаяся шапка врёт о том,
   какой это урок. */
.wg-wrap{overflow-x:auto;padding:var(--s-3) 0}
.wg-row{display:flex;align-items:center;gap:var(--s-3);min-width:max-content;
  padding:var(--s-2) var(--s-4);border-radius:var(--r-1)}
.wg-name{flex:0 0 210px;display:flex;align-items:center;gap:var(--s-2);min-width:0}
.wg-who{min-width:0;display:flex;flex-direction:column;gap:1px}
.wg-nm{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wg-cells{display:flex;gap:6px;flex:0 0 auto}
.wg-cell{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--r-1);text-decoration:none}
.wg-cell .crs-dot{width:18px;height:18px;box-shadow:none}
a.wg-cell:hover{background:var(--marker-soft)}
.wg-sum{flex:0 0 84px;text-align:right;font-variant-numeric:tabular-nums;
  font-size:var(--t-sm);color:var(--muted)}
/* Шапка: номера уроков и подписи колонок. Номер того урока, где стоит хоть
   кто-то, помечен — это связь сетки с рельсой, там та же строка поднята. */
.wg-head{font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);padding-bottom:var(--s-2)}
.wg-head .wg-col{width:30px;text-align:center;font-variant-numeric:tabular-nums;
  border-radius:var(--r-1);padding:2px 0}
.wg-head .wg-col.here{background:var(--marker-soft);color:var(--marker-ink)}
/* Ученик, который встал: подложка и причина словами вместо цифры. Больше одной
   такой строки на курс — редкость, и в этом весь смысл: она должна выделяться. */
.wg-row.stuck{background:var(--marker-soft)}
.wg-legend{display:flex;flex-wrap:wrap;gap:var(--s-4);padding:var(--s-3) var(--s-4) 0;
  margin-top:var(--s-2);border-top:1px solid var(--line);
  font-size:var(--t-sm);color:var(--muted)}
.wg-legend span{display:inline-flex;align-items:center;gap:6px}
.wg-legend .crs-dot{width:14px;height:14px;box-shadow:none;font-size:9px}
/* Настройки курса: поля и ряд действий под ними. */
.crs-set-acts{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-4)}
/* Полоса под названием курса в списке — про весь курс, а не про одного
   ученика. Тонкая: это справка, а не показатель, за которым следят. */
.crs-card-bar{height:4px;border-radius:var(--r-pill);background:var(--surface-2);
  overflow:hidden;margin-top:10px;max-width:320px}
.crs-card-bar>span{display:block;height:100%;background:var(--marker);border-radius:inherit}
.crs-card-done{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums;margin-top:5px}
/* Список с галочками в окне назначения: строка целиком — кнопка, галочка
   слева, под именем уровень и расписание. Записанный не нажимается и говорит
   об этом словом, а не серостью. */
.as-list{display:grid;gap:2px;margin-top:var(--s-3);max-height:46vh;overflow:auto}
.as-row{display:flex;align-items:center;gap:var(--s-3);width:100%;text-align:left;
  border:none;background:none;border-radius:var(--r-1);padding:var(--s-2) var(--s-3);
  cursor:pointer;font-family:var(--font-body);color:var(--ink);
  transition:background var(--dur-fast) var(--ease)}
.as-row:hover{background:var(--surface-2)}
.as-row.on{background:var(--marker-soft)}
.as-row:disabled{cursor:default;color:var(--muted)}
.as-row:disabled:hover{background:none}
.as-box{flex:0 0 auto;width:20px;height:20px;border-radius:6px;border:1.5px solid var(--line-2);
  display:inline-flex;align-items:center;justify-content:center;font-size:var(--t-sm);color:var(--ink)}
.as-row.on .as-box{background:var(--marker);border-color:var(--marker)}
.as-row.done .as-box{border-style:dashed}
.as-main{min-width:0;display:flex;flex-direction:column;gap:1px}
.as-nm{font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
/* Шапка курса на странице по открытой ссылке: сначала чей курс и о чём, потом
   форма. Человек пришёл из объявления и о платформе не знает ничего — начинать
   с полей ввода значит спрашивать раньше, чем ответил сам. */
/* Окно ссылки на курс: адрес плашкой, под ним тумблер со счётчиком. */
.cl-url{display:flex;align-items:center;gap:var(--s-3);background:var(--surface-2);
  border-radius:var(--r-1);padding:var(--s-2) var(--s-3);margin-top:14px}
.cl-url>span{flex:1;min-width:0;overflow-wrap:anywhere;font-size:var(--t-sm);color:var(--ink-2)}
.cl-row{display:flex;align-items:flex-start;gap:var(--s-3);margin-top:18px}
.cl-state{font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}

.cj-head{padding-bottom:var(--s-4);border-bottom:1px solid var(--line)}
.cj-head h1{font-family:var(--font-head);font-weight:700;font-size:26px;
  letter-spacing:-.03em;line-height:1.15;margin:var(--s-2) 0 var(--s-2)}
.cj-meta{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-3)}
.auth-card .cj-head+form,.auth-card .cj-head+.auth-err+form{margin-top:var(--s-4)}
@media(max-width:640px){
  .wg-name{flex:0 0 150px}
  .wg-sum{flex:0 0 64px}
  .crs-set-acts .btn{flex:1 1 auto;justify-content:center}
}

/* Экран по ссылке-приглашению начинается с того, кто пригласил */
.inviter{display:flex;align-items:center;gap:var(--s-3);background:var(--paper);border:1px solid var(--line);
  border-radius:var(--radius);padding:var(--s-3) var(--s-4);margin-bottom:var(--s-3)}
.inviter .inv-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);line-height:1.35}

.invite-form{display:flex;gap:var(--s-2);margin:var(--s-3) 0 var(--s-1);flex-wrap:wrap}
.invite-form input{flex:1;min-width:150px;border:1px solid var(--line-2);border-radius:var(--radius-sm);
  padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface)}
.invite-form input:focus{outline:none;border-color:var(--ink)}
.invite-item{border-top:1px solid var(--line);padding-top:var(--s-3);margin-top:var(--s-3)}

/* ---------- Онбординг: развилка «С чего начнём?» ---------- */
/* Колонка развилки центрирована целиком: раньше сама страница была в 1000px,
   а двери — в 660, и блок висел левее середины экрана. */
.start-page{max-width:720px}
.start-head{margin:var(--s-3) 0 var(--s-5)}
.start-head h1{font-family:var(--font-head);font-weight:700;font-size:clamp(26px,4vw,38px);
  letter-spacing:-.03em;line-height:1.08;margin:var(--s-2) 0 var(--s-3)}
.start-sub{color:var(--ink-2);font-size:var(--t-lg);line-height:1.55;max-width:560px}
/* Путь один, и он поднят. Двери были две и равные, и выбор между ними человек
   делал вслепую: обе обещали урок, а разницу в цене минуты не называла ни одна.
   Лист ИИ держится тенью, без рамки — рамка или тень, но не оба. */
.start-ai-card{background:var(--surface);border-radius:var(--r-3);padding:26px;
  box-shadow:var(--sh-2);margin-top:28px}
.start-ai-card .sa-head{display:flex;align-items:center;gap:14px}
.start-ai-card .sa-ic{width:44px;height:44px;flex-shrink:0;border-radius:var(--r-2);
  background:var(--marker);color:var(--marker-ink);
  display:inline-flex;align-items:center;justify-content:center}
.start-ai-card .sa-ic .spark{width:19px;height:19px;display:block}
.start-ai-card .sa-body{min-width:0}
.start-ai-card .sa-t{font-family:var(--font-head);font-weight:700;font-size:20px;letter-spacing:-.02em}
.start-ai-card .sa-d{font-size:var(--t-md);color:var(--muted);margin-top:2px}
/* Три шага: до нажатия человек не знает, что его ждёт за кнопкой, и «собрать
   урок с ИИ» звучит как заявка на долгий разговор. */
.start-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-2);margin-top:22px}
.start-step{background:var(--paper);border-radius:var(--r-1);padding:14px}
.start-step .ss-t{display:block;font-size:var(--t-md);line-height:1.5;color:var(--ink);margin-top:var(--s-2)}
.sa-act{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:22px}
/* Жёлтая заливка здесь по праву: это действие модели, а не главная кнопка
   интерфейса. Подъём под курсором — тот же, что у листа. */
.sa-act .btn.ai{padding:0 22px}
.sa-act .btn.ai:hover{transform:translateY(-1px);
  box-shadow:0 1px 2px rgba(23,26,33,.08),0 10px 22px -8px rgba(232,163,23,.7);
  transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.sa-act .btn.ai:active{transform:scale(.98)}

/* ---------- Первый вход с телефона ----------

   Сюда приходят из соцсети, то есть с телефона и в один заход. На 390 экран
   выглядел так: полоса с «Выйти» и напоминанием о почте, заголовок, абзац в
   три строки, карточка с тремя объяснениями в отдельных плашках — и только
   под ними, на восемьсот двенадцатом пикселе из шестисот сорока видимых,
   кнопка «Собрать урок». Единственное действие экрана было за полтора экрана
   прокрутки, и до него доходили не все.

   Три перестановки. Полоса сверху убирается: выходить из аккаунта на первом
   входе незачем, а напоминание о почте человек только что читал в форме
   регистрации — оно вернётся на всех остальных экранах. Кнопка поднимается
   к заголовку карточки: сначала то, что делают, потом объяснение, как это
   устроено. Объяснение при этом остаётся — оно и отвечает на вопрос «что
   будет, если нажать», — но лежит под кнопкой, а не над ней. */
@media(max-width:640px){
  .start-page{padding-top:var(--s-3)}
  body:has(.start-page)>.topbar{display:none}
  body:has(.start-page) .verify-bar{display:none}

  .start-head{margin:0 0 var(--s-4)}
  .start-head h1{font-size:26px;margin:6px 0 var(--s-2)}
  .start-sub{font-size:var(--t-md);line-height:1.5}

  .start-ai-card{padding:16px;margin-top:0;display:flex;flex-direction:column}
  .start-ai-card .sa-head{order:1}
  .start-ai-card .sa-act{order:2;margin-top:16px}
  .start-ai-card .start-steps{order:3}
  .start-ai-card .sa-ic{width:36px;height:36px}
  .start-ai-card .sa-t{font-size:var(--t-lg)}

  /* Кнопка сборки — главное действие экрана: во всю ширину и ростом 56.
     Выбор языка уходит под неё строкой, а не встаёт рядом: вдвоём в ряд они
     оставляли кнопке половину ширины. */
  .sa-act{flex-direction:column;align-items:stretch;gap:var(--s-3)}
  .sa-act .btn.ai{width:100%;min-height:56px;justify-content:center;font-size:var(--t-lg)}
  .sa-lang{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}

  /* Три объяснения — столбиком и без плашек: колонки по 1/3 ширины на 390
     превращались в три слова на строку. */
  .start-steps{grid-template-columns:1fr;gap:var(--s-2);margin-top:18px}
  .start-step{background:none;padding:0;display:flex;gap:var(--s-3);align-items:baseline}
  .start-step .ss-t{margin-top:0;font-size:var(--t-base);line-height:1.45}
}
@media (prefers-reduced-motion:reduce){.sa-act .btn.ai:hover{transform:none}}
/* «Сам» и «посмотреть чужой» — выходы для тех, кому сборка сейчас не нужна.
   Плоские потому, что равными с листом ИИ они снова превращали экран
   в развилку. Демо есть не у всех: без него левая занимает всю ширину. */
.start-flat{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:14px}
.start-flat.one{grid-template-columns:1fr}
.start-flat-card{display:flex;flex-direction:column;align-items:flex-start;text-align:left;width:100%;
  background:var(--surface);border:none;border-radius:var(--r-2);padding:var(--s-4) 18px;
  box-shadow:var(--sh-1);cursor:pointer;
  transition:background var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
.start-flat-card:hover{background:var(--surface-2);transform:translateY(-1px)}
.start-flat-card .sf-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink)}
.start-flat-card .sf-d{font-size:var(--t-sm);line-height:1.5;color:var(--muted);margin-top:var(--s-1)}
@media (max-width:560px){.start-flat{grid-template-columns:1fr}
  .start-steps{grid-template-columns:1fr}}
/* «Пропустить» — строка, а не кнопка-плашка: это выход, а не действие. */
.start-skip{margin-top:var(--s-5)}
.start-skip .more-link{font-size:var(--t-sm);font-weight:500;color:var(--muted)}

/* ---------- Служебная типографика (t-6) ----------
   Шестая ступень шкалы: 10.5px Manrope 600 с разрядкой .1em и табличными
   цифрами. До v3 она была набрана JetBrains Mono — третьим семейством на
   странице ради номеров блоков и служебных подписей. Семейство ушло, работа
   осталась: tabular-nums держит цифры одной ширины, и счётчик, меняющийся на
   месте, не дёргает строку. */
.eyebrow{font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:600}
/* Надстрочник бренд-цветом — чернилами маркера, а не самим маркером: #E8A317
   по бумаге даёт 2.07, и надпись 10.5px капсом на нём не читается. Тон тот же,
   тёплый, но её видно. */
.eyebrow.marker{color:var(--marker-ink)}
.code-box{font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-sm);letter-spacing:.08em;background:var(--paper);border:1px solid var(--line);border-radius:var(--r-1);padding:var(--s-2) var(--s-3)}

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

   Ручка сверху говорит, что лист можно смахнуть. Нижнее поле считается с
   безопасной зоной телефона: без неё последняя строка уезжает под жест «домой». */
.sheet-wrap{position:fixed;inset:0;z-index:220}
.sheet-scrim{position:absolute;inset:0;background:rgba(23,26,33,.55);opacity:0;
  transition:opacity var(--dur-slow) var(--ease)}
.sheet{position:absolute;left:0;right:0;bottom:0;max-height:82vh;overflow:auto;
  background:var(--surface);border-radius:var(--r-3) var(--r-3) 0 0;box-shadow:var(--sh-3);
  padding:var(--s-2) var(--s-3) calc(var(--s-4) + env(safe-area-inset-bottom,0px));
  transform:translateY(100%);transition:transform var(--dur-slow) var(--ease-s)}
.sheet-wrap.on .sheet-scrim{opacity:1}
.sheet-wrap.on .sheet{transform:none}
/* ---------- Шторка в тёмной теме (решение 13f) ----------
   Тени в темноте нет: «всплыло» говорят светлота листа и затемнённый экран под
   ним. Поэтому у шторки кант вместо тени, а подложка становится столом —
   полупрозрачная чернильная в темноте не видна вовсе, и шторка читалась
   приклеенной к странице. */
html[data-chrome="dark"] .sheet{box-shadow:var(--edge)}
html[data-chrome="dark"] .sheet-scrim{background:rgba(10,11,14,.72)}

.sheet-grip{display:block;width:36px;height:4px;border-radius:var(--r-pill);
  background:var(--line-2);margin:var(--s-2) auto var(--s-3)}
/* Ручка ловит смахивание вниз (sheetDrag в core.js): жест у неё не отдаётся
   прокрутке, а невидимые поля делают мишень в палец, а не в четыре пикселя. */
.sheet-grip{position:relative;touch-action:none;cursor:grab}
.sheet-grip::after{content:'';position:absolute;inset:-14px -48px}
.sheet-head{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
  padding:0 10px var(--s-2)}
.sheet-body{display:flex;flex-direction:column;gap:2px}
.sheet-row{display:block;width:100%;text-align:left;border:none;background:none;cursor:pointer;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink-2);
  padding:13px 10px;border-radius:var(--r-1);text-decoration:none;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.sheet-row:hover,.sheet-row:active{background:var(--surface-2);color:var(--ink)}
.sheet-row.on{color:var(--ink);background:var(--surface-2)}
.sheet-sep{height:1px;background:var(--line);margin:var(--s-2) 10px}
/* Страница под открытым листом не прокручивается: иначе смахивание по листу
   уводит за ним и её, и после закрытия человек оказывается не там, где был. */
body.sheet-open{overflow:hidden}

/* ---------- Свой флажок и свой тумблер ----------
   Родной input type=checkbox рисует операционная система: чужой шрифт, чужая
   галка, чужой цвет выделения — ровно то, что правило «ничего системного»
   запрещает. Своё — кнопка с role, а не подделка под ввод: так его слышит
   средство чтения с экрана и берёт клавиатура.

   Тумблер и флажок отвечают на разные вопросы. Флажок — «включить в список»,
   их бывает несколько подряд. Тумблер — «да или нет» на один вопрос, и рядом
   с ним всегда стоит подпись, чем этот выбор обернётся. */
/* Флажок рисуем сами: у родного вид задаёт операционная система — чужая галка,
   чужой цвет выделения, на Windows и на маке разные. appearance:none снимает её
   отрисовку, но оставляет сам input: он остаётся флажком для клавиатуры, для
   формы и для средства чтения с экрана. Подменять его кнопкой было бы хуже —
   вид тот же, а семантика потеряна. */
input[type="checkbox"]{appearance:none;-webkit-appearance:none;flex-shrink:0;
  width:18px;height:18px;margin:0;border-radius:6px;border:1px solid var(--line-2);
  background:var(--surface);cursor:pointer;position:relative;
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}
input[type="checkbox"]:hover{border-color:var(--ink-2)}
input[type="checkbox"]:checked{background:var(--ink);border-color:var(--ink)}
/* Галка — двумя линиями на псевдоэлементе, а не символом: у шрифта своя ширина
   галки, и в квадрате 18px она встаёт то по центру, то мимо. */
input[type="checkbox"]:checked::after{content:'';position:absolute;left:5px;top:1px;
  width:5px;height:10px;border:solid var(--paper);border-width:0 2px 2px 0;
  transform:rotate(45deg)}
input[type="checkbox"]:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--ink)}
input[type="checkbox"]:disabled{cursor:default;opacity:.5}

.swx{flex-shrink:0;width:34px;height:20px;border-radius:var(--r-pill);background:var(--line);
  border:none;padding:2px;display:inline-flex;align-items:center;cursor:pointer;
  transition:background var(--dur-fast) var(--ease)}
.swx::before{content:'';width:16px;height:16px;border-radius:var(--r-pill);background:var(--surface);
  box-shadow:var(--sh-1);transition:transform var(--dur-fast) var(--ease)}
.swx[aria-checked="true"]{background:var(--ink)}
.swx[aria-checked="true"]::before{transform:translateX(14px);background:var(--paper)}
.swx:focus-visible{outline:none;box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--ink)}
.swx:disabled{cursor:default;opacity:.5}
/* Строка тумблера: слева название вопроса, справа — что будет, если ответить
   так. Подпись меняется вместе с положением, иначе последствие приходится
   держать в голове. */
.swx-row{display:flex;align-items:center;gap:10px}
.swx-row .swx-t{font-size:var(--t-md);color:var(--ink)}
.swx-row .swx-s{margin-left:auto;text-align:right;font-size:var(--t-sm);color:var(--muted)}

/* ---------- Меню строки «…» ----------
   Третья и дальше кнопки плашки. Всплывает над экраном, поэтому третий уровень
   подъёма; форма плашки — r-1 внутри r-2, как у всего, что лежит в листе. */
.row-menu{position:fixed;z-index:210;min-width:184px;padding:var(--s-1);
  background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-3);
  display:flex;flex-direction:column;gap:1px}
.rm-item{display:block;width:100%;text-align:left;border:none;background:none;cursor:pointer;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink-2);
  padding:9px 10px;border-radius:var(--r-1);white-space:nowrap;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.rm-item:hover:not(:disabled){background:var(--surface-2);color:var(--ink)}
.rm-item:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ink)}
.rm-item:disabled{color:#B4B1A8;cursor:default}
/* Опасное — красным текстом и последним, как в диалогах: заливка отдала бы
   цвету ошибки второе значение. */
.rm-item.danger{color:var(--err)}
.rm-item.danger:hover:not(:disabled){background:var(--err-bg);color:var(--err)}
.rm-sep{height:1px;background:var(--line);margin:var(--s-1) 6px}
/* На телефоне действия строки видны всегда — этим занимается @media (hover:hover)
   у .r-act: где наведения нет, правило скрытия просто не применяется. Отдельное
   правило под .r-dots было мёртвым: такого класса не печатает ни один файл. */

/* ---------- Переключатель темы хрома ---------- */
.chrome-toggle{border:none;background:var(--surface);color:var(--muted);width:30px;height:30px;border-radius:var(--r-1);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:var(--sh-1);transition:color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.chrome-toggle:hover{color:var(--ink);box-shadow:var(--sh-2)}
/* В тёмной теме солнце жёлтое: это не статус и не акцент, а знак того, что
   переключатель сейчас показывает обратную тему. Кант даёт --sh-1. */
html[data-chrome="dark"] .chrome-toggle{color:var(--marker)}
.chrome-toggle svg{width:16px;height:16px}

/* ---------- Состояния: пустые и ошибки ---------- */
.empty{border:none}
.card.error{border:1px solid var(--err-line)}
/* Заголовок отказа — чернилами: красным набран надстрочник состояния, и
   двух красных строк подряд экрану не нужно. */
.empty.error .big{color:var(--ink)}

/* ---------- Лендинг ---------- */
/* Одна прокручиваемая страница по хендоффу design_handoff_lessona_landing:
   hero, шесть блоков с «живыми» макетами интерфейса, финальный CTA, футер.
   Цвета берутся платформенными токенами — в хендоффе стоят те же значения.
   Вся «жизнь» макетов — CSS-циклы по 9с; JS на странице нет. */
.lp{
  /* Чего нет в палитре платформы: жёлоб полосы прогресса и цвета тёмных
     блоков лендинга — они тёмные всегда, а не по теме хрома. */
  --lp-track:#EFEDE7;
  /* Заливка полотна тарифов. С жёлобом полосы значение совпадает случайно:
     тот назван под запас, и ходить в тарифы через него нельзя. */
  --lp-band:#EFEDE7;
  background:var(--paper);color:var(--ink);font-size:15px;line-height:1.65;overflow-x:hidden}
/* Цвета тёмных блоков объявлены на обоих, кто их носит. Лежали они внутри .lp,
   и тёмная половина регистрации — она вне лендинга — приходила без фона вовсе:
   var(--lp-dark) не разрешался, и обещание «Первый урок за вечер» полгода
   стояло чёрным по бумаге вместо белого по чернилам. Второй набор тех же
   шестнадцатеричных значений заводить нельзя: разъедется на первой правке. */
.lp,.auth-pitch{
  --lp-dark:#171A21; --lp-dark-panel:#1F232B; --lp-dark-line:#2F343D;
  --lp-dark-track:#2A2E36; --lp-dark-fill:#5D636E;
  --lp-dark-ink:#F2F2EF; --lp-dark-ink-2:#B9BAB5; --lp-dark-muted:#8B8D88;
}
.lp a{color:inherit;text-decoration:none}
.lp a:not(.lp-btn):hover{color:var(--marker-ink)}
/* Программное отключение движения (проп motion в хендоффе). Системное
   prefers-reduced-motion снимает анимации выше, глобально по платформе. */
.lp[data-motion="off"] *,.lp[data-motion="off"] *::before,.lp[data-motion="off"] *::after{animation:none !important}

/* Шапка и кнопки */
.lp-head{position:sticky;top:0;z-index:20;background:rgba(251,250,247,.9);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.lp-head-in{max-width:1160px;margin:0 auto;padding:14px 28px;display:flex;align-items:center;gap:var(--s-3)}
/* Лендинг вне шкалы хрома намеренно: у него свой ряд с clamp() из хендоффа */
.lp-head .brand{font-size:19px;letter-spacing:-.02em;gap:9px}
.lp-head nav{margin-left:auto;display:flex;align-items:center;gap:var(--s-1);flex-wrap:wrap}
/* «Войти» отбита с обеих сторон. Ряд шапки идёт с зазором 4px, и текстовая
   ссылка вплотную к тёмной кнопке читалась её продолжением: два слова подряд,
   одно на бумаге, другое на чернилах. */
.lp-login{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink-2);
  margin-left:var(--s-3);margin-right:var(--s-3)}
.lp a.lp-login:hover{color:var(--ink)}
/* Три кнопки страницы названы по-разному намеренно — не сводить к одной формуле */
.lp-btn{display:inline-flex;align-items:center;justify-content:center;text-align:center;
  font-family:var(--font-head);font-weight:600;white-space:nowrap}
.lp-btn.dark{background:var(--ink);color:var(--paper)}
.lp a.lp-btn.dark:hover{background:#000;color:#fff}
.lp-btn.sm{font-size:var(--t-base);padding:9px 15px;border-radius:var(--r-1)}
.lp-btn.md{font-size:15px;padding:14px 24px;border-radius:var(--r-1)}
.lp-btn.accent{background:var(--marker);color:var(--ink);font-size:15px;padding:14px 22px;border-radius:var(--r-1)}
.lp a.lp-btn.accent:hover{filter:brightness(1.06);color:var(--ink)}

/* Ритм страницы: 110px между секциями, 96px перед финальным CTA */
.lp-sec{max-width:1160px;margin:0 auto;padding:110px 28px 0}
.lp-sec-hero{padding-top:64px}
/* Ряд секции. После v4 такой ряд на странице один — первый экран; остальные
   макеты уехали в шаги онбординга, и у тех своя сетка. */
.lp-row{display:flex;flex-wrap:wrap;gap:56px;align-items:center}
/* Модификаторы с префиксом lp-: голые .hero, .cab и .block уже заняты
   платформой и притащили бы сюда свои сетки и рамки. */
/* Первый экран — сеткой, а не флексом, по той же причине, что и шаги: кнопка
   стоит под текстом на широком экране и под демо на телефоне, а во флексе она
   для этого обязана лежать внутри текстовой колонки — откуда её не вынуть. */
.lp-row.lp-top{display:grid;grid-template-columns:1fr 1.15fr;
  grid-template-areas:"side shot" "act shot";
  align-items:center;column-gap:52px;row-gap:26px}
.lp-top>.lp-side{grid-area:side;align-self:end}
.lp-top>.lp-shot{grid-area:shot}
.lp-hero-act{grid-area:act;min-width:0;align-self:start}
/* wrap-reverse: при схлопывании текст встаёт над макетом — так задумано */
.lp-row.rev{flex-wrap:wrap-reverse}
.lp-side{flex:1 1 360px;min-width:0}
.lp-side.w380{flex:1 1 380px}
.lp-side.w420{flex:1 1 420px}
.lp-shot{flex:1.1 1 440px;min-width:0}
.lp-shot.w420{flex:1.1 1 420px}
.lp-shot.w460{flex:1.15 1 460px}
.lp-head-group{max-width:60ch;margin-bottom:34px}
.lp-head-group.wide{max-width:62ch}
.lp-cta-sec{max-width:1160px;margin:96px auto 0;padding:0 28px}
.lp-cta-btn{flex:0 1 280px;display:flex;flex-direction:column;gap:10px}
.lp-footer{max-width:1160px;margin:0 auto;padding:34px 28px 64px;display:flex;flex-wrap:wrap;gap:20px;align-items:center}

/* Типографика: ширина в символах, а не в пикселях */
.lp h1{font-family:var(--font-head);font-weight:800;font-size:clamp(32px,4.2vw,50px);
  line-height:1.06;letter-spacing:-.03em;margin-bottom:20px;text-wrap:pretty}
.lp h2{font-family:var(--font-head);font-weight:700;font-size:clamp(27px,3.2vw,38px);
  line-height:1.12;letter-spacing:-.025em;margin-bottom:var(--s-4);text-wrap:pretty}
.lp .nw{white-space:nowrap}
/* Перечень возможностей идёт вторым абзацем и набран мельче обещания над ним:
   на первом экране сначала итог, потом из чего он складывается. */
.lp-body{font-size:var(--t-lg);line-height:1.62;color:var(--ink-2);max-width:48ch;
  margin-bottom:26px;text-wrap:pretty}
.lp-txt p{color:var(--ink-2);max-width:48ch;margin-bottom:14px;text-wrap:pretty}
.lp-txt p:last-child{margin-bottom:0}
.lp-txt.wide p{max-width:none;margin-bottom:var(--s-3)}
.lp-cta{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.lp-cta-note{font-size:var(--t-base);color:var(--muted)}

/* Общее для макетов интерфейса */
.lp-card{border:1px solid var(--line);border-radius:var(--r-2);background:var(--surface);
  box-shadow:0 20px 50px rgba(23,26,33,.07);overflow:hidden}
.lp-card.paper{background:var(--paper)}
.lp-card.lp-top{box-shadow:0 26px 64px rgba(23,26,33,.09)}
.lp-card.lp-dash{box-shadow:0 22px 54px rgba(23,26,33,.08)}
.lp-card.pad{padding:20px 22px}
.lp-card.pad22{padding:22px}
.lp-card.notes{padding:22px 20px;position:relative}
.lp-bar{display:flex;align-items:center;flex-wrap:wrap;gap:9px;padding:11px var(--s-4);border-bottom:1px solid var(--line)}
.lp-bar svg{flex-shrink:0;display:block}
.lp-bar-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-base)}
.lp-bar .lp-sub{margin-left:auto}
.lp-card-head{display:flex;align-items:center;margin-bottom:var(--s-4)}
.lp-card-t{font-family:var(--font-head);font-weight:700;font-size:13.5px}
.lp-card-top{display:flex;align-items:center;gap:var(--s-2);padding:10px 14px;border-bottom:1px solid var(--line);
  font-variant-numeric:tabular-nums;font-size:10px;color:var(--muted)}
.lp-meta{font-variant-numeric:tabular-nums;font-size:10px;color:var(--muted)}
.lp-meta.tr{letter-spacing:.1em}
.lp-meta.tr08{letter-spacing:.08em}
.lp-mono{font-variant-numeric:tabular-nums;font-size:11px;color:var(--muted)}
.lp-mono.ink{color:var(--marker-ink)}
.lp-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-sm)}
.lp-name.dim{color:var(--ink-2)}
.lp-sub{font-size:11.5px;color:var(--muted)}
.lp-sub.ink{color:var(--marker-ink)}
.lp-h3{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg)}
.lp-h3.sm{font-size:15px}
.lp-dot{width:7px;height:7px;border-radius:50%;background:var(--ok);flex-shrink:0;animation:lsnPulse 1.6s ease-in-out infinite}
.lp-dot.still{animation:none}
.lp-dot.grey{width:8px;height:8px;background:var(--line-2);animation:none}
.lp-live{margin-left:auto;display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--ink-2)}
.lp-ava{width:24px;height:24px;border-radius:50%;background:var(--line);font-family:var(--font-head);
  font-weight:600;font-size:11px;color:var(--ink-2);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lp-ava.lg{width:34px;height:34px;font-size:var(--t-base)}
.lp-ok{width:16px;height:16px;border-radius:50%;background:var(--ok-bg);color:var(--ok);font-size:10px;
  display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lp-ok.lg{width:19px;height:19px;font-size:11px;background:var(--ok);color:var(--lp-dark-ink)}
.lp-prog{display:flex;align-items:center;gap:10px}
/* .trk, а не .bar: глобальная .bar принесла бы свою высоту и margin */
.lp-prog .trk{flex:1;height:5px;border-radius:3px;background:var(--lp-track);overflow:hidden}
.lp-prog .trk i{display:block;height:100%;border-radius:3px;background:var(--marker)}
.lp-prog .n{font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted)}
.lp-note{background:var(--marker-soft);border:1px solid var(--marker);border-radius:var(--r-1);padding:7px 9px;
  font-size:11.5px;line-height:1.45;color:var(--marker-ink)}
.lp-note.dashed{background:none;border:1px dashed var(--line-2);color:var(--muted)}
.lp-pill{border:1px solid var(--line-2);border-radius:var(--r-pill);padding:2px 10px;white-space:nowrap;
  font-family:var(--font-head);font-weight:600;font-size:11.5px}
.lp-pill.sm{padding:1px 9px;font-size:11px}
.lp-pill.off{color:var(--muted)}
.lp-pills{margin-left:auto;display:flex;gap:6px}
.lp-chipbtn{margin-left:auto;background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--r-pill);
  padding:var(--s-1) 11px;font-family:var(--font-head);font-weight:600;font-size:11.5px;white-space:nowrap}

/* Первый экран: рабочее окно преподавателя */
.lp-desk{display:grid;grid-template-columns:132px minmax(0,1fr) 122px;min-height:346px}
.lp-desk>.l{border-right:1px solid var(--line);padding:14px var(--s-3);display:flex;flex-direction:column;gap:7px}
.lp-desk>.c{background:var(--surface);padding:18px 20px;display:flex;flex-direction:column;gap:var(--s-3)}
.lp-desk>.r{border-left:1px solid var(--line);padding:14px 10px;position:relative}
.lp-desk>.l>.lp-meta{margin-bottom:2px}
.lp-desk>.r>.lp-meta{margin-bottom:10px}
.lp-desk>.r .lp-note.dashed{margin-top:14px}
.lp-desk>.c .lp-prog{margin-top:auto}
.lp-slot{padding:var(--s-2) 9px;display:flex;flex-direction:column;gap:2px}
.lp-slot.on{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-1);box-shadow:0 1px 0 rgba(23,26,33,.03)}
.lp-slot .lp-sub{font-size:11px}
.lp-foot{margin-top:auto;border-top:1px solid var(--line);padding-top:10px;display:flex;flex-direction:column;gap:3px}
.lp-foot .lp-sub{font-size:11px}
.lp-task{border:1px solid var(--line);border-radius:var(--r-1);padding:11px 13px;position:relative}
.lp-task>.lp-meta{margin-bottom:6px}
.lp-task.plain{font-size:var(--t-base);line-height:1.9}
.lp-task.dashed{border-style:dashed;border-color:var(--line-2);font-size:var(--t-sm);color:var(--muted)}
.lp-line{font-size:13.5px;line-height:1.9}
.lp-line.sm{font-size:var(--t-sm);line-height:1.8}
/* «печатается» ответ: внешний span держит ширину пропуска, внутренний растёт */
.lp-type{display:inline-flex;align-items:baseline;vertical-align:baseline;min-width:74px;overflow:hidden;
  white-space:nowrap;border-bottom:2px solid var(--ink);font-family:var(--font-body)}
.lp-type .t{display:inline-block;overflow:hidden;white-space:nowrap}
.lp-tick{position:absolute;top:9px;right:11px;animation:lsnTick 9s ease-out infinite}
.lp-tf{display:flex;align-items:center;gap:10px;font-size:13.5px}
.lp-tf.sm{gap:var(--s-2);font-size:var(--t-sm)}
.lp-tf.sm .lp-pills{gap:5px}

/* Шаг 1 онбординга: сборка. Страница учебника со сканирующим лучом, поле
   запроса словами, список собранных блоков. */
.lp-tag{margin-left:auto;display:flex;align-items:center;gap:6px;background:var(--marker-soft);
  color:var(--marker-ink);border-radius:var(--r-pill);padding:3px 10px;font-variant-numeric:tabular-nums;font-size:10px;letter-spacing:.08em}
.lp-tag .d{width:5px;height:5px;border-radius:50%;background:var(--marker);animation:lsnPulse 1.4s ease-in-out infinite}
/* Ширину задаёт место, где карточка стоит: флекс-ряда импорта, под который тут
   была доля 178px, больше нет. */
.lp-src{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-1);padding:14px;
  position:relative;overflow:hidden;display:flex;flex-direction:column;gap:var(--s-2)}
.lp-src>.lp-meta{margin-bottom:2px}
.lp-src .ln{height:8px;border-radius:4px;background:var(--line)}
.lp-src .ln.mk{height:9px;background:var(--marker-soft)}
.lp-beam{position:absolute;left:0;right:0;top:6px;height:30px;border-top:1.5px solid var(--marker);
  background:linear-gradient(180deg,rgba(232,163,23,.20),transparent);animation:lsnScan 9s ease-in-out infinite}
.lp-res{flex:1;min-width:0;display:flex;flex-direction:column;gap:9px}
.lp-chip{border:1px solid var(--line);border-radius:var(--r-1);padding:10px var(--s-3);animation:lsnRise 9s ease-in-out infinite}
.lp-chip .cl{font-family:var(--font-head);font-weight:600;font-size:11px;color:var(--muted);margin-bottom:5px}

/* Тёмные полотна: «ИИ забирает рутину» и финальный призыв */
.lp-dark{background:var(--lp-dark);color:var(--lp-dark-ink);border-radius:var(--r-3);
  padding:clamp(30px,4vw,48px);display:flex;flex-wrap:wrap;gap:44px;align-items:center}
.lp-dark.end{padding:clamp(36px,5vw,64px);gap:36px}
.lp h2.on-dark{font-size:clamp(26px,3.2vw,36px);line-height:1.14}
.lp-dark.end h2.on-dark{font-size:clamp(26px,3.4vw,38px);margin-bottom:14px}
.lp-txt.on-dark p{color:var(--lp-dark-ink-2);max-width:46ch}
.lp-sub-dark{color:var(--lp-dark-ink-2);max-width:46ch;text-wrap:pretty}
.lp-meta.on-dark{color:var(--lp-dark-muted)}
/* Полоса осталась одна — сравнение времени в блоке «ИИ забирает рутину»
   (.lp-dtrack.dk). Прежний упрёк блоку — «обещает ИИ на всех тарифах целиком,
   а у бесплатного месячная квота» — снят текстом: слова «целиком» в нём
   больше нет, а сама квота названа числом в тарифах. */
.lp-dtrack{overflow:hidden}
.lp-dtrack>i{display:block;height:100%;border-radius:3px}

/* Шаг 3 онбординга: занятие. Две одинаковые карточки, у ученика заметка на
   четверть секунды позже — это и есть «видно обоим сразу». */
.lp-pair{display:flex;flex-wrap:wrap;gap:18px;align-items:stretch}
.lp-card.sync{flex:1 1 340px;min-width:0;box-shadow:0 20px 50px rgba(23,26,33,.06);
  padding:20px 22px;display:flex;flex-direction:column;gap:13px}
.lp-card.sync .lp-card-head{margin-bottom:0;gap:var(--s-2)}
.lp-card.sync .lp-card-t{font-size:var(--t-md)}
.lp-card.sync .lp-note{border-radius:var(--r-1);padding:7px 10px}
.lp-card.sync .lp-prog{margin-top:auto}
.lp-ask{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-1);padding:13px 15px}
.lp-ask>.lp-meta{margin-bottom:7px}
.lp-ask .q{font-size:13.5px;line-height:1.8;margin-bottom:var(--s-2)}
.lp-input{background:var(--surface);border:1px solid var(--line-2);border-radius:var(--r-1);padding:var(--s-2) 10px;
  font-size:13.5px;display:flex;align-items:center}
.lp-input.accent{border-color:var(--marker)}
/* Курсор идёт за текстом, а не по всему полю.
   Раньше .tw лежала прямо во flex-контейнере поля, и её width:100% в конце
   анимации разворачивался на всю ширину поля — курсор уезжал в пустой конец
   строки, отрываясь от текста, который «печатается».
   Обёртка сжата по содержимому (width:max-content), поэтому 100% у .tw — это
   ширина самого текста: курсор встаёт вплотную и едет вместе с ним. */
.lp-input .lp-tw{display:inline-flex;align-items:center;width:max-content;max-width:100%;min-width:0}
.lp-input .tw{overflow:hidden;white-space:nowrap}
.lp-input .car{width:1.5px;height:15px;background:var(--ink);margin-left:2px;flex-shrink:0;animation:lsnBlink 1s step-end infinite}

/* Шаг 5 онбординга: оплаты */
.lp-sum{display:flex;align-items:flex-end;gap:var(--s-4);margin-bottom:18px}
.lp-sum .lp-meta{margin-bottom:var(--s-1)}
.lp-money{font-family:var(--font-head);font-weight:700;font-size:32px;letter-spacing:-.025em}
.lp-spark{margin-left:auto;display:flex;align-items:flex-end;gap:7px;height:62px}
.lp-spark .c{width:16px;height:62px;display:flex;align-items:flex-end}
.lp-spark i{display:block;width:100%;border-radius:3px;background:var(--marker-soft);
  transform-origin:bottom;animation:lsnBar 2.4s ease-out infinite}
.lp-spark i.now{background:var(--marker)}
.lp-metrics{display:flex;gap:22px;flex-wrap:wrap;padding:13px 0;margin-bottom:var(--s-4);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.lp-metrics .n{font-family:var(--font-head);font-weight:700;font-size:17px}
.lp-metrics .l{font-size:11.5px;color:var(--muted)}
.lp-people{display:flex;flex-direction:column;gap:9px}
.lp-person{display:flex;align-items:center;gap:var(--s-3);padding:10px 13px}
.lp-person.on{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-1)}
.lp-person .who{min-width:0}
.lp-person .lp-name{font-size:13.5px}
.lp-person .sub{margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;gap:5px}
.lp-person .ticks{display:flex;gap:3px}
.lp-person .ticks span{width:9px;height:5px;border-radius:2px;background:var(--marker)}
/* седьмое деление гаснет — занятие списывается прямо сейчас */
.lp-person .ticks .off-now{animation:lsnDim 4.5s ease-in-out infinite}
.lp-person .ticks .spent{background:var(--lp-track)}

/* ---------- Готовые страницы v3 ----------
   Языковая метка, сравнение времени и карточка ученика. Всё, что ниже,
   объявлено до мобильного раздела: .lp-de и .lp-mo идут после и должны
   перебивать display этих классов. */

/* Языковая метка: флаг плюс название языка. Проходит через семь макетов —
   платформа перестала быть «про английский», и это видно в каждом окне.
   Флаги — те же SVG, что в FLAGS из core.js; лендинг core.js не тянет,
   поэтому в разметке лежит их копия. */
.lp-lang{display:inline-flex;align-items:center;gap:6px;margin-left:10px;font-size:11px;color:var(--muted)}
/* В блоке «Стиль» метка прижата к правому краю полосы */
.lp-lang.push{margin-left:auto}
.flag.sm{width:16px;height:11px}

/* Курсор в поле просьбы. Общего класса с .lp-input .car нет: тот flex-элемент
   внутри поля и не должен сжиматься, этот встроен в поток текста. */
.lp-caret{display:inline-block;width:1.5px;height:14px;background:var(--ink);margin-left:3px;
  vertical-align:-2px;animation:lsnBlink 1s step-end infinite}

/* Жёлтая точка в подвале карточки сборки: в импорте такая же точка про
   сошедшиеся данные, здесь про ИИ — черновик собрала модель. */
.lp-dot.marker{background:var(--marker)}

/* «ИИ забирает рутину»: полтора часа против десяти минут на тёмном полотне */
.lp-time{background:var(--lp-dark-panel);border:1px solid var(--lp-dark-line);
  border-radius:var(--r-2);padding:20px 22px}
.lp-time>.lp-meta{margin-bottom:var(--s-4)}
.lp-time-row{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-3)}
.lp-time-row.last{margin-bottom:0;padding-bottom:18px;border-bottom:1px solid var(--lp-dark-line)}
.lp-time-row .l{flex:0 0 92px;font-size:var(--t-base);color:var(--lp-dark-ink-2)}
.lp-time-row .l.on{font-family:var(--font-head);font-weight:600;color:var(--lp-dark-ink)}
.lp-time-row .v{flex:0 0 74px;text-align:right;font-variant-numeric:tabular-nums;
  font-size:11px;color:var(--lp-dark-muted)}
.lp-time-row .v.mk{color:var(--marker)}
.lp-dtrack.dk{flex:1;height:8px;border-radius:4px;background:var(--lp-dark-track)}
.lp-dtrack.dk>i.grey{background:var(--lp-dark-fill)}
/* Полоса Lessona растёт до своих 11%: ширину держит i, движение — вложенный
   span. Повесить lsnGrow прямо на i нельзя: анимация перебивает ширину и
   разворачивает полосу на весь жёлоб. */
.lp-dtrack.dk>i>span{display:block;height:100%;border-radius:4px;background:var(--marker);
  animation:lsnGrow 4.5s ease-out infinite}
.lp-time-ok{display:flex;align-items:center;gap:11px;margin-top:18px}
/* Кружок с галочкой зелёный, как в макете v4. Решение владельца 13 сентября
   2026 снимает прежнюю запись «светлый, а не зелёный: зелёный значит верно» —
   здесь галочка и есть подтверждение, что ИИ на всех тарифах есть. Только на
   лендинге; в продукте зелёный по-прежнему значит данные. */
.lp-time-ok .i{width:19px;height:19px;border-radius:50%;background:var(--ok);
  color:var(--lp-dark-ink);font-size:11px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lp-time-ok .t{font-family:var(--font-head);font-weight:600;font-size:13.5px}
.lp-time-ok .s{font-size:12px;color:var(--lp-dark-muted)}

/* Шаг 4 онбординга: карточка ученика глазами преподавателя — слева досье,
   справа занятия.
   Две колонки на flex, а не на гриде: правая шире левой втрое, и обе
   схлопываются сами. */
.lp-scard{display:flex;flex-wrap:wrap}
.lp-scard>.l{flex:1 1 240px;max-width:290px;min-width:0;box-sizing:border-box;
  border-right:1px solid var(--line);padding:18px;display:flex;flex-direction:column;gap:14px}
.lp-scard>.r{flex:3 1 320px;min-width:0;box-sizing:border-box;background:var(--surface);
  padding:18px 20px;display:flex;flex-direction:column;gap:14px;min-height:330px}
.lp-scard-who{display:flex;align-items:center;gap:var(--s-3)}
.lp-ava.xl{width:48px;height:48px;font-size:17px}
.lp-tags{display:flex;gap:6px;flex-wrap:wrap}
/* От .lp-pill отличается тем, что текст обычный: это метки ученика, а не
   варианты ответа в задании. */
.lp-tagpill{border:1px solid var(--line-2);border-radius:var(--r-pill);padding:3px 10px;
  font-size:11.5px;color:var(--ink-2)}
.lp-facts{display:flex;flex-direction:column;gap:var(--s-2);padding-top:var(--s-3);
  border-top:1px solid var(--line)}
.lp-fact{display:flex;align-items:baseline;gap:10px;font-size:var(--t-sm)}
.lp-fact .k{flex:0 0 78px;color:var(--muted)}
.lp-fact .v{min-width:0;overflow:hidden;text-overflow:ellipsis}
.lp-fact .v.nm{font-family:var(--font-head);font-weight:600}
/* Ссылка на звонок маркерным: это единственная строка карточки, которая ведёт
   наружу платформы. */
.lp-fact .v.ink{color:var(--marker-ink)}
.lp-subs{margin-top:auto;padding-top:14px;border-top:1px solid var(--line)}
.lp-subs-h{display:flex;align-items:baseline;gap:var(--s-2);margin-bottom:var(--s-2)}
.lp-subs-h .lp-mono{margin-left:auto}
/* Третье место страницы с делениями абонемента. Общего класса с .lp-person
   .ticks нет намеренно: там деления фиксированной ширины, здесь тянутся по
   ширине колонки. Пятое гаснет — занятие списывается прямо сейчас. */
.lp-subbar{display:flex;gap:3px}
.lp-subbar span{flex:1;height:6px;border-radius:2px;background:var(--marker)}
.lp-subbar .off-now{animation:lsnDim 4.5s ease-in-out infinite}
.lp-subbar .free{background:var(--lp-track)}
/* Своим классом, а не .lp-sub внутри .lp-subs: на телефоне строка прячется
   через .lp-de, а он одноклассовый и составному селектору проигрывает. */
.lp-subs-till{font-size:11px;color:var(--muted);margin-top:7px}
.lp-tabs{display:flex;gap:2px;flex-wrap:wrap;border-bottom:1px solid var(--line);padding-bottom:var(--s-3)}
.lp-tabs>span{padding:7px var(--s-3);font-size:var(--t-sm);color:var(--ink-2)}
.lp-tabs>span.on{display:flex;align-items:center;gap:var(--s-2);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-1);font-family:var(--font-head);
  font-weight:600;color:var(--ink)}
.lp-tabs .d{width:6px;height:6px;border-radius:50%;background:var(--marker);flex-shrink:0}
.lp-lessons{display:flex;flex-direction:column;gap:7px}
.lp-les{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:10px var(--s-3);font-size:var(--t-sm)}
.lp-les .tm{flex:0 0 60px;font-variant-numeric:tabular-nums;font-size:11px;color:var(--muted)}
.lp-les .t{font-family:var(--font-head);font-weight:600;min-width:0}
.lp-les .st{margin-left:auto;font-size:11px;color:var(--muted)}
/* Ближайшее занятие маркерным — то же значение, что у точки идущего занятия
   в расписании платформы. */
.lp-les.next{background:var(--marker-soft);border:1px solid var(--marker);
  border-radius:var(--r-1);color:var(--marker-ink)}
.lp-les.next .tm,.lp-les.next .st{color:var(--marker-ink)}
.lp-les.box{border:1px solid var(--line);border-radius:var(--r-1)}
/* Галочка и «пропущено» набраны нейтрально, хотя в макете они зелёная и
   красная: на платформе эти два цвета значат «верно» и «ошибка» и статусами
   занятия не распоряжаются. Отличают строки слова, а не цвет. */
.lp-les .ck{width:16px;height:16px;border-radius:50%;background:var(--surface-2);color:var(--muted);
  font-size:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lp-les.miss .st{color:var(--ink-2)}
.lp-scard-foot{margin-top:auto;padding-top:14px;border-top:1px solid var(--line);
  display:flex;gap:10px;flex-wrap:wrap;align-items:center}
/* Кнопки в макете нарисованы, а не работают: в разметке это span, поэтому
   наведения у них нет — как и в прежнем макете кабинета. */
.lp-btn.xs{font-size:var(--t-sm);padding:9px 15px;border-radius:var(--r-1)}
.lp-btn.line{border:1px solid var(--line-2);color:var(--ink-2)}

/* ---------- Поле запроса и список собранных блоков (шаг 1 онбординга) ----------
   Поле запроса набрано как настоящий текст преподавателя, а не как подпись
   к макету: в нём вся мысль блока — урок описывают словами. */
.lp-prompt{border:1px solid var(--line);border-radius:var(--r-1);background:var(--paper);padding:11px var(--s-3);margin-bottom:11px}
.lp-prompt p{margin:6px 0 0;font-size:var(--t-sm);line-height:1.5;color:var(--ink-2)}
.lp-res.gen{gap:6px}
.lp-res.gen .lp-chip{display:flex;align-items:center;gap:9px;padding:8px 11px}
.lp-res.gen .nn{font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);flex-shrink:0}
.lp-res.gen .lp-line{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lp-res.gen .cl{margin:0;flex-shrink:0}
/* На узком экране подпись поджимала текст задания до многоточия. В мобильном
   макете хендоффа этот блок сложен иначе: сначала само задание, под ним номер
   с подписью — так читается и то и другое. */
@media(max-width:620px){
  .lp-res.gen .lp-chip{flex-wrap:wrap;gap:3px 7px}
  .lp-res.gen .lp-line{flex:1 0 100%;order:-1;white-space:normal;overflow:visible;text-overflow:clip}
  /* «01 · карточки слов» одной строкой под заданием, как в мобильном макете */
  .lp-res.gen .cl::before{content:'· '}
}

/* ---------- Мобильный макет хендоффа ----------
   Мобильная версия в пакете сверстана отдельно, а не сжата из десктопной: там
   короче подписи и меньше второстепенных деталей в макетах. Держим это одной
   разметкой — иначе два файла разъедутся при первой же правке текста.

   .lp-de — то, что остаётся только на широком экране, .lp-mo — наоборот. */
.lp-mo{display:none}
@media(max-width:620px){
  .lp-de{display:none}
  .lp-mo{display:inline}

  /* Hero: расписание слева и подпись «ПОЛЯ» на телефоне уходят — в мобильном
     макете первый экран показывает сам урок и заметки к нему, без рабочего
     стола вокруг. */
  .lp-top .lp-desk>.l{display:none}
  .lp-top .lp-desk>.r>.lp-meta{display:none}

  /* Прогресс в панелях «У вас / У ученика»: на телефоне полосы дублируют друг
     друга дважды подряд и только шумят. */

}

/* Раскладка держится на flex-wrap: колонки схлопываются сами. Медиазапросы
   нужны только внутренним сеткам макетов — в хендоффе они не решены. */
@media(max-width:1000px){.lp-sec{padding-top:88px}}
@media(max-width:760px){
  .lp-desk{grid-template-columns:1fr;min-height:0}
  .lp-desk>.l{border-right:none;border-bottom:1px solid var(--line)}
  .lp-desk>.r{border-left:none;border-top:1px solid var(--line)}
  .lp-foot{margin-top:var(--s-3)}
  .lp-desk>.c .lp-prog{margin-top:var(--s-3)}
  /* Колонки карточки ученика встают друг под друга: рамка справа переезжает
     вниз, ограничение ширины левой снимается. */
  .lp-scard>.l{max-width:none;border-right:none;border-bottom:1px solid var(--line)}
}
@media(max-width:620px){
  .lp-sec{padding:80px var(--s-4) 0}
  .lp-sec-hero{padding-top:36px}
  .lp-head-in{padding:var(--s-3) var(--s-4);gap:10px}
  .lp-head nav{gap:var(--s-3)}
  .lp-row,.lp-row.lp-top{gap:36px}
  .lp-cta-sec{margin-top:72px;padding:0 var(--s-4)}
  .lp-footer{padding:28px var(--s-4) 48px}
  .lp-money{font-size:28px}
  /* Типографика мобильной вёрстки. У неё в хендоффе свой ряд, а не нижняя
     граница десктопного clamp(): заголовки там мельче на 3–4px. Разница
     решает — на 393px «И работает на всех тарифах» неразрывной строкой при
     27px упиралась в край тёмного блока, хотя абзацы под ней заканчивались
     сильно левее, и блок читался кривым. При 23px строка встаёт на место. */
  /* 34px, а не 31px из хендоффа: на 31px «Lessona – AI-платформа» помещается
     в одну строку, и имя перестаёт стоять отдельно. На 34px перенос после
     «Lessona –» происходит сам, без принудительного <br> — а он здесь только
     вредит: text-wrap:pretty перебалансирует остаток и оставляет
     «AI-платформа» одинокой строкой. Сознательное отступление от макета. */
  .lp h1{font-size:34px}
  .lp h2{font-size:24px}
  .lp h2.on-dark{font-size:24px}
  .lp-txt p{font-size:14.5px}
  .lp-dark{padding:26px 22px;border-radius:var(--r-2)}
  .lp-dark.end{padding:26px 22px}
}

/* ---------- Третий заход: якоря шапки, первый экран, три новых блока ----------
   Всё с префиксом lp-: голые .plan, .step, .card заняты платформой и притащили
   бы сюда свои сетки и рамки. */

/* Якоря шапки. Стоят вне nav, сразу за знаком: 12px гэпа .lp-head-in плюс
   16px здесь дают отступ от знака в 28px, как в макете. */
.lp-nav-links{display:flex;gap:var(--s-1);margin-left:var(--s-4)}
.lp-nav-a{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink-2);
  padding:7px 12px;border-radius:var(--r-1);transition:background var(--dur-fast) var(--ease)}
/* У ссылок лендинга на наведении меняется цвет; у якоря — только подложка,
   иначе строка меню «дышит» цветом при каждом проходе мыши. */
.lp a.lp-nav-a:hover{background:var(--surface-2);color:var(--ink-2)}

/* Первый экран. Заголовок, абзац и ряд «кнопка плюс условие» набраны общими
   правилами .lp h1 / .lp-body / .lp-cta; строка языков под кнопкой — .lp-langs
   там же, где и остальное про первый экран. */

/* Полотно «Как начать» жёлтое, номера шагов — в жёлтых кругах. Решение
   владельца в макетах v4 (12 сентября 2026): на витрине это приглашение
   начать, и выделено оно тем же цветом, каким на странице отмечена работа ИИ.
   Прежняя запись «номер шага приглушённый, а не жёлтый» этим снята. Внутри
   продукта значения жёлтого прежние — исключение живёт только на лендинге. */
.lp-pane{background:var(--marker-soft);border:1px solid var(--marker);border-radius:var(--r-3);
  padding:clamp(28px,3.6vw,44px)}
.lp-pane .lp-txt p{color:var(--marker-ink)}

/* «Как начать». Шапка листа осталась в две колонки на случай второй
   половины, но правая пуста: флаги уехали под кнопку первого экрана. */
.lp-pane-head{display:flex;flex-wrap:wrap;gap:var(--s-5);align-items:flex-end;margin-bottom:26px}
.lp-pane-head .lp-head-group{flex:1 1 420px;min-width:0;max-width:none;margin-bottom:0}
.lp-pane-head .lp-txt p{max-width:52ch}
.lp-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}
.lp-step{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-2);
  padding:22px 24px;box-sizing:border-box;min-width:0}
.lp-step .n{width:34px;height:34px;border-radius:50%;background:var(--marker-soft);color:var(--marker-ink);
  display:flex;align-items:center;justify-content:center;font-family:var(--font-head);
  font-variant-numeric:tabular-nums;font-size:14px;font-weight:700;margin-bottom:14px}
.lp-step .t{font-family:var(--font-head);font-weight:700;font-size:18px;letter-spacing:-.02em;margin-bottom:7px}
.lp-step .s{font-size:13.5px;line-height:1.55;color:var(--muted)}
/* Второй призыв страницы крупнее первого: он стоит внизу листа, где решение
   уже принимают, а не читают. */
.lp-btn.lg{font-weight:700;font-size:17px;border-radius:var(--r-1);padding:17px 32px}
.lp-pane .lp-cta{margin-top:26px;gap:14px}
.lp-pane .lp-cta-note{font-size:13.5px}

/* Тарифы. Витрина, а не рабочая сетка: механика включается 15 сентября.
   Полотно с заливкой — свой токен --lp-band, а не --lp-track: тот назван под
   жёлоб полосы, и совпадение значений случайное. */
.lp-plans{background:var(--lp-band);border-radius:var(--r-3);padding:clamp(30px,4vw,48px)}
/* Отступ под заголовком — с запасом на подъём Pro: карточка поднята на 14
   пикселей, и когда 14 сентября сняли заглушку «Тарифы появятся 15 сентября»,
   при --s-4 она подошла к заголовку на два пикселя. */
.lp-plans .lp-head-group{max-width:58ch;margin-bottom:var(--s-6)}
/* Колонки заданы числом, а не auto-fit: на средней ширине auto-fit оставляет
   две колонки, и Pro со своим order:-1 уезжает в первую строку один. */
.lp-plan-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-4);align-items:stretch}
.lp-plan{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-2);
  padding:24px 26px;display:flex;flex-direction:column;box-sizing:border-box;min-width:0}
/* Единственная рамка на странице, которая что-то значит. Чернильная, а не
   маркерная: жёлтый на платформе — это ИИ, а не «этот тариф лучше». */
.lp-plan.top{border:1.5px solid var(--ink);padding:28px;
  box-shadow:0 22px 54px rgba(23,26,33,.12);transform:translateY(-14px)}
.lp-plan-head{display:flex;align-items:center;gap:10px}
.lp-plan-head .nm{font-family:var(--font-head);font-weight:700;font-size:19px;letter-spacing:-.02em}
.lp-plan.top .lp-plan-head .nm{font-size:21px}
.lp-plan-badge{background:var(--ink);color:var(--paper);border-radius:var(--r-pill);padding:3px 10px;
  font-family:var(--font-head);font-weight:700;font-size:11px;white-space:nowrap}
/* Подпись стоит между именем и ценой, из-за чего цены в трёх карточках не
   выстраиваются по одной линии. Так в макете; подгонять не надо. */
.lp-plan-for{font-size:var(--t-base);line-height:1.5;color:var(--ink-2);margin-top:var(--s-2);text-wrap:pretty}
.lp-plan-price{display:flex;align-items:baseline;gap:var(--s-2);margin:10px 0 20px}
.lp-plan-price .v{font-family:var(--font-head);font-weight:700;font-size:34px;letter-spacing:-.03em}
.lp-plan.top .lp-plan-price .v{font-size:40px}
.lp-plan-price .p{font-size:var(--t-base);color:var(--muted)}
.lp-plan-list{display:grid;gap:10px}
.lp-plan-list>div{display:flex;gap:10px;align-items:baseline}
.lp-plan-list .k{font-family:var(--font-head);font-weight:700;font-size:15px;min-width:34px;
  font-variant-numeric:tabular-nums}
.lp-plan-list .d{font-size:13.5px;line-height:1.5;color:var(--ink-2)}
/* Кнопки прижаты к низу карточки: у Pro+ над ценой стоит подпись, и без этого
   три кнопки встали бы на разной высоте. */
.lp-plan-foot{display:block;margin-top:auto;padding-top:24px}
.lp-plan-btn{display:block;padding:12px;text-align:center;border:1px solid var(--line-2);
  border-radius:var(--r-1);font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  color:var(--ink);transition:background var(--dur-fast) var(--ease)}
.lp-plan-btn.dark{background:var(--ink);border-color:var(--ink);color:var(--paper);
  padding:15px;font-weight:700;font-size:15px}
/* Общее правило лендинга перекрасило бы текст кнопки на наведении, а в макете
   кнопки цвет не меняют. Все три кнопки — ссылки на регистрацию: Pro и Pro+
   стали ими 14 сентября, вместе со снятой заглушкой о дате. Тёмной кнопке Pro
   светлый фон наведения не годится — светлый текст на нём пропал бы, — и она
   темнеет, как тёмные кнопки страницы (.lp-btn.dark). */
.lp a.lp-plan-foot:hover{color:inherit}
.lp a.lp-plan-foot:hover .lp-plan-btn{background:var(--surface-2)}
.lp a.lp-plan-foot:hover .lp-plan-btn.dark{background:#000;border-color:#000;color:#fff}
.lp-plans-foot{margin-top:14px;font-size:var(--t-base);color:var(--muted);text-wrap:pretty}

/* Тарифы и шаги на узком экране встают столбцом. Порядок — Free, Pro, Pro+,
   как в мобильной странице v4: разбор v3 ставил Pro первым, готовая страница
   ставит по цене, и она сильнее разбора. */
@media(max-width:900px){
  /* Три якоря в шапке телефона не помещаются рядом со знаком и кнопкой */
  .lp-nav-links{display:none}
  .lp-plan-grid{grid-template-columns:1fr;max-width:420px;margin-left:auto;margin-right:auto}
  /* В столбце подъём на 14 пикселей не читается; рамка и плашка остаются */
  .lp-plan.top{transform:none}
}
@media(max-width:620px){
  .lp-pane,.lp-plans{padding:24px 20px;border-radius:var(--r-2)}
  /* Приподнятая карточка в столбце стоит вровень с остальными, и её лишние
     четыре пикселя отступа на 390px уже мешают. */
  .lp-plan.top{padding:24px 26px}
}

/* Анимации макетов. Общий цикл 9с — он и создаёт впечатление живого продукта,
   поэтому длительности и задержки перенесены из хендоффа как есть. */
@keyframes lsnScan{0%{transform:translateY(-6px);opacity:0}6%{opacity:1}42%{transform:translateY(148px);opacity:1}54%{opacity:0}100%{transform:translateY(148px);opacity:0}}
@keyframes lsnRise{0%,6%{opacity:0;transform:translateY(9px)}16%,88%{opacity:1;transform:none}97%,100%{opacity:0;transform:translateY(-5px)}}
@keyframes lsnPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.3;transform:scale(.82)}}
@keyframes lsnBlink{0%,45%{opacity:1}46%,100%{opacity:0}}
@keyframes lsnGrow{0%,12%{width:0}44%,88%{width:100%}98%,100%{width:0}}
@keyframes lsnNote{0%,10%{opacity:0;transform:translate(8px,12px) rotate(-7deg)}22%{opacity:1;transform:translate(0,0) rotate(-3deg)}52%{opacity:1;transform:translate(0,0) rotate(-3deg)}68%,88%{opacity:1;transform:translate(-7px,-14px) rotate(-1deg)}98%,100%{opacity:0;transform:translate(-7px,-14px) rotate(-1deg)}}
@keyframes lsnBar{0%,8%{transform:scaleY(.12)}34%,100%{transform:scaleY(1)}}
@keyframes lsnTick{0%,34%{opacity:0;transform:scale(.5)}44%,90%{opacity:1;transform:scale(1)}99%,100%{opacity:0;transform:scale(1)}}
@keyframes lsnDim{0%,46%{opacity:1}58%,100%{opacity:.16}}
@keyframes lsnRing{0%,100%{box-shadow:0 0 0 0 rgba(232,163,23,.5)}50%{box-shadow:0 0 0 7px rgba(232,163,23,0)}}

/* ---------- Лендинг: шесть экранов онбординга ----------
   v4 меняет способ чтения страницы: вместо двенадцати секций, которые надо
   листать, пять секций на странице и шесть экранов, которые надо пройти.
   Довод и порядок — в views/landing.html, тут только механика.

   Показом управляет :target, без JS. Это не изящество ради изящества: при
   выключенном JS страница остаётся прежним длинным лендингом, весь текст лежит
   на одном адресе, и исполнять скрипты, чтобы его прочесть, не нужно ни
   человеку, ни поисковику.

   Класс .lp-scr, а не .lp-step: .lp-step на этой же странице уже занят
   карточками «Как начать», и второй смысл завёлся бы у него молча. */
.lp-scr{display:none}
/* svh рядом с vh: на телефоне полосы Safari съедают до 150 пикселей, и экран
   с единственной кнопкой обязан входить в меньшую из высот, а не в большую. */
.lp-scr:target{display:flex;flex-direction:column;background:var(--paper);
  min-height:100vh;min-height:100svh}
/* Открыт шаг — страница уступает место целиком. Иначе шаг встанет посреди
   лендинга, и «пройти» опять превратится в «листать». */
.lp:has(.lp-scr:target)>:not(.lp-scr){display:none}

/* Шапка шага: знак, шесть сегментов, счётчик. Ни «Закрыть», ни «Пропустить» —
   так в макете. Выход один, и это знак слева: он же говорит, куда выход. */
.lp-scr-top{flex:0 0 auto;height:64px;padding:0 28px;display:flex;align-items:center;
  gap:var(--s-4);border-bottom:1px solid var(--line)}
.lp-scr-top .brand{font-size:17px;letter-spacing:-.02em;gap:9px}
.lp-segs{flex:1;max-width:520px;margin:0 auto;display:flex;gap:6px}
.lp-segs i{flex:1;height:4px;border-radius:2px;background:var(--line)}
/* Закрашено столько сегментов, сколько шагов пройдено. Числом в разметке, а не
   классом на каждом сегменте: счётчик рядом называет то же число, и расходиться
   им негде. */
.lp-segs[data-on="1"] i:nth-child(-n+1),
.lp-segs[data-on="2"] i:nth-child(-n+2),
.lp-segs[data-on="3"] i:nth-child(-n+3),
.lp-segs[data-on="4"] i:nth-child(-n+4),
.lp-segs[data-on="5"] i:nth-child(-n+5),
.lp-segs[data-on="6"] i{background:var(--ink)}

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

   Шапка шага неподвижна: она рамка, меняется то, что внутри. У кого в системе
   включено «уменьшить движение», всё это снимает общее правило платформы, и
   шаг просто появляется — в конечном виде, без пустого кадра. */
@keyframes lsnStepIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@keyframes lsnSegFill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.lp-scr:target .lp-scr-side h2,
.lp-scr:target .lp-scr-side .lp-txt,
.lp-scr:target .lp-scr-shot,
.lp-scr:target .lp-scr-act{animation:lsnStepIn var(--dur-slow) var(--ease-s) both}
.lp-scr:target .lp-scr-side .lp-txt{animation-delay:50ms}
.lp-scr:target .lp-scr-shot{animation-delay:100ms}
.lp-scr:target .lp-scr-act{animation-delay:160ms}
/* Новый сегмент: жёлоб остаётся, чернильная заливка едет поверх. Какой сегмент
   новый, говорит тот же data-on, что красит пройденные. На регистрации шестой
   заполняется при загрузке — это и есть вход в шестой шаг. */
.lp-segs i{position:relative;overflow:hidden}
.lp-scr:target .lp-segs[data-on="1"] i:nth-child(1),
.lp-scr:target .lp-segs[data-on="2"] i:nth-child(2),
.lp-scr:target .lp-segs[data-on="3"] i:nth-child(3),
.lp-scr:target .lp-segs[data-on="4"] i:nth-child(4),
.lp-scr:target .lp-segs[data-on="5"] i:nth-child(5),
.lp-tour .lp-segs[data-on="6"] i:nth-child(6){background:var(--line)}
.lp-scr:target .lp-segs[data-on="1"] i:nth-child(1)::after,
.lp-scr:target .lp-segs[data-on="2"] i:nth-child(2)::after,
.lp-scr:target .lp-segs[data-on="3"] i:nth-child(3)::after,
.lp-scr:target .lp-segs[data-on="4"] i:nth-child(4)::after,
.lp-scr:target .lp-segs[data-on="5"] i:nth-child(5)::after,
.lp-tour .lp-segs[data-on="6"] i:nth-child(6)::after{content:'';position:absolute;inset:0;
  background:var(--ink);transform-origin:left center;
  animation:lsnSegFill var(--dur-slow) var(--ease-s) 80ms both}
.lp-scr-n{font-family:var(--font-head);font-weight:600;font-size:13px;color:var(--muted);
  font-variant-numeric:tabular-nums;min-width:120px;text-align:right}

/* Тело шага сеткой, а не флексом. Кнопка обязана стоять под текстом на широком
   экране и последней на телефоне; во флексе для этого она должна лежать внутри
   текстовой колонки — и тогда на телефоне её оттуда не вынуть. */
.lp-scr-body{flex:1;min-height:0;width:100%;max-width:1160px;margin:0 auto;padding:28px;
  display:grid;grid-template-columns:1fr 1.15fr;column-gap:56px;align-items:center;
  grid-template-areas:"top shot" "side shot" "act shot" "bot shot";
  grid-template-rows:1fr auto auto 1fr}
/* Две пустые строки сверху и снизу — не украшение, а мера. Демо справа выше
   текста с кнопкой, и лишнюю высоту сетка раздаёт тем строкам, что умеют
   расти: без пустых это были строки текста и кнопки, и между ними вырастала
   полоса в полсотни пикселей. Отступ кнопки задан ей самой, а не зазором
   строк, иначе тот же зазор встал бы и над текстом. */
.lp-scr-side{grid-area:side;min-width:0}
.lp-scr-shot{grid-area:shot;min-width:0}
.lp-scr-act{grid-area:act;min-width:0;padding-top:30px}
.lp-scr-side h2{font-family:var(--font-head);font-weight:700;font-size:clamp(26px,3vw,38px);
  line-height:1.12;letter-spacing:-.025em;margin-bottom:16px;text-wrap:pretty}
/* Шаг занятия — единственный горизонтальный: две карточки «у вас» и «у ученика»
   рядом и есть его мысль, а в половине ширины они её не показывают. */
.lp-scr-body.wide{grid-template-columns:1fr;
  grid-template-areas:"top" "side" "act" "shot" "bot";
  grid-template-rows:1fr auto auto auto 1fr}
.lp-scr-body.wide .lp-scr-shot{padding-top:30px}
.lp-scr-body.wide .lp-txt p{max-width:62ch}

/* Первый экран: обрез демо, ссылка под ним, ряд языков под кнопкой */
.lp-crop{max-height:236px;overflow:hidden;position:relative}
/* transparent, а не белый с нулевой альфой: градиенты смешиваются с учётом
   премножения, и прозрачный конец не подкрашивает середину — зато в тёмной
   теме затухание уходит в свою бумагу, а не в светлую. */
.lp-fade{position:absolute;left:0;right:0;bottom:0;height:90px;pointer-events:none;
  background:linear-gradient(180deg,transparent,var(--paper))}
.lp-look{text-align:center;margin-top:14px;font-family:var(--font-head);font-weight:600;font-size:13px}
.lp-look a{color:var(--marker-ink)}
.lp-langs{display:flex;align-items:center;gap:8px;margin-top:22px;font-size:12.5px;color:var(--muted)}
.lp-flagrow{display:flex;align-items:center;gap:4px}
/* Значок «собрано с ИИ» не мигает: в шапке демо он подпись, а не работа,
   которая идёт прямо сейчас. */
.lp-tag.still{letter-spacing:0;font-size:11.5px;font-weight:600}
/* Уровень стоит рядом с названием урока, а не улетает вправо: в шапке макета
   .lp-sub по умолчанию отжат в конец строки, а тут он подпись к названию. */
.lp-bar .lp-sub.lp-lvl{margin-left:0}

/* Шаг 1: два входа в урок */
.lp-two{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:stretch}
.lp-two>*{min-width:0;margin:0}
.lp-two .lp-src{min-height:150px}
/* Обведён чернилами тот, в котором курсор: показано не «выберите одно из двух»,
   а «вот я пишу словами». */
.lp-two .lp-prompt.on{background:var(--surface);border:1.5px solid var(--ink)}
.lp-two .lp-prompt p{font-size:14px;color:var(--ink)}
/* Стрелка приглушённая, но не волосяная: она говорит «а дальше вот что», и
   линейным серым её просто не видно. */
.lp-down{display:flex;justify-content:center;margin:10px 0;color:var(--muted);font-size:16px;line-height:1}

/* Шаг 2: правка одного блока словами */
.lp-sub.push{margin-left:auto;font-variant-numeric:tabular-nums}
.lp-blocks{padding:18px;display:flex;flex-direction:column;gap:8px}
.lp-blk{border:1px solid var(--line);border-radius:var(--r-1);padding:11px 14px;position:relative}
/* Соседи приглушены, а не спрятаны: правится один блок, но урок вокруг остаётся
   на месте, и это видно. */
.lp-blk.dim{opacity:.55}
.lp-blk.pick{border:1.5px solid var(--marker);box-shadow:0 0 0 4px rgba(232,163,23,.14);padding-right:80px}
.lp-blk>.lp-meta{margin-bottom:4px}
.lp-fillw{display:inline-flex;align-items:center;justify-content:center;min-width:80px;height:28px;
  vertical-align:middle;border-radius:8px;background:var(--surface-2);border-bottom:2px solid var(--muted);
  font-family:var(--font-head);font-weight:600;font-size:14px;line-height:1;color:var(--ink-2)}
.lp-aibtn{position:absolute;top:10px;right:10px;height:32px;padding:0 12px;border-radius:var(--r-1);
  background:var(--marker-soft);color:var(--marker-ink);display:flex;align-items:center;
  font-family:var(--font-head);font-weight:700;font-size:12.5px;animation:lsnRing 2s ease-in-out infinite}
.lp-fix{border:1px solid var(--marker);border-radius:var(--r-1);background:var(--marker-soft);padding:12px 14px}
.lp-fix .lp-meta.ink{color:var(--marker-ink);letter-spacing:.06em;font-weight:600;margin-bottom:4px}

@media(max-width:900px){
  /* На телефоне кнопка всегда последняя: сначала обещание, потом показ, потом
     действие. Порядок «текст → кнопка → демо» на узком экране убрал бы показ
     за сгиб, а он и есть довод. */
  .lp-scr-body,.lp-scr-body.wide{grid-template-columns:1fr;
    grid-template-areas:"top" "side" "shot" "act" "bot";
    grid-template-rows:1fr auto auto auto 1fr}
  .lp-scr-body .lp-scr-shot,.lp-scr-body.wide .lp-scr-shot{padding-top:22px}
  .lp-scr-act{padding-top:12px}
  /* Кнопка шага — главное действие экрана: во всю ширину и 56 пикселей, как
     главное действие любого экрана телефона. Слева в углу она читалась бы
     ссылкой «дальше по тексту», а не единственным ходом со страницы. */
  .lp-scr-act .lp-btn{display:flex;width:100%;min-height:56px;font-size:16px}
}
@media(max-width:620px){
  /* Первый экран телефона считается по остатку, а не по вёрстке на глаз.
     Заголовок и абзац занимают, сколько занимают; демо забирает остаток и им же
     обрезается; кнопка стоит внизу экрана. Так сгиб гарантирован при любой
     длине текста, а не только при той, что была в макете, — а длина текста тут
     меняется чаще всего остального.

     Порядок: сначала обещание, потом показ, потом действие. Кнопка после
     показа, а не до него — тот же довод, что у шагов онбординга. */
  /* Высота ограничена сверху, а не задана. Задать нельзя: на высоком телефоне
     (852, 932) содержимое короче экрана, остаток достаётся демо, и под
     обрезанной карточкой вырастала пустая полоса в полтораста пикселей —
     обрез обещал продолжение, а под ним было ничего.

     max-height флексу для сжатия достаточно: когда содержимое выше предела,
     высота становится определённой и демо сжимается ровно на разницу; когда
     ниже — экран ровно по содержимому, и сразу за ним начинается следующий
     блок. Вычитается шапка: она в потоке и стоит своими 56 пикселями. */
  .lp-sec-hero{box-sizing:border-box;padding:22px 16px 16px;
    max-height:calc(100vh - 56px);max-height:calc(100svh - 56px);
    display:flex;flex-direction:column}
  /* align-items возвращаем в stretch. В ряду он стоит center — для двух колонок
     это правильно, а в колонке center означает «по ширине содержимого», и демо
     разъезжалось до 732 пикселей, унося за собой боковую прокрутку страницы. */
  .lp-row.lp-top{flex:1;min-height:0;display:flex;flex-direction:column;
    flex-wrap:nowrap;align-items:stretch;gap:0}
  /* Три сброса, все от ряда, который на широком экране правильный: перенос в
     колонке раскладывает детей не строками, а колонками — и демо уезжало вправо
     за край страницы; center в колонке означает «по ширине содержимого», а
     end/start прижимали бы колонку к правому и левому краю. */
  .lp-top>.lp-side,.lp-top>.lp-shot,.lp-hero-act{flex:0 0 auto;align-self:stretch}
  /* Только сжимается, не растёт: внутри карточка своей высоты, и растяжка
     добавила бы не урок, а воздух внутри рамки. */
  .lp-top>.lp-shot{flex:0 1 auto;min-height:0;overflow:hidden;position:relative;margin-top:12px}
  /* Затухание переезжает на обрезающую рамку: внутри карточки оно осталось бы
     за нижним краем видимого и обрез вышел бы ножом по строке. */
  .lp-crop{max-height:none}
  .lp-top .lp-fade{display:none}
  .lp-top>.lp-shot::after{content:'';position:absolute;left:0;right:0;bottom:0;height:56px;
    pointer-events:none;background:linear-gradient(180deg,transparent,var(--paper))}
  /* «Смотреть, как это работает» на телефоне лишнее: кнопка ведёт туда же и
     стоит на экране рядом. */
  .lp-look{display:none}
  .lp-hero-act{margin-top:12px}
  .lp-langs{display:none}
  /* Кнопка на всю ширину и 56 пикселей — главное действие экрана по правилу
     телефона. Подпись уходит под неё строкой, а не встаёт рядом. */
  .lp-sec-hero .lp-cta{flex-direction:column;align-items:stretch;gap:8px}
  .lp-sec-hero .lp-cta .lp-btn{width:100%;min-height:56px;font-size:16px}
  /* Кегли первого экрана — из мобильного макета v4, а не с нижней границы
     десктопного clamp(): 30 и 14 вместо 34 и 16. Дело не в красоте: экран
     считается по остатку, и каждая лишняя строка абзаца отнимает его у демо —
     на 34/16 абзац занимал семь строк, а демо оставалось 80 пикселей. */
  .lp-sec-hero h1{font-size:30px;line-height:1.08;letter-spacing:-.035em;margin-bottom:10px}
  .lp-sec-hero .lp-body{font-size:14px;line-height:1.5;margin-bottom:0}
  .lp-sec-hero .lp-cta-note{font-size:12.5px;text-align:center}
  /* Тёмная кнопка из шапки на телефоне снята: то же действие стоит на этом же
     экране во всю ширину, и второй раз занимать им строку шапки незачем. */
  .lp-head .lp-btn.dark.sm{display:none}
  /* Две оставшиеся цели шапки — знак и «Войти». Вид не меняем, зону дотягиваем
     до 44 (правило 1e). Ссылки подвала не трогаем: они стоят в два ряда с
     зазором 20, и зоны по 44 перехватывали бы нажатия друг у друга. */
  .lp-head .brand,.lp-login{position:relative}
  .lp-head .brand::after,.lp-login::after{content:'';position:absolute;
    left:-8px;right:-8px;top:50%;height:44px;transform:translateY(-50%)}
  .lp-scr-top{height:56px;padding:0 16px;gap:12px}
  /* Знака в шапке шага на телефоне нет — так в мобильном макете v4: строка
     отдана сегментам и счётчику. Выход со шага на телефоне — «назад» самого
     браузера: шаги живут в адресе (#step1…), и он возвращает ровно на шаг. */
  .lp-scr-top .brand{display:none}
  .lp-segs{gap:4px}
  .lp-scr-n{min-width:0}
  .lp-scr-body{padding:18px 16px 16px}
  .lp-scr-side h2{font-size:var(--t-d1);margin-bottom:8px}
  .lp-scr-body .lp-scr-shot,.lp-scr-body.wide .lp-scr-shot{padding-top:10px}
  /* Подписи внутри демо на телефоне крупнее, чем на широком экране. Это не
     прихоть макета: правило телефона запрещает кегли ниже 12, а десятка в
     служебных метках макета была рассчитана на экран в три раза шире. */
  .lp-scr .lp-meta,.lp-scr .lp-sub,.lp-scr .lp-mono,.lp-scr .lp-tag,
  .lp-scr .lp-card-top,.lp-scr .lp-chip .cl{font-size:12px}
  .lp-scr .lp-card.pad{padding:12px}
  .lp-two{gap:8px}
  .lp-two .lp-src{min-height:80px}
  .lp-two .lp-prompt{padding:12px}
  .lp-down{margin:8px 0 0}
  /* Строка блока остаётся одной строкой. Общее мобильное правило переносит
     подпись под текст задания — оно писалось для длинных названий из учебника,
     а здесь названия короткие, и перенос стоит лишних сорок пикселей на шаг. */
  .lp-scr .lp-res.gen .lp-chip{flex-wrap:nowrap;padding:8px 12px}
  .lp-scr .lp-res.gen .lp-line{flex:1;order:0;white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis}
  .lp-scr .lp-res.gen .cl::before{content:none}
  .lp-blocks{padding:12px;gap:8px}
  .lp-blk{padding:8px 12px}
  /* Значок ИИ остаётся в углу, а место ему освобождает подпись блока, а не весь
     блок: отступ на всю карточку сдвинул бы и текст задания, а он тут главный. */
  .lp-blk.pick{padding:12px}
  .lp-blk.pick>.lp-meta{padding-right:64px}
  .lp-aibtn{top:8px;right:8px}
  .lp-fix{padding:10px 12px}
  .lp-langs{margin-top:16px;font-size:12px}
  /* Двухклассовые правила макетов сильнее одноклассового .lp-de, и «только на
     широком экране» на них не действовало: у .lp-card.sync и правой половины
     карточки ученика свой display. Называем их прямо — это дешевле, чем ронять
     специфичность самих макетов ради одного исключения. */
  .lp-res.gen .lp-chip.lp-de{display:none}
}

/* Шестой шаг онбординга лендинга — страница регистрации. Полоса та же, что на
   шагах, и класс сегментов тот же нарочно: разойтись им нельзя, они об одном.
   [hidden] объявляем сами — display:flex сильнее заводского display:none у
   атрибута, и полоса показывалась бы всем. */
.lp-tour{height:64px;padding:0 28px;display:flex;align-items:center;gap:var(--s-4);
  border-bottom:1px solid var(--line);background:var(--paper)}
.lp-tour[hidden]{display:none}
.lp-tour .brand{font-size:17px;letter-spacing:-.02em;gap:9px}
@media(max-width:620px){.lp-tour{display:none}}

/* Шаг 4 на широком экране: досье и занятия рядом, как в макете. Колонка демо
   здесь шире, чем у остальных шагов, — 1.3 против 1.15, пропорция макета, — а
   досье не делит ширину с занятиями: в макете у него ровно 240. При 1.15
   карточке не хватало полутора пикселей, занятия уезжали под досье, и справа
   сверху оставался пустой белый прямоугольник. Перенос колонок снят только
   здесь и только шире 900: уже — карточка и должна вставать столбцом. */
@media(min-width:901px){
  #step4 .lp-scr-body{grid-template-columns:1fr 1.3fr}
  #step4 .lp-scard{flex-wrap:nowrap}
  #step4 .lp-scard>.l{flex:0 0 240px;max-width:none}
  #step4 .lp-scard>.r{flex:1 1 auto}
}

/* ---------- Телефонные карточки шагов 3–5 ----------
   В мобильной странице v4 эти три макета собраны заново, а не сжаты из
   широких: одна страница на двоих вместо пары панелей, верх досье вместо
   досье целиком, чипы вместо колонок чисел. Держим обе версии в разметке
   (.lp-dsk и .lp-mob): сжимать широкие правилами пришлось бы по десятку
   исключений на макет, и каждое ломалось бы от первой правки текста. */
.lp-mob{display:none}

/* ---------- Лендинг на телефоне по мобильной странице v4 ----------
   Хвост страницы в макете — не острова карточек на бумаге с отступами по
   восемьдесят пикселей, а сплошные полосы: белая «ИИ забирает рутину»,
   бумажные тарифы, белая «Как начать», чёрный призыв во всю ширину. Отступ
   полосы 32, граница между полосами — линия или смена цвета. Так страница на
   390 читается лентой. Правила стоят последними в разделе лендинга: им надо
   перебить и общий мобильный слой, и ряд третьего захода. */
@media(max-width:620px){
  .lp-scr-shot>.lp-dsk{display:none}
  .lp-scr-shot>.lp-mob{display:block}

  .lp-sec:not(.lp-sec-hero){padding:32px 16px}
  .lp-sec h2,.lp-cta-sec h2{font-size:26px;line-height:1.15;letter-spacing:-.03em;margin:0}
  .lp-cta-sec .lp-dark.end h2.on-dark{font-size:26px;margin:0}
  .lp-sec .lp-txt p,.lp-cta-sec .lp-sub-dark{font-size:16px;line-height:1.55;max-width:none;margin:10px 0 0}

  /* «ИИ забирает рутину»: текст на белой полосе, тёмная — только карточка
     замера. Неразрывность «И работает на всех тарифах» снята: на тёмном
     полотне строка стояла в узкой колонке, на полосе во всю ширину она сама
     встаёт как надо, а в 26-м кегле неразрывной ей не хватает 390. */
  #ai-time{background:var(--surface);border-top:1px solid var(--line)}
  #ai-time .lp-dark{display:block;background:none;color:var(--ink);padding:0;border-radius:0}
  #ai-time h2.on-dark{color:var(--ink)}
  #ai-time .nw{white-space:normal}
  #ai-time .lp-txt.on-dark p{color:var(--ink-2)}
  #ai-time .lp-side+.lp-side{margin-top:16px}
  /* Цвет текста карточке задаём сами: полоса вокруг теперь светлая и отдаёт
     чернила по наследству, а подпись «ИИ включён на всех тарифах» своего цвета
     не имеет — и на тёмной карточке исчезала целиком. */
  #ai-time .lp-time{color:var(--lp-dark-ink);background:var(--lp-dark);border:0;border-radius:18px;padding:18px;
    box-shadow:0 1px 2px rgba(23,26,33,.05),0 18px 44px -14px rgba(23,26,33,.2)}
  #ai-time .lp-time>.lp-meta{color:var(--marker);font-size:12.5px;font-weight:600;letter-spacing:.12em;margin:0}
  #ai-time .lp-time-row{margin:14px 0 0}
  #ai-time .lp-time-row:not(.last){padding-bottom:14px;border-bottom:1px solid var(--lp-dark-line)}
  #ai-time .lp-time-row.last{padding-bottom:0;border-bottom:0}
  #ai-time .lp-time-row .l{flex:0 0 78px;font-family:var(--font-head);font-size:14px;font-weight:600;
    color:var(--lp-dark-muted)}
  #ai-time .lp-time-row .l.on{color:var(--lp-dark-ink)}
  #ai-time .lp-time-row .v{flex:0 0 auto;font-family:var(--font-head);font-size:16px;font-weight:700;
    color:var(--lp-dark-ink)}
  #ai-time .lp-time-row .v.mk{color:var(--marker)}
  #ai-time .lp-time-ok{margin-top:18px;padding-top:16px;border-top:1px solid var(--lp-dark-line);gap:10px}
  #ai-time .lp-time-ok .i{width:22px;height:22px;font-size:12px;background:var(--ok-bg);color:var(--ok)}
  #ai-time .lp-time-ok .t{font-size:15px}
  #ai-time .lp-time-ok .s{font-size:12.5px;line-height:1.5;margin-top:6px}

  /* Тарифы: без серого полотна, три полные карточки подряд */
  #pricing .lp-plans{background:none;padding:0;border-radius:0}
  #pricing .lp-head-group{margin-bottom:0}
  .lp-plan-grid{max-width:none;gap:10px;margin-top:14px}
  .lp-plan,.lp-plan.top{padding:16px}
  .lp-plan-head .nm,.lp-plan.top .lp-plan-head .nm{font-size:16px}
  .lp-plan-badge{font-size:12px}
  .lp-plan-for{font-size:14px;margin-top:6px}
  .lp-plan-price{margin:6px 0 0;gap:7px}
  .lp-plan-price .v{font-size:22px}
  .lp-plan.top .lp-plan-price .v{font-size:26px}
  .lp-plan-price .p{font-size:12.5px}
  .lp-plan-list{gap:8px;margin-top:12px}
  .lp-plan-list .k{font-size:16px}
  .lp-plan-list .d{font-size:14px}
  .lp-plan-foot{padding-top:14px}
  .lp-plan-btn{display:flex;align-items:center;justify-content:center;min-height:48px;
    box-sizing:border-box;padding:0 12px;font-size:14px}
  .lp-plan-btn.dark{min-height:52px;font-size:16px;font-weight:600}
  .lp-plans-foot{font-size:12.5px;line-height:1.5;margin-top:12px}

  /* «Как начать»: на телефоне полоса белая, а не жёлтая — жёлтыми остаются
     круги с номерами, как в макете. Три шага — строки одной карточки, а не
     три карточки: столбик из трёх островов занимал экран на то, что читается
     за три секунды. */
  #onboarding{background:var(--surface);border-top:1px solid var(--line)}
  #onboarding .lp-pane{background:none;border:0;border-radius:0;padding:0}
  #onboarding .lp-pane-head{margin-bottom:0}
  #onboarding .lp-txt p{color:var(--ink-2)}
  .lp-steps{display:block;margin-top:16px;background:var(--surface);border:1px solid var(--line);
    border-radius:18px;overflow:hidden;box-shadow:0 1px 2px rgba(23,26,33,.05),0 18px 44px -14px rgba(23,26,33,.2)}
  .lp-step{display:grid;grid-template-columns:34px 1fr;column-gap:12px;align-items:start;
    padding:14px;border:0;border-radius:0;background:none}
  .lp-step+.lp-step{border-top:1px solid var(--line)}
  .lp-step .n{grid-row:1 / span 2;margin:0}
  .lp-step .t{font-size:16px;font-weight:600;letter-spacing:0;margin:0}
  .lp-step .s{font-size:14px;line-height:1.5;color:var(--ink-2);margin-top:2px}
  #onboarding .lp-cta{flex-direction:column;align-items:stretch;gap:10px;margin-top:16px}
  #onboarding .lp-btn.lg{display:flex;min-height:56px;padding:0 16px;font-size:16px;font-weight:600}
  #onboarding .lp-cta-note{font-size:12.5px;text-align:center}

  /* Чёрный призыв во всю ширину, без скругления: последняя полоса ленты, а не
     карточка на бумаге */
  .lp-cta-sec{margin:0;padding:0}
  .lp-dark.end{display:block;border-radius:0;padding:32px 16px}
  .lp-cta-btn{margin-top:20px}
  .lp-cta-btn .lp-btn.accent{display:flex;width:100%;min-height:56px;box-sizing:border-box;font-size:16px}

  /* Шаг 5 на телефоне — один абзац с переносами, как в макете: два абзаца
     встают строками одного, без зазора. */
  #step5 .lp-txt p{margin-bottom:0}

  /* Шаг 3: одна страница на двоих */
  .lp-duo{background:var(--paper)}
  .lp-duo-head{height:52px;padding:0 14px;display:flex;align-items:center;gap:10px;
    border-bottom:1px solid var(--line);background:var(--surface)}
  .lp-duo-avas{display:flex;align-items:center}
  .lp-duo-avas .a{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;
    justify-content:center;font-family:var(--font-head);font-size:12px;font-weight:700;box-sizing:border-box}
  .lp-duo-avas .a.t{background:var(--ink);color:var(--paper)}
  .lp-duo-avas .a.s{background:var(--marker-soft);color:var(--marker-ink);margin-left:-6px;
    border:2px solid var(--surface)}
  .lp-duo-who{flex:1;min-width:0}
  .lp-duo-who .t{font-family:var(--font-head);font-size:14px;font-weight:600}
  .lp-duo-who .s{font-size:12.5px;color:var(--muted);margin-top:1px;white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis}
  .lp-duo-dot{width:7px;height:7px;flex:0 0 7px;border-radius:50%;background:var(--marker);
    animation:lsnPulse 1.4s ease-in-out infinite}
  .lp-duo-body{padding:14px}
  .lp-duo-task{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:12px}
  .lp-duo-task .k{font-size:12.5px;font-weight:600;letter-spacing:.06em;color:var(--muted)}
  .lp-duo-task .q{font-size:15px;line-height:1.5;margin-top:6px}
  .lp-duo-in{display:flex;align-items:center;margin-top:10px;padding:10px 12px;border-radius:var(--r-1);
    background:var(--surface-2);font-size:15px;white-space:nowrap}
  /* Кружок «Кс» на 22 пикселя, а не 20, и с 12-м кеглем: две буквы в 10-м, как
     в макете, — единственный текст шага ниже 12, и правило телефона важнее. */
  .lp-duo-typing{display:flex;align-items:center;gap:7px;margin-top:8px;font-size:12.5px;color:var(--muted)}
  .lp-duo-typing .a{width:22px;height:22px;flex:0 0 22px;border-radius:50%;background:var(--marker-soft);
    color:var(--marker-ink);display:flex;align-items:center;justify-content:center;
    font-family:var(--font-head);font-size:12px;font-weight:700;letter-spacing:-.02em}

  /* Шаг 4: верх досье */
  .lp-mstu{padding:14px}
  .lp-mstu-who{display:flex;align-items:center;gap:12px}
  .lp-mstu-who .a{width:44px;height:44px;flex:0 0 44px;border-radius:50%;background:var(--line);
    display:flex;align-items:center;justify-content:center;font-family:var(--font-head);
    font-size:13px;font-weight:700;color:var(--ink-2)}
  .lp-mstu-who .t{font-family:var(--font-head);font-size:16px;font-weight:600}
  .lp-mstu-who .s{font-size:12.5px;color:var(--muted);margin-top:2px}
  .lp-mchips{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
  .lp-mchips>span{border-radius:var(--r-pill);background:var(--surface-2);padding:6px 12px;
    font-size:12.5px;color:var(--ink-2)}
  .lp-mchips>span.on{background:var(--ink);color:var(--paper);font-family:var(--font-head);font-weight:600}
  .lp-mchips>span.mk{background:var(--marker-soft);color:var(--marker-ink);font-weight:600}
  .lp-mfacts{border:1px solid var(--line);border-radius:14px;padding:4px 12px;margin-top:12px}
  .lp-mfacts>div{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:10px 0}
  .lp-mfacts>div+div{border-top:1px solid var(--line)}
  .lp-mfacts .k{font-size:14px;color:var(--ink-2)}
  .lp-mfacts .v{font-family:var(--font-head);font-size:16px;font-weight:600}
  .lp-mfacts .v.mk{font-family:inherit;font-size:14px;font-weight:400;color:var(--marker-ink)}
  .lp-msub{border-radius:14px;background:var(--marker-soft);border:1px solid var(--marker);padding:12px;margin-top:10px}
  .lp-msub .h{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
  .lp-msub .k{font-size:12.5px;font-weight:600;letter-spacing:.1em;color:var(--marker-ink)}
  .lp-msub .v{font-family:var(--font-head);font-size:16px;font-weight:700;color:var(--marker-ink);
    font-variant-numeric:tabular-nums}
  .lp-msub .bar{display:flex;gap:5px;margin-top:10px}
  .lp-msub .bar i{flex:1;height:6px;border-radius:var(--r-pill);background:var(--marker-ink)}
  .lp-msub .bar i.free{background:rgba(122,84,6,.22)}
  .lp-msub .till{font-size:12.5px;color:var(--marker-ink);margin-top:6px}

  /* Шаг 5: доход */
  .lp-mpay{padding:16px}
  .lp-mpay-top{display:flex;align-items:flex-end;gap:14px}
  .lp-mpay-top .m{flex:1}
  .lp-mpay-top .k{font-size:12.5px;font-weight:600;letter-spacing:.1em;color:var(--muted)}
  .lp-mpay-top .v{font-family:var(--font-head);font-size:34px;line-height:1;font-weight:700;
    letter-spacing:-.035em;margin-top:8px;font-variant-numeric:tabular-nums}
  .lp-mpay-top .bars{display:flex;align-items:flex-end;gap:4px;height:48px}
  .lp-mpay-top .bars i{width:10px;border-radius:3px;background:var(--marker-soft)}
  .lp-mpay-top .bars i.now{background:var(--marker)}
  .lp-mpay .lp-mchips{margin-top:14px}
  .lp-mrow{display:flex;align-items:center;gap:12px;min-height:64px;box-sizing:border-box;
    margin-top:12px;padding:10px 6px 10px 12px;border:1px solid var(--line);border-radius:14px}
  .lp-mrow .a{width:34px;height:34px;flex:0 0 34px;border-radius:50%;background:var(--line);
    display:flex;align-items:center;justify-content:center;font-family:var(--font-head);
    font-size:13px;font-weight:700;color:var(--ink-2)}
  .lp-mrow .w{flex:1;min-width:0}
  .lp-mrow .t{font-family:var(--font-head);font-size:16px;font-weight:600}
  .lp-mrow .s{font-size:12.5px;font-weight:600;color:var(--marker-ink);margin-top:2px}
  .lp-mrow .b{height:44px;padding:0 14px;box-sizing:border-box;display:flex;align-items:center;
    background:var(--marker-soft);border:1px solid var(--marker);border-radius:var(--r-1);
    font-family:var(--font-head);font-size:14px;font-weight:600;color:var(--marker-ink)}
}

/* ---------- Заготовки: библиотека кусков урока ---------- */
/* Заготовки живут строками одного листа, а не плитками: обложки у заготовки
   нет и быть не может, узнают её по составу — сколько блоков и каких. Раскрытый
   список блоков занимал полкарточки и отвечал на тот же вопрос, что
   перечисление типов одной строкой. */
.sn-note{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}
.sn-list{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-2);padding:var(--s-2)}
/* Пятая колонка — «Вставить». Заготовку заводят ради одного движения, а
   вставить её можно было только изнутри урока: строка про неё рассказывала, но
   ничего не предлагала. */
.sn-row{position:relative;display:grid;grid-template-columns:34px minmax(0,1fr) 72px auto 30px;
  align-items:center;gap:14px;padding:13px 14px;border-radius:var(--r-1)}
.sn-row+.sn-row{border-top:1px solid var(--surface-2)}
.sn-row:hover{background:var(--paper)}
.sn-row-ic{width:34px;height:34px;border-radius:var(--r-1);background:var(--surface-2);color:var(--ink-2);
  display:flex;align-items:center;justify-content:center}
.sn-row-ic svg{display:block}
.sn-row-main{min-width:0}
.sn-row-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);letter-spacing:-.015em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sn-row-sub{margin-top:3px;font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sn-row-date{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted)}
/* Пустой экран объясняет, что такое заготовка: «сохраните из конструктора» без
   примеров ничего не говорит тому, кто ни одной заготовки не видел. */
/* Карточка узкая — 460, чтобы абзац читался, — и потому её надо ставить по
   середине листа самой: .empty центрирует своё содержимое, а не себя, и без
   этих полей карточка прижималась к левому краю пустой страницы. */
.sn-empty{max-width:460px;margin:0 auto;background:var(--surface);border-radius:var(--r-2);
  box-shadow:var(--sh-1);padding:var(--s-5)}
.sn-empty .big{font-size:var(--t-h1);letter-spacing:-.015em;margin-bottom:var(--s-2)}
.sn-empty p{font-size:var(--t-md);line-height:1.6}
.sn-empty-acts{display:flex;gap:var(--s-2);flex-wrap:wrap}
.sn-empty-sep{height:1px;background:var(--surface-2);align-self:stretch;margin:var(--s-5) 0 var(--s-4)}
.sn-empty-list{list-style:none;margin:var(--s-2) 0 0;padding:0;display:flex;flex-direction:column;gap:7px;
  font-size:var(--t-base);color:var(--ink-2)}

/* Режим выбора блоков в конструкторе */
.bpick{width:16px;height:16px;border:2px solid var(--line-2);border-radius:5px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;font-size:var(--t-label);color:var(--paper);font-weight:700}
.bpick.on{border-color:var(--ink);background:var(--ink)}
.block.picked{border-color:var(--ink);box-shadow:0 0 0 2px var(--surface-2)}
/* У выбранной карточки ряд значков виден без наведения: галочка в нём и есть
   признак выбора, а прятать признак до наведения мыши значит его не показать. */
.block.picked .btools{opacity:1}
.icon-btn.pick.on{color:var(--ink);border-color:var(--line)}
/* Панель действий над выбором. Пилюля над уроком: действий в ней столько же,
   сколько у одного блока, поэтому на узком экране она переносит строку, а не
   уезжает за край. */
.select-bar{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);z-index:120;
  display:flex;align-items:center;gap:var(--s-2);background:var(--surface);border:1px solid var(--line-2);
  border-radius:var(--r-3);padding:var(--s-2) var(--s-3);box-shadow:var(--sh-3);
  flex-wrap:wrap;justify-content:center;max-width:calc(100vw - 32px)}
.select-bar .sb-text{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
  white-space:nowrap;margin-right:var(--s-1)}
.select-bar .sb-group{display:flex;gap:var(--s-1)}
.select-bar .sb-tip{font-size:var(--t-sm);color:var(--muted);flex-basis:100%;text-align:center}
/* «Удалить» — контурная, а не залитая. Общий .btn.danger залит красным: он
   рассчитан на кнопку подтверждения в окне, где она одна и главная. В ряду из
   шести действий сплошной красный прямоугольник кричит громче всего остального,
   а надпись на нём (белая по общему правилу, красная по этому) пропадала вовсе —
   получалась красная плашка без слова, которая называла себя только под мышью. */
.select-bar .btn.danger{background:none;color:var(--err);border-color:var(--line-2)}
.select-bar .btn.danger:hover:not([disabled]){border-color:var(--err);background:var(--err-bg)}
.select-bar [disabled]{opacity:.4;pointer-events:none}
/* Пока открыто окно, полоса выбора уходит: она висит над затемнением (z-index
   120 против 100 у .scrim) и лежала поверх окна, которое сама же открыла —
   получалось два ряда кнопок друг на друге. Действуют в окне, а не мимо него. */
body:has(.scrim.open) .select-bar{display:none}
.icon-btn svg{width:15px;height:15px;display:block}

/* ---------- Карточка ученика: рабочее досье ----------
   Слева профиль, справа вкладками занятия, домашние, словарь и приватные заметки. */
/* Второй вид списка учеников: карточки людей. Сетка сама решает, сколько
   колонок влезло, — на широком экране их четыре, в узком окне две. */
.stu-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:var(--s-2)}
.stu-card{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:13px;cursor:pointer;min-width:0;
  transition:box-shadow var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
.stu-card:hover{box-shadow:var(--sh-2);transform:translateY(-2px)}
.stu-card.off{opacity:.55}
.stu-card.off:hover{opacity:1}
.stu-card .stu-ava{width:42px;height:42px;font-size:var(--t-md)}
.sc-name{display:block;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  margin-top:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sc-sub{display:block;font-size:var(--t-sm);color:var(--muted);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.stu-card .bar{height:4px;margin:9px 0 0}
/* Заголовок свёрнутой группы над сеткой карточек: в списке он стоит внутри
   листа и берёт его отступ, здесь листа нет. Селектор двойной: общее правило
   .panel-group-head стоит в файле ниже и обнуляло отступ сверху, и строка
   прилипала к карточкам. Поле слева 14 оставлено от него: по нему стоят
   «показать» под строкой и текст внутри карточек. */
.panel-group-head.stu-cards-head{padding-top:var(--s-5)}

/* Панель карточки ученика шире на два поля: восемь фактов столбиком оставляли
   её правую половину пустой, а саму карточку — длиннее экрана. */
.stu-grid{display:grid;grid-template-columns:360px minmax(0,1fr);gap:20px;align-items:start}
.stu-panel{background:var(--surface);border:none;border-radius:var(--r-2);padding:22px;
  box-shadow:var(--sh-2);position:sticky;top:74px}
.stu-panel .sp-head{display:flex;align-items:center;gap:var(--s-3);margin-bottom:var(--s-4)}
.stu-panel .sp-name{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.025em;line-height:1.15}
/* Уровень и «когда заходил» — одной строкой: это одна мысль «кто передо мной
   сейчас», а порознь они занимали в панели две строки из шести. */
/* В своём контексте: имя общее с подписью панели «Стиль» в конструкторе, и без
   ограничения это правило перебивало там интерлиньяж — соседние селекторы
   вокруг написаны так же. */
.stu-panel .sp-sub{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums;margin-top:3px}
/* Цели — плашками сразу под именем: с ними сверяются, открывая карточку, а не
   ищут их среди почты и телефона. Больше трёх не показываем. */
.sp-goals{display:flex;flex-wrap:wrap;gap:6px;margin-top:18px}
.sp-goal{background:var(--paper);border-radius:var(--r-pill);padding:6px 11px;
  font-size:var(--t-sm);color:var(--ink-2)}
.sp-goal.more{border:none;cursor:pointer;font-family:inherit;color:var(--marker-ink)}
.sp-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px var(--s-3);
  padding:20px 0 0;margin-top:20px;border-top:1px solid var(--line)}
/* На телефоне сведения идут в одну колонку. Две по сто сорок пикселей не
   вмещали строку со значком: «свободный график» занимало колонку целиком, и
   карандаш правки — сорок четыре, как всё нажимаемое на телефоне, — уезжал на
   свою строку и висел под текстом ничьим значком. То же было у почты с
   кнопкой «Задать почту для входа». */
@media(max-width:640px){
  .sp-facts{grid-template-columns:minmax(0,1fr);gap:14px}
}
.sp-fact{display:flex;flex-direction:column;align-items:flex-start;
  gap:3px;font-size:var(--t-sm);min-width:0}
.sp-fact .k{color:var(--muted);flex-shrink:0}
.sp-fact .v{display:flex;align-items:center;justify-content:flex-start;gap:var(--s-2);
  min-width:0;max-width:100%;flex-wrap:wrap;overflow-wrap:anywhere;
  color:var(--ink-2);font-variant-numeric:tabular-nums}
.sp-fact .v.wrap{flex-wrap:wrap}
.sp-balance{background:var(--paper);border-radius:var(--r-1);padding:14px;margin-top:18px}
.sp-bal-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  font-size:var(--t-sm);color:var(--muted)}
.sp-bal-head b{font-family:var(--font-body);font-size:var(--t-base);font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--ink)}
.sp-bal-sub{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted)}
.sp-balance .bar{margin:10px 0 6px}
/* Две кнопки под абонементом: назначить занятие и продлить пакет. Тёмная —
   назначение: из карточки ученика чаще всего уходят именно за этим. */
.sp-bal-acts{display:flex;gap:var(--s-2);margin-top:10px}
.sp-bal-acts .btn{flex:1;justify-content:center}

/* Ближайшее занятие под профилем: когда, о чём и дверь в класс. Плашка на
   бумаге, как абонемент, — это тоже факт об ученике, а не действие. */
.sp-next{background:var(--paper);border-radius:var(--r-1);padding:14px;margin-top:18px}
.sp-next .sn-when{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
  letter-spacing:-.01em;margin-top:var(--s-1)}
.sp-next .sn-what{font-size:var(--t-sm);color:var(--muted);margin:2px 0 10px}
.sp-next .btn{width:100%;justify-content:center}
/* Когда занятия впереди нет, карточка говорит об этом словом, а не пустотой. */
.sp-next.empty-next .sn-when{color:var(--muted);font-size:var(--t-base);margin-bottom:10px}

/* Занятия делятся на впереди и позади: подпись раздела внутри вкладки. */
.eyebrow.stu-part{display:block;margin:18px 0 8px}
.eyebrow.stu-part:first-child{margin-top:0}
/* Ближайшее занятие обведено: из списка впереди оно единственное, к которому
   готовятся сейчас. */
.row.stu-next.first{box-shadow:inset 0 0 0 1px var(--line-2)}
.row.stu-next{border-radius:var(--r-1)}

/* Крошка над карточкой: куда назад и что открыто. */
.stu-trail{display:flex;align-items:center;gap:var(--s-2);margin-bottom:var(--s-3)}
.stu-trail .stu-back{margin-bottom:0}
.stu-who{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink-2)}
.sp-bal-n{font-family:var(--font-head);font-weight:700;font-size:20px;letter-spacing:-.02em}
/* Полоса показывает остаток пакета: она гаснет вместе с ним, а не заполняется
   по мере траты. Жёлтое — то, что осталось, тот же счёт, что в клетках на
   вкладке «Абонементы». Зелёного здесь нет: хвалить нечего, это не успех. */
.sp-balance .bar>span{background:var(--marker)}
.sp-balance .bar.low{background:var(--err)}
.sp-balance .bar.low>span{background:var(--err)}
.sp-note-line{margin-top:var(--s-3);background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-sm)}
.sp-note-line a{color:inherit;font-weight:700}
.stu-panel .field{margin-bottom:var(--s-3)}

.pt-nav{display:flex;gap:3px;background:var(--surface-2);border-radius:var(--r-pill);
  padding:3px;width:100%;margin-bottom:var(--s-4);overflow-x:auto}
.pt-nav button{border:none;background:transparent;padding:var(--s-2) var(--s-4);border-radius:var(--r-pill);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--muted);cursor:pointer;white-space:nowrap;
  flex:1;display:inline-flex;align-items:center;justify-content:center;gap:7px}
.pt-nav button:hover{color:var(--ink)}
.pt-nav button.on{color:var(--ink);background:var(--surface);box-shadow:var(--sh-1)}
/* Счётчик горит жёлтым не у открытой вкладки, а у той, где что-то ждёт
   преподавателя: «эта вкладка открыта» и так видно, а сданная работа раньше
   ничем себя не выдавала. */
.pt-count{background:var(--surface);color:var(--muted);border-radius:var(--r-pill);
  font-variant-numeric:tabular-nums;font-size:var(--t-label);font-weight:600;padding:2px 7px}
.pt-count.wait{background:var(--marker-soft);color:var(--marker-ink)}

/* Два числа над списком занятий */
.stu-nums{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-bottom:var(--s-3)}
.stu-nums.one{grid-template-columns:1fr}
.stu-num{background:var(--surface);border-radius:var(--r-2);padding:14px var(--s-4);box-shadow:var(--sh-1)}
.stu-num b{display:block;font-family:var(--font-head);font-weight:700;font-size:20px;
  letter-spacing:-.02em}
.stu-num span{display:block;font-size:var(--t-sm);color:var(--muted);margin-top:3px}

/* ---------- Вкладка «Разбор» ----------
   Пара «как сказал → как правильно» раскладывается в две колонки со стрелкой
   между ними. Раньше она жила одной строкой внутри заголовка, и стрелку
   приходилось искать глазами в середине фразы. */
.mk-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3)}
.mk-h{font-family:var(--font-head);font-weight:700;font-size:17px;letter-spacing:-.01em}
.mk-c{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted)}
.mk-add{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--s-2);margin:14px 0}
.mk-add input{width:100%;background:var(--surface);border:none;border-radius:var(--r-1);
  padding:var(--s-3) 14px;font-family:inherit;font-size:var(--t-base);color:var(--ink);
  box-shadow:var(--sh-1)}
.mk-add input::placeholder{color:var(--muted)}
.mk-add input:focus{outline:none;box-shadow:0 0 0 1.5px var(--ink)}
.mk-add .btn{border-radius:var(--r-1);padding:var(--s-3) var(--s-4);font-size:var(--t-sm)}
.mk-card{background:var(--surface);border-radius:var(--r-1);padding:var(--s-3) 14px;
  box-shadow:var(--sh-1);margin-bottom:6px;
  transition:transform var(--dur-fast) var(--ease)}
.mk-card:hover{transform:translateY(-1px)}
.mk-card.off{opacity:.55}
.mk-pair{display:grid;grid-template-columns:minmax(0,1fr) 18px minmax(0,1fr);gap:10px;
  align-items:center}
.mk-pair.one{grid-template-columns:minmax(0,1fr)}
.mk-pair .mk-wrong{font-size:var(--t-md)}
.mk-arrow{font-size:var(--t-sm);color:var(--muted);text-align:center}
.mk-right{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.mk-meta{font-size:var(--t-label);font-variant-numeric:tabular-nums;color:var(--muted);margin-top:var(--s-2)}
.mk-acts{display:flex;gap:6px;margin-top:10px}

/* ---------- Вкладка «Абонементы» ----------
   Клетки вместо полосы: занятие — единица, а не процент, и «осталось четыре»
   видно счётом. Жёлтое — остаток, серое — потраченное. */
.sub-card{background:var(--surface);border-radius:var(--r-2);padding:18px;box-shadow:var(--sh-1)}
.sub-card-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-3)}
.sub-n{font-family:var(--font-head);font-weight:700;font-size:18px;letter-spacing:-.02em;
  margin-top:6px}
.sub-meta{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted);margin-top:2px}
.sub-left{text-align:right;flex-shrink:0}
.sub-left>b{display:block;font-family:var(--font-head);font-weight:700;font-size:18px;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.sub-left>span{display:block;font-size:var(--t-sm);color:var(--muted)}
.sub-tools{display:inline-flex;gap:2px;margin-top:6px}
.sub-cells{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:var(--s-1);margin-top:var(--s-4)}
/* Полоса закрашивается по мере того, как пакет расходуется: жёлтое — уже
   проведённые занятия, серое — те, что впереди. Это решение владельца от
   7 сентября, и оно отменяет прежнее «жёлтое — остаток». Читают полосу как
   любую другую — слева направо и как заполнение: полная значит «пакет прожит»,
   и это ровно тот момент, когда пора продлевать. */
.sub-cells i{display:block;height:8px;border-radius:3px;background:var(--surface-2)}
.sub-cells i.done{background:var(--marker)}
/* Тот же светофор, что у полосы: кончившийся пакет красный целиком, а пакет с
   истёкшим сроком остаётся жёлтым — занятия у ученика есть. */
.sub-cells.low i{background:var(--err-bg)}
.sub-cells.low i.done{background:var(--err)}
.sub-sub{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted);margin-top:10px}
.sub-past{display:flex;flex-direction:column;gap:6px;margin-top:var(--s-3)}
.sub-past-row{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  background:var(--surface);border-radius:var(--r-1);padding:var(--s-3) 14px;box-shadow:var(--sh-1)}
.sub-past-n{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sub-past-m{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted);margin-top:1px}
.sub-past-r{display:flex;align-items:center;gap:var(--s-2);flex-shrink:0}
.sub-past-r .sub-tools{margin-top:0}
.sub-sum{font-size:var(--t-base);font-weight:600;font-variant-numeric:tabular-nums;
  color:var(--ink-2)}
.sub-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  margin-top:14px}
.sub-foot-t{font-size:var(--t-sm);color:var(--muted)}
.sub-foot-t b{font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}

/* Приватные заметки об ученике */
.sn-add{display:block;background:var(--surface);border-radius:var(--r-2);padding:14px;
  box-shadow:var(--sh-1);margin-bottom:var(--s-3)}
.sn-add textarea{width:100%;border:none;padding:0;font-family:inherit;font-size:var(--t-base);
  background:transparent;resize:vertical;line-height:1.6;color:var(--ink)}
.sn-add textarea::placeholder{color:var(--muted)}
.sn-add textarea:focus{outline:none}
/* Кнопка молчит, пока писать нечего: пустое «Сохранить» звало нажать себя и
   ничего не делало. */
.sn-add-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  margin-top:26px}
.sn-priv{font-size:var(--t-label);font-variant-numeric:tabular-nums;color:var(--muted)}
.sn-save{background:var(--surface-2);border-color:transparent;color:var(--muted);
  border-radius:var(--r-1);padding:var(--s-2) 13px;font-size:var(--t-sm)}
.sn-save.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.sn-item{background:var(--surface);border:none;border-radius:var(--r-1);padding:14px;
  box-shadow:var(--sh-1);margin-bottom:6px}
.sn-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.sn-when{font-size:var(--t-label);font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted)}
.sn-when.fresh{color:var(--marker-ink)}
.sn-tools{display:flex;gap:2px}
.sn-item.editing{box-shadow:0 0 0 1.5px var(--ink)}
.sn-item textarea{width:100%;border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-md);background:var(--paper);resize:vertical;line-height:1.6}
.sn-text{font-size:var(--t-md);line-height:1.6;color:var(--ink-2);margin-top:var(--s-2)}
.sn-meta{display:flex;align-items:center;gap:var(--s-1);margin-top:var(--s-2)}
.sn-meta .eyebrow{flex:1}

@media(max-width:900px){
  .stu-grid{grid-template-columns:minmax(0,1fr)}
  .stu-panel{position:static}
}

/* ---------- Очередь проверки ----------
   Слева колонка работ, справа сама работа. Экран рабочий: преподаватель идёт
   подряд, «Проверено, дальше» ведёт к следующей без возврата в список. */
.review-grid{display:grid;grid-template-columns:320px minmax(0,1fr);align-items:start;min-height:calc(100vh - 52px)}
.review-list{border-right:1px solid var(--line);padding:var(--s-5) var(--s-4);position:sticky;top:52px;max-height:calc(100vh - 52px);overflow-y:auto;display:flex;flex-direction:column}
/* Список работ: заголовок, массовое действие карточкой сверху, две группы.
   «Принять автопроверенное» стоит первым, а не прижато к низу колонки: это не
   выход из очереди, а первый шаг в ней — снять с экрана то, что читать не надо.
   Счётчик в шапке — служебное число, а не жёлтая плашка: жёлтый в проверке
   значит ИИ и отмену массового действия, а число работ ни то, ни другое. */
.review-list .rl-head{display:flex;align-items:baseline;gap:var(--s-2)}
.rl-title{font-family:var(--font-head);font-weight:700;font-size:19px;letter-spacing:-.015em}
.review-list .rl-head .count-plain{margin-left:auto}
.rl-sum{margin-top:var(--s-1);font-size:var(--t-label);color:var(--muted);font-variant-numeric:tabular-nums}
.rl-bulk-card{display:flex;align-items:center;gap:var(--s-3);margin-top:var(--s-4);
  background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);padding:var(--s-3);
  transition:box-shadow var(--dur-fast) var(--ease)}
.rl-bulk-card:hover{box-shadow:var(--sh-2)}
.rl-bulk-main{display:flex;flex-direction:column;gap:2px;min-width:0}
.rl-bulk-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
.rl-bulk-sub{font-size:var(--t-label);color:var(--muted);font-variant-numeric:tabular-nums}
.rl-bulk-card .btn{margin-left:auto;flex-shrink:0}
.rl-group{margin-top:var(--s-5)}
.rl-group .eyebrow{padding:0 var(--s-3) var(--s-2)}
/* Работа в очереди — рельса слева, а не рамка: колонка из семи рамок читается
   таблицей, и выбранная работа в ней ничем не отличалась от остальных. */
.rl-item{display:flex;align-items:flex-start;gap:var(--s-3);width:100%;text-align:left;
  border:none;background:none;border-radius:var(--r-2);padding:var(--s-3);cursor:pointer;
  box-shadow:inset 3px 0 0 var(--line);margin-bottom:var(--s-2);
  transition:background var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.rl-item:hover{background:var(--surface-2)}
.rl-item.on{background:var(--surface);box-shadow:inset 3px 0 0 var(--ink),var(--sh-2)}
.rl-item .stu-ava{background:var(--surface-2);color:var(--muted);font-weight:600;font-size:var(--t-label)}
.rl-body{flex:1;min-width:0}
.rl-item .rl-name{display:block;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rl-item .rl-lesson{display:block;font-size:var(--t-sm);color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rl-item .rl-when{display:block;margin-top:var(--s-1);font-size:var(--t-label);color:var(--muted);
  font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Посчитанная работа — строкой без карточки: её принимают, не открывая. */
.rl-auto{display:flex;align-items:center;gap:var(--s-3);width:100%;text-align:left;border:none;
  background:none;border-radius:var(--r-1);padding:9px var(--s-3);cursor:pointer;
  transition:background var(--dur-fast) var(--ease)}
.rl-auto:hover{background:var(--surface-2)}
.rl-auto.on{background:var(--surface);box-shadow:var(--sh-1)}
.rl-auto-name{flex:1;min-width:0;font-size:var(--t-sm);color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Счёт верных на строке автопроверенного: табличные цифры, иначе столбец
   дёргается на каждой второй работе. Приглушён — решение принимают по нему,
   но читают всё-таки имя. */
.rl-auto-score{margin-left:auto;flex-shrink:0;font-size:var(--t-sm);color:var(--muted);
  font-variant-numeric:tabular-nums}
.review-work{background:var(--surface);padding:var(--s-5) var(--s-6) 0;min-width:0;
  display:flex;flex-direction:column;min-height:calc(100vh - 52px)}
/* Шапка работы: имя с уроком слева, срок и кнопки справа. Выравнивание по
   центру, а не по базовой линии: длинное название переносится на вторую строку,
   и при выравнивании по базовой линии кнопки уезжали вверх, к первой строке
   заголовка, — ряд выглядел сломанным. */
.rw-top{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s-5);
  margin-bottom:var(--s-4);flex-wrap:wrap}
.rw-top .btn{flex-shrink:0;align-self:flex-start}
/* В заголовке только имя ученика: урок, вид работы и тема — это контекст, и он
   стоит строкой ниже. Прежний заголовок «Имя · Урок · домашка» рос до трёх
   строк на длинном названии и переставал отвечать, чью работу открыли. */
.rw-title{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;
  font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);letter-spacing:-.025em}
.rw-kind{background:var(--surface-2);border-radius:var(--r-pill);padding:var(--s-1) 10px;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--ink-2);letter-spacing:0}
.rw-ctx{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-2)}
.rw-ctx-lesson{font-size:var(--t-md);color:var(--ink-2)}
.rw-ctx-dot{width:3px;height:3px;border-radius:var(--r-pill);background:var(--line-2);flex-shrink:0}
.rw-ctx-theme{font-size:var(--t-label);color:var(--muted)}
/* Служебные строки справа — по одной на строку: «сдано · срок был» одной
   строкой через точку читалось как одна дата. */
.rw-sub{display:flex;flex-direction:column;align-items:flex-end;gap:5px;flex-shrink:0;
  text-align:right;font-size:var(--t-label);color:var(--muted);font-variant-numeric:tabular-nums}

/* Сводка работы: сколько заданий, чем кончились, и карта работы справа —
   по сегменту на задание в порядке следования. Зелёный и красный здесь
   данные: верно и ошибка. */
.rw-stats{display:flex;align-items:center;gap:var(--s-5);flex-wrap:wrap;background:var(--paper);
  border-radius:var(--r-2);padding:var(--s-3) var(--s-4);margin-bottom:var(--s-4)}
.rw-stats-total{font-size:var(--t-sm);color:var(--muted)}
.rw-stats-total b{font-family:var(--font-head);font-weight:700;font-size:18px;color:var(--ink);
  font-variant-numeric:tabular-nums;margin-right:6px}
.rw-stats-sep{width:1px;height:26px;background:var(--line);flex-shrink:0}
.rw-stat{display:inline-flex;align-items:center;gap:7px;font-size:var(--t-sm);color:var(--ink-2);
  font-variant-numeric:tabular-nums}
.rw-stat i{width:7px;height:7px;border-radius:var(--r-pill);background:var(--line);flex-shrink:0}
.rw-stat.v-ok{color:var(--ok)}
.rw-stat.v-ok i{background:var(--ok)}
.rw-stat.v-err{color:var(--err)}
.rw-stat.v-err i{background:var(--err)}
.rw-stat.v-manual{color:var(--ink);font-weight:600}
.rw-stat.v-manual i{background:var(--ink)}
.rw-stat.v-empty{color:var(--muted)}
.rw-map{display:flex;gap:3px;margin-left:auto;flex-shrink:0}
.rw-map-seg{width:26px;height:6px;border-radius:var(--r-pill);background:var(--line)}
.rw-map-seg.v-ok{background:var(--ok)}
.rw-map-seg.v-err{background:var(--err)}
.rw-map-seg.v-manual{background:var(--ink)}

/* ---------- Показ правильного ответа ----------
   Здесь стояла своя анатомия задания: рамка, шапка с номером и типом, плашка
   вердикта, две колонки «что ответил / как правильно». Она заменена самим
   уроком — работа показывается движком блоков, — и от неё осталось только то,
   чего в уроке нет: правильный ответ под ошибочным заданием. */
.rw-col-label{font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-label);letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);margin-bottom:var(--s-1)}
.rw-val{font-size:var(--t-md);line-height:1.5}
/* Правильный ответ — справка, а не второй ответ: приглушён целиком */
.rw-val.right,.rw-val.right *{color:var(--muted)}
/* Правильный ответ и «не отвечал» — приписки под заданием на листе работы, а не
   часть урока: отбиты сверху линией, набраны мельче. Ученик их не видит
   никогда — этот лист собирается только для проверяющего. */
.rw-right{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px dashed var(--line-2)}
/* Задание, к которому ученик не притронулся: чип на месте ответа. Строкой
   «ученик не отвечал» это терялось среди приписок — а «пропустил» и
   «ошибся» разные вещи, и видно это должно быть там, где стоял бы ответ. */
.rw-none{margin-top:var(--s-3)}
/* Пустое задание из пропусков: чипы «не отвечал» стоят в самой фразе, а верное
   собрано строкой под ней — иначе фраза превратилась бы в решённую. */
.rw-none-right{font-size:var(--t-sm);color:var(--muted)}
.rw-none-right b{color:var(--ink-2);font-weight:600}
.rw-none-chip{display:inline-block;border-radius:var(--r-1);padding:var(--s-1) var(--s-3);
  font-size:var(--t-md);color:var(--muted);box-shadow:inset 0 0 0 1px var(--line)}
/* Лист работы платформенный: темой урока он больше не красится. У одного
   преподавателя уроки в разных темах, и очередь меняла цвет от работы к
   работе, хотя работа в ней одна и та же. */
.rw-sheet{flex:1;min-width:0}
/* Анатомия блока одна на все типы: номер, название типа, вердикт плашкой
   справа, рельса слева его цветом. Фона у блока нет — лист уже белый. */
.rw-block{border-radius:var(--r-2);padding:var(--s-4) 18px;margin-bottom:var(--s-3);
  box-shadow:inset 3px 0 0 var(--line),0 0 0 1px var(--surface-2)}
.rw-block.v-ok{box-shadow:inset 3px 0 0 var(--ok),0 0 0 1px var(--surface-2)}
.rw-block.v-err{box-shadow:inset 3px 0 0 var(--err),0 0 0 1px var(--surface-2)}
/* Блок, который ждёт человека, — единственный поднятый на листе: к нему и
   идут, всё остальное платформа посчитала сама. */
.rw-block.v-manual{box-shadow:inset 3px 0 0 var(--ink),var(--sh-2);padding:18px}
.rw-block-head{display:flex;align-items:center;gap:var(--s-3)}
.rw-num{font-size:var(--t-label);color:var(--muted);font-variant-numeric:tabular-nums;flex-shrink:0}
.rw-ic{display:inline-flex;align-items:center;color:var(--muted);flex-shrink:0}
.rw-type{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink)}
.rw-block.v-empty .rw-type{color:var(--muted)}
.rw-verdict{margin-left:auto;flex-shrink:0;border-radius:var(--r-pill);padding:var(--s-1) 10px;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);white-space:nowrap}
.rw-verdict.v-ok{background:var(--ok-bg);color:var(--ok)}
.rw-verdict.v-err{background:var(--err-bg);color:var(--err)}
.rw-verdict.v-manual{background:var(--ink);color:var(--paper);padding:var(--s-1) 11px}
.rw-verdict.v-empty{box-shadow:inset 0 0 0 1px var(--line);color:var(--muted)}
/* Формулировка задания уехала из шапки под неё: в шапке место занял вердикт,
   а формулировка бывает длиной в две строки и вердикт из ряда выдавливала. */
.rw-instr{margin-top:var(--s-3);font-size:var(--t-md);line-height:1.5;color:var(--ink-2)}

/* Пара вердикта и поле оценки стоят в одну строку: это один вопрос, заданный
   двумя способами. На узком экране пара уходит на свою строку первой — нажимают
   её чаще, чем печатают. */
.rw-verdict-seg{margin-bottom:0;flex-shrink:0}
.rw-grade{display:flex;gap:var(--s-2);margin-top:var(--s-3);align-items:flex-start;flex-wrap:wrap}
.rw-grade .rw-score{width:110px;flex-shrink:0;border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface)}
.rw-grade .rw-comment{flex:1;min-width:180px;border:1px solid var(--line-2);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface);resize:vertical;line-height:1.5}
.rw-grade .rw-score:focus,.rw-grade .rw-comment:focus{outline:none;border-color:var(--ink)}

.rw-foot{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-top:auto;
  margin-left:calc(var(--s-6) * -1);margin-right:calc(var(--s-6) * -1);
  border-top:1px solid var(--line);background:var(--paper);padding:var(--s-4) var(--s-6);
  position:sticky;bottom:0;z-index:5}
.rw-foot-main{display:flex;flex-direction:column;gap:3px;min-width:0}
.rw-foot-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.rw-foot-sub{font-size:var(--t-label);color:var(--muted)}
/* Поле общей оценки без лейбла: плейсхолдер и есть подпись, а строка над полем
   в полосе завершения только поднимала саму полосу. */
.rw-total{margin-left:auto;width:230px;max-width:100%;border:none;background:var(--surface);
  border-radius:var(--r-1);padding:var(--s-2) var(--s-3);font:inherit;font-size:var(--t-md);
  color:var(--ink);box-shadow:inset 0 0 0 1px var(--line)}
.rw-total:focus{outline:none;box-shadow:inset 0 0 0 1px var(--ink)}
.rw-foot .btn{padding:11px 18px}

/* Ответ ученика — только чтение, преподаватель не может ответить за него */
.ans-row{display:flex;flex-wrap:wrap;gap:var(--s-2);align-items:center}
.ans-list{display:flex;flex-direction:column;gap:var(--s-1)}
.ans-line{font-size:var(--t-base);line-height:1.5}
/* Ответ «Слова и картинки» — миниатюрой: номер фотографии был из перемешанного
   порядка ученика и преподавателю ничего не скажет. Рядом с неверной показана
   правильная, приглушённая, как подсказка «должно было быть так». */
.ans-thumb{width:34px;height:34px;object-fit:cover;border-radius:var(--r-1);flex-shrink:0;border:2px solid transparent}
.ans-thumb.ok{border-color:var(--ok)}
.ans-thumb.err{border-color:var(--err)}
.ans-thumb.hint-thumb{opacity:.45;border-style:dashed;border-color:var(--line-strong)}
.ans-gap{display:inline-flex;align-items:center;gap:var(--s-1);font-size:var(--t-base);color:var(--muted)}
.ans-chip{display:inline-block;border-radius:var(--r-1);padding:3px var(--s-3);font-weight:600;font-size:var(--t-base);border:1px solid var(--line-2);background:var(--paper)}
.ans-chip.ok{border-color:var(--ok);background:var(--ok-bg);color:var(--ok)}
.ans-chip.err{border-color:var(--err);background:var(--err-bg);color:var(--err)}
.ans-chip.miss{border-style:dashed;color:var(--muted)}
.ans-correct{font-size:var(--t-sm);color:var(--ok)}
.ans-empty{font-size:var(--t-base);color:var(--muted);font-style:italic}
.ans-legend{font-size:var(--t-sm);color:var(--muted)}

@media(max-width:1100px){
  .review-grid{grid-template-columns:minmax(0,1fr)}
  .review-list{position:static;max-height:none;border-right:none;border-bottom:1px solid var(--line);display:block;overflow-x:visible;padding:var(--s-4)}
  .review-work{padding:var(--s-4) var(--s-4) 0;min-height:0}
  .rw-foot{margin-left:calc(var(--s-4) * -1);margin-right:calc(var(--s-4) * -1);padding:var(--s-4)}
}

/* ---------- Полоса режима просмотра урока ----------
   Узкая, чтобы не спорить с уроком: чей это режим, что ответы не сохраняются,
   и два выхода — в конструктор и обратно в каталог. */
.preview-bar{position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:var(--s-3);
  background:var(--surface);border-bottom:1px solid var(--line);padding:var(--s-2) var(--s-4);min-height:44px}
/* Плашка называет режим, фраза рядом объясняет его словами — обычным текстом,
   а не капсом: капсом читают наклейку, а не предложение. */
.preview-bar .pb-label{font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.1em;
  text-transform:uppercase;white-space:nowrap;color:var(--marker-ink);background:var(--marker-soft);
  border-radius:var(--r-pill);padding:3px 9px;font-weight:600}
.preview-bar .pb-note{font-size:var(--t-sm);color:var(--muted);white-space:nowrap}
/* Почему кнопка погашена — рядом с ней, а не в подсказке при наведении:
   наводить на погашенное никто не станет. */
.ex-acts .ex-why{font-size:var(--t-sm);color:var(--muted)}
.preview-bar .pb-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ink-2)}
.preview-bar .pb-seg{margin-bottom:0;flex-shrink:0}
.preview-bar .pb-actions{margin-left:auto;display:flex;gap:var(--s-2);flex-shrink:0}
@media(max-width:700px){.preview-bar .pb-title{display:none}}
/* На телефоне от подписи остаётся «Просмотр»: с полной фразой полоса вместе с
   кнопками не влезала в ширину экрана и уводила урок в боковую прокрутку. */
@media(max-width:560px){.preview-bar .pb-note{display:none}}

/* ---------- «Сегодня»: домашняя преподавателя ---------- */
/* Карточка ближайшего занятия — единственная на экране с тенью: это то, ради
   чего страницу открывают. Лицо 64px, чтобы узнавать с одного взгляда, и
   остаток абонемента прямо в подписи — за ним больше не надо идти в профиль. */
/* Единственный поднятый лист на экране: ближайшее занятие. Всё остальное на
   главной лежит — на sh-1 или прямо на бумаге. Рамки нет: лист держится
   тенью, и в тёмном хроме за неё отвечает кант из sh-2. */
.now-card{background:var(--surface);border-radius:var(--radius);
  padding:var(--s-4);margin-bottom:var(--s-3);box-shadow:var(--sh-2)}
/* Идущее занятие — точка и кант маркером: это «пришло от преподавателя»,
   четвёртая работа жёлтого, а не статус «всё хорошо». */
.now-card.is-live{box-shadow:var(--sh-2),0 0 0 3px var(--marker-soft)}
/* Карточка держит ширину контейнера — на «Расписании» её правый край совпадает
   с краем строк дня под ней, на «Сегодня» — с краем боковой колонки.

   У отсчёта постоянное место: правый верхний угол карточки. Он стоял то сразу
   за подписью, то у края — в зависимости от длины названия урока, — и каждый раз
   его приходилось искать заново. Угол не зависит ни от чего: пришёл на экран,
   посмотрел в одну точку. */
.now-card .nc-head{display:grid;grid-template-columns:64px minmax(0,1fr) auto;gap:var(--s-4);align-items:start}
.now-card .nc-body{min-width:0}
.now-card .until,.now-card .nc-when-box,.now-card .nc-badge{align-self:start}
/* Лицо в главной карточке — на чернилах, а не на подложке: оно тут якорь всего
   экрана, и светло-серый кружок эту роль не держал. */
.now-card .stu-ava{width:64px;height:64px;font-size:21px;font-weight:600;
  background:var(--surface-2);color:var(--muted)}
.now-card .nc-title{font-family:var(--font-head);font-weight:700;font-size:20px;letter-spacing:-.02em;margin-top:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.now-card .nc-sub{font-size:var(--t-base);color:var(--muted);margin-top:5px}
.now-card .nc-right{display:flex;flex-direction:column;align-items:flex-end;gap:var(--s-2)}
/* На телефоне отсчёт и кнопки уходят под текст: втроём в ряд они оставляли
   названию урока восемьдесят пикселей. */
@media(max-width:560px){
  .now-card .nc-head{grid-template-columns:48px minmax(0,1fr);gap:var(--s-3)}
  .now-card .stu-ava{width:48px;height:48px;font-size:var(--t-lg)}
  /* .until/.nc-badge — третья колонка сетки, а на телефоне колонок только две:
     без явного grid-column элемент садился в первую, узкую (48px) колонку под
     лицом и вылезал текстом «через 2 дня» за её пределы. Отдаём ему вторую
     строку целиком, рядом с лицом, а не поверх текста. */
  /* justify-self обязателен: элемент грида по умолчанию растягивается на всю
     колонку, и заливка «идёт сейчас» тянулась во всю ширину карточки, хотя
     надписи в ней три слова. Прижимаем к началу — плашка становится по тексту. */
  .now-card .until,.now-card .nc-when-box,.now-card .nc-badge{grid-column:2;grid-row:2;justify-self:start}
  .now-card .nc-actions{justify-content:flex-start}
  /* Название не обрезаем многоточием, а переносим: «Ученик пробы · Weath…» не
     называет ни ученика, ни урок. Строки хватает на двоих. */
  .now-card .nc-title{white-space:normal;overflow:visible;font-size:18px;line-height:1.25}
  /* Отсчёт и часы — в строку и по левому краю. Коробка «когда» сверстана для
     правого угла карточки (text-align:right), и на телефоне, переехав под
     текст, оставляла «через 3 дня» слева, а «15:50 — 16:40» — у правого края:
     две величины об одном стояли по разным краям. */
  .now-card .nc-when-box{text-align:left;display:flex;align-items:baseline;
    gap:var(--s-2);flex-wrap:wrap}
  .now-card .until{font-size:var(--t-lg)}
  /* Главное действие — во всю ширину, остальные делят строку под ним. Раньше
     три кнопки ломались как придётся, и «Сменить материал» оставалась внизу
     одна, читаясь главной.

     Ширину второстепенным даём по содержимому (flex-basis:auto), а не поровну.
     Делёж поровну держался, пока их было две; с третьей — «Провести · Сменить
     материал · Звонок» — на каждую приходилось по девяносто пикселей, и
     «Сменить материал» обрезалось на полуслове. Без min-width:0 флексбокс не
     ужимает кнопку ниже её собственного текста и переносит лишнюю на
     следующую строку. */
  .now-card .nc-actions .btn.primary{flex:1 0 100%;justify-content:center}
  .now-card .nc-actions .btn:not(.primary){flex:0 1 auto;justify-content:center}
}
.now-card .nc-badge{display:inline-flex;align-items:center;gap:var(--s-1);background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--r-pill);padding:3px var(--s-3);font-family:var(--font-head);font-weight:700;font-size:var(--t-sm);white-space:nowrap}
.now-card .nc-progress{margin-bottom:var(--s-3)}
.now-card .nc-progress .bar{margin-top:0}

/* ---------- Кабинет ученика: «когда» крупно (хендофф v2, Р-3) ----------
   Компоненты общие с преподавательскими, отличается масштаб и порядок, не язык.
   У преподавателя главное в карточке — с кем занятие, поэтому там лицо 64px;
   у ученика преподаватель один, и главное — когда. «Сегодня, 19:15» — самый
   крупный текст экрана, ради этой строки кабинет и открывают. */
.next-card{display:flex;flex-direction:column;gap:10px;padding:20px}
.next-card .eyebrow{display:flex;align-items:center;gap:6px}
.next-card .nc-when{font-family:var(--font-head);font-weight:700;font-size:28px;
  line-height:1.15;letter-spacing:-.01em}
.next-card .nc-what{font-size:var(--t-md);color:var(--ink-2)}
.next-card .nc-actions{justify-content:flex-start;margin-top:var(--s-1)}
/* На телефоне «Войти в класс» тянется во всю оставшуюся ширину: это
   единственное действие первого экрана, и мельчить ему незачем. На большом
   экране карточка шириной с полосу — растянутая кнопка была бы во весь стол. */
@media(max-width:640px){
  .next-card .nc-actions .btn.primary{flex:1;justify-content:center}
}

/* Свой абонемент ученика — на экране «Занятия», а не в кабинете (subSheet в
   schedule.js). Тёмный лист: на светлой странице занятий это единственное, что
   не про ближайший урок, и белой карточкой оно терялось между ними.

   Цвета задаём числами базовой палитры, а не через --ink и --paper: лист тёмный
   в обеих темах, а в тёмной эти имена меняются местами и лист стал бы светлым
   на светлом. Ровно тот же приём, что у .lookup — всплывашки словаря. */
.sub-sheet{background:#171A21;color:#EDECE8;border-radius:var(--r-2);
  padding:var(--s-4) 18px;margin-bottom:14px}
.sub-sheet .ss-head{display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--s-4);margin-bottom:14px}
.sub-sheet .eyebrow{color:#8C8C86}
.sub-sheet .ss-sub{font-size:var(--t-sm);color:#8C8C86;margin-top:5px}
/* Остаток числом: его читают взглядом, а не перечитывают строкой. */
.sub-sheet .ss-num{font-family:var(--font-head);font-weight:700;font-size:32px;
  letter-spacing:-.02em;line-height:1;text-align:right;flex-shrink:0;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.sub-sheet .ss-num span{display:block;font-size:var(--t-sm);font-weight:400;
  color:#8C8C86;margin-top:6px;letter-spacing:0}
/* Полоса делений, а не сплошная: занятия считаются штуками, и восемь клеток
   отвечают на «сколько прожито» точнее любой доли. Жёлтое — проведённые
   занятия, тёмное — те, что впереди. Это та же единственная серия данных
   платформы, и тот же счёт, что в карточке ученика у преподавателя. */
/* Правила именно этого листа, а не всех клеток платформы. Имя .sub-cells носят
   два разных места: тёмный лист абонемента у ученика (здесь) и клетки в карточке
   ученика у преподавателя, на белой бумаге. Эти стоят в файле ниже и доставались
   обоим — пустая клетка в карточке красилась #33363D, то есть почти чёрным на
   белом, и читалась как заполненная. */
.sub-sheet .sub-cells{display:flex;gap:var(--s-1)}
.sub-sheet .sub-cells>i{flex:1;height:6px;border-radius:var(--r-pill);background:#33363D}
.sub-sheet .sub-cells>i.done{background:var(--c-marker)}
.sub-sheet .sub-cells.out>i{background:var(--c-err)}
/* Длинный абонемент клетками не показать — волосок вместо деления. */
.sub-sheet .bar.sub-wide{background:#33363D;margin:0}
.sub-sheet .bar.sub-wide>span{background:var(--c-marker)}
/* В тёмном хроме приём перестаёт работать: #171A21 на столе #1B1E24 — разница в
   четыре пункта, лист просто пропадает. Там он становится обычным поднятым
   листом платформы, а «единственное тёмное на светлой странице» остаётся
   приёмом светлой темы. */
html[data-chrome="dark"] .sub-sheet{background:var(--c-surface);box-shadow:var(--sh-2)}
html[data-chrome="dark"] .sub-sheet .sub-cells>i{background:var(--c-line)}
html[data-chrome="dark"] .sub-sheet .bar.sub-wide{background:var(--c-line)}

/* Слова с прошлого занятия — плашками маркером. Правило «жёлтое = заметки и
   выделения» здесь не нарушено, а исполнено: это и есть выделения с полей
   урока, просто собранные в одно место. */
.deck-chips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-bottom:var(--s-1)}
.deck-word{background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--r-pill);
  padding:6px var(--s-3);font-size:var(--t-base)}
.deck-more{background:none;border:1px dashed var(--line-2);color:var(--muted);
  border-radius:var(--r-pill);padding:6px var(--s-3);font-size:var(--t-base);font-family:inherit;cursor:pointer}
.deck-more:hover{border-style:solid;color:var(--ink)}

/* Отсчёт до занятия — mono, как всё измеримое на платформе. Без плашки: в
   карточке он и так стоит один в своём углу, а обводка делала из него кнопку. */
/* Отсчёт крупно, интервал под ним мелко: «через 2 ч» отвечает на вопрос
   «когда бежать», а «13:00 — 13:50» — на «сколько это займёт». */
.nc-when-box{text-align:right;flex-shrink:0}
.until{font-variant-numeric:tabular-nums;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.02em;color:var(--ink);white-space:nowrap;flex-shrink:0;display:block}
.until-range{display:block;font-size:var(--t-label);color:var(--muted);margin-top:3px;
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* Кнопки карточки — слева, под сведениями о занятии, а не прижаты к правому
   краю: в широкой карточке между «Открыть класс» и тем, к чему она относится,
   лежала половина экрана, а слева стояла пустота. */
.nc-actions{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;justify-content:flex-start;margin-top:18px}
.now-card .nc-actions{margin-top:var(--s-3)}

/* ---------- Рабочий стол «Сегодня»: главная колонка и боковая ----------
   Было две равные половины, и в день с пустой очередью проверки левая стояла
   пустой рамкой в пол-экрана, пока справа лежали абонементы. Теперь колонки
   разного веса: слева ход дня (занятие, лента, кто выпадает), справа — что
   ждёт (проверка, абонементы, забытые отметки). Главная уже, чем весь экран,
   поэтому карточка занятия перестала растягиваться на всю ширину. */
.desk{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:var(--s-5);align-items:start}
.desk-main,.desk-side{display:flex;flex-direction:column;gap:var(--s-4);min-width:0}
/* Внутри секции отступы прежние; обнуляем только последний, иначе к зазору
   колонки прибавляется хвостовой margin блока и секции разъезжаются. */
.desk-main>section>:last-child,.desk-side>section>:last-child{margin-bottom:0}
/* Схлопывается раньше, чем боковая колонка становится теснее своих строк:
   в «Без отметки» у строки два действия, и в колонке уже ~320px они не стоят. */
@media(max-width:1100px){.desk{grid-template-columns:1fr}}

/* Панель — карточка со своим заголовком и плотным списком внутри */
.panel{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:6px;display:flex;flex-direction:column;gap:6px}
/* Шапка листа: слева название, справа «сколько показано из скольких» —
   служебной подписью, а не плашкой. Плашкой счётчик остаётся там, где он
   метка: в меню и на вкладках. */
.panel-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);padding:14px 14px var(--s-3)}
.panel-head .count-pill{margin-left:auto}
.panel-count{font-size:var(--t-label);font-weight:600;letter-spacing:.1em;color:var(--muted);
  font-variant-numeric:tabular-nums;font-family:var(--font-body);white-space:nowrap}
/* Число при заголовке страницы («Ученики 5») стоит внутри h1, на его строке. */
.head>.panel-count{margin-left:var(--s-3)}
/* Строк больше пяти — собираются в группы по причине. */
.panel-group{margin-top:var(--s-3);display:flex;flex-direction:column;gap:6px}
.panel-group-head{font-size:var(--t-label);font-weight:600;letter-spacing:.1em;color:var(--muted);
  font-variant-numeric:tabular-nums;padding:0 14px 6px}

/* Строка внутри панели: та же анатомия, но плотнее — панель уже сама карточка,
   и вторая рамка внутри неё лишняя. Разделяет волосяная линия. */
/* Плашка внутри листа. Разделяют не волосяные линии, а зазор 6 — он же gap
   листа, и он же даёт концентрические углы: r-1 внутри r-2. */
.row.tight{background:var(--paper);border:none;border-radius:var(--r-1);
  padding:11px 13px;margin:0;grid-template-columns:40px minmax(5rem,1fr) auto;gap:var(--s-3)}
.row.tight:hover{background:var(--surface-2);box-shadow:none;transform:none}
/* Идёт сейчас — точка маркером слева от текста. Класс .is-live платформа уже
   печатает строке идущего занятия в расписании (slotRow), поэтому правило
   написано на него, а не на своё имя: два имени для одного состояния разошлись
   бы на первом же новом списке. Не .live: это имя самой точки (см. .live выше),
   и строка с ним сама становилась точкой.

   Состояния «выбрана» тут нет: чёрный кант выбранной строки нужен спискам-
   выборщикам, а они собраны на .row.tight.bare.act, и выделение там делает сам
   выбор — строка исчезает из списка. Правило было мёртвым и убрано. */
.row.is-live{position:relative}
.row.is-live::before{content:'';position:absolute;left:5px;top:calc(50% - 3px);
  width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker);
  animation:pulse 1.4s ease-in-out infinite}
.row.tight.bare{grid-template-columns:minmax(5rem,1fr) auto}
/* Рельса у строки полки: состояние видно раньше текста. Та же геометрия и те
   же два цвета, что у карточки «Сдать» на обзоре (.todo-card): красная — срок
   прошёл, маркер — работа начата или пришла с правками. */
.row.tight.rail-err,.row.tight.rail-err:hover{box-shadow:inset 3px 0 0 var(--err)}
.row.tight.rail-mark,.row.tight.rail-mark:hover{box-shadow:inset 3px 0 0 var(--marker)}
/* Ход начатой работы: тонкая полоса под подписью, без числа процентов — оно
   здесь ничего не добавит к «5 из 12», уже стоящему рядом. */
.hw-bar{height:3px;border-radius:var(--r-pill);background:var(--line);margin-top:7px;
  max-width:220px;overflow:hidden}
.hw-bar>i{display:block;height:100%;background:var(--marker);border-radius:inherit}
/* Оценка проверенной работы — рядом с кнопкой, а не подписью под названием:
   это итог работы, и читают его вместе с решением «открывать или нет». */
.hw-score{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
  color:var(--ink-2);white-space:nowrap}
/* Строка с двумя действиями в узкой колонке: кнопки встают под именем, а не
   рядом. В боковой колонке «Провести» и «Не состоялось» занимают её половину, и
   имени оставалось на «Pet…» — но выбирать исход занятия по обрезанному имени
   как раз и нельзя. Под именем места ровно столько же, сколько у самой строки. */
.row.tight.stack{grid-template-columns:40px minmax(0,1fr)}
.row.tight.stack>.r-side,.row.tight.stack>.r-act{grid-column:2;justify-content:flex-start}
.row.tight.bare.stack{grid-template-columns:minmax(0,1fr)}
.row.tight.bare.stack>.r-side,.row.tight.bare.stack>.r-act{grid-column:1;justify-content:flex-start}
.row.tight .stu-ava{width:36px;height:36px;font-size:var(--t-sm)}
.row.tight .r-title{font-size:var(--t-md)}
.row.tight .r-sub{font-size:var(--t-sm)}
.row.tight .r-time{font-size:var(--t-sm)}

/* ---------- Кабинет: разбор проверенной работы ----------
   Экран отвечает на один вопрос — «что у меня не сошлось»: шапка с оценкой,
   список мест, которые стоит разобрать, и работа целиком по кнопке под ними. */
/* Оценка стоит рядом с названием, а не у правого края: у края она читалась
   отдельным числом ни о чём, а это итог именно этой работы. Колонка названия
   сжимается по содержимому, но не шире свободного места — длинное название
   переносится, а не выдавливает оценку. */
.hw-rev-top{display:grid;grid-template-columns:minmax(0,auto) auto;justify-content:start;
  align-items:center;gap:2px var(--s-4);margin:14px 0 var(--s-4)}
.hw-rev-when{grid-column:1;font-size:var(--t-label);text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);font-variant-numeric:tabular-nums}
.hw-rev-title{grid-column:1;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  line-height:1.2;word-break:break-word}
/* Оценка — справа от названия и крупно: это итог работы, и читают его первым. */
.hw-rev-score{grid-column:2;grid-row:1 / span 2;font-size:var(--t-lg);color:var(--ink)}
.hw-rev-list{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:2px 16px}
/* Тип задания и чем оно кончилось — одной строкой: плашка договаривает то,
   чего не говорит номер. */
.hw-rev-task{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md);margin-bottom:var(--s-2)}
.hw-rev-add{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-top:var(--s-3)}
.hw-rev-words{font-size:var(--t-sm);color:var(--muted);min-width:0;word-break:break-word}
/* Верное — строкой без карточки: читать там нечего, а карточка обещала бы
   содержимое. */
.hw-rev-ok{font-size:var(--t-sm);color:var(--muted);padding:var(--s-3) 2px 0}
@media(max-width:640px){
  .hw-rev-title{font-size:var(--t-lg)}
  .hw-rev-list{padding:2px 12px}
}

/* Хвост ленты занятий: тихая строка, а не ссылка акцентом — это подпись, что
   дальше смотреть в расписании, а не главное действие экрана. */
.more-line{font-size:var(--t-sm);color:var(--ink-2);padding:var(--s-3) 14px;background:none;border:none;
  cursor:pointer;text-align:left;font-family:var(--font-head);font-weight:600;
  display:flex;align-items:center;gap:var(--s-2)}
/* Шеврон — только у раскрытия того же списка. Там, где строка ведёт на другой
   экран, в тексте уже стоит стрелка перехода, и два знака подряд врут. */
.more-line.expand::after{content:'';width:0;height:0;border-left:4px solid transparent;
  border-right:4px solid transparent;border-top:4px solid var(--muted)}
.more-line:hover{color:var(--ink)}
/* Статус и инструменты — в колонках постоянной ширины. У .row две последние
   колонки auto, каждая строка — своя сетка, и ширина этих колонок считалась по
   содержимому строки: «проведено», «через 2 дня» и «отменено» разной длины, а
   у проведённого занятия на одну кнопку меньше. Из-за этого статусы вставали
   лесенкой — у каждой строки на своём месте. Теперь у всех на одном, по левому
   краю своей колонки. */
/* Строка занятия: одна анатомия, меняется правый край и подложка.
   Слева время и длительность, потом лицо 34, потом имя с уровнем и подписью,
   справа — колонка действий постоянной ширины. Статусного слова нет там, где
   состояние уже сказано подложкой: иначе строка повторяет себя дважды.
   Раньше на строке висели четыре значка сразу и слово статуса в отдельной
   колонке — двенадцать элементов на плашку, из которых нужен был один. */
.sch-row{grid-template-columns:66px 34px minmax(6rem,1fr) 132px;gap:var(--s-3);align-items:center;
  padding:11px var(--s-3);margin-bottom:0;background:var(--paper);border-radius:var(--r-1)}
.sch-row:hover{background:var(--paper);box-shadow:none;transform:none}
.sch-row .r-time{display:flex;flex-direction:column;align-items:flex-start;gap:1px;text-align:left}
.sch-row .r-time .t{font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--t-base)}
.sch-row .r-time .d{font-size:var(--t-label);color:var(--muted);font-variant-numeric:tabular-nums}
.sch-row .r-time .d.mark{color:var(--marker-ink)}
.sch-row .r-sub{margin-top:2px}
.r-lvl{font-variant-numeric:tabular-nums;font-weight:500;font-size:var(--t-label);color:var(--muted)}
.r-inclass{font-weight:500;font-size:var(--t-sm);color:var(--marker-ink)}
.sch-err{color:var(--err)}
.sch-soon{color:var(--marker-ink)}
/* Полоса хода идущего занятия встаёт на место темы: пока занятие идёт, тема уже
   открыта в классе, а «сколько прошло» не видно больше нигде. */
.sch-prog{display:block;height:5px;max-width:320px;margin:var(--s-2) 0 0}
.sch-acts{display:flex;align-items:center;justify-content:flex-end;gap:6px;flex-wrap:wrap}
.sch-until{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}
/* Отсчёт уступает место действию: держать в колонке и то и другое незачем —
   «через 3 дня» человек уже прочёл, пока вёл мышь к строке. */
@media(hover:hover){.sch-row:hover .sch-until{display:none}}
/* «Проведено» — плашка-факт, серая. Зелёный и красный на платформе значат
   данные, верно и ошибку; «занятие состоялось» — не «верно». */
.sch-mark{font-size:var(--t-label);font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);background:var(--surface-2);border-radius:var(--r-pill);padding:var(--s-1) 9px}

/* Шесть состояний — подложкой и правым краем */
.sch-row.focus,.sch-row.focus:hover{padding:13px var(--s-3);
  box-shadow:0 0 0 1.5px var(--ink),0 12px 28px -14px rgba(23,26,33,.2)}
.sch-row.focus .r-time .t{font-size:var(--t-md)}
.sch-row.focus .r-title{font-size:var(--t-lg)}
.sch-row.is-live,.sch-row.is-live:hover{
  box-shadow:0 0 0 1.5px var(--marker),0 12px 28px -14px rgba(23,26,33,.2)}
.sch-row.is-live .stu-ava{background:var(--marker-soft);color:var(--marker-ink)}
.sch-row.unmarked,.sch-row.unmarked:hover{background:var(--err-bg)}
.sch-row.unmarked .stu-ava{background:var(--surface)}
.sch-row.cancelled,.sch-row.cancelled:hover{background:var(--surface-2)}
.sch-row.cancelled .r-time .t{color:var(--muted);text-decoration:line-through}
.sch-row.cancelled .stu-ava{background:var(--line)}
.sch-row.cancelled .r-title{color:var(--muted)}
.sch-row.done{opacity:.6}
.sch-row.done:hover{opacity:1}
/* Строка внутри свёрнутого прошедшего — та же, но плотнее и тише */
.sch-row.compact{padding:10px var(--s-3);margin-bottom:var(--s-1)}
.sch-row.compact .r-time .t{font-size:var(--t-sm);color:var(--ink-2)}
.sch-row.compact .r-title{font-size:var(--t-md)}
.sch-row.compact .r-sub{font-size:var(--t-sm)}

/* Лента строк: контейнера-карточки больше нет — строка .row сама себе граница */
.day-list{margin-bottom:var(--s-3)}

/* Личное дело в списке дня — та же строка, но приглушённой заливкой: занятие
   на белом, дело на подложке. Это не статус и не предупреждение, а «здесь
   не ученик», и цвета оно не заслуживает: маркер закреплён за занятиями и
   заметками, и отдавать его походу к врачу нельзя. */
.sch-row.is-event,.sch-row.is-event:hover{background:var(--surface-2)}
.sch-row.is-event .r-title{font-weight:600}

/* ---------- Полка дня ----------
   Дата держит левый край и никуда не уезжает, занятия лежат листом справа.
   Раньше день был заголовком над лентой строк: на длинной неделе заголовок
   уходил вверх, и было не понять, к какому дню относится строка. */
.sch-shelf{display:grid;grid-template-columns:92px minmax(0,1fr);gap:var(--s-4);
  align-items:start;margin-bottom:var(--s-4)}
.sch-date{padding-top:10px;display:flex;flex-direction:column;align-items:flex-start}
.sch-date .w{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted)}
.sch-date .d{font-family:var(--font-head);font-weight:700;font-size:30px;letter-spacing:-.03em;
  margin-top:2px;color:var(--ink-2);font-variant-numeric:tabular-nums}
.sch-date .m{font-size:var(--t-label);color:var(--muted)}
.sch-date.is-today .w{color:var(--marker-ink)}
.sch-date.is-today .d{color:var(--ink)}
.sch-today{margin-top:10px;font-size:var(--t-label);font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;color:var(--marker-ink);background:var(--marker-soft);
  border-radius:var(--r-pill);padding:var(--s-1) 9px}
/* Лист дня. Сегодняшний поднят сильнее: это единственный день, по которому
   сегодня принимают решения. */
/* Колонка листа — minmax(0,1fr), а не неявная auto: у неявной нижняя граница —
   min-content строки, и длинное название урока (nowrap с многоточием) не
   обрезалось, а раздвигало лист, за ним и окно телефона — до 810 у ученика на
   названии в две строки. Та же засада, что у каталога уроков 14 сентября. */
.sch-sheet{background:var(--surface);border-radius:var(--r-2);padding:6px;
  box-shadow:var(--sh-1);display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-1)}
.sch-sheet.is-today{box-shadow:var(--sh-2)}

/* Прошедшее свёрнуто в строку под сегодня, а не хвостом под всей неделей:
   «что было вчера» спрашивают рядом с «что сегодня». */
.sch-past{width:100%;text-align:left;font-family:var(--font-body);font-size:var(--t-base);
  color:var(--ink-2);background:var(--surface-2);border:none;border-radius:var(--r-1);
  padding:var(--s-3) var(--s-4);display:flex;align-items:center;justify-content:space-between;
  gap:var(--s-3);cursor:pointer;transition:background var(--dur-fast) var(--ease)}
.sch-past:hover{background:var(--line)}
.sch-past b{font-weight:600;font-variant-numeric:tabular-nums}
.sch-past-go{font-family:var(--font-body);font-size:var(--t-sm);color:var(--marker-ink);
  background:none;border:none;padding:0;cursor:pointer;white-space:nowrap}
.sch-past.open,.sch-past.open:hover{display:block;padding:6px;cursor:default;
  background:var(--surface-2)}
.sch-past-day{display:flex;align-items:center;justify-content:space-between;gap:var(--s-2);
  font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);padding:var(--s-2) 10px var(--s-1)}

/* Подряд идущие пустые дни — одна строка, а не пять пустых полок */
.sch-free{width:100%;text-align:left;background:var(--surface-2);border:none;
  border-radius:var(--r-1);padding:var(--s-3) var(--s-4);font-family:var(--font-body);
  font-size:var(--t-base);color:var(--muted);cursor:pointer}
.sch-free b{font-weight:400;color:var(--marker-ink)}
.sch-free:hover b{text-decoration:underline}

/* ---------- Правая колонка списка ----------
   Форма недели, что ждёт отметки и по каким дням кто занимается — то, чего не
   видно в самой ленте. Только у преподавателя. */
/* ---------- Список на телефоне ----------

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

   Поэтому дата поднимается над листом одной строкой — «ПОНЕДЕЛЬНИК · 7
   сентября · СЕГОДНЯ», — и день получает всю ширину. Порядок и смысл те же:
   сначала сказано, какой это день, потом что в нём. */
@media(max-width:640px){
  .sch-shelf{grid-template-columns:minmax(0,1fr);gap:var(--s-2)}
  .sch-date{flex-direction:row;align-items:baseline;flex-wrap:wrap;
    gap:var(--s-2);padding:0 0 2px}
  .sch-date .d{font-size:20px;margin-top:0}
  .sch-today{margin-top:0}
  /* У прошедшего и у свободных дней дата пустая — пустая строка над листом
     выглядела бы пропущенным заголовком. */
  .sch-date:empty{display:none}
}


/* ---------- Расписание на телефоне: лента дня (хендофф schedule_mobile) ----------

   Вид «Список» у преподавателя на узком экране (schedule-phone.js): один день,
   полоска недели над ним, всё остальное — шторками. Сетка недели осталась за
   переключателем, как была (решение владельца 13 сентября).

   Кегли и отступы макета сведены на ступени шкалы: макет набран где на
   полпикселя, где на два мельче или крупнее, и на телефоне эта разница не
   видна, а девятая и десятая ступень расползлись бы по платформе. Мимо шкалы
   один размер — имя в листе занятия и заголовок шторки, 19px: между временем
   26px и текстом 16px другой ступени нет.

   Радиусы — ступени платформы: строка 10 (в макете 12, но 12 из формы
   платформы ушло), ближайшее занятие 16, шторка 22.

   Двух цветов макета в палитре хрома не было — «совсем тихий» текст и точка
   «в этот день что-то стоит». Заведены здесь же, с тёмными значениями. */
:root{--sm-faint:#A8A6A0;--sm-dot:#C6C3BA}
html[data-chrome="dark"]{--sm-faint:#6B6E76;--sm-dot:#4B4F58}

.top-plus{display:none}
@media(max-width:640px){
  .app-main .topbar .top-plus{display:inline-flex;align-items:center;justify-content:center;
    position:relative;flex:0 0 auto;width:36px;height:36px;border:none;background:none;cursor:pointer;
    border-radius:var(--r-1);font-size:var(--t-h1);font-weight:400;line-height:1;color:var(--ink-2)}
  .app-main .topbar .top-plus::after{content:'';position:absolute;inset:-4px}
  /* У ряда действий и у «⋯» обоих margin-left:auto — свободное место делилось
     пополам, и «+» вставал посередине шапки. Прижимаем «⋯» к «+». */
  .app-main .topbar .top-actions:has(.top-plus)+.top-more{margin-left:0}
  .page-head .sch-new{display:none}
}

/* Лента живёт от края до края экрана: полоска недели — это граница под шапкой,
   а не карточка на странице. Поля страницы на телефоне — s-3 сверху, s-4 по бокам. */
/* Не .sm: так по всей платформе называется модификатор размера у .btn и .stu-ava */
.sm-page{margin:calc(-1 * var(--s-3)) calc(-1 * var(--s-4)) 0}
.sm-seg{padding:var(--s-3) var(--s-4) 0}
.sm-seg .seg{margin:0}

/* Полоска недели. touch-action:pan-y — горизонтальный жест отдаём свайпу, а
   вертикальный остаётся прокрутке страницы. */
.sm-strip{padding:var(--s-2) var(--s-3) var(--s-3);border-bottom:1px solid var(--line);
  touch-action:pan-y;user-select:none;-webkit-user-select:none;overflow:hidden}
.sm-strip.open{background:var(--surface);box-shadow:var(--sh-1)}
.sm-strip-h{display:flex;align-items:center;justify-content:space-between;gap:var(--s-2);
  min-height:32px;padding:0 var(--s-1) var(--s-1)}
.sm-mon{display:inline-flex;align-items:center;gap:var(--s-1);min-height:32px;padding:0;border:none;
  background:none;cursor:pointer;font-family:var(--font-head);font-weight:700;font-size:var(--t-md);
  letter-spacing:-.02em;color:var(--ink)}
.sm-mon i{font-style:normal;font-size:var(--t-label);color:var(--ink-2)}
.sm-range{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}
/* «Сегодня» — жёлтый чип: текст на нём всегда чернильный, в тёмной теме тоже */
.sm-today{position:relative;border:none;cursor:pointer;background:var(--marker);color:#171A21;
  border-radius:var(--r-pill);padding:var(--s-1) var(--s-3);font-family:var(--font-body);
  font-weight:600;font-size:var(--t-sm)}
.sm-today::after{content:'';position:absolute;inset:-8px -4px}
.sm-days,.sm-mgrid,.sm-wk{display:grid;grid-template-columns:repeat(7,1fr)}
.sm-d{display:flex;flex-direction:column;align-items:center;padding:0;border:none;background:none;
  cursor:pointer;font-family:var(--font-body)}
.sm-d .w{font-size:var(--t-label);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.sm-d .n{display:flex;align-items:center;justify-content:center;align-self:stretch;height:34px;
  margin:var(--s-1) var(--s-1) 0;border-radius:var(--r-1);font-family:var(--font-head);font-weight:600;
  font-size:var(--t-md);font-variant-numeric:tabular-nums;color:var(--ink-2);
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.sm-d.off .w,.sm-d.off .n{color:var(--sm-faint)}
.sm-d.on .w{color:var(--ink)}
.sm-d.on .n{background:var(--ink);color:var(--paper);font-weight:700}
.sm-d i,.sm-c i{display:block;width:4px;height:4px;border-radius:var(--r-pill);margin:var(--s-1) auto 0}
.sm-c i{margin-top:0}
.sm-d i.has,.sm-c i.has{background:var(--sm-dot)}
.sm-d i.now,.sm-c i.now{background:var(--marker)}
.sm-wk{text-align:center;font-size:var(--t-label);font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);padding-bottom:var(--s-1)}
.sm-wk .off{color:var(--sm-faint)}
.sm-c{display:flex;flex-direction:column;align-items:center;justify-content:center;height:34px;padding:0;
  border:none;background:none;cursor:pointer;border-radius:var(--r-1);font-family:var(--font-head);
  font-weight:600;font-size:var(--t-md);line-height:1.3;font-variant-numeric:tabular-nums;color:var(--ink-2)}
.sm-c.off{color:var(--sm-faint);font-weight:500}
.sm-c.out{color:var(--sm-dot);font-weight:500}
.sm-c.on{background:var(--ink);color:var(--paper);font-weight:700}
.sm-c.on i.has{background:var(--sm-faint)}
/* Неделя уезжает в сторону свайпа: без движения смена чисел читалась бы как
   сбой, а не как листание. */
@keyframes smInL{from{opacity:.35;transform:translateX(18px)}to{opacity:1;transform:none}}
@keyframes smInR{from{opacity:.35;transform:translateX(-18px)}to{opacity:1;transform:none}}
.sm-in-l{animation:smInL var(--dur-base) var(--ease-s)}
.sm-in-r{animation:smInR var(--dur-base) var(--ease-s)}

/* Лента дня */
/* Колонки ленты и блоков под ней — minmax(0,1fr), как у .sch-sheet: имя ученика
   и название урока в «Ближайшем» и в «Без отметки» идут строкой с многоточием,
   и неявная колонка auto раздвигалась по ним до 860. */
.sm-feed{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);padding:var(--s-3) var(--s-4) 0}
.sm-dayh{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-label);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.sm-dot{display:inline-block;flex:0 0 auto;width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker)}
.sm-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-3);padding:var(--s-3);
  background:var(--surface);border-radius:var(--r-1);box-shadow:var(--sh-1);cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:background var(--dur-fast) var(--ease)}
.sm-row:active{background:var(--surface-2)}
.sm-time{flex:0 0 52px;display:flex;flex-direction:column;line-height:1.35;font-size:var(--t-base);
  font-variant-numeric:tabular-nums;color:var(--ink)}
.sm-time b{font-weight:600}
.sm-time i{font-style:normal;font-size:var(--t-label);color:var(--muted)}
.sm-time i.mark{font-weight:600;color:var(--marker-ink)}
.sm-main{flex:1;min-width:0;display:flex;flex-direction:column}
.sm-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);line-height:1.35;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-sub{font-size:var(--t-sm);line-height:1.45;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-err{color:var(--err)}
.sm-go{flex:0 0 auto;font-size:var(--t-lg);line-height:1;color:var(--muted)}
.sm-ok{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;
  border-radius:var(--r-pill);background:var(--ok-bg);color:var(--ok);font-size:var(--t-label);font-weight:700}
.sm-inclass{font-family:var(--font-body);font-weight:500;font-size:var(--t-sm);color:var(--marker-ink)}
.sm-prog{display:block;height:5px;margin-top:var(--s-2);border-radius:var(--r-pill);background:var(--surface-2);overflow:hidden}
.sm-prog span{display:block;height:100%;border-radius:var(--r-pill);background:var(--marker)}
.sm-mini{position:relative;flex:0 0 auto;border:none;cursor:pointer;border-radius:var(--r-1);
  padding:var(--s-2) var(--s-3);background:var(--surface-2);color:var(--ink-2);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm)}
.sm-mini::after{content:'';position:absolute;inset:-6px -2px}
.sm-mini.ink{background:var(--ink);color:var(--paper)}
.sm-two{flex-basis:100%;display:grid;grid-template-columns:1fr 1fr;gap:var(--s-2)}
.sm-b{height:44px;border:none;cursor:pointer;border-radius:var(--r-1);background:var(--surface);color:var(--ink-2);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.sm-b.ink{background:var(--ink);color:var(--paper)}
/* Пять состояний — подложкой и правым краем, как в строке на десктопе (16n) */
.sm-row.done{opacity:.62}
.sm-row.off{background:var(--surface-2);box-shadow:none}
.sm-row.off .sm-time b{color:var(--muted);text-decoration:line-through}
.sm-row.off .sm-name{color:var(--muted)}
.sm-row.off .sm-mini{background:var(--surface)}
.sm-row.unmarked{background:var(--err-bg);box-shadow:none}
.sm-row.is-live{box-shadow:0 0 0 1.5px var(--marker),0 12px 28px -14px rgba(23,26,33,.2)}
.sm-row.ev{background:var(--surface-2);box-shadow:none}
/* Ближайшее — чернильная карточка с «Войти в класс»; в темноте — тёмный лист с кантом (13a) */
.sm-next{padding:var(--s-3) var(--s-4) var(--s-4);border-radius:var(--r-2);background:var(--ink);color:var(--paper);cursor:pointer}
.sm-next-st{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-label);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--marker)}
.sm-next-h{display:flex;align-items:baseline;gap:var(--s-2);min-width:0;margin-top:var(--s-2)}
.sm-next-h b{flex:0 0 auto;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.sm-next-h span{min-width:0;font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-next-s{margin-top:var(--s-1);font-size:var(--t-sm);color:var(--sm-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-next .sm-debt{color:#E88579}
.sm-enter{display:flex;align-items:center;justify-content:center;width:100%;height:48px;margin-top:var(--s-3);
  border:none;cursor:pointer;border-radius:var(--r-1);background:var(--paper);color:var(--ink);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}

/* Блоки под лентой: без отметки, пустой день, первый день */
.sm-sec{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s-2);padding:var(--s-5) var(--s-4) 0}
.sm-lab{font-size:var(--t-label);font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.sm-card{display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3);background:var(--surface);
  border-radius:var(--r-1);box-shadow:var(--sh-1)}
.sm-card[role="button"]{cursor:pointer}
.sm-empty{padding:var(--s-5) var(--s-4) 0}
.sm-empty.first{padding-top:var(--s-6)}
.sm-empty h2{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);letter-spacing:-.025em;
  line-height:1.25;color:var(--ink)}
.sm-empty p{margin-top:var(--s-2);font-size:var(--t-md);line-height:1.55;color:var(--ink-2)}
.sm-empty .sm-btn{margin-top:var(--s-4)}
.sm-empty .sm-lab{margin:var(--s-5) 0 var(--s-2)}
.sm-empty .sm-card+.sm-card{margin-top:var(--s-2)}
.sm-steps{margin-top:var(--s-5);padding:var(--s-4);background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
.sm-step{display:flex;align-items:center;gap:var(--s-3)}
.sm-step+.sm-step{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--surface-2)}
.sm-step-n{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;
  border-radius:7px;background:var(--surface-2);color:var(--ink-2);font-family:var(--font-head);
  font-weight:700;font-size:var(--t-label)}
.sm-step-t{flex:1;font-size:var(--t-md);color:var(--ink-2)}
.sm-step.now .sm-step-n{background:var(--ink);color:var(--paper)}
.sm-step.now .sm-step-t{font-weight:600;color:var(--ink)}
.sm-step.next .sm-step-n{color:var(--sm-faint)}
.sm-step.next .sm-step-t{color:var(--muted)}
.sm-btn{display:flex;align-items:center;justify-content:center;width:100%;height:48px;border:none;cursor:pointer;
  border-radius:var(--r-1);background:var(--surface-2);color:var(--ink);font-family:var(--font-head);
  font-weight:600;font-size:var(--t-md);text-decoration:none}
.sm-btn.primary{background:var(--ink);color:var(--paper)}
.sm-note{margin-top:var(--s-2);font-size:var(--t-sm);color:var(--muted);text-align:center}

/* Шторки расписания: своя стопка поверх общего листа (smSheet). Подложка
   светлее общей — день за шторкой должен читаться: закрытие вернёт в него. */
.sm-wrap .sheet-scrim{background:rgba(23,26,33,.38)}
.sheet.sm-sheet{max-height:88vh;background:var(--paper);border-radius:var(--r-3) var(--r-3) 0 0;
  padding:var(--s-2) 0 calc(var(--s-3) + env(safe-area-inset-bottom))}
/* Ручка — единственное место, за которое шторку тянут вниз: выключенный
   touch-action отдаёт жест коду, а невидимые поля делают мишень в палец. */
.sm-sheet .sheet-grip{position:relative;width:38px;margin:var(--s-1) auto var(--s-3);touch-action:none;cursor:grab}
.sm-sheet .sheet-grip::after{content:'';position:absolute;inset:-14px -48px}
.sm-pad{padding:0 var(--s-4)}
.sm-shead{display:flex;align-items:center;justify-content:space-between;gap:var(--s-2);margin-bottom:var(--s-3)}
.sm-shead b{font-family:var(--font-head);font-weight:700;font-size:19px;letter-spacing:-.025em;color:var(--ink)}
.sm-x{position:relative;display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;
  margin-right:calc(-1 * var(--s-2));border:none;background:none;cursor:pointer;border-radius:var(--r-1);
  font-size:var(--t-lg);color:var(--muted)}
.sm-x::after{content:'';position:absolute;inset:-4px}
/* Лист занятия (16e) */
.sm-st{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-label);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.sm-st.err{color:var(--err)}
.sm-when{display:flex;align-items:baseline;gap:var(--s-2);margin-top:var(--s-2)}
.sm-when b{font-family:var(--font-head);font-weight:700;font-size:var(--t-d1);letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;color:var(--ink)}
.sm-when span{font-size:var(--t-base);color:var(--muted);font-variant-numeric:tabular-nums}
.sm-when em,.sm-chips em{font-style:normal}
.sm-who{margin-top:var(--s-2);font-family:var(--font-head);font-weight:600;font-size:19px;letter-spacing:-.02em;color:var(--ink)}
.sm-chips{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-2)}
.sm-chips span{padding:var(--s-1) var(--s-3);border-radius:var(--r-pill);background:var(--surface-2);
  color:var(--ink-2);font-size:var(--t-sm);font-weight:600}
.sm-chips .ok{background:var(--ok-bg);color:var(--ok)}
.sm-chips .err{background:var(--err-bg);color:var(--err)}
.sm-acts{display:grid;gap:var(--s-2);margin-top:var(--s-4)}
.sm-links{margin-top:var(--s-3);border-top:1px solid var(--line)}
.sm-link{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;height:52px;
  padding:0 var(--s-4);border:none;background:none;cursor:pointer;text-align:left;
  font-family:var(--font-body);font-size:var(--t-md);color:var(--ink-2)}
.sm-link span{font-size:var(--t-lg);color:var(--muted)}
.sm-link+.sm-link::before{content:'';position:absolute;left:var(--s-4);right:var(--s-4);top:0;height:1px;background:var(--line)}
.sm-link:active{background:var(--surface-2)}
.sm-foot{padding:var(--s-3) var(--s-4) 0;border-top:1px solid var(--line)}
.sm-sheet.new .sm-foot{border-top:none;padding-top:var(--s-4)}
/* Отметка (16m) */
.sm-mh{display:flex;align-items:baseline;gap:var(--s-2);min-width:0}
.sm-mh b{flex:0 0 auto;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;color:var(--ink)}
.sm-mh span{min-width:0;font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-mh-s{margin-top:var(--s-1);font-size:var(--t-sm);color:var(--err)}
.sm-sheet.mark .sm-lab{margin:var(--s-4) 0 var(--s-2)}
.sm-opts{display:grid;gap:var(--s-2)}
.sm-opt{display:flex;align-items:center;gap:var(--s-3);width:100%;padding:var(--s-3);border:none;cursor:pointer;
  text-align:left;background:var(--surface);border-radius:var(--r-1);box-shadow:var(--sh-1);color:var(--ink)}
.sm-opt span{flex:1;display:flex;flex-direction:column}
.sm-opt b{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.sm-opt i{font-style:normal;font-size:var(--t-sm);color:var(--muted)}
.sm-opt em{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;
  border-radius:var(--r-pill);background:var(--ink);color:var(--paper);font-style:normal;
  font-size:var(--t-label);font-weight:700}
.sm-opt.on{box-shadow:0 0 0 1.5px var(--ink)}
.sm-plate{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2);margin-top:var(--s-3);
  padding:var(--s-3);border-radius:var(--r-1);background:var(--surface-2);font-size:var(--t-base);color:var(--ink-2)}
.sm-plate b{font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
/* Перенос и выбор времени — сетка свободных слотов (16h) */
.sm-bigday{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);letter-spacing:-.025em;color:var(--ink)}
.sm-pair{display:flex;gap:var(--s-2);margin-top:var(--s-3)}
.sm-soft{flex:1;height:40px;border:none;cursor:pointer;border-radius:var(--r-1);background:var(--surface-2);
  color:var(--ink-2);font-family:var(--font-body);font-weight:600;font-size:var(--t-base)}
.sm-sheet.move .sm-lab,.sm-sheet.pick .sm-lab{margin:var(--s-5) 0 var(--s-2)}
.sm-slots{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s-2)}
.sm-slot{height:52px;border:none;cursor:pointer;border-radius:var(--r-1);background:var(--surface);box-shadow:var(--sh-1);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);font-variant-numeric:tabular-nums;color:var(--ink)}
.sm-slot.on{background:var(--ink);color:var(--paper);font-weight:700;box-shadow:none}
.sm-slot.own{background:var(--surface-2);box-shadow:none;font-size:var(--t-base);color:var(--ink-2)}
.sm-own{grid-column:1/-1;display:flex;gap:var(--s-2)}
.sm-form .sm-own{margin-top:calc(-1 * var(--s-1))}
.sm-own input{flex:1;min-width:0;height:48px;padding:0 var(--s-3);border:1px solid var(--line-2);border-radius:var(--r-1);
  background:var(--surface);font-size:var(--t-lg);color:var(--ink)}
.sm-own .sm-b{flex:0 0 auto;height:48px;padding:0 var(--s-4)}
.sm-cap{margin-top:var(--s-3);font-size:var(--t-sm);line-height:1.5;color:var(--muted)}
.sm-mnav{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--s-2)}
.sm-mnav b{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);color:var(--ink)}
.sm-mnav .sm-x{margin:0;font-size:var(--t-h1);color:var(--ink-2)}
/* Постановка (16g) */
.sm-form{display:grid;gap:var(--s-3)}
.sm-form .sm-lab{margin-bottom:var(--s-2)}
.sm-field{display:flex;align-items:center;gap:var(--s-2);width:100%;height:48px;padding:0 var(--s-3);
  border:1px solid var(--line-2);border-radius:var(--r-1);background:var(--surface);cursor:pointer;text-align:left;
  font-family:var(--font-body);font-size:var(--t-md);font-weight:600;font-variant-numeric:tabular-nums;color:var(--ink)}
.sm-field b{flex:1;min-width:0;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sm-field:active,.sm-field:focus-visible{border-color:var(--ink)}
.sm-field .stu-ava.xs{background:var(--surface-2);color:var(--ink-2)}
.sm-cols{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-2)}
.sm-durs{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s-2)}
.sm-durs button{height:44px;border:none;cursor:pointer;border-radius:var(--r-1);background:var(--surface-2);
  color:var(--ink-2);font-family:var(--font-body);font-weight:600;font-size:var(--t-md);font-variant-numeric:tabular-nums}
.sm-durs button.on{background:var(--ink);color:var(--paper);font-weight:700}
.sm-repeat{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);padding:var(--s-3);
  background:var(--surface);border-radius:var(--r-1);box-shadow:var(--sh-1)}
.sm-repeat span{display:flex;flex-direction:column;min-width:0}
.sm-repeat b{font-size:var(--t-md);font-weight:600;color:var(--ink)}
.sm-repeat i{font-style:normal;font-size:var(--t-sm);color:var(--muted)}
.sm-sw{position:relative;flex:0 0 auto;width:44px;height:26px;border:none;cursor:pointer;border-radius:var(--r-pill);
  background:var(--line-2);transition:background var(--dur-fast) var(--ease)}
.sm-sw::before{content:'';position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:var(--r-pill);
  background:var(--surface);box-shadow:var(--sh-1);transition:transform var(--dur-fast) var(--ease)}
.sm-sw[aria-checked="true"]{background:var(--ink)}
.sm-sw[aria-checked="true"]::before{transform:translateX(18px);background:var(--paper)}
.sm-more{display:flex;align-items:center;justify-content:center;gap:var(--s-2);width:100%;min-height:44px;
  margin-top:var(--s-1);border:none;background:none;cursor:pointer;font-family:var(--font-body);
  font-size:var(--t-base);color:var(--ink-2)}
.sm-more span{color:var(--muted)}
.sm-list{display:grid;padding:0 var(--s-2)}
.sm-li{display:flex;align-items:center;gap:var(--s-3);width:100%;min-height:56px;padding:var(--s-2);border:none;
  background:none;cursor:pointer;border-radius:var(--r-1);text-align:left;color:var(--ink)}
.sm-li.on,.sm-li:active{background:var(--surface-2)}

/* Полоса возврата (16j): над вкладками во всю ширину, «Вернуть» жёлтой кнопкой —
   это отмена уже сделанного, того же рода, что в массовых действиях. */
@media(max-width:640px){
  .toast.undo{left:var(--s-3);right:var(--s-3);width:auto;max-width:none;transform:translateY(20px);
    bottom:calc(58px + env(safe-area-inset-bottom));border-radius:var(--r-1);
    padding:var(--s-3);gap:var(--s-3);font-size:var(--t-md);font-weight:600}
  .toast.undo.on{transform:none}
  .toast.undo>span{flex:1;min-width:0}
  .toast.undo .toast-sub{font-weight:400;font-size:var(--t-sm);color:var(--sm-faint)}
  .toast.undo .toast-act{border-radius:var(--r-1);padding:var(--s-2) var(--s-3);background:var(--marker);
    color:#171A21;font-weight:700;font-size:var(--t-base)}
}

/* Тёмная тема (16q, 16r): не инверсия. Тени уходят — карточки держатся фоном
   на ступень светлее; прошедшее опускается на подложку. Ближайшее по 16q
   переворачивалось светлым, а на главной и в кабинете ученика оно тёмное (13a);
   владелец 14 сентября попросил свести к одному. Теперь и здесь тёмный лист с
   кантом, светлеет одно «Войти в класс». */
html[data-chrome="dark"] .sm-strip.open{background:var(--paper);box-shadow:none}
html[data-chrome="dark"] .sm-row,html[data-chrome="dark"] .sm-card,html[data-chrome="dark"] .sm-steps,
html[data-chrome="dark"] .sm-opt,html[data-chrome="dark"] .sm-slot,html[data-chrome="dark"] .sm-repeat{box-shadow:none}
html[data-chrome="dark"] .sm-row.done{opacity:1;background:var(--paper)}
html[data-chrome="dark"] .sm-row.done .sm-time,html[data-chrome="dark"] .sm-row.done .sm-name{color:var(--muted)}
html[data-chrome="dark"] .sm-row.off,html[data-chrome="dark"] .sm-row.ev{background:var(--paper)}
html[data-chrome="dark"] .sm-row.is-live{box-shadow:0 0 0 1.5px var(--marker)}
html[data-chrome="dark"] .sm-next{background:var(--c-surface);color:var(--c-ink);box-shadow:var(--sh-1)}
html[data-chrome="dark"] .sm-next-s{color:var(--c-ink-2)}
html[data-chrome="dark"] .sm-enter{background:var(--c-ink);color:var(--c-paper)}
html[data-chrome="dark"] .sm-opt.on{box-shadow:0 0 0 1.5px var(--ink)}
html[data-chrome="dark"] .sm-chips span:not(.ok):not(.err),html[data-chrome="dark"] .sm-plate,
html[data-chrome="dark"] .sm-btn:not(.primary){background:var(--surface)}
html[data-chrome="dark"] .sm-wrap .sheet-scrim{background:rgba(9,10,13,.58)}

/* Ширина 320 (16k, 16l): мишени не уменьшаются, сжимаются поля, колонка
   времени и вторые строки в спокойных состояниях. Долг, галочка и «Войти в
   класс» остаются. */
@media(max-width:360px){
  .sm-page{margin-left:calc(-1 * var(--s-3));margin-right:calc(-1 * var(--s-3))}
  .sm-seg,.sm-feed,.sm-sec,.sm-empty{padding-left:var(--s-3);padding-right:var(--s-3)}
  .sm-strip{padding:var(--s-2)}
  .sm-d .n,.sm-c{height:32px}
  .sm-row{gap:var(--s-2)}
  .sm-time{flex-basis:46px;font-size:var(--t-sm)}
  .sm-row:not(.is-live) .sm-time i{display:none}
  .sm-next-h b{font-size:var(--t-lg)}
  .sm-pad{padding:0 var(--s-3)}
  .sm-link{height:50px;padding:0 var(--s-3)}
  .sm-link+.sm-link::before{left:var(--s-3);right:var(--s-3)}
  .sm-when b{font-size:var(--t-h1)}
  .sm-who{font-size:var(--t-lg)}
  .sm-when em,.sm-chips em{display:none}
}

.sch-two{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:20px;align-items:start}
@media(max-width:1180px){.sch-two{grid-template-columns:minmax(0,1fr)}}
.sch-days{min-width:0}
.sch-rail{display:flex;flex-direction:column;gap:var(--s-3);position:sticky;top:74px}
@media(max-width:1180px){.sch-rail{position:static}}
.rail-card{background:var(--surface);border-radius:var(--r-2);padding:var(--s-4);box-shadow:var(--sh-1)}
/* Поднята сильнее соседок намеренно: она единственная требует решения */
.rail-card.raised{box-shadow:var(--sh-2)}
.rail-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-2)}
.rail-n{font-size:var(--t-label);font-weight:600;font-variant-numeric:tabular-nums;color:var(--muted)}
.rail-note{font-size:var(--t-sm);color:var(--muted);margin-top:10px;line-height:1.45}
.week-bars{display:flex;align-items:flex-end;gap:var(--s-1);height:44px;margin-top:var(--s-3)}
/* День без занятий — полоска в три пикселя, и попасть в неё нельзя ни на
   телефоне, ни мышью. Вид оставляем: столбик и должен быть низким, он говорит
   «здесь пусто». Расширяем только место нажатия — на всю высоту колонки. */
.week-bars .wb{position:relative;flex:1;min-width:0;padding:0;border:none;border-radius:5px;
  background:var(--surface-2);cursor:pointer;min-height:3px}
.week-bars .wb::after{content:'';position:absolute;left:0;right:0;bottom:0;height:44px}
.week-bars .wb.none{background:var(--line);height:3px}
.week-bars .wb.now{background:var(--marker)}
.week-x{display:flex;gap:var(--s-1);margin-top:6px;font-size:var(--t-label);
  font-variant-numeric:tabular-nums;color:var(--muted)}
.week-x span{flex:1;text-align:center}
.week-x .now{font-weight:600;color:var(--ink)}
.nm-item{background:var(--paper);border-radius:var(--r-1);padding:10px 11px;margin-top:6px}
.nm-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nm-when{font-size:var(--t-sm);font-variant-numeric:tabular-nums;color:var(--muted);margin-top:1px}
.nm-acts{display:flex;gap:6px;margin-top:10px}
.reg-list{display:flex;flex-direction:column;gap:var(--s-2);margin-top:var(--s-3)}
.reg-row{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.reg-n{font-size:var(--t-sm);color:var(--ink-2);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.reg-t{font-size:var(--t-sm);font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}

/* ---------- Расписание сеткой недели ----------
   Дни столбцами, время сверху вниз, занятие — плашкой длиной в своё занятие:
   пятьдесят минут и есть пятьдесят минут. Полчаса и час выглядят по-разному,
   три занятия подряд читаются сплошной полосой, а щель между 19:50 и 20:00 —
   щелью, а не свободными получасом.

   Устройство: полчаса — клетка (--cal-row), по ней расставлены линии и по ней
   нажимают на пустое место; плашки лежат поверх колонки дня и посчитаны в
   долях этой же клетки (см. calChip в public/js/schedule.js). Высоту клетки
   держит здесь CSS, а не разметка, — на телефоне она меньше, и считай её
   разметка в точках, вёрстка и стили разъехались бы ровно на телефоне.

   Часы сетки считает schedule.js: показываются рабочие часы недели, а не
   сутки, иначе таблица была бы пустой на три четверти.

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

   Плашка стала белой карточкой с цветной рельсой слева, и различие несёт
   рельса: маркер — впереди, серое — проведено, красное — прошло без отметки.
   Идущее занятие берёт маркер и ореол, ближайшее — чёрный контур, тот же, что
   у строки списка и у карточки на главной. */
.cal-bar{display:flex;align-items:center;gap:var(--s-2);margin-bottom:var(--s-3);flex-wrap:wrap}
.cal-bar .spacer{flex:1}
.cal-bar .cal-range{font-family:var(--font-head);font-weight:700;font-size:var(--t-md);
  min-width:132px;text-align:center}

/* Прокрутка вбок, а не перенос: семь дней недели — это семь дней недели, и на
   узком экране лучше довезти их пальцем, чем показать четыре и сделать вид,
   что неделя такая. Колонка времени при этом остаётся на месте — без неё
   уехавшая вбок сетка перестаёт значить что-либо. */
.cal-wrap{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  overflow-x:auto}
.cal{display:grid;grid-template-columns:62px repeat(7,minmax(104px,1fr));min-width:780px;
  /* Полчаса — 32 точки. На 24 пятидесятиминутное занятие занимало сорок, и
     вторая строка плашки (время и уровень ученика) в неё не помещалась: её
     прятало правило по высоте, и от занятия оставалось одно имя. Заодно на
     низкой клетке было не разобрать, что занятие начинается в 14:15, а не в
     14:00: пятнадцать минут занимали шесть точек. */
  --cal-row:32px}

.cal-corner{position:sticky;left:0;z-index:5;background:var(--surface);
  border-bottom:1px solid var(--line)}
.cal-day{padding:var(--s-2) var(--s-1);text-align:center;border-left:1px solid var(--line);
  border-bottom:1px solid var(--line);
  font-family:var(--font-head);font-size:var(--t-sm);font-weight:600;color:var(--muted)}
.cal-day .w{display:block;text-transform:lowercase;letter-spacing:.04em}
.cal-day .d{display:inline-flex;align-items:center;justify-content:center;
  min-width:26px;height:26px;margin-top:5px;border-radius:var(--r-pill);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
  letter-spacing:-.02em;color:var(--ink)}
/* Выходной приглушён целиком: раньше серел только день недели, а число стояло
   таким же чёрным, как в будни, — край недели по нему не читался. */
.cal-day.off .w,.cal-day.off .d{color:var(--line-2)}
.cal-day.today .d{font-weight:700;font-size:var(--t-md)}
/* Сегодня — закрашенный кружок с числом, как активный пункт меню: цвета у
   платформы нет, акцент чёрный. Столбец под ним отбит сильной линией по краям,
   а не заливкой: разница листа и бумаги в 1.09 в тёмном хроме не переживает
   перевод, а линия переживает (docs/design/06-ПРАВИЛА.md). */
.cal-day.today .d{background:var(--accent);color:var(--accent-ink)}

.cal-gutter{position:sticky;left:0;z-index:4;background:var(--surface)}
.cal-time{height:var(--cal-row);box-sizing:border-box;border-top:1px solid var(--line);
  padding:2px var(--s-2) 0 0;text-align:right;
  font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted)}
/* Половинных линий на сетке нет: час размечен одной линией, а клетка получаса
   осталась только мишенью — по ней нажимают и в неё бросают плашку. Раньше
   линий было вдвое больше, чем подписей, и сетка читалась плотнее, чем есть. */
.cal-time.half{border-top-color:transparent}

.cal-col{position:relative;border-left:1px solid var(--line)}
.cal-col.off{background:var(--paper)}
.cal-col.today{box-shadow:inset 1px 0 0 var(--line-2),inset -1px 0 0 var(--line-2);
  background:color-mix(in srgb,var(--marker-soft) 34%,var(--surface))}

.cal-slot{height:var(--cal-row);box-sizing:border-box;border-top:1px solid var(--line)}
.cal-slot.half{border-top-color:transparent}
/* Пустая клетка — главное действие этого вида, поэтому она отвечает на
   наведение и сама говорит, во сколько поставит занятие: подписывать все
   получасовые строки в колонке времени значило бы удвоить её шум ради
   сведения, которое нужно раз в день. */
.cal-slot.free{cursor:pointer;position:relative}
.cal-slot.free:hover{background:var(--surface-2)}
.cal-slot.free::before{content:'+ ' attr(data-t);position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);
  opacity:0;transition:opacity var(--dur-fast) var(--ease)}
.cal-slot.free:hover::before{opacity:1}
/* Куда упадёт то, что тянут. Маркер здесь уместен: это «выделение» в чистом
   виде — платформа показывает, куда смотрит рука. */
.cal-slot.over,.cal-chip.over{box-shadow:inset 0 0 0 2px var(--marker)}
.cal-slot.over{background:var(--marker-soft)}

/* Черта «сейчас» с точкой на краю дня */
.cal-now{position:absolute;left:0;right:0;height:1px;background:var(--marker);
  z-index:3;pointer-events:none}
.cal-now::before{content:'';position:absolute;left:-4px;top:-3px;width:7px;height:7px;
  border-radius:50%;background:var(--marker)}

/* Высота приходит разметкой — она и есть длительность. Нижний предел здесь, а
   не там: занятие на десять минут в сетке всё равно должно называться, а
   имя короче своей строки не бывает. */
.cal-chip{position:absolute;z-index:2;box-sizing:border-box;overflow:hidden;min-height:22px;
  background:var(--surface);border:none;border-left:3px solid var(--marker);
  border-radius:var(--r-1);box-shadow:var(--sh-1);
  color:var(--ink);padding:5px var(--s-2) 4px 7px;cursor:pointer;
  /* Помещается ли вторая строка, решает высота плашки в пикселях, а не
     длительность занятия: высота строки сетки меняется с шириной окна (38px на
     ноутбуке, 24px на широком экране), и одно и то же пятидесятиминутное
     занятие то влезало, то теряло хвосты букв под нижним краем. Спрашиваем у
     самой плашки. */
  container-type:size;
  transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease)}
.cal-chip:hover{transform:translateY(-1px);box-shadow:var(--sh-2);z-index:3}
.cal-chip[draggable="true"]{cursor:grab}
.cal-chip[draggable="true"]:active{cursor:grabbing}
.cal-chip .cc-n{display:block;font-family:var(--font-head);font-weight:600;
  font-size:var(--t-sm);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-chip .cc-m{display:block;font-variant-numeric:tabular-nums;font-size:var(--t-label);
  color:var(--muted);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Короткому занятию второй строки не хватает — остаётся имя */
.cal-chip.tight .cc-m{display:none}
/* Порог считается по внутренней высоте плашки, а не по внешней: запрос к
   контейнеру меряет content box, а у плашки ещё девять точек полей. Двум
   строкам — имени и подписи — нужно около тридцати; всё, что ниже, оставляет
   одно имя. На прежних сорока шести под нож попадало обычное пятидесятиминутное
   занятие: внутри него оставался сорок один пиксель. */
@container (max-height:30px){.cal-chip .cc-m{display:none}}
/* Личное дело — дырка в рабочем дне: бумага вместо маркера и пунктир вместо
   линии. Рядом с залитыми занятиями это читается без подписи: жёлтое — ученик,
   пунктир — своё. */
.cal-chip.is-event{background:var(--paper);border-left-style:dashed;
  border-left-color:var(--line-2);box-shadow:none;color:var(--ink-2)}
.cal-chip.is-event .cc-n{font-weight:600}
.cal-chip.is-event:hover{border-left-color:var(--ink-2)}
/* Идёт сейчас — рамка и ореол, как у карточки ближайшего занятия: заливкой это
   больше не отличить, она у всех занятий. */
.cal-chip.is-live{border-left-color:var(--marker);box-shadow:0 0 0 2px var(--marker-soft);z-index:3}
/* Ближайшее занятие — чёрный контур. Отдельной карточки наверху страницы больше
   нет, и «следующее» называет именно он: тот же приём, что в списке и на главной. */
.cal-chip.next{box-shadow:0 0 0 1.5px var(--ink),0 8px 20px -10px rgba(23,26,33,.3);z-index:3}
/* Исход прошедшего занятия — цветом, а не бледностью.

   Раньше проведённое и отменённое отличались только прозрачностью, 0,6 против
   0,5, и на неделе из десяти жёлтых плашек эта разница не читалась вовсе:
   имя зачёркнуто — значит что-то не так, а что именно, приходилось наводить
   мышь и читать подсказку. Заодно бледность съедала сам текст.

   Теперь у каждого исхода своя заливка, и слово стоит рядом со временем
   (см. calChip в schedule.js). Цвета не новые: «проведено» берёт --ok, тот
   самый, которым платформа помечает верное и сделанное, а отменённое уходит в
   нейтральную подложку — оно ничего не занимает и никого не ждёт. Маркер
   остаётся у того, что впереди, и в этом весь смысл: жёлтое на неделе — это
   работа, которая ещё предстоит.

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

   Пунктир отменённому не даём: он занят личным делом («бумага вместо маркера и
   пунктир вместо линии»), и две бледные плашки с пунктиром слева читались
   одинаково. Отменённое отличается от дела по трём признакам сразу: заливкой
   (плита против бумаги), рельсой (сплошная против пунктира) и зачёркнутым
   именем. */
.cal-chip.done{border-left-color:var(--line-2);opacity:.55}
.cal-chip.off{background:var(--surface-2);border-left-color:var(--line);
  box-shadow:none;color:var(--muted)}
.cal-chip.off .cc-n{text-decoration:line-through}
.cal-chip.off .cc-m{color:var(--muted)}
/* Прошедшее без отметки — единственное состояние, которому плашка отдаёт
   подложку: оно ждёт решения, а остальные просто есть. */
.cal-chip.unmarked{background:var(--err-bg);border-left-color:var(--err);box-shadow:none}
.cal-chip.unmarked .cc-m{color:var(--err)}
.cal-chip.past:not(.off):not(.done):not(.unmarked):not(.next){opacity:.72}
.cal-chip.dragging{opacity:.35}

/* На телефоне сетка едет вбок, клетка ниже, и колонкам хватает имени: точное
   время и уровень ученика уходят, они есть в подсказке и в форме. */
@media(max-width:760px){
  .cal{grid-template-columns:46px repeat(7,minmax(92px,1fr));min-width:690px;--cal-row:38px}
  .cal-chip .cc-m{display:none}
  /* Кроме исхода: время и уровень на телефоне убираются как украшение, а
     «проведено» и «отменено» — то, ради чего на прошедшую неделю и смотрят. */
  .cal-chip.done .cc-m,.cal-chip.off .cc-m{display:block}
}

/* Переключатель вида стоит в шапке страницы по нижней линии заголовка, а
   собственный нижний отступ у .seg рассчитан на форму. */
.page-head .seg{margin-bottom:0}
/* Тип нового: занятие или своё дело. Над полями, потому что от него зависят
   сами поля. */
.seg.sl-kind{margin-bottom:var(--s-3)}
/* «Когда и сколько» — одной строкой формы: длительность относится ко времени
   начала, а не к статусу, рядом с которым стояла раньше.

   Раньше эта пара жила в .cover-grid — сетке из четырёх равных колонок, сделанной
   под мелкие поля обложки урока. Двум полям доставалось по четверти окна, и
   статус в свою четверть не влезал: сегментированный контрол не сжимается ниже
   своего содержимого, поэтому «Не состоялось» ломалось на две строки, колонка
   раздувалась, а у поля длительности подпись переносилась и само оно съезжало
   вниз. Здесь колонки разного веса и обе с minmax(0,…), то есть сжиматься умеют.

   Статус и повтор после этого встали своей строкой во всю ширину: трём
   состояниям нужно около 330 точек, и делить их не с чем. */
.sl-cols{display:grid;grid-template-columns:minmax(0,1fr) 132px;gap:var(--s-3);align-items:start}
/* Число в поле на всю ширину окна выглядит полем для строки. Ограничиваем само
   поле, а не колонку: подпись и подсказка под ним остаются полной ширины. */
.sl-narrow input{max-width:132px}
/* На узком экране в один столбец, и ограничение с поля снимаем: там оно уже
   и так во всю доступную ширину, а обрезок в 132 точки читался бы как поломка. */
@media(max-width:560px){
  .sl-cols{grid-template-columns:1fr}
  .sl-narrow input{max-width:none}
}
/* Три состояния исхода на телефоне в строку не встают — переносим, а не
   выпускаем за край окна. */
.seg.sl-status{flex-wrap:wrap}

/* Переходы из окна занятия — в класс, в карточку ученика, на звонок. Стоят над
   полями и отбиты линией снизу: это не часть формы, а выходы из неё, и путать
   их с «Сохранить» нельзя. */
.sl-jump{display:flex;flex-wrap:wrap;gap:var(--s-2);margin:0 0 var(--s-3);
  padding-bottom:var(--s-3);border-bottom:1px solid var(--line)}
.count-pill{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;
  background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--r-pill);
  font-variant-numeric:tabular-nums;font-size:var(--t-label);padding:0 7px;font-weight:600}
/* Нейтральный счётчик — там, где число не про ИИ и не про новое от преподавателя. */
.count-pill.flat{background:var(--surface-2);color:var(--muted)}
/* Счётчик совсем без плашки: в шапке листа число говорит «сколько всего»,
   и плашка вокруг него читалась бы как ещё одна метка. */
.count-plain{font-size:var(--t-label);font-weight:600;color:var(--muted);
  font-variant-numeric:tabular-nums;margin-left:auto}
/* Подвал листа: слева — куда уехало остальное, справа — массовое действие. */
.panel-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);
  padding:var(--s-4) 14px var(--s-3);font-size:var(--t-sm)}
.panel-foot>a,.panel-foot>button:first-child{color:var(--marker-ink);background:none;border:none;
  font:inherit;cursor:pointer;text-align:left;padding:0}
.panel-foot>button:last-child{color:var(--muted);background:none;border:none;font:inherit;
  cursor:pointer;padding:0}
.panel-foot>button:last-child:hover{color:var(--ink)}
.more-link{background:none;border:none;color:var(--accent);font-family:var(--font-head);font-weight:600;font-size:var(--t-base);cursor:pointer;padding:var(--s-1) 0}
.more-link:hover{text-decoration:underline}



/* ---------- «Оплаты»: доход по месяцам ----------
   Единственный раздел, где месяц листается назад: это отчёт, а не рабочий стол.
   Сумма в строке набрана заголовочным шрифтом и стоит справа — по суммам идут
   глазами, а не по именам. Цветом деньги не выделяем: маркер закреплён за
   заметками, и «доход» не повод его занимать. */
/* Ряд месяца: стрелка, название, стрелка и «Добавить доход». На телефоне его
   нет — там месяц листает своя строка-переключатель (1h, .pp-month). */
.month-nav{display:flex;align-items:center;gap:var(--s-1)}
.month-nav .mn-label{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
  min-width:148px;text-align:center;text-transform:capitalize}
/* Стрелки месяца — белые кнопки 34×34, как остальные кнопки хрома, а не значки
   без формы: месяц листают часто, и попадать по ним надо не целясь. */
.mn-btn{width:34px;height:34px;flex-shrink:0;display:inline-flex;align-items:center;
  justify-content:center;background:var(--surface);border:none;border-radius:var(--r-1);
  box-shadow:var(--sh-1);font-family:inherit;font-size:var(--t-base);color:var(--ink-2);
  cursor:pointer}
.mn-btn:hover{background:var(--surface-2)}
.mn-btn:disabled{opacity:.3;cursor:default}
.mn-btn:disabled:hover{background:var(--surface)}
.mn-add{margin-left:6px}

/* ---------- Полгода дохода отдельной карточкой ----------
   Раньше столбики ютились в углу первого показателя и читались украшением к
   сумме месяца. Здесь у графика свой вопрос — куда всё движется, — и суммы
   стоят подписью под каждым столбиком, а не прячутся в подсказке.
   Маркер тут цвет данных, а не заметок: урока на этом экране нет. */
.pay-chart{background:var(--surface);border-radius:var(--r-2);padding:22px var(--s-5);
  box-shadow:var(--sh-1);margin-bottom:var(--s-4)}
/* ---------- Хвост экрана денег ----------
   Две колонки: слева кто сколько заплатил, справа — то, что читают взглядом.
   На узком экране колонки складываются в одну, порядок остаётся тот же. */
.pay-two{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:var(--s-5);
  align-items:start;margin-top:var(--s-4)}
@media(max-width:1000px){.pay-two{grid-template-columns:1fr}}
.pay-main,.pay-side{min-width:0}
.pay-two .sec-title:first-child{margin-top:0}
/* Свод по ученику: строка на человека, оплаты внутри — по нажатию. */
.pay-group .chev{color:var(--muted);font-size:var(--t-sm);margin-left:var(--s-2)}
.pay-group-rows{margin:0 0 var(--s-3) var(--s-5);border-left:1px solid var(--line);padding-left:var(--s-3)}
/* Долг: занятия провели, деньги не пришли. Красный здесь — данные, обратный
   знак к «оплачено», а не тревога. */
.pay-debt{background:var(--err-bg);border-radius:var(--r-2);padding:14px;margin-bottom:var(--s-4)}
.pay-debt .pd-big{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.02em;color:var(--err);margin:var(--s-1) 0 var(--s-2)}
.pay-debt .pd-row{background:none;padding-left:0;padding-right:0}
.pay-debt .pd-row .r-sub{color:var(--ink-2)}
/* Запас вперёд: две строки «что» — «сколько», числа справа столбиком. */
.pay-ahead{background:var(--paper);border-radius:var(--r-2);padding:14px;margin-top:var(--s-4)}
.pay-ahead .pa-line{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);
  font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-2)}
.pay-ahead .pa-line b{font-family:var(--font-head);font-size:var(--t-base);color:var(--ink);
  font-variant-numeric:tabular-nums;white-space:nowrap}

.pay-chart-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3)}
.pay-bars{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;align-items:end;
  margin-top:18px}
.pay-bars .pb-f{display:flex;align-items:flex-end;height:92px}
.pay-bars .pb-f i{display:block;width:100%;border-radius:7px;background:var(--surface-2)}
.pay-bars .pb.now .pb-f i{background:var(--marker)}
.pay-bars .pb.run .pb-f i{background:var(--line)}
.pb-x{display:flex;align-items:baseline;justify-content:space-between;gap:6px;margin-top:var(--s-2);
  font-size:var(--t-label);font-variant-numeric:tabular-nums;color:var(--muted)}
.pb-x b{font-weight:400}
.pb-x em{font-style:normal}
.pay-bars .pb.now .pb-x{color:var(--ink);font-weight:600}

.pay-row{display:flex;align-items:center;gap:var(--s-3);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--s-3) var(--s-3);margin-bottom:var(--s-2)}
.pay-row .t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.pay-row .s{font-size:var(--t-sm);color:var(--muted);margin-top:1px}
.pay-sum{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.01em;
  white-space:nowrap;flex-shrink:0}
/* Доход не от ученика — вместо аватара нейтральный значок */
/* Расход пакета в строке оплаты: полоса и подпись под ней */
.pay-used{display:flex;flex-direction:column;align-items:flex-end;gap:3px;min-width:120px}
.pay-used .bar{width:110px;margin:0}
.pay-ext{width:28px;height:28px;border-radius:50%;background:var(--surface-2);color:var(--muted);
  display:flex;align-items:center;justify-content:center;font-family:var(--font-head);
  font-weight:700;font-size:var(--t-sm);flex-shrink:0}

/* Состояние обрыва связи во время занятия */
/* ---------- Сплэш загрузки класса ----------
   Занятие открывается с запросом к серверу, и до ответа страница была белым
   листом — на живом уроке это самые тревожные полторы секунды. Здесь тот же
   мотив «Поле», собранный на глазах: линия прочерчивается, стикер приклеивается.
   Разметка лежит в class.html, поэтому видна сразу, ещё до первого скрипта.
   Заставка помечена .unthemed: applyTheme успевает покрасить body раньше, чем
   она снимается, и без этого шрифт и бумага на секунду уезжали в тему урока. */
.class-splash{position:fixed;inset:0;z-index:100;background:var(--paper);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--s-4)}
.class-splash .cs-glyph{position:relative;width:72px;height:72px}
.class-splash .cs-glyph::before{content:'';position:absolute;top:0;bottom:0;left:40%;width:1.5px;
  background:var(--line-2);transform-origin:top;animation:csLine .5s ease-out both}
.class-splash .cs-glyph::after{content:'';position:absolute;left:calc(40% - 14px);top:20px;
  width:34px;height:34px;background:var(--marker);border-radius:4px;
  animation:csStick .4s cubic-bezier(.34,1.3,.64,1) .35s both}
.class-splash .cs-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--muted)}
@keyframes csLine{from{transform:scaleY(0)}to{transform:scaleY(1)}}
@keyframes csStick{from{transform:rotate(-14deg) scale(.6);opacity:0}
  to{transform:rotate(-4deg) scale(1);opacity:1}}
/* Без анимации мотив всё равно собран: обе части на месте и в конечном виде */
@media (prefers-reduced-motion:reduce){
  .class-splash .cs-glyph::after{transform:rotate(-4deg)}
}

.conn-lost{background:var(--surface);border:1px solid var(--err-line);border-radius:var(--radius);padding:var(--s-3) var(--s-4);margin-bottom:var(--s-4)}
.conn-lost .lbl{display:flex;align-items:center;gap:var(--s-2);font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:var(--err);font-weight:500}
.conn-lost .lbl .dot{width:8px;height:8px;border-radius:50%;background:var(--err);animation:pulse 1.5s infinite}
.conn-lost .t{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);margin:var(--s-2) 0 var(--s-1)}
.conn-lost .s{font-size:var(--t-base);color:var(--muted);line-height:1.5}
.conn-lost .btn{margin-top:var(--s-3)}

.mobile-nav{display:none}
@media(max-width:640px){
  /* Граница с содержимым — сильной линией: под полосу уезжает текст страницы, а
     её собственный фон отличается от бумаги мягко, и в тёмном хроме полоса
     переставала быть краем экрана. */
  .mobile-nav{display:grid;grid-template-columns:repeat(4,1fr);position:fixed;left:0;right:0;bottom:0;
    z-index:50;background:var(--surface);border-top:1px solid var(--line-2)}
  /* Где ты сейчас — верхней рамкой чернилами: подчёркивание сверху читается как
     вкладка, а закраска пункта — как нажатая кнопка. */
  /* 52 в высоту и 13 кеглем, как в кадрах 2d, 12d и 12e: полоса — главные двери
     телефона, и подпись 10.5 в строке 45 читалась служебной сноской. */
  .mobile-nav{padding-bottom:env(safe-area-inset-bottom)}
  .mobile-nav button,.mobile-nav a,.step-nav a{display:flex;align-items:center;justify-content:center;
    min-height:52px;border:none;border-top:2px solid transparent;background:transparent;
    color:var(--muted);font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
    padding:0;text-align:center;cursor:pointer;text-decoration:none}
  .mobile-nav button.on,.mobile-nav a.on,.step-nav a.on{color:var(--ink);border-top-color:var(--ink)}
  /* У «Проверки» — точка, а не число: полоса делит ширину телефона на четыре, и
     счётчик в ней ломает слово. Есть ли что проверить — этого достаточно. */
  .mobile-nav .mn-dot{display:inline-block;width:5px;height:5px;border-radius:var(--r-pill);
    background:var(--marker);vertical-align:middle;margin-left:5px}
  .cab{padding-bottom:80px}
  .cab-nav{display:none}
  /* на телефоне нижняя навигация заменяет меню — не дублируем */
  .app.with-mobile-nav>.sidebar{display:none}
  /* Запас под закреплённую полосу держит подвал страницы, а не содержимое:
     он стоит после него и кончается выше полосы (см. .app-foot). */
}

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

   Перенос без порога. Прежде правило включалось ниже 1280px, а на ноутбучных
   1366 и 1440 ряд просто не помещался и уезжал вправо: чтобы нажать «Изменить с
   ИИ», приходилось листать страницу вбок. Порог тут вообще ни при чём — важно
   не число пикселей, а длина ряда, и решать это должен флекс. Пока ряд
   помещается, height:auto и min-height:52px оставляют шапку ровно такой, какой
   она была. */
body>.topbar{height:auto;min-height:52px;flex-wrap:wrap;row-gap:var(--s-2);
  padding-top:var(--s-2);padding-bottom:var(--s-2)}
.top-actions{flex-wrap:wrap;row-gap:var(--s-2)}

/* ---------- Шапка страницы без меню на телефоне ----------
   На занятии в шапке собирается больше всего: знак, путь до ученика, название
   урока, присутствие, поиск слова, смена материала, выход. В 375px этот ряд не
   встаёт и просто уезжал за край экрана — страницу приходилось отдалять
   пальцами. Путь сворачиваем до возврата (с кем ты в комнате, говорит плашка
   присутствия), а ряду действий разрешаем перенос — на случай, если и после
   этого тесно. */
@media(max-width:640px){
  body>.topbar{height:auto;min-height:52px;flex-wrap:wrap;row-gap:var(--s-2);
    padding-top:var(--s-2);padding-bottom:var(--s-2)}
  body>.topbar .brand,body>.topbar .top-sep,
  body>.topbar .top-step,body>.topbar .top-back~.top-back{display:none}
  /* Ряд действий начинается с нулевой ширины и потому остаётся на одной строке с
     возвратом, а переносится уже внутри себя: иначе он целиком уходил на свою
     строку и шапка вырастала в три этажа поверх урока.

     Правило только для шапок без меню: в кабинете ряд стоит в шапке один, и
     растянутый во всю ширину он прижимал тему и «Выйти» к левому краю — под
     ними начинается полоса разделов, и кнопки читались её началом. */
  body>.topbar .top-actions{flex-wrap:wrap;row-gap:var(--s-2);flex:1 1 0;min-width:0}
  /* Перенос внутри ряда тоже вправо: обе полосы по правому краю, а не вразнобой */
  .app-main .topbar .top-actions{justify-content:flex-end}
  /* Возврата в шапке нет (первый вход) — значит ряд действий в ней один, и стоять
     ему у правого края: прижатый к левому, он читается началом строки, а не её
     концом. Со ссылкой возврата всё как было: ряд идёт сразу за ней. */
  body>.topbar:not(:has(.top-back)) .top-actions{justify-content:flex-end}
  /* Строка поиска слова из шапки уходит: она шире всех кнопок вместе взятых, а
     слово в уроке и так ищется выделением (initLookup), не набором. */
  body>.topbar .ws-host{display:none}
}

/* ---------- Просмотр: подпись режима на телефоне (решение 5b) ----------
   На телефоне от длинной фразы про ответы оставалась одна плашка «Просмотр», и
   режим не объяснялся. Короткая подпись объясняет: это тот же урок глазами
   ученика. На широком экране её нет — там стоит полная фраза. */
.pb-short{display:none}
@media(max-width:640px){
  .pb-short{display:inline;font-size:var(--t-sm);color:var(--muted)}
}

/* ---------- Конструктор на телефоне (решение 5a) ----------

   Главная поломка видна на продакшн-кадре: полоса «Выдать ученику» закреплена
   у края экрана и режет список блоков пополам — последний блок урока читался
   только прокруткой под кнопку. Держим под ней запас: содержимое кончается над
   полосой, а не под ней.

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

   Обложка: полоса 72 вместо 200. Две кнопки поверх неё занимали 160 пикселей
   до заголовка урока — на телефоне остаётся одна, вторая уходит в «⋯» блока
   обложки (пока — рядом, но узкой). */
@media(max-width:640px){
  /* Запас под закреплённой полосой. Считаем по ней самой: у неё внутри
     safe-area-inset, и вычесть его на глаз нельзя. */
  .workspace:has(~.bld-bar:not([hidden])),
  body:has(.bld-bar:not([hidden])) .workspace{padding-bottom:104px}
  /* Напоминание про почту — служебное, и в шапке без меню ему тоже не место:
     оно забирало целую строку поверх пути и переключателя. */
  body>.topbar .verify-bar{display:none}
  /* Один режим — одна кнопка. «Редактор» не называем: он и есть основной. */
  .hdr-seg{background:none;padding:0;margin:0}
  .hdr-seg>button.on{display:none}
  .hdr-seg>button{min-height:36px;padding:0 var(--s-3);
    border:1px solid var(--line-2);border-radius:var(--r-1);background:var(--surface)}
  /* Обложка полосой: 200 пикселей картинки до заголовка урока на телефоне
     дороже, чем сама картинка. */
  .cover-img,.cover .field-cover{height:72px}
  .cover-acts{right:var(--s-2);top:var(--s-2);gap:6px}
  .cover-acts .btn{min-height:36px;padding:0 10px;font-size:var(--t-sm)}
}

/* ---------- Ученики: приглашение под списком (решение 4b) ----------
   В шапке страницы оно читалось кнопкой панели, хотя это единственное действие
   экрана. Под списком это главное действие с объяснением, что произойдёт. */
.stu-invite{display:none}
@media(max-width:640px){
  .stu-invite{display:block;margin-top:var(--s-5)}
  .stu-invite>.btn{width:100%;min-height:52px}
  .stu-invite>.small{margin-top:var(--s-2);line-height:1.5}
  /* Кнопка из шапки уходит: одно действие — одно место. */
  #studentsPage>.page-head>.btn.primary,.page-head>.btn.primary.stu-head-invite{display:none}
}

/* ---------- Подвал страницы уехал в шторку (решение 4a) ----------
   Жалоба, операционка и телеграм на телефоне лежали внизу страницы, до которой
   ученику надо пролистать весь кабинет. Теперь они в шторке под «⋯» — там же,
   где тема и выход. */
@media(max-width:640px){
  .app-foot{display:none}
  .top-more-body .app-foot{display:flex}
}

/* ---------- Телефон: цели и кнопки по экранам (решения 3b, 3c, 4c) ----------

   Мелочи, которые в замерах лежали по одной, а правятся одним правилом: строка
   автопроверенной работы (35), полки расписания «Свободно» и «Прошедшие 30
   дней» (42), строка «показать» в карточках учеников (40). Все они — цели, у
   которых своей высоты не хватало на два пикселя или на девять.

   Кнопки разделов, где действие одно на страницу, поднимаем до 52: «Новый
   курс», «Открыть урок» в пустых заготовках, «Пригласить ученика». На широком
   экране они остаются прежними — там кнопка 34 стоит в ряду с другими, а на
   телефоне она главное действие экрана и единственное. */
/* ---------- Расписание на телефоне (решение 3b) ----------

   Свободные дни стояли полками во всю ширину — дата строкой, под ней «Свободно ·
   назначить занятие» второй строкой, — и три пустых дня подряд занимали столько
   же места, сколько три занятия. Дню, в котором ничего нет, столько не надо:
   одна строка 44, дата и приглашение назначить рядом.

   Переключатель «Календарь / Список» на узком экране уезжает первой строкой
   содержимого во всю ширину: рядом с одной целью шапки он не встаёт, а слова у
   него те же и прятать их некуда. */
@media(max-width:640px){
  /* Не встают дата и «Свободно» в одну строку — «Свободно» уходит строкой ниже.
     Раньше строка не переносилась: дата не сжималась, «Свободно» ужималось до
     нуля и вылезало из своей коробки — у ученика на 320 «вторник 15 сентября ·
     Сегодня» вместе со «Свободно» раздвигали окно до 336 (найдено 15 сентября
     при проверке правок код-ревью). Сжимать саму дату нельзя: с переносом внутри
     она складывалась в столбик нулевой ширины. */
  .sch-shelf:has(>.sch-free){display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--s-3);
    min-height:44px;padding:0}
  .sch-shelf:has(>.sch-free) .sch-date{flex:0 0 auto;display:flex;align-items:baseline;
    gap:6px;padding:0}
  .sch-shelf>.sch-free{flex:1 0 auto;width:auto;justify-content:flex-start;
    min-height:44px;padding:0;background:none;border:none;text-align:left}
}
/* Правило «переключатель вида уезжает вниз на 320» из спеки сюда не переносим:
   там оно про шапку страницы, где рядом с ним стоит одна цель «⋯», а у нас
   «Календарь / Список» живёт в теле. В теле он помещается и на 320 — вместе с
   «Сегодня» это 248 пикселей из 288, — а во всю ширину он забирал третий этаж
   и делал шапку выше, чем была. */

@media(max-width:640px){
  .rl-auto{min-height:48px}
  .sch-shelf .sch-free,.sch-shelf .sch-past,.panel-group .more-line{min-height:44px}
  /* Главное действие страницы — 52, и во всю ширину: на телефоне оно одно.
     Своей строкой: в расписании рядом с ним стоят переключатель вида и
     «Сегодня», и втроём они роняли шапку в три этажа — 112 пикселей до первого
     занятия. Переключателю с «Сегодня» хватает одной строки, действию — своей. */
  .page-head>.btn.primary,.page-head>.btn.ai,
  .empty>.btn,.empty .btn.primary{min-height:52px}
  .page-head>.btn.primary{flex:1 0 100%}
}

/* ---------- Кабинет ученика: работы строками (решение 4a) ----------

   Первый экран кабинета отвечает на два вопроса: когда занятие и что сдавать.
   На второй отвечала карточка с кнопкой «Открыть» — три строки и кнопка на
   каждую работу, и две работы уже съедали экран.

   Строка: жетон с числом заданий (сразу видно, работа на девять или на три),
   название, подпись со сроком и сделанным, стрелка. Нажимается вся строка —
   кнопка внутри неё была бы вторым способом сделать то же.

   На широком экране карточка остаётся карточкой: там место есть, и кнопка с
   именем действия («Открыть» или «Продолжить») говорит больше стрелки. */
.tc-num,.tc-chev{display:none}
@media(max-width:640px){
  /* Строки «Мои уроки» и «Прогресс» — 56, как все строки-разделы телефона. */
  .cab-more>button{min-height:56px}
  /* Жалоба уехала в шторку под «⋯» вместе с остальным служебным (решение 4a),
     и строкой в конце обзора она теперь второй раз о том же. */
  .cab-report{display:none}
}

/* ---------- Стопка заметок на телефоне (решение 6d) ----------

   Поля сбоку от урока на телефоне нет — оно от 1300px, — и три заметки к одному
   блоку ложились полосой в 120 пикселей над заданием. Видна первая, за ней
   кнопка со счётчиком. Стопка намекает на остальные слоями: у первой наклейки
   появляются две тени-ступени, как у бумаги под бумагой.

   На широком экране стопки нет: там заметки стоят на поле столбиком и места у
   урока не отнимают. */
.note-stack>.ns-more{display:none}
@media(max-width:640px){
  .note-stack:not(.open)>.margin-slot:not(:first-child){display:none}
  /* Слои: две ступени охры под первой наклейкой. Сдвиг маленький — это намёк
     на бумагу под бумагой, а не веер. */
  .note-stack:not(.open)>.margin-slot:first-child .sticky{
    box-shadow:2px 3px 0 rgba(138,106,0,.08),
               6px 7px 0 -1px var(--note-stack-2),
               11px 13px 0 -2px var(--note-stack-3)}
  .note-stack>.ns-more{display:flex;align-items:center;gap:6px;
    min-height:44px;padding:0 var(--s-1);margin:0 0 var(--s-2);
    border:none;background:none;cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
    color:var(--marker-ink)}
  .note-stack .ns-t-less{display:none}
  .note-stack.open .ns-t{display:none}
  .note-stack.open .ns-t-less{display:inline}
  .note-stack .ns-chev{width:6px;height:6px;
    border-right:2px solid var(--marker-ink);border-bottom:2px solid var(--marker-ink);
    transform:rotate(45deg);transition:transform var(--dur-fast) var(--ease)}
  .note-stack.open .ns-chev{transform:rotate(-135deg)}
  /* Стопка отбита от блока, к которому относится: без отступа она читалась
     продолжением задания. */
  .note-stack{margin:var(--s-2) 0 var(--s-3)}
}

/* ---------- Занятие: три раздела аккордеоном (решение 3a) ----------

   Урок, домашка и сданная работа шли одной лентой в 3.6 экрана, хотя во время
   занятия нужен один из трёх. Теперь это разделы: заголовок-строка 56 и тело,
   раскрыт один. Свёрнутый несёт состояние, поэтому заглядывать в него, чтобы
   узнать, что там, не надо.

   На широком экране разделы стоят подряд, как стояли: место есть, и прятать
   домашку не от чего. Заголовки там не печатаются вовсе — их работу делают
   собственные подписи разделов на листе. */
.cls-sec>.cs-head{display:none}
@media(max-width:640px){
  .cls-sec{border-bottom:1px solid var(--line)}
  .cls-sec:last-child{border-bottom:none}
  .cls-sec>.cs-head{display:flex;align-items:center;gap:var(--s-3);width:100%;
    min-height:56px;border:none;background:none;cursor:pointer;text-align:left;
    padding:0;color:inherit}
  .cs-head .cs-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Подпись отбирает остаток строки и обрезается: состояние бывает длиннее
     места, а название раздела — никогда. */
  .cs-head .cs-s{flex:1;min-width:0;text-align:right;font-size:var(--t-sm);
    color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .cs-head .cs-chev{flex:0 0 auto;width:7px;height:7px;
    border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
    transform:rotate(-45deg);transition:transform var(--dur-fast) var(--ease)}
  .cls-sec.open>.cs-head .cs-chev{transform:rotate(45deg)}
  .cls-sec:not(.open)>.cs-body{display:none}
  /* С 18 сентября раздел на экране один и заголовка-строки у него нет: урок и
     домашку переключает «Урок · Домашка» (.cls-tabs), раздела «Сданная работа»
     больше нет вовсе. Правила строки выше остались для шаговой раскладки. */

  /* Кнопка заметки — чипом у правого края, а не строкой во всю ширину. Строк
     между блоками было одиннадцать, и вместе они держали 396 пикселей ленты,
     хотя каждая только предлагает добавить заметку. */
  .note-insert{display:flex;justify-content:flex-end;margin:0}
  .note-insert button{min-height:32px;padding:0 10px;border-radius:var(--r-pill)}
  .note-insert .ni-word{display:inline}

  /* Запас под нижней полосой: она закреплена у края экрана, и без запаса
     последний блок урока ложился под неё — дочитать его было нечем. */
  .class-grid:has(~.class-bar:not([hidden])){padding-bottom:96px}
  body:has(.class-bar:not([hidden])) .class-canvas{padding-bottom:96px}
}

/* ---------- Каталог на телефоне: что над списком (решение 12e) ----------

   Над списком стояло 460 пикселей: поле поиска, две кнопки сборки, колонка
   папок с подсказкой про перетаскивание и полка «2 урока не дособраны». В
   первый экран после этого попадало три урока из двадцати одного.

   Папки становятся чипами в прокручиваемой строке: прокручивается строка, а не
   страница. Подсказка про перетаскивание уходит — тащить на телефоне нечем, а
   место она занимала целым абзацем. Полка черновиков уходит туда же: её работу
   делает чип «Черновики». Поиск уезжает целью в шапку. Сборка закрепляется над
   нижней полосой — она не должна уезжать совсем, но и первый экран занимать ей
   незачем. */
@media(max-width:640px){
  /* Чипы: одна строка, горизонтальная прокрутка внутри себя. */
  .fold-head,.fold-note{display:none}
  #folderCol{margin:0 calc(var(--s-4) * -1);padding:0 var(--s-4)}
  .fold-list{display:flex;flex-direction:row;gap:var(--s-2);overflow-x:auto;
    overflow-y:hidden;padding-bottom:2px;scrollbar-width:none}
  .fold-list::-webkit-scrollbar{width:0;height:0}
  .fold-row{flex:0 0 auto;width:auto;min-height:36px;border-radius:var(--r-pill);
    padding:0 var(--s-3);background:var(--surface-2);color:var(--ink-2);
    display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
  .fold-row.on{background:var(--ink);color:var(--paper)}
  .fold-row .fr-x{display:none}
  .fold-row::after{content:'';position:absolute;left:0;right:0;top:50%;
    height:44px;transform:translateY(-50%)}
  .fold-row{position:relative}
  /* Полка черновиков: её работу делает чип, и второй раз о том же незачем. */
  .draft-shelf{display:none}
  /* Поиск каталога: поле по умолчанию скрыто, показывается по цели в шапке.
     Правило через #catSearch: класс .search-inp носит и поиск в словаре
     ученика, и без id тот пропадал насовсем — цели поиска у кабинета нет
     (код-ревью 15 сентября). */
  .page:not(.search-on) #catSearch{display:none}
  .page.search-on #catSearch{display:block;width:100%;min-height:44px;font-size:16px;
    margin-bottom:var(--s-2)}
  /* Сборка урока — закреплённой полосой над нижней навигацией: «Собрать урок с
     ИИ» не уезжает совсем, а первый экран отдаёт списку. */
  .cat-make{position:fixed;left:0;right:0;bottom:56px;z-index:40;
    display:flex;gap:var(--s-2);padding:var(--s-2) var(--s-4);
    background:var(--paper);border-top:1px solid var(--line)}
  .cat-make>.btn{min-height:52px}
  .cat-make>.btn.ai{flex:1 1 auto}
  .cat-make>.btn:not(.ai){flex:0 1 auto}
  /* Запас под обе полосы, чтобы последний урок не ложился под кнопку. */
  .app .page:has(.cat-layout){padding-bottom:136px}
}
/* Цель поиска нужна только телефону: на широком экране поле стоит в шапке
   страницы и всегда на виду. */
@media(min-width:641px){.cat-find{display:none}}

/* ---------- Каталог на телефоне: строка вместо карточки (решение 12e) ----------

   Двадцать один урок карточками по 300 пикселей — это 6790px и 10.6 экрана
   прокрутки, а первое действие лежало на 791-м. Карточка нужна там, где её
   рассматривают: обложка, уровень, две кнопки. На телефоне у неё другая работа
   — найти нужный урок в списке, — и для неё хватает строки: название и
   состояние.

   Обложка уходит вместе с плашкой «ЧЕРНОВИК» и галочкой выбора; и то, и другое
   переехало — состояние в подпись, выбор в меню строки. Значка-буквы нет
   вовсе: на 56 пикселях он держал бы 34 ширины и не сообщал ничего.

   «Предпросмотр» и «Изменить» уехали в «⋯». Цена названа в спеке: два частых
   действия спрятаны за одно нажатие. Взамен в первый экран попадает шесть
   уроков вместо двух. */
@media(max-width:640px){
  .cat-grid{display:flex;flex-direction:column;gap:0}
  .cat-card{display:block;position:relative;min-height:56px;
    padding:var(--s-2) 44px var(--s-2) 0;
    background:none;box-shadow:none;border-radius:0;border:none;
    border-bottom:1px solid var(--line)}
  .cat-card:hover{background:none;box-shadow:none;transform:none}
  .cat-card>.cc-cover{display:none}
  .cat-card .cc-body{display:block;padding:0}
  .cat-card .cc-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .cat-card .cc-sub{font-size:var(--t-sm);color:var(--muted);margin-top:1px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* «⋯» прижата к правому краю строки и стоит по центру её высоты: в потоке
     она уводила подпись на третью строку. Место под неё держит padding-right
     самой строки. */
  .cat-card .cc-acts{position:absolute;right:0;top:50%;transform:translateY(-50%);
    margin:0;padding:0;border:none;gap:0}
  .cat-card .cc-acts>*:not(.cc-more){display:none}
  /* Выбранный урок — заливкой строки, а не галочкой на обложке: обложки нет. */
  .cat-card.picked{background:var(--surface-2);border-radius:var(--r-1);
    padding-left:var(--s-3);padding-right:52px}
  /* Заголовок группы липкий: в списке из двадцати одного урока «РАНЬШЕ» уезжает
     за край, и, пролистав, перестаёшь понимать, что за строки идут. */
  .cat-group-head{position:sticky;top:48px;z-index:3;min-height:32px;
    background:var(--paper);margin:0;padding:var(--s-2) 0}
  .cat-group-head.later{margin-top:var(--s-4)}
}

/* ---------- Оплаты на телефоне (решение 1h; вторая сверка 14 сентября) ----------

   Первый экран — своей разметкой (.pay-phone в payments.js): месяц одной
   обведённой строкой, доход крупно, под ним «Оплата ученика» и «Со стороны»,
   две плитки. Первая сверка переставляла широкие блоки стилями и оставила над
   доходом два белых квадрата со стрелками и широкую «Добавить доход», действия
   — над доходом, а у плиток — надзаголовок в две строки и «−38 400 ₽ к
   августу» второй подписью «в среднем», где она читалась про цену занятия.

   Шапка страницы, три показателя и пустое состояние на телефоне молчат: всё,
   что в них есть, говорит первый экран, а кнопки пустого состояния стоят под
   доходом. Разница цены занятия с прошлым месяцем на телефон не едет — в
   макете её нет, и на плитке в 78 пикселей третьей строкой она не живёт.

   Высоты строк заданы явно: у тела 1.55, и с ним лист дохода вырастал на
   десяток пикселей против макета, где кегли стоят плотно. */
.pay-phone{display:none}
@media(max-width:640px){
  #paymentsPage>.page-head,#paymentsPage>.stats,#paymentsPage>.empty{display:none}
  .pay-phone{display:block}
  /* Месяц: стрелки 44 по краям строки, название посередине */
  .pp-month{height:44px;display:flex;align-items:center;justify-content:space-between;
    padding:0 var(--s-1);border:1px solid var(--line);border-radius:var(--r-1)}
  .pp-arrow{flex:0 0 44px;width:44px;height:42px;display:flex;align-items:center;justify-content:center;
    border:none;background:none;border-radius:var(--r-1);font-family:inherit;font-size:var(--t-lg);
    color:var(--ink-2);cursor:pointer}
  .pp-arrow:active{background:var(--surface-2)}
  .pp-arrow:disabled{color:var(--sm-faint);background:none;cursor:default}
  .pp-label{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);line-height:1.3;
    text-transform:capitalize;font-variant-numeric:tabular-nums}
  /* Доход — белым листом, число на дисплейной ступени: его читают с расстояния
     вытянутой руки, а не рассматривают. */
  .pp-income{margin-top:var(--s-3);padding:var(--s-3) var(--s-4) var(--s-4);background:var(--surface);
    border-radius:14px;box-shadow:var(--sh-1)}
  .pp-income .eyebrow{line-height:1.35}
  .pp-big{margin-top:var(--s-2);font-family:var(--font-head);font-weight:700;font-size:var(--t-d2);
    letter-spacing:-.03em;line-height:1.25;font-variant-numeric:tabular-nums}
  .pp-sub{margin-top:var(--s-1);font-size:var(--t-base);line-height:1.4;color:var(--muted);
    font-variant-numeric:tabular-nums}
  /* Действия: главное тянется, «Со стороны» — по слову, обведённой */
  .pp-acts{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--s-2);margin-top:var(--s-3)}
  .pp-acts>.btn{min-height:52px;font-size:var(--t-lg)}
  /* Вес 0,4,0 — как у общего правила вторичных кнопок телефона
     (.btn:not(.primary):not(.ai):not(.ghost)): иначе к рамке добавлялся его
     внутренний кант с тенью, и кнопка читалась обведённой дважды. */
  .pay-phone .pp-acts>.btn:not(.primary){padding:0 var(--s-4);background:none;border-color:var(--line-2);box-shadow:none}
  /* Плитки: число, что это, из чего собрано. Снизу отступа нет — как в
     макете, три строки и занимают высоту плитки. */
  .pp-tiles{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-2);margin-top:var(--s-3)}
  .pp-tile{min-width:0;min-height:78px;padding:var(--s-3) var(--s-3) 0;background:var(--surface);
    border-radius:12px;box-shadow:var(--sh-1)}
  .pp-n{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);line-height:1.27;
    font-variant-numeric:tabular-nums;white-space:nowrap}
  .pp-l,.pp-s{font-size:var(--t-sm);line-height:1.36;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pp-l{color:var(--ink-2)}
  .pp-s{color:var(--muted)}
  /* Полгода — плотной карточкой без подписей под столбиками, как в макете:
     суммы остаются экранному чтецу. Месяц без дохода — чертой. */
  .pay-chart{margin:var(--s-3) 0 0;padding:var(--s-3) var(--s-4) var(--s-4);border-radius:12px}
  .pay-chart-head{line-height:1.35}
  .pay-bars{gap:var(--s-2);margin-top:var(--s-3)}
  .pay-bars .pb-f{height:46px}
  .pay-bars .pb-f i{min-height:2px;border-radius:6px}
  .pay-bars .pb.zero .pb-f i{background:var(--line);border-radius:var(--r-pill)}
  .pay-bars .pb.zero.now .pb-f i{background:var(--marker)}
  .pb-x{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
}

/* ---------- Пустое состояние на телефоне: без картинки ----------
   Значок над заголовком занимал 90 пикселей и ничего не объяснял. На телефоне
   это целая седьмая часть экрана, отданная украшению; текст и действие
   объясняют пустоту сами. */
@media(max-width:640px){.empty::before{display:none}}

/* Кнопка «⋯» карточки занятия — только на телефоне: на широком экране все
   действия стоят рядом и прятать их не от чего. */
.nc-more{display:none}

/* ---------- Показание строкой (решение 2a) ----------

   Плитки с числом в углу читались системным экраном, а список работ на 390 —
   лентой из чужих имён, хотя вопрос к нему один: много ли на проверке. Поэтому
   на телефоне блок отвечает строкой: жетон с числом, название, подпись и
   стрелка. Тап ведёт в раздел — там список и есть.

   Вне телефона показания не нужны: на широком экране список виден целиком, и
   строка-итог над ним говорила бы то же самое дважды. */
.readout{display:none}
@media(max-width:640px){
  .readout{display:flex;align-items:center;gap:var(--s-3);min-height:60px;
    padding:var(--s-2) 0;text-decoration:none;color:inherit}
  /* Жетон — таблетка с числом. Жёлтый только там, где число значит ожидание
     («на проверке» просит преподавателя): это счётчик, третье значение
     маркера. У «без отметки» жетон тихий — там число про количество. */
  .ro-num{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
    min-width:38px;height:38px;padding:0 10px;border-radius:var(--r-pill);
    background:var(--surface-2);color:var(--ink);
    font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);
    font-variant-numeric:tabular-nums}
  .ro-num.mark{background:var(--marker-soft);color:var(--marker-ink)}
  .ro-body{flex:1;min-width:0}
  .ro-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  /* Вторая строка — то, что можно не дочитать: на узком обрезается, на широком
     договаривает. Первая строка не обрезается никогда. */
  .ro-s{font-size:var(--t-sm);color:var(--muted);margin-top:1px;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .ro-chev{flex:0 0 auto;width:7px;height:7px;margin-right:2px;
    border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
    transform:rotate(-45deg)}
}

/* ---------- Главная на телефоне: порядок ленты (решение 1f) ----------

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

   Переставляем на месте: колонки становятся display:contents, их секции —
   прямыми детьми ленты, и порядок им задаёт order. Переписывать раскладку в JS
   не нужно, а значит широкий экран не рискует вовсе. */
@media(max-width:640px){
  .app .page:has(.desk){display:flex;flex-direction:column}
  .desk,.desk-main,.desk-side{display:contents}
  /* Без прямого потомка. display:contents убирает БОКС колонки, но не её место
     в дереве: секции остаются детьми .desk-main и .desk-side, и селектор
     `.page>.d-now` не совпадал ни с чем — порядок оставался исходным, то есть
     «Требуют внимания» с сорока двумя строками вставали сразу за занятием, а
     показания уезжали под них. Видно это стало только на настоящих данных: в
     тестовом аккаунте этот блок пуст. */
  .page .d-now{order:1}
  /* Списков проверки и забытых отметок телефон не показывает: на их месте
     показания одним листом (.d-readouts, решение 2a) */
  .page .d-readouts{order:2}
  .page .d-review,.page .d-unmarked{display:none}
  .page>.page-head{order:4}
  .page>.steps{order:5}
  .page .week-ahead{order:6}
  .page .d-expiring{order:7}
  .page .d-attention{order:8}
  .page>.src-strip{order:9}
  /* Блок недели живёт внутри секции занятия, а порядок раскладывает секции —
     значит и ему нужно стать её братом. display:contents у секции с занятием
     разбирает её на части: карточка и неделя расходятся по своим местам. */
  .page .d-now{display:contents}
  .page .d-now>.now-card,.page .d-now>.now-plate,.page .d-now>.day-list{order:1}

  /* На карточке занятия одно действие — войти в класс. «Провести», выбор
     материала и ссылка на звонок уходят под «⋯»: три зовущие кнопки подряд
     занимали 120 пикселей первого экрана и спорили между собой, хотя за
     десять минут до занятия нужна одна. */
  /* Только в карточке главной преподавателя (.d-now): у неё есть «⋯», туда эти
     кнопки и уходят. Без .d-now правило прятало «Звонок» и у ученика — в
     кабинете и в расписании, где «⋯» нет, и зайти в звонок с телефона было
     неоткуда (код-ревью 15 сентября). */
  .d-now .nc-actions{flex-wrap:nowrap;align-items:center;gap:var(--s-2)}
  .d-now .nc-actions>.btn:not(.primary){display:none}
  /* Главное действие забирает остаток строки, «⋯» стоит рядом и не переносится:
     ряд с wrap отдавал primary всю ширину, и кнопка «ещё» уезжала на свою
     строку — карточка вырастала на 60 пикселей ради одного значка. */
  /* Селектор в три класса: правило выше (.now-card .nc-actions .btn.primary)
     отдаёт главной кнопке всю ширину — flex:1 0 100%, — и «⋯» после него
     уезжало на свою строку. Перебиваем той же силой и ниже по файлу. */
  .now-card .nc-actions .btn.primary{flex:1 1 auto;min-height:52px;min-width:0}
  .nc-more{display:inline-flex;flex:0 0 auto;width:44px;height:44px}
  /* Сборка урока — два действия в строку, и оба во всю ширину пары: главное
     забирает остаток, второстепенное сжимается по тексту. */
  /* Только главная: правило писалось под её пару «Собрать урок с ИИ / Собрать
     самому», а без привязки к странице оно ловило и «Поставить занятие» в
     расписании — тому нужна своя строка во всю ширину, и вместо неё он вставал
     третьим этажом шапки. Признак главной — стол с колонками. */
  .page:has(.desk)>.page-head{gap:var(--s-2)}
  .page:has(.desk)>.page-head>.btn.ai{flex:1 1 auto;min-height:52px}
  .page:has(.desk)>.page-head>.btn:not(.ai){flex:0 1 auto;min-height:52px}
}

/* ---------- Первые шаги: строка после первого занятия (решение 7g) ----------

   Карточка на 380 пикселей оправдана, пока занятий нет: первый экран всё равно
   пустой, и незакрытый шаг там объяснён с кнопкой под ним. Как только занятие
   поставлено, первый экран принадлежит занятию — и шаги отвечают строкой: имя,
   «3 из 4», стрелка. Раскрывается по тапу, шаги внутри те же.

   Цена решения названа в спеке: незакрытый шаг больше не кричит. Взамен человек
   видит своё занятие сразу, а не после двух экранов прокрутки. */
.steps-row{display:none}
@media(max-width:640px){
  .steps.folded{padding:0;background:none;box-shadow:none;border:none}
  .steps.folded>*:not(.steps-row){display:none}
  .steps.folded.open{background:var(--surface);border-radius:var(--r-2);
    box-shadow:var(--sh-1);padding:var(--s-4)}
  .steps.folded.open>*{display:revert}
  .steps.folded.open>.steps-row{display:flex}
  .steps.folded .steps-row{display:flex;align-items:center;gap:var(--s-3);
    width:100%;min-height:56px;border:none;background:none;cursor:pointer;
    text-align:left;padding:0;color:inherit}
  .steps-row .sr-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .steps-row .sr-n{margin-left:auto;font-size:var(--t-sm);color:var(--muted);
    font-variant-numeric:tabular-nums}
  .steps-row .sr-chev{flex:0 0 auto;width:7px;height:7px;
    border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
    transform:rotate(-45deg);transition:transform var(--dur-fast) var(--ease)}
  .steps.folded.open .steps-row .sr-chev{transform:rotate(45deg)}
}

/* ---------- Настройки на телефоне: аккордеон (решение 1i; вторая сверка 14 сентября) ----------

   Шесть строк по 60 вместо 3.9 экрана сплошного списка. Колонка разделов уходит
   совсем: строки и есть разделы, и вести к якорям больше некуда. Подпись несёт
   текущее значение — настройку видно, не раскрывая раздел.

   Строки — одним белым листом, подпись под названием, справа «›», как в 1i.
   Первая сверка оставила строки на бумаге, а подпись — справа в той же строке,
   где длинное значение резалось на полуслове; лист появлялся только у
   раскрытой карточки, и она выпрыгивала из списка отдельной плашкой. В макете
   раскрытая строка остаётся в листе, темнеет шапкой и вместо значения говорит,
   о чём раздел. Тариф без строки-заголовка сворачивался в черту в пиксель —
   строку ему дописывает buildSetAccordion.

   Лист не режем по краю (overflow): в нём живут выпадающий выбор языка и
   полоса сохранения. Скругление шапке первой строки задано отдельно. */
@media(max-width:640px){
  .set-nav{display:none}
  .set-grid{display:block}
  /* Подпись аккаунта — одной строкой над листом, без нынешнего года */
  .page-head:has(>.set-since){margin-bottom:0}
  .set-since{padding-bottom:0;line-height:1.5}
  .set-since .since-y{display:none}
  .set-body{display:block;margin-top:var(--s-3);background:var(--surface);border-radius:14px;box-shadow:var(--sh-1)}
  .set-card{padding:0;background:none;border-radius:0;box-shadow:none;border-bottom:1px solid var(--line)}
  .set-body>.set-act{border-bottom:none}
  .set-body>.set-act>.head{min-height:60px}
  /* Строка — 60 вместе с чертой: название, под ним подпись, стрелка справа */
  .set-card>.head{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--s-3);
    align-content:center;align-items:center;min-height:59px;margin:0;padding:var(--s-2) var(--s-4);cursor:pointer}
  .set-body>.set-card:first-child>.head{border-radius:14px 14px 0 0}
  .set-card>.head .sc-t{grid-column:1;min-width:0;display:flex;align-items:center;gap:var(--s-2);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);line-height:1.3}
  .set-card>.head .sc-sum,.set-card>.head .sc-desc{grid-column:1;min-width:0;font-family:var(--font-body);
    font-weight:400;font-size:var(--t-sm);line-height:1.5;color:var(--muted)}
  .set-card>.head .sc-sum{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .set-card>.head .sc-desc{display:none}
  .set-card>.head .sc-chev{grid-column:2;grid-row:1 / span 2;font-style:normal;font-size:var(--t-lg);
    line-height:1;color:var(--muted);transition:transform var(--dur-fast) var(--ease)}
  .set-card>.head .sc-chev::before{content:'›'}
  /* Раскрытая: шапка темнеет и остаётся в листе, у тела поля 16 */
  .set-card:not(.open)>*:not(.head),.set-card>.set-sub{display:none}
  .set-card.open{padding:0 var(--s-4) var(--s-4)}
  .set-card.open>.head{margin:0 calc(var(--s-4) * -1) var(--s-4);padding:var(--s-3) var(--s-4);
    background:var(--surface-2);border-bottom:1px solid var(--line)}
  .set-card.open>.head .sc-sum{display:none}
  .set-card.open>.head .sc-desc{display:block}
  .set-card.open>.head .sc-chev{color:var(--ink-2);transform:rotate(90deg)}
  .set-card.open>.head+.set-sub+*,.set-card.open>.head+:not(.set-sub){margin-top:0}
  /* Поля — 46 и кегль 16 на белом: iOS увеличивает страницу на любом поле
     мельче шестнадцати и обратно её не уменьшает. */
  .set-card input,.set-card select,.set-card textarea{min-height:46px;font-size:var(--t-lg)}
  .set-body .field input{background:var(--surface)}
  .set-body .field label{margin-bottom:var(--s-1);font-weight:400}
  /* «НЕ ПОДТВЕРЖДЕНА» — на строке подписи «Почта», у правого края: внутри поля
     на 390 плашка ложилась поверх адреса, а место под неё съедало пол-поля. */
  .set-body .in-wrap .in-tag{top:-14px;right:0}
  .set-body .in-wrap.tagged>input{padding-right:var(--s-3)}
  /* Профиль: лицо рядом с именем, почта и телефон во всю ширину */
  .prof-row{display:grid;grid-template-columns:56px minmax(0,1fr);gap:var(--s-3);align-items:center}
  .prof-fields{display:contents}
  .prof-fields>.field:not(:first-child){grid-column:1 / -1}
  .prof-photo .stu-ava{width:56px;height:56px;font-size:var(--t-lg);font-weight:600;color:var(--muted)}
  .prof-photo .quiet-act{margin-top:var(--s-1)}
  /* «Отправить письмо» — обведённой кнопкой перед пояснением, а не словом после */
  .set-body .field-note{margin-top:var(--s-3);color:var(--muted)}
  .set-body .field-note:has(.quiet-act.mark){flex-wrap:nowrap;align-items:center}
  .set-body .field-note .quiet-act.mark{order:-1;flex:0 0 auto;min-height:44px;padding:0 var(--s-3);
    border:1px solid var(--line-2);border-radius:var(--r-1);color:var(--ink);font-size:var(--t-md)}
  /* Пароли — друг под другом: вдвоём в строку на 326 пикселях поле оставляло
     под пароль меньше места, чем занимало слово «показать». */
  #sec-security .two-fields{flex-direction:column;gap:var(--s-3)}
  /* Строка-действие: жмётся вся, стрелка не крутится — раскрывать нечего. */
  .set-act{cursor:pointer}
  /* Полоса сохранения — над нижней навигацией. Липкой внутри листа она легла бы
     его строкой, а у низа экрана пряталась под навигацию. Пока она на экране,
     листу прибавлен запас снизу, чтобы последняя строка выходила из-под неё. */
  .save-bar{position:fixed;left:var(--s-4);right:var(--s-4);bottom:calc(64px + env(safe-area-inset-bottom));margin:0}
  .set-body:has(>.save-bar:not([hidden])){margin-bottom:calc(var(--s-6) * 2)}
}
/* Факт подписи аккаунта не рвётся посередине: строка переносится по «·». */
.set-since .sf{white-space:nowrap}
/* Спрятанная полоса сохранения прозрачна, но стоит на месте — чтобы уходить
   плавно, — и забирала нажатия под собой: на телефоне у нижней строки списка,
   на широком экране у нижнего края окна. Нажатия она принимает, только когда
   видна. */
.save-bar:not(.on){pointer-events:none}
/* Вне телефона строка-действие не нужна — жалоба стоит в колонке разделов, — а
   подписи, стрелки и дописанная строка тарифа принадлежат аккордеону. До 14
   сентября подпись стояла на широком экране вплотную к названию карточки:
   «ПрофильМобильная проба · имя видят ученики». */
@media(min-width:641px){.set-act,.sc-sum,.sc-desc,.sc-chev,.sc-made{display:none}}

/* ---------- Титул страницы на телефоне: один раз ----------

   Он стоит в шапке (правило 1a), и второй раз в теле не нужен: «ДЕНЬГИ /
   Оплаты» над содержимым повторяли слово из панели и забирали до 90 пикселей
   первого экрана — ровно там, где должно начинаться то, ради чего страницу
   открыли.

   Прячем заголовок с надзаголовком и распорку, но не сам .page-head: в нём
   стоят и действия страницы — поиск, переключатель вида, «Собрать урок с ИИ».
   Где после этого не осталось ничего, ряд складывается сам (:has), вместе с
   отступом под ним. */
@media(max-width:640px){
  .page-head>div:has(>h1),.page-head>div:has(>.head),
  .page-head>h1,.page-head>.head,.page-head>.spacer{display:none}
  /* Складывается ряд только тогда, когда в нём не осталось НИЧЕГО, кроме
     титула и распорки. Условие пишем через «нет такого ребёнка, который не
     титул и не распорка»: короткое `:not(div)` унесло бы с собой и действия,
     свёрстанные вложенным блоком, — на «Оплатах» так пропадал переключатель
     месяца вместе со всей строкой. */
  .page-head:not(:has(>*:not(.spacer):not(h1):not(.head):not(:has(>h1)):not(:has(>.head)))){display:none}
  /* Поля страницы — 16 по сетке телефона, а не 32 как на компьютере. Сверху
     12: шапка уже отделена своей чертой, и второй отступ под ней отодвигал
     первый блок на 80-й пиксель вместо 48-го. */
  .app .page{padding:var(--s-3) var(--s-4) 96px}
}

/* ---------- Шапка телефона: одна строка, одна цель (правило 1a) ----------

   48 пикселей и никогда не переносится. Титул страницы стоит в шапке, поэтому
   в теле его нет и первый блок начинается сразу под ней.

   Всё служебное уходит в шторку под «⋯» (openTopMore в core.js): ряд действий
   и напоминание про почту скрыты, а не удалены — узлы из них и переносятся в
   шторку живыми. Узел с классом .top-keep остаётся на виду: так в занятии
   держится «Закрыть» — выход из идущего урока в шторку не прячут. */
.top-more{display:none}
@media(max-width:640px){
  .app-main .topbar,body>.topbar{min-height:48px;height:auto}
  .app-main .topbar .top-actions>*:not(.top-keep){display:none}
  .app-main .topbar .verify-bar{display:none}
  /* «⋯» — 44 во все стороны, как в кадрах: цель пальца без невидимых
     расширений. Своего авто-отступа слева у неё нет: к правому краю шапку
     прижимает ряд действий (.top-actions, margin-left:auto), и два авто-отступа
     делили остаток пополам — лицо ученика вставало посередине шапки. */
  .top-more{display:inline-flex;align-items:center;justify-content:center;
    position:relative;flex:0 0 auto;width:44px;height:44px;
    border:none;background:none;cursor:pointer;border-radius:var(--r-1);
    font-size:var(--t-lg);line-height:1;color:var(--ink-2)}
  /* Точка «внутри есть о чём узнать» — маркерная: это счётчик в меню. */
  .top-more .top-dot{position:absolute;top:9px;right:9px;width:6px;height:6px;
    border-radius:var(--r-pill);background:var(--marker)}
  /* Внутри шторки перенесённые узлы встают столбиком и во всю ширину: в шапке
     они стояли рядом, а здесь каждый — строка меню. */
  .sheet-body.top-more-body{display:flex;flex-direction:column;align-items:stretch;
    gap:var(--s-2)}
  .top-more-body>*{width:100%;justify-content:flex-start;min-height:48px}
  .top-more-body .top-user{display:flex;align-items:center;color:var(--muted);
    font-size:var(--t-sm);min-height:0;padding:0 var(--s-1)}
  .top-more-body .verify-bar{flex-wrap:wrap;row-gap:var(--s-2)}
}

/* ---------- Цели нажатия на телефоне: правило 1e ----------

   В замерах ниже 44px почти всё служебное: кнопки шапки 36, переключатели
   24–30, ссылки в подвале 18, «в словарь» на стикере 38. Поднять их до 44 в
   лоб — значит добавить по 60–80px в шапку каждой страницы и раздуть
   переключатели до кнопок.

   Поэтому вид цели не меняем, а дотягиваем зону нажатия невидимым
   псевдоэлементом: кнопка остаётся 28–36 на глаз, палец попадает в 44. Растём
   только по вертикали — соседи в переключателе стоят вплотную, и боковая
   прибавка перехватывала бы нажатия друг у друга. Где цель узкая и стоит
   одна (стрелки месяца), прибавляем и ширину.

   Цена, про которую надо помнить: замеры по DOM продолжат показывать 36 и 28.
   Правило проверяется наличием этого псевдоэлемента, а не высотой узла — так
   его и считает tools/mobile-shots.js. */
@media(max-width:640px){
  /* «Показать» у пароля в этот список не входит: кнопка стоит поверх поля
     через position:absolute, и relative выбрасывал её из поля в строку рядом —
     до 13 сентября «показать» на телефоне висело над правым углом поля. Зоне
     ::after хватает и absolute: такой элемент сам служит ей опорой. */
  .topbar .btn.sm,.topbar .icon-btn,.chrome-toggle,.top-back,
  .verify-bar .vb-act,.seg button,.mhead .icon-btn,.md-phone .btn.sm,
  .mat-drop .more-link,.set-nav button,.sb-acts button,
  .note-insert button,.sticky .svoc,.ex-acts .check-btn,.ex-head .hw-add-btn,
  .steps-head .more-link,.steps-foot a,.r-side .more-link,.cat-group-head .cat-sort,
  .rw-ctx .rw-ctx-open,.more-line,.usel .usel-btn,.prof-photo .quiet-act,
  .field-note .quiet-act{position:relative}
  .topbar .btn.sm::after,.topbar .icon-btn::after,.chrome-toggle::after,
  .top-back::after,.verify-bar .vb-act::after,.seg button::after,
  .mhead .icon-btn::after,.md-phone .btn.sm::after,.mat-drop .more-link::after,
  .set-nav button::after,.sb-acts button::after,.pw-wrap .pw-word::after,
  .note-insert button::after,.sticky .svoc::after,.ex-acts .check-btn::after,
  .ex-head .hw-add-btn::after,.steps-head .more-link::after,.steps-foot a::after,
  .r-side .more-link::after,.cat-group-head .cat-sort::after,
  .rw-ctx .rw-ctx-open::after,.more-line::after,.usel .usel-btn::after,
  .prof-photo .quiet-act::after,.field-note .quiet-act::after{
    content:'';position:absolute;left:0;right:0;top:50%;height:44px;
    transform:translateY(-50%)}
}

/* ---------- Строка на телефоне: в две полосы ----------
   Рядом имя, статус и кнопки на 375px не стоят. Сетка отдавала место правым
   колонкам — они «auto» и меряются по содержимому, — и от имени оставалось
   «Ал…», а строка вдобавок вылезала за край экрана: страницу приходилось
   отдалять. Флекс с переносом кладёт лицо и имя в первую полосу, статус и
   действия — во вторую, и обрезать больше нечего. */
@media(max-width:640px){
  .row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2) var(--s-3);padding:10px var(--s-3)}
  .row>.r-anchor,.row>.r-time{flex:0 0 auto}
  /* имя забирает остаток первой полосы, поэтому всё, что за ним, переносится */
  .row>.r-main{flex:1 1 60%;min-width:0}
  /* вторая полоса: статус и кнопки идут подряд и не растягиваются на всю ширину */
  .row>.r-side{flex:0 1 auto;justify-content:flex-start;flex-wrap:wrap;white-space:normal}
  .row>*{min-width:0}
  .sch-row .r-side{flex-wrap:wrap;white-space:normal}
}

@media(max-width:1079px){.sticky.aside{margin:0 0 var(--s-3)}}
@media(max-width:960px){
  .workspace,.class-grid,.cab{grid-template-columns:minmax(0,1fr)}
  .workspace.style-open{grid-template-columns:minmax(0,1fr)}
  .rail,.tpanel,.cab-nav{position:static;max-height:none}
  .rail{flex-direction:column}
  .rail-list{max-height:230px}
  .cab-nav{flex-direction:row;overflow:auto;gap:var(--s-1)}
  .cover-grid{grid-template-columns:1fr 1fr}
  /* Колонка грида по умолчанию не уже своего содержимого. Из-за этого окно
     занятия на телефоне уезжало вбок: рядом с «Длительностью» стоял переключатель
     статуса из трёх слов («Запланировано · Проведено · Не состоялось»), он не
     помещался в половину экрана и распирал окно шире экрана — оно листалось
     влево-вправо и целиком не показывалось. В окне ставим поля друг под друга,
     переключателю разрешаем переноситься. */
  .modal .cover-grid{grid-template-columns:1fr}
  .cover-grid>*{min-width:0}
  .modal .seg{flex-wrap:wrap}
  .style-panel{position:static;max-height:none}
  .top-title{display:none}   /* на телефоне в панели помещается только возврат */
  /* Своё имя на узком экране убираем: кнопка «Выйти» рядом и так говорит, чей
     это вход. */
  .top-user{display:none}
}

/* ---------- Курсы ---------- */
/* Список курсов строками. Плитка с обложкой о курсе не говорила ничего — они
   все одинаковые, — а важное (сколько уроков и кто записан) пряталось мелкой
   строкой под названием. */
.crs-cards{display:grid;gap:var(--s-2)}
.crs-card{display:flex;align-items:center;gap:var(--s-3);background:var(--surface);
  border:1px solid transparent;border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:var(--s-3) var(--s-4);cursor:pointer;
  transition:box-shadow var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
.crs-card:hover{box-shadow:var(--sh-2);transform:translateY(-1px)}
/* Знак курса — тот же мотив «Поле», что на обложке, но без буквы: в строке она
   читалась бы как второе название. */
.crs-mark{position:relative;flex:0 0 auto;width:46px;height:46px;
  display:flex;align-items:center;justify-content:center}
.crs-mark::before{content:'';position:absolute;left:50%;top:0;bottom:0;width:1.5px;background:var(--line-2)}
.crs-mark i{position:relative;width:26px;height:26px;border-radius:var(--r-1);background:var(--marker);
  transform:rotate(-4deg);box-shadow:0 6px 14px -6px rgba(138,106,0,.55)}
.crs-card-main{flex:1 1 auto;min-width:0}
.crs-card-head{display:flex;align-items:baseline;gap:var(--s-2);flex-wrap:wrap}
.crs-card-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.02em}
.crs-card-sub{margin-top:var(--s-1);font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}
.crs-card-acts{flex:0 0 auto;display:flex;align-items:center;gap:var(--s-2)}
/* Черновик лежит на бумаге пунктиром и не поднимается: он ещё не курс. */
.crs-card.draft{background:var(--surface-2);border:1px dashed var(--line-2);box-shadow:none}
.crs-card.draft:hover{box-shadow:none;transform:none}
.crs-card.draft .crs-card-title{color:var(--ink-2)}
.crs-card.draft .crs-mark::before{opacity:.5}
.crs-card.draft .crs-mark i{background:var(--line);transform:none;box-shadow:none}
/* Счётчик у заголовка и подпись под названием курса: цифры не должны ездить */
.crs-count{font-variant-numeric:tabular-nums}
.crs-people{margin-top:var(--s-5)}

/* Пустой раздел — обычная страница, а не рамка с определением: рамка на
   полэкрана читалась как «здесь не дорисовали». */
.crs-lede{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
  letter-spacing:-.025em;line-height:1.25;max-width:30ch}
.crs-lede-sub{font-size:var(--t-md);line-height:1.6;color:var(--ink-2);
  margin-top:var(--s-2);max-width:62ch}
.crs-offer{margin-top:var(--s-5)}
/* Кнопки под рельсой встают по левому краю тел строк, а не страницы */
.crs-offer-acts{display:flex;gap:var(--s-2);padding-left:calc(32px + var(--s-4))}
/* Предложенная рельса ничего не открывает: строки в ней не отзываются на
   наведение, а линия кончается у последней точки — «Добавить урок» тут нет. */
.crs-offer .crs-rail::before{bottom:38px}
.crs-offer .crs-step-body:hover{background:var(--surface);transform:none}

/* Рельса курса. Порядок — главное, что есть у курса, и линия с точками
   говорит о нём раньше текста. Линия не доходит до строки «Добавить урок»:
   она про то, что в курсе уже есть. */
.crs-rail{position:relative}
.crs-rail::before{content:'';position:absolute;left:15px;top:12px;bottom:42px;
  width:1.5px;background:var(--line-2)}
.crs-rail.empty-rail::before{display:none}
.crs-step{display:flex;align-items:flex-start;gap:var(--s-4);margin-bottom:var(--s-2);position:relative}
/* Ручка переноса урока в курсе. Появляется при наведении на строку: постоянно
   видимая, она стояла бы шестым значком в каждой строке курса. */
.crs-grip{flex:0 0 auto;cursor:grab;color:var(--line-strong);font-size:13px;line-height:1;
  user-select:none;opacity:0;margin-right:-4px;
  transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.crs-step:hover .crs-grip{opacity:1}
.crs-grip:hover{color:var(--muted)}
.crs-grip:active{cursor:grabbing}
.crs-step.dragging{opacity:.4}
/* Черта места — та же, что в рельсе конструктора и на листе. */
.crs-step.drop-before::before,.crs-step.drop-after::after{content:'';position:absolute;
  left:32px;right:0;height:2px;background:var(--accent);border-radius:2px;z-index:2}
.crs-step.drop-before::before{top:-3px}
.crs-step.drop-after::after{bottom:-3px}
@media(max-width:640px){.crs-grip{display:none}}
/* Кольцо цвета бумаги — им точка разрезает линию */
.crs-dot-col{flex:0 0 auto;width:32px;display:flex;justify-content:center;padding-top:15px}
.crs-dot{width:20px;height:20px;border-radius:var(--r-pill);box-shadow:0 0 0 4px var(--paper);
  display:inline-flex;align-items:center;justify-content:center;font-size:var(--t-label);line-height:1}
.crs-dot.done{background:var(--ok-bg);color:var(--ok)}
/* Жёлтая — «ждёт проверки»: это не состояние ученика, а работа преподавателю,
   и на курсе она единственная требует его руки. Заливкой, а не кольцом: кольцо
   уже занято «открыт, но не сдан». */
.crs-dot.sent{background:var(--marker)}
.crs-dot.open{border:1.5px solid var(--marker)}
.crs-dot.shut{border:1.5px solid var(--line-2);background:var(--paper)}
/* Три уровня тела строки: пройденный шаг поднят листом, шаг, на котором
   кто-то стоит, — поднят сильнее, закрытый у всех лежит на бумаге. */
.crs-step-body{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:var(--s-3);
  border-radius:var(--r-2);padding:var(--s-3) var(--s-4);
  transition:background var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease)}
.crs-step-body:hover{background:var(--surface-2)}
.crs-step-body.passed{background:var(--surface);box-shadow:var(--sh-1)}
.crs-step-body.passed:hover{background:var(--surface);transform:translateX(2px)}
.crs-step-body.here{background:var(--surface);box-shadow:var(--sh-2)}
.crs-step-body.here:hover{background:var(--surface)}
.crs-step-num{flex:0 0 auto;width:18px;font-size:var(--t-sm);color:var(--muted);
  font-variant-numeric:tabular-nums}
.crs-step-body.here .crs-step-num{color:var(--marker-ink);font-weight:600}
.crs-step-main{flex:1 1 auto;min-width:0}
.crs-step-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);letter-spacing:-.015em}
.crs-step-body:not(.passed):not(.here) .crs-step-title{color:var(--ink-2)}
.crs-step-sub{margin-top:3px;font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}
.crs-step .crs-rule{margin-top:0;flex:0 0 auto;flex-wrap:nowrap}
.crs-step .crs-acts{margin-left:auto}
/* «Добавить урок» стоит в конце рельсы с тем же отступом, что тела строк */
.crs-step-add .crs-dot-col{padding-top:0}
.crs-add{flex:1 1 auto;text-align:left;border:1px dashed var(--line-2);background:none;
  border-radius:var(--r-2);padding:var(--s-3) var(--s-4);font-family:var(--font-head);
  font-weight:600;font-size:var(--t-base);color:var(--muted);cursor:pointer;
  transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}
.crs-add:hover{background:var(--surface);color:var(--ink)}

.crs-list{display:flex;flex-direction:column}
.crs-row{display:flex;align-items:flex-start;gap:var(--s-3);padding:var(--s-3) 0;border-top:1px solid var(--line)}
.crs-row:first-child{border-top:none}
/* Номер моноширинным: в курсе он не украшение, а порядок прохождения, и
   колонка не должна ездить от ширины цифр. */
.crs-num{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);padding-top:2px;flex-shrink:0}
.crs-main{flex:1;min-width:0}
.crs-title{font-size:var(--t-md);font-weight:600;line-height:1.35}
.crs-rule{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;margin-top:5px;font-size:var(--t-sm);color:var(--muted)}
.crs-rule .usel{width:auto}
.crs-rule .usel-btn,.crs-rule-btn{width:auto;height:auto;min-height:0;gap:var(--s-2);
  padding:5px 11px;border:1px solid var(--line);border-radius:var(--r-1);background:none;
  font-family:inherit;font-size:var(--t-sm);font-weight:600;color:var(--ink-2);white-space:nowrap}
.crs-rule .usel-btn:hover,.crs-rule-btn:hover{background:var(--surface-2);border-color:var(--line)}
/* Список правил уже строки: он открывается от правого края плашки */
.crs-rule .usel-list{left:auto;right:0;min-width:180px}
/* На шаге, где кто-то стоит, правило — жёлтое: «пришло от преподавателя» */
.crs-step-body.here .crs-rule .usel-btn{background:var(--marker-soft);
  border-color:var(--marker);color:var(--marker-ink)}
.crs-step-body.here .crs-rule .usel-btn:hover{background:var(--marker-soft);border-color:var(--marker)}
.crs-step-body:not(.passed):not(.here) .crs-rule .usel-btn{color:var(--muted)}
.crs-step-body:not(.passed):not(.here) .crs-rule .usel-btn:hover{background:var(--surface);color:var(--ink-2)}
/* Плашка-подпись: в предложении на пустом разделе менять нечего — курса нет */
.crs-rule-btn{display:inline-flex;align-items:center;flex:0 0 auto}
.crs-rule-btn.plain{cursor:default}
.crs-rule-btn.plain:hover{background:none}
.crs-date{font-size:var(--t-sm);padding:var(--s-1) var(--s-2);border:1px solid var(--line);
  border-radius:var(--r-1);background:var(--surface-2);color:var(--ink)}
.crs-acts{display:flex;gap:2px;flex-shrink:0}

.crs-stu{display:flex;align-items:flex-start;gap:10px;padding:var(--s-3) 0;border-top:1px solid var(--line)}
.crs-stu:first-child{border-top:none}
/* Полоса прохождения. Жёлоб виден всегда — по пустой полосе сразу понятно,
   что человек курс ещё не начинал, а отсутствие полосы читалось бы как сбой. */
.crs-bar{height:4px;border-radius:var(--r-pill);background:var(--line);margin-top:7px;overflow:hidden}
.crs-bar span{display:block;height:100%;background:var(--accent);border-radius:var(--r-pill)}

/* Курс глазами ученика: строка урока кликабельна, запертая — приглушена
   и не реагирует. Замок вместо номера, потому что номер запертого урока
   ученику ничего не даёт — ему нужно знать, что туда пока нельзя. */
.crs-head{display:flex;align-items:center;gap:var(--s-2)}
.crs-row.locked{opacity:.55;cursor:default}
.crs-row:not(.locked):hover{background:var(--surface-2)}
.crs-row{border-radius:var(--radius-sm);padding-left:var(--s-2);padding-right:var(--s-2);margin:0 -var(--s-2)}
.lib-card .crs-bar{margin-top:var(--s-2)}

/* ---------- Помощь в самостоятельном уроке ----------
   Оба блока набраны как «Пример»: полосой слева и служебной меткой. Разница
   в цвете полосы — подсказка нейтральная, разбор идёт по следам ошибки и
   потому берёт цвет ошибки. Курсива здесь нет: в отличие от примера, это не
   образец задания, а обращённая к ученику речь. */
.ex-hint,.ex-explain{display:flex;gap:var(--s-3);align-items:flex-start;margin:10px 0 0;padding:var(--s-2) var(--s-3);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.ex-hint{border-left:2px solid var(--accent);background:var(--accent-soft)}
.ex-explain{border-left:2px solid var(--err);background:var(--err-bg)}
.exh-label,.exx-label{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;padding-top:3px;flex-shrink:0}
.exh-label{color:var(--accent-soft-ink)}
.exx-label{color:var(--err)}
.exh-text,.exx-text{font-size:var(--t-md);line-height:1.6;color:var(--ink-2)}

/* ---------- Правовой документ (политика обработки данных) ----------
   Страница, которую читают целиком, а не сканируют глазами: колонка узкая
   (60–70 знаков в строке), межстрочный интервал крупнее обычного, заголовки
   разделов нумерованы. Это не экран платформы, а текст, на который человек
   ссылается, — поэтому здесь нет ни карточек, ни теней. */
.doc-wrap{max-width:720px;margin:0 auto;padding:var(--s-6) var(--s-5) 80px}
.doc-wrap .brand{margin-bottom:var(--s-6)}
.doc h1{font-size:clamp(25px,3.4vw,32px);line-height:1.15;margin-bottom:var(--s-2)}
.doc .doc-date{font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);margin-bottom:var(--s-6)}
.doc h2{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);
  margin:var(--s-6) 0 var(--s-3);line-height:1.3}
.doc p{font-size:var(--t-md);line-height:1.75;color:var(--ink-2);margin-bottom:var(--s-3)}
.doc ul{margin:0 0 var(--s-3) var(--s-5);padding:0}
.doc li{font-size:var(--t-md);line-height:1.75;color:var(--ink-2);margin-bottom:var(--s-2)}
.doc strong{color:var(--ink);font-weight:600}
.doc a{color:var(--accent);font-weight:500}
/* Реквизиты оператора: единственное место, где текст обязан быть точным до
   буквы, поэтому он вынесен из потока и набран моноширинным. */
.doc-req{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-4);margin-bottom:var(--s-4);font-size:var(--t-base);line-height:1.7}
.doc-req .k{color:var(--muted)}

/* ---------- Полоса «подтвердите почту» ----------
   Живёт в самой панели, а не полосой под ней: это не ошибка и не срочность, а
   напоминание, и полоса на 56px первым элементом каждого экрана ставила
   действие, которое делают один раз в жизни, выше работы на сегодня.
   Маркерный цвет, а не красный: человек ничего не сломал. Убрать нельзя —
   уходит само, когда адрес подтверждён, иначе о нём забудут в тот же день. */
.verify-bar{display:flex;align-items:center;gap:var(--s-2);min-width:0;margin-right:auto;
  /* Своя доля панели, а не вся ширина содержимого: напоминание важное, но оно
     не главное на экране, и отбирать место у названия открытого урока не
     должно. Обрезается первым — адрес в нём наименее нужен. */
  flex:0 1 300px;
  color:var(--marker-ink);font-size:var(--t-sm)}
.verify-bar .vb-dot{width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker);
  flex-shrink:0}
.verify-bar .vb-dot.vb-bad{background:var(--err)}
/* Адрес обрезается, а не переносит панель: её высота 52 и расти ей нельзя. */
.verify-bar .vb-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.verify-bar b{font-weight:600}
.verify-bar .vb-act{background:none;border:none;color:var(--marker-ink);
  font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
  border-radius:var(--r-1);padding:5px var(--s-2);cursor:pointer;flex-shrink:0;
  transition:background var(--dur-fast) var(--ease)}
.verify-bar .vb-act:hover{background:var(--marker-soft)}
.verify-bar .vb-act:disabled{color:var(--muted);cursor:default;background:none}
/* На узком экране остаются точка и действие: адрес человек и так знает. */
@media (max-width:860px){
  .verify-bar .vb-text{display:none}
}
/* Знак из шапки телефона уходит совсем: слева стоит название раздела, и знак
   рядом с ним — второе «где я» в одной строке. Дорога на главную у знака
   осталась только на широком экране; на телефоне туда ведёт нижняя полоса.

   Прежние обходные правила отсюда убраны: и знак, и название прятались, когда
   в шапке стояло напоминание о почте, — вдвоём они не помещались и роняли
   панель во вторую строку. Напоминание больше в шапке не живёт, оно уехало в
   шторку под «⋯» (правило 1a), и прятать название не от чего. */
@media (max-width:640px){
  /* Поля шапки по кадрам: 16 слева — название вровень с полем страницы, 8
     справа — глиф «⋯» в цели 44 встаёт там же, где у страницы кончается поле. */
  .app-main .topbar{flex-wrap:nowrap;gap:var(--s-2);padding:0 var(--s-2) 0 var(--s-4)}
  .app-main .topbar .brand{display:none}
  /* Название раздела — ступень заголовка строки, 16: это и есть заголовок
     страницы, и в теле его после этого нет. Обрезается многоточием, если место
     всё-таки кончилось, а не лезет на соседа. */
  .app-main .topbar .top-here{min-width:0;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;font-size:var(--t-lg)}
  .app-main .topbar .top-user{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Правый край панели не жмётся и не переносится. У напоминания о почте своя
     доля в 300px, и на 375px оно забирало её целиком: лицу, теме и «Выйти»
     оставалось 99px, они уезжали во вторую строку и вылезали за панель — её
     высота 52 и расти ей нельзя. Уступает напоминание: адрес в нём и так
     скрыт, а кнопка «Отправить письмо» помещается в остаток. */
  .app-main .topbar .top-actions{flex-wrap:nowrap;flex-shrink:0}
}

/* «Сообщить о проблеме» — последним пунктом меню, приглушённо.
   Это не раздел платформы, а запасной выход, и выглядеть он должен так:
   заметно тому, кто ищет, и незаметно тому, кто работает. */
.sidebar .nav-report{margin-top:var(--s-2);padding-top:var(--s-3);
  border-top:1px solid var(--line);border-radius:0;
  color:var(--muted);font-weight:500;font-size:var(--t-sm)}
.sidebar .nav-report:hover{color:var(--ink)}

/* ---------- Первые шаги ----------
   Панель для нового преподавателя над рабочим столом. Маркерная полоса слева —
   тот же приём, что у примера задания: «это подсказка, а не часть работы».
   Раскрыт только текущий шаг: четыре развёрнутых карточки — это экскурсия,
   а нужна одна следующая вещь. */
.steps{border:1px solid var(--line);border-left:3px solid var(--marker);
  border-radius:var(--radius);background:var(--surface);
  padding:var(--s-4);margin-bottom:var(--s-5)}
.steps-head{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-bottom:var(--s-3)}
.steps-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);line-height:1.25}
.steps-list{display:flex;flex-direction:column;gap:var(--s-1)}
.step{display:flex;gap:var(--s-3);align-items:flex-start;padding:var(--s-2) 0}
.step-mark{flex:0 0 20px;height:20px;border-radius:50%;border:1.5px solid var(--line-2);
  display:flex;align-items:center;justify-content:center;font-size:var(--t-label);
  color:var(--ok);margin-top:1px}
.step.done .step-mark{border-color:var(--ok);color:var(--ok)}
.step.now .step-mark{border-color:var(--marker);border-style:dashed}
.step-t{font-size:var(--t-md);font-weight:500;color:var(--ink-2)}
.step.done .step-t{color:var(--muted);text-decoration:line-through;text-decoration-color:var(--line-2)}
.step.now .step-t{font-family:var(--font-head);font-weight:600;color:var(--ink)}
.step-d{font-size:var(--t-base);color:var(--muted);margin-top:3px;line-height:1.5}
.step-act{display:flex;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-3)}

/* «Откуда узнали» на первом экране — под карточками, тише их.
   Пунктирная рамка, а не карточка: это не действие платформы, а вопрос от
   человека к человеку, и выглядеть он должен как записка на полях. */
.src-strip{border:1px dashed var(--line-2);border-radius:var(--radius);
  padding:var(--s-4);margin-top:var(--s-5)}
.src-strip.done{color:var(--muted);font-size:var(--t-base);border-style:solid}
.src-q{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);margin-bottom:var(--s-3)}
.src-more{display:flex;gap:var(--s-2);align-items:center;flex-wrap:wrap;margin-top:var(--s-3)}
.src-more input{flex:1;min-width:220px;border:1px solid var(--line-2);border-radius:var(--radius-sm);
  padding:var(--s-2) var(--s-3);font-size:var(--t-base);background:var(--surface)}
.src-more input:focus{outline:none;border-color:var(--ink)}

/* ---------- Подсказка на месте ----------
   Пузырь у самой кнопки, а не поверх экрана: он договаривает последний шаг
   онбординга, а не устраивает экскурсию. Тёмный, как попап перевода, — это
   речь платформы, а не часть страницы, и путать их не надо.

   Подсвеченная цель обведена маркером, но не затемняет остальное: затемнение
   превращает подсказку в модальное окно, а работать человеку никто не мешает. */
.hint-pop{position:absolute;z-index:80;max-width:340px;
  background:var(--ink);color:var(--bg);border-radius:var(--radius-sm);
  padding:var(--s-3) var(--s-4);box-shadow:var(--shadow);
  display:flex;flex-direction:column;gap:var(--s-3);align-items:flex-start}
.hint-text{font-size:var(--t-base);line-height:1.5}
.hint-pop .btn{background:var(--bg);color:var(--ink);border:none}
.hint-pop .btn:hover{background:var(--surface)}
.hint-target{position:relative;box-shadow:0 0 0 3px var(--marker-soft),0 0 0 4px var(--marker);
  border-radius:var(--radius-sm)}
@media (max-width:640px){.hint-pop{max-width:calc(100vw - 24px)}}



/* Строка про чат под первыми шагами: отделена чертой, набрана тише шагов —
   это не пятый шаг, а приглашение рядом с ними. */
.steps-foot{margin-top:var(--s-3);padding-top:var(--s-3);border-top:1px solid var(--line);
  font-size:var(--t-base);color:var(--muted);line-height:1.5}

/* «Lessona вводит тарифы!» над приветствием главной (today.js, plansNotice).
   Сосед панели первых шагов и выглядит как она: карточка с маркерной чертой
   слева, заголовок крупнее текста, кнопка под текстом. */
.plans-notice{border:1px solid var(--line);border-left:3px solid var(--marker);
  border-radius:var(--radius);background:var(--surface);padding:var(--s-4);margin-bottom:var(--s-5)}
.plans-notice .pn-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);
  line-height:1.25;margin:0 0 var(--s-2)}
.plans-notice p{margin:0 0 var(--s-2);font-size:var(--t-base);line-height:1.55;color:var(--ink-2);max-width:72ch}
.plans-notice .pn-acts{margin-top:var(--s-3)}
/* «Запросов к ИИ стало больше» (today.js, limitsNotice) — та же карточка, плюс
   короткий прайс: три строки, тариф человека подсвечен. На телефоне строка
   ломается надвое: название и цена сверху, запросы и ученики под ними.
   «Напишите нам» — кнопка (открывает форму), но выглядит ссылкой, как ссылка в
   прошлой плашке. */
.plans-notice .linkish{color:var(--accent);text-decoration:underline;text-underline-offset:2px}
.plans-notice .pn-prices{display:grid;gap:2px;margin:var(--s-3) 0;max-width:72ch;font-size:var(--t-base)}
.plans-notice .pn-price{display:grid;grid-template-columns:9em 9em 1fr;column-gap:var(--s-3);align-items:baseline;
  padding:6px 10px;border-radius:var(--radius-sm);line-height:1.45;color:var(--ink-2)}
.plans-notice .pn-price b{color:var(--ink);font-weight:600;white-space:nowrap}
.plans-notice .pn-price.cur{background:var(--marker-soft)}
.plans-notice .pn-mine{margin-left:2px;font-size:11px;font-weight:600;color:var(--marker-ink)}
.plans-notice .pn-cost{white-space:nowrap}
.plans-notice .pn-thanks{color:var(--ink);font-weight:600}
@media (max-width:640px){
  .plans-notice .pn-price{grid-template-columns:1fr auto;row-gap:1px}
  .plans-notice .pn-what{grid-column:1 / -1;color:var(--muted)}
}

/* ---------- Телеграм: значки внизу меню ----------
   Постоянный дом ссылок. Раздел в настройках, который стоял здесь раньше, был
   странным местом: в настройки ходят менять своё, а не искать сообщество.
   Значки же видны с любого экрана и не занимают строки меню — самолётик
   объясняет себя сам, подпись только уточняет. Приглушены сильнее пунктов
   меню: это выход наружу, а не раздел платформы. */
.sidebar .nav-tg{display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  padding:var(--s-2) var(--s-3) 0;color:var(--muted)}
.sidebar .nav-tg>svg{flex-shrink:0;opacity:.7}
.sidebar .nav-tg a{display:inline;width:auto;padding:0;border-radius:0;
  color:var(--muted);font-size:var(--t-sm);font-weight:500;font-family:var(--font-body)}
.sidebar .nav-tg a:hover{color:var(--ink);background:none;text-decoration:underline}
.nav-tg-sep{font-size:var(--t-sm);opacity:.5}

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

   Подвал — обычный конец страницы: черта во всю ширину, ссылки в столбик по
   левому краю. Ниже 860px, ровно там, где меню становится полосой. */
.app-foot{display:none}
@media(max-width:860px){
  .sidebar .nav-report,.sidebar .nav-tg{display:none}
  .app-foot{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s-3);
    order:4;border-top:1px solid var(--line);padding:var(--s-5) var(--s-5) var(--s-6)}
  /* Край экрана под содержимым держал запас в 120px — теперь его держит подвал,
     и прежний запас только отрывал бы его от страницы пустой полосой. */
  .app .page{padding-bottom:var(--s-6)}
  /* Жалоба и операционка — тем же приглушённым голосом, что и внизу меню:
     заметно тому, кто ищет, незаметно тому, кто работает. Междустрочие задано
     явно: кнопка не наследует его от страницы, и строка жалобы вставала на три
     пикселя ниже соседней ссылки — ровно та беда, из-за которой эти пункты и
     уехали сюда из полосы меню. */
  /* Голос один на весь подвал: и жалоба, и оба адреса. Набранные крупнее и
     темнее, адреса выпирали из конца страницы сильнее, чем всё, что над ними,
     а подвал — не место звать. Отличает их самолётик, а не размер. */
  .af-link,.af-tg a{border:none;background:none;padding:0;cursor:pointer;text-align:left;
    text-decoration:none;font-family:var(--font-head);font-weight:500;
    font-size:var(--t-sm);line-height:1.55;color:var(--muted)}
  .af-link:hover,.af-link.on,.af-tg a:hover{color:var(--ink)}
  /* Два адреса — двумя строками, каждый со своим значком: в столбик это не
     повтор, а признак строки. Пояснений под ними нет — имя говорит всё, а
     вторая строка мелким под каждой ссылкой делала из подвала раздел. */
  .af-tg{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s-2)}
  .af-tg a{display:flex;align-items:center;gap:7px}
  .af-tg svg{flex-shrink:0;opacity:.7}
}
/* На телефоне подвала нет ни у кого. Жалоба, чат и канал — не то, ради чего
   открывают платформу с телефона, а стояли они концом каждой страницы: чертой
   во всю ширину и тремя строками сразу под содержимым, то есть заметнее всего,
   что на экране. У преподавателя те же ссылки лежат под «Ещё» в нижней полосе.
   Выше 640px (планшет, узкое окно) подвал остаётся: там он и правда конец
   длинной страницы, а не половина первого экрана. */
@media(max-width:640px){
  .app-foot{display:none}
}
/* Запас под нижней полосой телефона. Прежние 32 держал подвал, а подвала на
   телефоне нет — и конец страницы уходил под полосу высотой 53: «Изменить
   данные» в карточке ученика, «Откуда вы узнали» на главной, последняя домашка в
   разделе (владелец, 14 сентября). Вес у правила ниже, чем у страниц со своим
   запасом: каталогу нужно место ещё и под полосой «Собрать урок с ИИ». */
@media(max-width:640px){
  .with-mobile-nav{--mnav-h:53px}
  .with-mobile-nav .page{padding-bottom:calc(var(--mnav-h) + var(--s-5))}
}

/* Чат как равная альтернатива форме жалобы: своя рамка, а не строчка мелким
   шрифтом под полем. Пунктиром — предложение, а не часть формы. */
.fb-alt{border:1px dashed var(--line-2);border-radius:var(--radius-sm);
  padding:var(--s-3) var(--s-4);margin:0 0 var(--s-4)}
.fb-alt-t{display:inline-flex;align-items:center;gap:7px;font-family:var(--font-head);
  font-weight:600;font-size:var(--t-md);text-decoration:none}
.fb-alt-t:hover{text-decoration:underline}
.fb-alt-d{font-size:var(--t-base);color:var(--muted);line-height:1.5;margin-top:5px}

/* Канал в подвале лендинга. Не мелкой капителью, как соглашения: их читают по
   обязанности, а сюда идут по своей воле — значит это ссылка, а не сноска.
   Но и не кнопка: подвал не место звать, человек добрался сюда сам. */
.lp-tg{display:inline-flex;align-items:center;gap:7px;margin-left:var(--s-4);
  font-size:var(--t-base);font-weight:500;color:var(--ink-2);text-decoration:none}
.lp-tg:hover{color:var(--ink)}
.lp-tg svg{opacity:.8}
.lp-tg:hover svg{opacity:1}
.lp-legal{display:flex;gap:20px;margin-left:auto}
/* На узком экране подвал встаёт столбиком по левому краю. Раньше канал занимал
   строку целиком, а соглашения прижимались к правому краю строкой ниже — три
   ссылки читались как три разных подвала. Общий левый край связывает их в один,
   а пара соглашений остаётся парой: она в одну строку помещается и на 375px. */
@media(max-width:620px){
  .lp-footer{flex-direction:column;align-items:flex-start;gap:var(--s-4)}
  .lp-tg{margin-left:0}
  .lp-legal{margin-left:0}
}

/* ---------- Разбор сданной домашки на занятии ----------
   Не урок целиком, а список того, что сделано: номер, задание, ответ ученика и
   правильный. Смотрят вдвоём и вслух, поэтому строки крупные и разделены —
   палец ведут по экрану, а не вчитываются. */
.ws-sheet{max-height:min(62vh,560px);overflow:auto;margin:var(--s-3) 0 0}
.ws-head{font-family:var(--font-head);font-weight:700;font-size:var(--t-base);
  color:var(--muted);padding-bottom:var(--s-2);border-bottom:1px solid var(--line);margin-bottom:var(--s-2)}
/* Имя строки — .ws-item, а не .ws-row: .ws-row уже занят строкой в выпадашке
   поиска слов (см. выше), и правила листа работы, стоящие ниже, молча меняли
   ей отступы и рисовали разделители. */
.ws-item{display:flex;gap:var(--s-3);align-items:flex-start;padding:var(--s-3) 0;
  border-bottom:1px solid var(--line)}
.ws-item:last-child{border-bottom:none}
.ws-num{flex-shrink:0;width:26px;text-align:right;font-variant-numeric:tabular-nums;
  font-size:var(--t-sm);color:var(--muted);padding-top:2px}
/* Цвет несёт левый край строки, а не заливка: залитые полосы во весь список
   читаются как тревога, а половина работы обычно верна. */
.ws-item.err .ws-num{color:var(--err)}
.ws-item.ok .ws-num{color:var(--ok)}
.ws-item.skip{opacity:.6}
.ws-body{flex:1;min-width:0}
.ws-task{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);margin-bottom:var(--s-2)}
.ws-cols{display:flex;gap:var(--s-4);flex-wrap:wrap}
.ws-col{flex:1;min-width:180px}
.ws-lab{display:block;font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);margin-bottom:2px}
.ws-mark{margin-top:var(--s-2);font-size:var(--t-sm);color:var(--ink-2);
  border-left:2px solid var(--accent);padding-left:var(--s-3)}
/* Написанное своими словами — блоком, а не строкой: его читают вслух целиком. */
.ws-written{white-space:pre-wrap;word-break:break-word;font-size:var(--t-md);line-height:1.6;
  background:var(--surface-2);border-radius:var(--radius-sm);padding:var(--s-2) var(--s-3);margin-top:2px}
.ws-field+.ws-field{margin-top:var(--s-2)}
.ws-field b{font-size:var(--t-sm);color:var(--muted);font-weight:600}

/* ---------- Разбор работы прямо на листе занятия ----------
   Тот же разбор, что в очереди проверки, но не в окне поверх урока, а разделом
   внизу листа. Своей высоты и своей прокрутки у него здесь нет: лист один, и
   вторая полоса прокрутки внутри страницы — это два разных «вниз» на одном
   экране. */
.ws-sheet.in-lesson{max-height:none;overflow:visible;margin:var(--s-2) 0 0}
/* Поля разбора под ответом: вердикт, «как надо», комментарий. Ставим их в
   строку и приглушённо — читают тут ответ ученика, а поля заполняют по ходу
   разговора. */
.ws-fix{display:flex;align-items:flex-start;gap:var(--s-2);flex-wrap:wrap;margin-top:var(--s-3)}
.ws-verdict{margin-bottom:0;flex-shrink:0}
.ws-verdict button{padding:4px 10px;font-size:var(--t-label)}
.ws-verdict button.on{color:var(--ink)}
.ws-in{flex:1 1 190px;min-width:0;border:1px solid var(--line);border-radius:var(--r-1);
  background:var(--surface);color:var(--ink);font-family:inherit;font-size:var(--t-sm);
  padding:6px var(--s-2)}
.ws-in:focus{outline:none;border-color:var(--ink-2)}
/* «Как надо» — целая фраза, а не слово: поле растёт вместе с ней. */
.ws-how{flex-basis:100%;resize:vertical;min-height:34px;line-height:1.5}
.ws-foot{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;margin-top:var(--s-4)}
/* Переключатель «показать ученику» — у своего раздела и справа: заголовок
   называет раздел, переключатель говорит, видит ли его второй. */
.hw-sw{display:inline-flex;align-items:center;gap:var(--s-2);margin-left:auto}
.hw-sw-lab{font-size:var(--t-label);text-transform:uppercase;letter-spacing:.06em;
  font-family:var(--font-head);font-weight:600;color:var(--muted)}
@media(max-width:640px){
  /* На телефоне переключатель уходит под заголовок: в строку с названием
     раздела он не встаёт, а сжимать ради него название значит терять то, что
     раздел вообще называет. */
  .hw-sw{margin-left:0;flex-basis:100%;justify-content:flex-start;margin-top:var(--s-2)}
  .ws-fix{gap:var(--s-1)}
}

/* У блока в очереди проверки вердикт один — плашка в шапке. Карточка блока в
   режиме чтения печатает его же вторым разом внизу (.ex-acts в acts()), и на
   девяти заданиях подряд это девять лишних плашек, повторяющих сказанное. */
.rw-block .ex-acts{display:none}

/* Работа, где оценивать нечего: карточка над листом. Решение «принять не
   глядя» принимают до чтения заданий, поэтому она стоит выше их, а не строкой
   под ними мелким шрифтом. */
.rw-auto{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);
  padding:18px;margin-bottom:var(--s-4)}
.rw-auto-head{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap}
.rw-auto-sub{font-size:var(--t-sm);color:var(--muted)}
.rw-auto p{margin:10px 0 14px;font-size:var(--t-md);line-height:1.55;color:var(--ink-2)}
.rw-auto-acts{display:flex;gap:var(--s-2);flex-wrap:wrap}
/* Дверь в сам урок из строки контекста — тем же тихим голосом, что и остальной
   контекст: это справка, а не действие над работой. */
.rw-ctx-open{color:var(--marker-ink);text-decoration:none}
.rw-ctx-open:hover{text-decoration:underline}

/* ---------- Разбор ИИ: предложение и итог ----------
   Ничто из этого не запускается само: разбор тратит обращение из тарифа.
   Сначала заметное предложение с остатком, потом — вывод карточкой.

   Обе плашки жёлтые, и это законно: маркер значит «работа модели», одно из
   четырёх его значений. Главная кнопка внутри — чёрная, а не жёлтая: плашка
   уже жёлтая, и жёлтая кнопка на жёлтом перестала бы читаться кнопкой. */
.ai-offer{background:var(--marker-soft);border-radius:var(--r-2);padding:18px;margin-bottom:var(--s-4)}
.ai-offer-t{font-family:var(--font-head);font-weight:600;font-size:15px;color:var(--ink)}
.ai-offer p{margin:7px 0 14px;font-size:var(--t-md);line-height:1.55;color:var(--marker-ink)}
.ai-offer-acts{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap}
.ai-offer-left{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--marker-ink)}
/* Действия кончились: полотно гаснет до обычной подложки. Жёлтый — знак того,
   что здесь работает модель, и над «недоступно» он обещал бы работу. */
.ai-offer.out{background:var(--surface-2)}
.ai-offer.out p{color:var(--ink-2)}
/* Итог — на бумаге, а не на маркере: вывод читают как текст, и жёлтое полотно
   под абзацем спорило бы с ним. Принадлежность к модели называет точка. */
.ai-result{background:var(--paper);border-radius:var(--r-2);padding:18px;margin-bottom:var(--s-4)}
.ai-result-head{display:flex;align-items:center;gap:var(--s-2)}
.ai-result-head i{width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker);flex-shrink:0}
.ai-result-head .eyebrow{color:var(--marker-ink)}
.ai-result p{margin:10px 0 0;font-size:var(--t-md);line-height:1.6;color:var(--ink)}
.ai-result-acts{display:flex;gap:var(--s-2);margin-top:14px}

/* ---------- Предложение модели в очереди проверки ----------
   Стоит РЯДОМ с полем оценки, а не в нём: пока предложение не взяли, это чужая
   догадка, и выглядеть она должна чужой. Маркерный кант — общий знак работы
   модели на платформе. */
.rw-hint{display:flex;align-items:flex-start;gap:var(--s-3);margin-top:var(--s-2);
  padding:var(--s-2) var(--s-3);border-left:2px solid var(--marker);
  background:var(--marker-soft);border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.rw-hint-lab{display:inline-flex;align-items:center;gap:var(--s-1);flex-shrink:0;
  font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--marker-ink);padding-top:3px}
.rw-hint-lab svg{width:12px;height:12px}
.rw-hint-body{flex:1;min-width:0;font-size:var(--t-sm);line-height:1.55;color:var(--ink)}
.rw-hint .btn{flex-shrink:0}

/* ---------- Проверка письменного ответа: до и после рядом ----------
   Две колонки одной высоты: слева работа, как её сдали, справа — она же с
   правками преподавателя. Рядом, а не одна под другой: глаз ходит между ними
   строка в строку, и разница видна без прокрутки. */
.rw-pair{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-3);margin-bottom:var(--s-2)}
.rw-side{min-width:0;display:flex;flex-direction:column}
.rw-side-lab{font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);margin-bottom:var(--s-1)}
.rw-text{flex:1;white-space:pre-wrap;word-break:break-word;font-size:var(--t-md);line-height:1.65;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--s-3);min-height:64px}
/* Правую половину правят прямо в тексте — она и выглядит полем, но только
   когда в неё целятся: рамка по наведению, а не всегда. */
.rw-text.now{cursor:text}
.rw-text.now:hover{border-color:var(--line-2);background:var(--surface)}
.rw-text.edit{font-family:inherit;color:var(--ink);resize:vertical;outline:none}
.rw-text.edit:focus{border-color:var(--accent);background:var(--surface)}
/* Красным — что убрали или заменили, зелёным — что появилось. Зачёркивание на
   левой половине: цветом одним «убрали» от «добавили» не отличить тому, кто
   различает цвета хуже нас. */
mark.d-was{background:var(--err-bg);color:var(--err);text-decoration:line-through;
  border-radius:3px;padding:0 2px}
mark.d-now{background:var(--ok-bg,#E7F3EC);color:var(--ok);border-radius:3px;padding:0 2px}
.rw-hint-fix{margin-left:var(--s-2);font-weight:600}
@media (max-width:900px){
  .rw-pair{grid-template-columns:1fr}
}
/* Сданная домашка — строка панели хода урока, а не кнопка в шапке: панель это
   оглавление занятия, и «что он сделал дома» такой же его пункт. */
.tp-work{color:var(--accent)}
.tp-work:hover{text-decoration:underline}
/* Исправленный текст в разборе на занятии — под сданным, со своей подписью. */
.ws-fixed{margin-top:var(--s-2);border-left:2px solid var(--ok)}
.ws-fix-lab{display:block;font-variant-numeric:tabular-nums;font-size:var(--t-label);text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);margin-bottom:2px}

/* Правая колонка, пока в ней предложение модели, а не решение преподавателя:
   маркерный кант — общий знак работы модели на платформе. */
.rw-text.now.offer{border-color:var(--marker);background:var(--marker-soft)}
.rw-hint .btn.primary{background:var(--ink);color:var(--paper);border-color:var(--ink)}

/* Заголовок работы не схлопывается до нуля: у него есть свой пол, и на узком
   экране ряд переносится целиком, а не выжимает название в столбик по слову.
   Так и ломалась вёрстка при экране в половину ширины. */
.rw-head-main{flex:1 1 220px;min-width:200px}
/* Ответ, показанный самим уроком, гасим там, где рядом стоят колонки «до и
   после»: они показывают тот же текст, и второй раз он читается как ошибка. */
.rw-block.has-fix .open-read{display:none}
/* Начать правку, когда правок ещё нет. Тише кнопки действия: это приглашение,
   а не то, что делают в каждой работе. */
.rw-start{background:none;border:1px dashed var(--line-2);border-radius:var(--radius-sm);
  color:var(--muted);font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
  padding:5px var(--s-3);cursor:pointer;margin-bottom:var(--s-2)}
.rw-start:hover{border-color:var(--ink);color:var(--ink)}


/* ---------- Проверка с телефона: очередь карточками, работа по заданию ----------
   Хендофф v4, кадры 3c и 3a. На 390 колонка работ и сама работа рядом не
   встают, а лента из всех заданий шла в три экрана. Поэтому здесь два экрана:
   очередь — карточками групп, работа — по одному заданию, как у ученика
   (review.js: renderListPhone, renderWorkPhone). Широкий экран не тронут. */
@media(max-width:640px){
  body.rv-work .review-list,body:not(.rv-work) .review-work{display:none}
  body.rv-work .app-main>.topbar,body.rv-work .mobile-nav{display:none}
  .review-list{padding:var(--s-3) var(--s-4) var(--s-5);border-bottom:none}

  .rvp-card{margin-top:var(--s-3);padding:var(--s-3);background:var(--surface);
    border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .rvp-card.rvp-main{margin-top:0;padding:var(--s-1);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  .rvp-head{display:flex;align-items:center;gap:var(--s-3)}
  .rvp-main .rvp-head{padding:var(--s-3) var(--s-3) var(--s-1)}
  .rvp-head>div{flex:1;min-width:0}
  .rvp-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink)}
  .rvp-s{font-size:var(--t-sm);color:var(--muted)}
  .rvp-row{display:flex;align-items:center;gap:var(--s-3);width:100%;padding:var(--s-2) var(--s-3);
    border:none;border-top:1px solid var(--line);border-radius:var(--r-2);background:none;
    cursor:pointer;text-align:left;color:var(--ink)}
  .rvp-row .stu-ava{width:44px;height:44px;flex:0 0 44px;background:var(--surface-2);color:var(--muted);
    font-size:var(--t-base);font-weight:600}
  .rvp-body{flex:1;min-width:0;display:flex;flex-direction:column}
  .rvp-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rvp-sub{font-size:var(--t-sm);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rvp-open{flex:0 0 auto;display:inline-flex;align-items:center;height:44px;padding:0 var(--s-4);
    border-radius:var(--r-1);background:var(--ink);color:var(--paper);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
  /* Подложка темнее бумаги — как у остальных листов второй сверки (3c): белые
     карточки групп на бумаге читались одним полотном. Экран работы — там же. */
  body:has(.review-list){background:var(--work-ground)}
  .rvp-accept{flex:0 0 auto}
  /* «Принять» — рамкой без подложки и тени, как в 3c; вес как у общего правила
     вторичных кнопок телефона, иначе его кант и тень побеждают. */
  .rvp-head>.btn.rvp-accept:not(.primary){min-height:44px;padding:0 var(--s-4);background:none;
    box-shadow:inset 0 0 0 1px var(--line-2)}
  .rvp-auto{display:flex;align-items:center;gap:var(--s-3);width:100%;margin-top:var(--s-3);
    padding:var(--s-3) 0 0;border:none;border-top:1px solid var(--line);background:none;
    cursor:pointer;text-align:left;color:var(--ink)}
  .rvp-aname{font-size:var(--t-md);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rvp-auto .rvp-sub{white-space:normal}
  .rvp-score{flex:0 0 auto;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
    font-variant-numeric:tabular-nums}
  .rvp-go{flex:0 0 auto;font-size:var(--t-lg);color:var(--muted)}
  .rvp-note{margin-top:var(--s-3);font-size:var(--t-sm);line-height:1.5;color:var(--muted)}

  /* Экран работы: своя шапка вместо шапки платформы, одно задание, полоса внизу.
     Нижняя навигация прячется: на её месте полоса действий, как у ученика на
     экране шага. */
  body.rv-work .review-work{--foot-h:84px;min-height:100vh;padding:0 0 calc(var(--foot-h) + env(safe-area-inset-bottom));
    background:var(--paper)}
  .rvw-head{position:sticky;top:0;z-index:40;display:flex;align-items:center;gap:var(--s-1);
    min-height:48px;padding:0 var(--s-1);background:var(--paper);border-bottom:1px solid var(--line)}
  .rvw-back,.rvw-more{flex:0 0 auto;width:44px;height:44px;border:none;background:none;
    cursor:pointer;border-radius:var(--r-1);font-size:var(--t-lg);color:var(--ink-2)}
  .rvw-mid{flex:1;min-width:0}
  .rvw-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rvw-sub{font-size:var(--t-sm);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rvw-all{flex:0 0 auto;min-height:44px;padding:0 var(--s-2);border:none;background:none;cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--ink-2)}
  .rvw-body{padding:var(--s-3) var(--s-4) 0}
  body.rv-work .rw-block,body.rv-work .rw-block.v-ok,body.rv-work .rw-block.v-err,
  body.rv-work .rw-block.v-manual{padding:var(--s-4);border-radius:var(--r-3);background:var(--surface);
    box-shadow:var(--sh-2)}
  /* Вердикт открытого ответа — пара кнопок во всю ширину. Нейтральные, пока не
     выбрали: цвет появляется после выбора, это уже данные об ответе. */
  body.rv-work .rw-grade{display:grid;grid-template-columns:96px minmax(0,1fr);gap:var(--s-2)}
  body.rv-work .rw-verdict-seg{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr;
    gap:var(--s-2);padding:0;background:none;box-shadow:none}
  body.rv-work .rw-verdict-seg button{height:44px;border-radius:var(--r-1);background:var(--surface);
    box-shadow:inset 0 0 0 1px var(--line-2);font-family:var(--font-head);font-weight:600;
    font-size:var(--t-md);color:var(--ink)}
  body.rv-work .rw-verdict-seg button:first-child.on{background:var(--ok-bg);color:var(--ok);
    box-shadow:inset 0 0 0 1px var(--ok)}
  body.rv-work .rw-verdict-seg button:last-child.on{background:var(--err-bg);color:var(--err);
    box-shadow:inset 0 0 0 1px var(--err)}
  /* Поля 16px: мельче iOS увеличивает страницу и обратно не отдаёт */
  body.rv-work .rw-grade .rw-score{width:auto;min-height:46px;font-size:var(--t-lg)}
  body.rv-work .rw-grade .rw-comment{min-width:0;min-height:46px;font-size:var(--t-lg)}
  .rvw-foot{position:fixed;left:0;right:0;bottom:0;z-index:50;display:flex;align-items:center;gap:var(--s-2);
    padding:var(--s-2) var(--s-4) calc(var(--s-3) + env(safe-area-inset-bottom));
    background:var(--paper);border-top:1px solid var(--line)}
  .rvw-prev{flex:0 0 auto;width:52px;height:52px;border:none;border-radius:var(--r-1);cursor:pointer;
    background:var(--surface);box-shadow:var(--sh-1);font-size:var(--t-lg);color:var(--ink-2)}
  .rvw-next{flex:1;min-width:0;height:52px;display:flex;align-items:center;justify-content:center;
    gap:var(--s-2);border:none;border-radius:var(--r-1);cursor:pointer;background:var(--ink);color:var(--paper);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .rvw-next span{color:var(--sm-faint)}
  .rvw-done{flex:0 0 auto;height:52px;padding:0 var(--s-4);border:none;border-radius:var(--r-1);cursor:pointer;
    background:var(--surface);box-shadow:var(--sh-1);font-family:var(--font-head);font-weight:600;
    font-size:var(--t-lg);color:var(--ink)}
  .rvw-foot.last .rvw-done{flex:1;background:var(--ink);color:var(--paper);box-shadow:none}
  /* Строка оглавления работы: номер, задание, вердикт справа */
  .rvw-row{display:flex;align-items:center;gap:var(--s-3)}
  .rvw-row .sr-num{flex:0 0 auto;font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}
  .rvw-row .sr-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .rvw-row .rw-verdict{margin-left:auto}
  /* Предложение разобрать на телефоне — строкой: абзац про модель уводил само
     задание за край первого экрана, а сказано в нём то же, что в кнопке. */
  body.rv-work .ai-offer{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s-2) var(--s-3);padding:var(--s-3) var(--s-4)}
  body.rv-work .ai-offer p{display:none}
  body.rv-work .ai-offer-t{flex:1;min-width:0}
  body.rv-work .rw-type{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .rvw-lab{display:block;margin-top:var(--s-4);font-size:var(--t-label);font-weight:600;letter-spacing:.1em;
    text-transform:uppercase;color:var(--muted)}
  .rvw-score{width:100%;min-height:46px;margin-top:var(--s-2);padding:0 var(--s-3);border:1px solid var(--line-2);
    border-radius:var(--r-1);background:var(--surface);font-size:var(--t-lg);color:var(--ink)}
  html[data-chrome="dark"] body.rv-work .rw-block{box-shadow:none}
}

/* ---------- Текстовая половина строки не схлопывается ----------
   Та же беда, что была в шапке проверенной работы: у текста стоит min-width:0,
   чтобы он умел обрезаться, а сосед-кнопка не ужимается — и на узком экране
   текст выжимается в столбик по одному слову. Пол плюс перенос строки решают
   это разом: не влезли рядом — встали друг под другом. */
.imgm-ed{flex-wrap:wrap}
.imgm-ed>div{min-width:160px}
.stu-panel .sp-head{flex-wrap:wrap}
.stu-panel .sp-head>div:first-child{min-width:170px}
.teacher-mark>div{min-width:150px}

/* ---------- Сборка с ИИ ----------
   Блок, пришедший от модели прямо сейчас, проявляется: за минуту разбора их
   приходит два десятка, и без движения непонятно, где появился очередной. */
@keyframes blockIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.block.arrived,.card.arrived,.pv-plain.arrived,.sticky.arrived{animation:blockIn var(--dur-base) var(--ease) both}
@media (prefers-reduced-motion:reduce){
  .block.arrived,.card.arrived,.pv-plain.arrived,.sticky.arrived{animation:none}
}

/* Строка хода сборки и отчёт после неё — в шапке конструктора, рядом с
   кнопкой, которой сборку и запустили. */
.ai-bar{display:inline-flex;align-items:center;gap:var(--s-2);font-size:var(--t-sm);
  color:var(--muted);white-space:nowrap}
.ai-bar .spin{width:13px;height:13px;border-width:2px;flex-shrink:0}
.ai-bar.done{color:var(--ink);background:var(--marker-soft);border-radius:var(--r-pill);
  padding:3px var(--s-3)}
.ai-bar.done .more-link{font-size:var(--t-sm)}
/* Шапка конструктора делится на три зоны: слева путь и статус, в центре — на
   чей взгляд смотрим, справа действия. Переключатель вида стоял в правой
   группе, среди действий, и читался ещё одной кнопкой — хотя он не действие, а
   вопрос «чьими глазами». Центрируем по всей ширине панели, а не по свободному
   месту: иначе он ездит от длины названия урока.

   Ниже 1100px возвращаем его в поток — там панель и так тесная, и абсолютно
   поставленный переключатель наехал бы на название. */
/* Левая зона: путь, название урока и всё, что говорит о нём самом.

   Одной строкой: место отдаёт название урока — оно обрезается многоточием, —
   а состояние и отмена стоят целиком. Перенос был разрешён на весь ряд, и от
   одной лишней плашки («ЧЕРНОВИК · Опубликовать») шапка вырастала вдвое,
   роняя «сохранено» и отмену на второй этаж. Переносится она только там, где
   иначе не встаёт вовсе, — на телефоне (правило ниже). */
.top-left{display:flex;align-items:center;gap:var(--s-3);min-width:0;flex-wrap:nowrap}
.top-left .top-title{flex:0 1 auto;min-width:6rem}
.top-left #saveState,.top-left .pub-chip{flex-shrink:0}
/* Состояние урока и действие при нём — одной строкой. Внутри инлайнового span
   они переносились сами по себе, и от этого шапка вырастала вдвое даже там,
   где места хватало. */
.top-left #pubState{display:inline-flex;align-items:center;gap:var(--s-2);flex-shrink:0}
@media(max-width:640px){.top-left{flex-wrap:wrap;row-gap:var(--s-2)}}
.top-mid{display:flex;align-items:center;flex-shrink:0}
/* Пока панель узкая, середина идёт сразу за левой зоной, а действия остаются
   у правого края (margin-left:auto у .top-actions): своей строки переключатель
   не занимает — на телефоне шапка и так в три этажа.
   Развернулась — крайние зоны берут по равной доле, и середина встаёт ровно по
   центру панели, без всякой координаты. */
@media(min-width:1100px){
  /* Доли равные — но только когда посередине действительно что-то стоит.

     Делить панель пополам ради середины, которой нет, значит запирать ряд
     действий в половину ширины. На занятии середины нет вовсе, а ряд действий
     длиннее левой зоны — поиск слова, смена материала, «Под ученика»,
     «Домашка», «Завершить», — и в свою половину он не вставал даже на 1920.
     «Закрыть» с переключателем темы уезжали на второй этаж на любой ширине:
     шапка вырастала до 117 пикселей, а кнопка выхода оставалась на второй
     строке одна. Без середины ряд берёт свою ширину, а левая зона жмётся —
     название урока для этого и обрезается многоточием. */
  body>.topbar:has(.top-mid) .top-left,
  body>.topbar:has(.top-mid) .top-actions{flex:1 1 0}
  body>.topbar .top-actions{justify-content:flex-end}
}
/* Тесно — напоминание про почту забирает себе целую строку и перестаёт
   отнимать место у заголовка. Просторно (от 1500) — стоит в одном ряду со
   всем остальным, как и задумано. */
@media(max-width:1499px){
  body>.topbar .verify-bar{flex:1 0 100%;margin-right:0}
  /* На вложенной странице (конструктор, занятие) знак уступает место пути:
     «← Уроки» и название урока говорят, где мы, точнее логотипа, а слева в
     ряду стоят ещё состояние урока, «сохранено» и отмена. Знак остаётся на
     всех остальных страницах и на широком экране. */
  body>.topbar:has(.top-back) .brand{display:none}
}
.topbar .hdr-seg{margin-bottom:0;flex-shrink:0}

/* Состояние урока в шапке — плашка, а не кнопка: точка и слово. Она стоит в
   левой зоне, у названия урока, потому что говорит о самом уроке, а не о том,
   что с ним можно сделать. Опубликованное нажимается (возврат в черновик), но
   формой этого не обещает — об этом сказано подсказкой. */
.pub-chip{display:inline-flex;align-items:center;gap:6px;border:none;background:none;
  font-family:var(--font-head);font-size:var(--t-label);font-weight:600;letter-spacing:.08em;
  color:var(--muted);padding:0;cursor:pointer;flex-shrink:0}
.pub-chip>i{width:6px;height:6px;border-radius:var(--r-pill);background:var(--ok);flex-shrink:0}
.pub-chip:hover{color:var(--ink-2)}
/* Черновик — плашкой без действия: действие рядом, своей кнопкой. */
.pub-chip.draft{cursor:default}
.pub-chip.draft:hover{color:var(--muted)}
.pub-chip.draft>i{background:var(--muted)}

/* Материалы в окне сборки: страницы учебника, файлы, вставленный текст. */
/* Пунктирной рамки нет: она рисовала мишень для мыши, хотя файлы кладут в окно
   целиком, а чаще всего вставляют из буфера. Рамка появляется только под
   перетаскиванием — там она отвечает на «попаду ли я». */
.mat-zone{border:1px solid transparent;border-radius:var(--radius-sm);
  padding:var(--s-2) 0;margin-top:var(--s-3);
  transition:border-color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}
.mat-zone.over{border-color:var(--marker);background:var(--marker-soft);padding:var(--s-3)}
/* Приглашение — одна строка слева, а не плакат по центру: пока страниц нет,
   это подпись к пустому месту, а не главное в окне. */
.mat-drop{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--s-2);
  font-size:var(--t-sm);color:var(--muted);line-height:1.5}
.mat-drop b{color:var(--ink);font-weight:600}
.mat-drop .md-how{flex-shrink:1;min-width:0}
.mat-drop .md-text{margin-left:auto}
/* Со страницами на её месте — заголовок со счётчиком и «+ Добавить». */
.mat-head{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-sm)}
.mat-head:empty{display:none}
.mat-head b{color:var(--ink);font-weight:600}
.mat-head .mh-n{font-variant-numeric:tabular-nums;color:var(--muted)}
.mat-head .more-link:first-of-type{margin-left:auto}
/* Список учеников в окне «Кому задать домашку»: колонка с прокруткой. Класс
   стоял в разметке, а правила у него не было вовсе — на двадцати учениках окно
   вырастало за край экрана. */
/* Имя выбранного акцента — в том же ряду, что кружки: подпись к выбору, а не
   отдельная строка под ним. */
.swatches .sw-name{margin-left:var(--s-2);font-size:var(--t-sm);color:var(--ink-2);align-self:center}

.lesson-pick{display:flex;flex-direction:column;gap:2px;max-height:46vh;overflow:auto}
.mat-links{display:flex;gap:var(--s-4);justify-content:center;margin-top:var(--s-2)}
.mat-list{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-3)}
.mat-list:empty{display:none}
.mat-item{position:relative;width:96px;border:1px solid var(--line);border-radius:var(--radius-sm);
  overflow:hidden;background:var(--paper);cursor:grab}
.mat-item img{display:block;width:100%;height:110px;object-fit:cover}
.mat-doc{display:flex;align-items:center;justify-content:center;height:110px;
  font:600 12px/1 var(--font-body);font-variant-numeric:tabular-nums;color:var(--muted);background:var(--line-soft,var(--paper))}
.mat-doc.wait{font-size:18px}
.mat-name{font-size:var(--t-label);padding:var(--s-1) 6px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;color:var(--muted)}
.mat-n{position:absolute;top:4px;left:4px;z-index:1;font:600 10.5px/1 var(--font-body);font-variant-numeric:tabular-nums;
  background:var(--ink);color:var(--paper);border-radius:var(--r-pill);padding:3px 6px}
.mat-acts{position:absolute;top:0;right:0;left:0;display:flex;justify-content:flex-end;gap:1px;
  padding:2px;opacity:0;transition:opacity var(--dur-fast) var(--ease);background:linear-gradient(var(--paper),transparent)}
.mat-item:hover .mat-acts{opacity:1}
.mat-acts .icon-btn{width:22px;height:22px;font-size:var(--t-sm)}
.mat-item.dragging{opacity:.4}
.mat-item.drop-before{box-shadow:-3px 0 0 var(--accent)}
.mat-item.drop-after{box-shadow:3px 0 0 var(--accent)}
.mat-item.cropped::after{content:'✂';position:absolute;bottom:26px;right:4px;font-size:var(--t-label);
  background:var(--paper);border-radius:var(--r-pill);padding:1px var(--s-1);color:var(--muted)}
.mat-hint{font-size:var(--t-label);color:var(--muted);margin-top:var(--s-2);line-height:1.5}
.mat-hint:empty{display:none}

/* Метки на карточке блока: что придумано моделью и где не нашлось ключа. */
.gen-mark{font-size:var(--t-label);color:var(--marker-ink);background:var(--marker-soft);
  border-radius:var(--r-1);padding:2px 6px;flex-shrink:0;white-space:nowrap}

/* В виде «как у ученика» кнопок вставки между блоками нет: ученик их не видит. */
.workspace.student-view .insert{display:none}
/* Рельса в этом виде — оглавление, а не инструмент: выбор блоков, разделы и
   «+ Добавить блок» относятся к сборке, а не к чтению. Ширину колонки при этом
   не трогаем: переключение вида не должно двигать текст под курсором. */
.workspace.student-view .rail-head,
.workspace.student-view .rail-tabs,
.workspace.student-view .rail-add{display:none}
.workspace.student-view .rail-list{gap:2px}
.toc-head{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);font-variant-numeric:tabular-nums;padding:0 var(--s-1) var(--s-2)}
.toc-item{display:flex;align-items:baseline;gap:9px;padding:var(--s-2) 0;cursor:pointer}
.toc-num{width:22px;flex-shrink:0;text-align:right;font-size:var(--t-label);font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--muted)}
.toc-label{font-size:var(--t-sm);color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.toc-item:hover .toc-label{color:var(--ink)}

/* ---------- Тариф ----------
   Полоса расхода, а не одно число: «осталось 43» ничего не говорит, пока не
   видно, из скольких. Цвет ошибки — только когда действительно на исходе. */
.plan-use{margin-bottom:var(--s-4)}
.plan-row{font-size:var(--t-base);margin-bottom:var(--s-2)}
.plan-row b{font-size:var(--t-lg);font-variant-numeric:tabular-nums}
.plan-use .bar{height:6px;background:var(--line);border-radius:var(--r-pill);overflow:hidden;margin-bottom:6px}
.plan-use .bar span{display:block;height:100%;background:var(--accent);border-radius:var(--r-pill)}
/* Действия кончились — полоса заполнена целиком и уходит в чернила. Красный на
   платформе означает ошибку, а исчерпанный лимит — состояние, о котором надо
   знать. То же правило у абонемента (.bar.low) и у общей .bar.full. */
.plan-use .bar.full>span{background:var(--ink)}

/* Ряд плашек выбора: языки в настройках. Цели ученика в карточке набраны тем
   же .chip, но своим рядом (.chip-row) — там они внутри панели профиля. */
.chips{display:flex;flex-wrap:wrap;gap:var(--s-2)}
/* Основной язык — тот, что подставляется новому уроку: заметнее остальных
   выбранных, но различие всё равно одно и читается сразу. */
.chip.selected.main{border-color:var(--accent);background:var(--accent);color:var(--paper)}


/* ---------- «Урок готов» ----------
   Было полосой в одну строку: «Урок готов. Что дальше:» и одна кнопка. Стало
   карточкой, потому что вопросов здесь три, а не один, и у каждого свой ответ:
   провести, поставить, задать. Лист поднят над страницей — это единственное
   место, где человек в этот момент принимает решение. */
/* Карточка «Урок готов» в конструкторе. Имя своё: .next-card занято тёмным
   листом ближайшего занятия в кабинете ученика (ниже по файлу, в телефонном
   блоке), и его заливка чернилами доставалась и этой карточке. */
.ready-card{background:var(--surface);border-radius:var(--r-3);box-shadow:var(--sh-2);
  padding:18px;margin-bottom:var(--s-4)}
.nc-head{display:flex;align-items:flex-start;gap:var(--s-3)}
.nc-h-main{flex:1;min-width:0}
.nc-ok{width:26px;height:26px;border-radius:var(--r-pill);background:var(--surface-2);
  color:var(--ink);display:flex;align-items:center;justify-content:center;
  font-size:var(--t-sm);flex-shrink:0}
.nc-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.01em}
.nc-meta{font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums;margin-top:2px}
/* Записка о том, почему выходы закрыты: жёлтая, потому что говорит платформа —
   это её правило, а не состояние урока. */
.nc-note{background:var(--marker-soft);color:var(--marker-ink);border-radius:var(--r-1);
  padding:var(--s-3);font-size:var(--t-sm);line-height:1.55;margin-top:var(--s-3)}
/* Выходы: строки во всю ширину, главный — чернилами. Стрелка справа говорит,
   что строка уводит, а не переключает. */
.nc-ways{display:flex;flex-direction:column;gap:var(--s-2);margin-top:var(--s-3)}
.nc-way{display:flex;align-items:center;gap:var(--s-3);width:100%;text-align:left;
  border:1px solid var(--line);background:var(--paper);border-radius:var(--r-2);
  padding:11px 14px;cursor:pointer;font-family:var(--font-body);color:var(--ink);
  transition:border-color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}
.nc-way:hover{border-color:var(--line-2);background:var(--surface-2)}
.nc-way.main{background:var(--ink);border-color:var(--ink);color:var(--bg)}
.nc-way.main:hover{background:var(--ink);opacity:.92}
.nc-w-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.nc-w-main b{font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
.nc-w-main em{font-style:normal;font-size:var(--t-sm);color:var(--muted)}
.nc-way.main .nc-w-main em{color:rgba(255,255,255,.62)}
.nc-w-go{flex-shrink:0;color:var(--muted)}
.nc-way.main .nc-w-go{color:rgba(255,255,255,.62)}
/* Подвал: то, что ничего не меняет. */
.nc-foot{display:flex;flex-wrap:wrap;gap:var(--s-4);margin-top:var(--s-3)}

/* Готовое сообщение к ссылке — одинаково в карточке и в окне приглашения. */
.inv-share{background:var(--surface-2);border-radius:var(--r-1);padding:var(--s-3);margin-top:var(--s-3)}
.inv-msg{font-size:var(--t-sm);line-height:1.55;color:var(--ink-2);margin:var(--s-1) 0 var(--s-2)}
.inv-msg .inv-url{color:var(--muted);word-break:break-all}

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

   Над листом полоса всегда одна: в виде «Как у ученика» «Что дальше» не
   рисуется вовсе (renderNext в builder.js). */
.next-bar{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;
  padding:var(--s-3) var(--s-5);background:var(--paper);
  border-bottom:1px solid var(--line);font-size:var(--t-base)}
.next-t{font-weight:600}
.view-bar{display:flex;align-items:center;gap:var(--s-3);flex-wrap:wrap;
  padding:9px var(--s-5);background:var(--surface-2);
  border-bottom:1px solid var(--line);font-size:var(--t-sm)}
.vb-dot{width:6px;height:6px;border-radius:var(--r-pill);background:var(--ink);flex-shrink:0}
.vb-text{color:var(--ink-2)}
.vb-act{margin-left:auto;display:flex;align-items:center;gap:14px;flex-shrink:0}
.vb-act a{font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);
  color:var(--ink-2);text-decoration:none;white-space:nowrap}
.vb-act a:hover{color:var(--ink)}
@media (max-width:640px){
  .view-bar{padding:9px var(--s-3)}
  /* Двери вида переносятся внутри своего ряда: «Открыть отдельной вкладкой ↗» и
     «Вернуться к редактору» вместе — 377, ряд не сжимался, и на 320 и 375
     кнопка уходила за край экрана и раздвигала окно. Правило через .view-bar:
     класс .vb-act носит и кнопка «Отправить письмо» в напоминании про почту. */
  .view-bar .vb-act{flex-shrink:1;min-width:0;flex-wrap:wrap;justify-content:flex-end;row-gap:var(--s-2)}
}
@media (max-width:640px){.next-bar{padding:var(--s-3)}}

/* ---------- Окно сборки: помещается на ноутбуке ----------
   Шапка, листаемая середина и подвал у него теперь общие (.modal.framed).
   Своего осталось только то, ради чего окно и ужимали: поле просьбы ниже
   обычного, зона материала — две строки, а не плакат. */
/* Окно сборки — 640, как в макете, а не общие 720 для широких окон: в нём одно
   поле и три коротких списка, и лишние восемьдесят точек делали строку примеров
   длиннее, чем её читают. */
.modal.wide.build-modal{width:min(640px,calc(100vw - 2*var(--s-4)))}

/* Ряд «Снять · Из файлов» — только на телефоне (см. import.js). На компьютере
   страницы приносят перетаскиванием и Ctrl+V, камеры там нет. */
.md-phone{display:none}

/* ---------- Окно сборки на телефоне ----------

   На 390 окно превращается в экран. Уменьшенный настольный диалог оставлял
   поля по 24 с каждой стороны, подвал в две колонки и «Собрать» ростом 38
   рядом с «Отменой» — а это единственное действие экрана, и нажимают его
   большим пальцем. Просьба, страницы и настройки листаются в середине, кнопка
   стоит внизу и не уезжает вместе с ними.

   Подвал разворачивается в столбик: «соберётся примерно 8 заданий · останется
   99 действий из 100» — это последствие нажатия, и читают его до кнопки, а не
   сбоку от неё. */
@media(max-width:640px){
  #importScrim{padding:0}
  .modal.wide.build-modal{width:100%;max-width:none;height:100dvh;max-height:none;border-radius:0}
  .build-modal .mhead{padding:var(--s-4) var(--s-4) 0}
  .build-modal .mbody{padding:var(--s-3) var(--s-4) var(--s-4)}
  .build-modal .mfoot{grid-template-columns:1fr;gap:var(--s-2);padding:var(--s-3) var(--s-4)
    calc(var(--s-3) + env(safe-area-inset-bottom))}
  .build-modal .mfoot-left{flex-wrap:wrap}
  /* «Отмена» рядом с главным действием на телефоне лишняя: окно закрывают
     крестом сверху, а место в нижнем ряду стоит дороже. */
  .build-modal .mfoot-btns>.btn:not(.primary){display:none}
  .build-modal .mfoot-btns{display:grid}
  .build-modal .mfoot-btns .btn.primary{min-height:54px;justify-content:center;font-size:var(--t-lg)}
  /* Кегль поля — 16: ниже него iOS сам приближает страницу при попадании в
     него и обратно не отдаляет. Остальное в окне поднимаем до 13, чтобы разрыв
     был в три пункта, а не в три с половиной от самого мелкого: подписи полей,
     обещание и кнопки страниц стояли на 12,5 и рядом с полем выглядели
     сносками. Высота поля меньше — подсказка в нём теперь короткая. */
  .build-modal #aiInstr{min-height:96px;font-size:var(--t-lg);line-height:1.45}
  .build-modal .mat-drop,.build-modal .gen-f label,.build-modal #imPromise,
  .build-modal .md-phone .btn,.build-modal .rv-hint{font-size:var(--t-base)}
  /* Перетаскивание и Ctrl+V на телефоне не работают — вместо них две кнопки. */
  .build-modal .md-how,.build-modal .md-files{display:none}
  .build-modal .md-phone{display:flex;width:100%;gap:var(--s-2);margin-top:var(--s-2)}
  .build-modal .md-phone .btn{flex:1;min-height:44px;justify-content:center}
  /* Уровень и объём друг под другом: в строку они встают только на широком.
     flex:0 0 auto обязателен — базовое .gen-f{flex:1 1 150px} в колонке тянет
     поля по высоте, и между «Уровнем» и «Объёмом» вырастала пустая треть
     экрана. */
  .build-modal .gen-opts{flex-direction:column;align-items:stretch;gap:var(--s-3)}
  .build-modal .gen-f{width:100%;flex:0 0 auto}
  .build-modal .gen-size .onepick{flex:1;min-height:44px;text-align:center}
}
.build-modal #aiInstr{min-height:84px}
.build-modal .mat-zone{padding:var(--s-2) var(--s-3)}
.build-modal .mat-drop{text-align:left}
/* Место будущих блоков — пока идёт сборка. Серые плашки в листе и серые строки
   в структуре: по ним видно, что урок ещё не кончился, а пустое место под
   последним блоком от конца урока не отличить. */
.blk-skel{display:flex;flex-direction:column;gap:var(--s-2);margin-top:var(--s-2)}
.blk-skel>i{display:block;height:52px;border-radius:var(--r-2);background:var(--surface-2);
  animation:skelPulse 1.6s ease-in-out infinite}
.blk-skel>i:nth-child(2){animation-delay:.15s}
.blk-skel>i:nth-child(3){animation-delay:.3s}
.rail-skel{height:26px;border-radius:var(--r-1);background:var(--surface-2);margin:2px 0;
  animation:skelPulse 1.6s ease-in-out infinite}
.rail-run{display:flex;align-items:center;gap:var(--s-2);padding:6px 4px;
  font-size:var(--t-sm);color:var(--muted)}
.rail-run>i{width:12px;height:12px;border-radius:var(--r-pill);flex-shrink:0;
  border:2px solid var(--line);border-top-color:var(--marker);animation:spin .8s linear infinite}
/* Счётчик пришедших блоков в шапке структуры: «3 из ~9». Тильда не украшение —
   точного числа не знает и сама модель. */
.rail-head .rail-n{font-variant-numeric:tabular-nums;font-size:var(--t-label);color:var(--muted);
  margin-left:var(--s-2)}
/* Подпись под полосой хода: ждать не нужно, лист живой. */
.ai-panel-note{font-size:var(--t-sm);color:var(--muted);margin-top:var(--s-2)}
/* Язык урока у кнопки сборки на первом экране: подпись, значение и — пока язык
   один — приглашение добавить второй. */
.sa-lang{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap}
.sa-lang-one{font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
/* Три списка в ряд: уровень, объём, язык. Ряд — сам .gen-opts (флекс и
   промежуток у него уже есть), поля тянутся поровну. На узком экране
   переносятся, но прячутся — никогда: их видно сразу, в этом и была правка. */
.gen-f{min-width:0;flex:1 1 150px}
.gen-f .usel{width:100%}
/* Подпись «ко странице» перед примерами: они говорят не про урок вообще, а про
   то, что взять с приложенной страницы. */
.rv-lab{font-variant-numeric:tabular-nums;font-size:var(--t-label);letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted);align-self:center;margin-right:var(--s-1)}
.build-modal .mat-links{justify-content:flex-start;gap:var(--s-3);margin-top:var(--s-1)}
.build-modal .status:empty{display:none}
.build-modal #imQuota{margin-right:auto;font-size:var(--t-sm)}
.build-modal #imQuota.bad{color:var(--err)}
.gen-note{font-size:var(--t-sm);color:var(--muted);line-height:1.5}
/* Заметка и ссылка «настроить» — в одну строку, а не столбиком: как flex-колонка
   ряда настроек она растягивала кнопку на всю ширину и центрировала слово. */
.gen-opts>.gen-note{flex-direction:row;align-items:baseline;gap:6px}
.gen-note .more-link{padding:0;font-size:var(--t-sm)}
.gen-opts{align-items:flex-end}
.gen-opts .usel{min-width:168px}
.mat-item.failed{border-color:var(--err)}

/* Языки — выпадающими списками: одна строка на язык, слово на каждое
   действие. Плашки с тремя действиями на одну были короче, но что нажимать,
   было неясно. */
.lang-row{display:inline-flex;align-items:center;gap:var(--s-2)}
.lang-row .usel{min-width:168px}
.lang-rows{display:flex;flex-direction:column;gap:var(--s-2);align-items:flex-start}
.lang-pick{display:inline-block;min-width:150px}
.lang-pick .usel-btn{padding:5px var(--s-3);font-size:var(--t-sm)}
.lang-row .more-link{white-space:nowrap}
/* Язык в настройках — плашка во всю ширину: код, название, действие. Выпадающий
   список остался один, в строке добавления, где он и нужен. С первого входа
   список языков ушёл совсем: там спрашивают язык одного урока, а не список
   преподавателя. */
.set-body .lang-rows{display:grid;gap:var(--s-2);margin-top:18px;align-items:stretch}
.set-body .lang-row{display:flex;align-items:center;gap:var(--s-3);background:var(--paper);
  border-radius:var(--r-1);padding:var(--s-3) 14px}
.lang-chip{width:30px;height:30px;flex-shrink:0;display:inline-flex;align-items:center;
  justify-content:center;border-radius:var(--r-1);background:var(--surface);box-shadow:var(--sh-1);
  font-family:var(--font-body);font-weight:700;font-size:var(--t-label);color:var(--ink-2);
  font-variant-numeric:tabular-nums}
.lang-name{flex:1;min-width:0;font-family:var(--font-head);font-weight:600;font-size:var(--t-md)}
.lang-main{font-family:var(--font-body);font-weight:600;font-size:var(--t-label);letter-spacing:.08em;
  color:var(--ink);background:var(--surface-2);border-radius:var(--r-pill);padding:var(--s-1) 10px;
  white-space:nowrap}
.lang-add .usel-btn{border-style:dashed;background:none;box-shadow:none;height:auto;
  padding:11px 14px;font-family:var(--font-head);font-weight:600;font-size:var(--t-base);
  color:var(--muted)}
.lang-add .usel-btn:hover{background:var(--paper);border-color:var(--line);color:var(--ink)}
.lang-add .usel-chev{display:none}

/* ---------- Панель хода сборки в уроке ----------
   Стоит там, куда встают блоки, и липнет к верху экрана, пока они приходят:
   полоса с процентами видна всегда, блоки собираются под ней. */
.ai-panel{position:sticky;top:70px;z-index:6;background:var(--surface);color:var(--ink);
  border:1px solid var(--marker);border-radius:var(--radius);padding:var(--s-4) var(--s-5);
  margin:var(--s-3) 0;box-shadow:var(--shadow)}
.ai-panel-head{display:flex;align-items:center;gap:var(--s-3)}
.ai-panel-t{flex:1;min-width:0}
.ai-panel-t b{font-family:var(--font-head);font-size:var(--t-lg);display:block;letter-spacing:-.01em}
.ai-panel-pct{font-variant-numeric:tabular-nums;font-size:24px;font-weight:600;min-width:70px;text-align:right;
  font-variant-numeric:tabular-nums}
.ai-track{height:10px;border-radius:var(--r-pill);background:var(--surface-2);margin-top:var(--s-3);overflow:hidden}
/* Шаги под полосой: сделанный с галкой, идущий с кольцом, будущий приглушён.
   До этого была одна подменяемая строка — видно только текущее, а сколько
   всего и что позади, приходилось держать в голове. */
.ai-steps{display:grid;gap:7px;margin-top:14px;font-size:var(--t-md)}
.ai-step{display:flex;align-items:center;gap:9px;color:#B4B1A8}
.ai-step>i{width:14px;height:14px;border-radius:var(--r-pill);flex-shrink:0;
  background:var(--surface-2);position:relative}
.ai-step.done{color:var(--muted)}
.ai-step.done>i{background:var(--ok-bg)}
/* Галка линиями, а не символом: у шрифта своя ширина галки, и в кружке 14px
   она встаёт то по центру, то мимо. */
.ai-step.done>i::after{content:'';position:absolute;left:4.5px;top:2px;
  width:3px;height:6px;border:solid var(--ok);border-width:0 1.6px 1.6px 0;transform:rotate(45deg)}
.ai-step.now{color:var(--ink)}
.ai-step.now>i{background:none;border:2px solid var(--marker-soft);
  border-top-color:var(--marker);animation:spin 700ms linear infinite}
.ai-fill{height:100%;background:var(--marker);border-radius:var(--r-pill);transition:width var(--dur-slow) var(--ease)}
.ai-bar b{font-variant-numeric:tabular-nums}

/* Та же панель — плавающей внизу экрана: для действий с ИИ, у которых нет
   потока (aiWait в core.js). Место и слой — как у тоста. */
.ai-panel.floating{position:fixed;left:50%;bottom:24px;top:auto;margin:0;
  width:min(560px,calc(100vw - 32px));z-index:190;opacity:0;pointer-events:none;
  transform:translateX(-50%) translateY(16px);transition:opacity var(--dur-base) var(--ease),transform var(--dur-base) var(--ease)}
.ai-panel.floating.on{opacity:1;pointer-events:auto;transform:translateX(-50%)}
/* На телефоне панель хода поднимается над нижней полосой конструктора: обе
   закреплены у нижнего края, и панель ложилась поверх «Выдать ученику».
   Правило стоит здесь, а не в общем телефонном блоке выше по файлу: у медиа-
   запроса нет своего веса, и объявление .ai-panel.floating из этих строк
   выигрывало у него просто потому, что идёт позже. */
@media(max-width:640px){
  .ai-panel.floating{left:var(--s-4);right:var(--s-4);width:auto;
    bottom:calc(74px + env(safe-area-inset-bottom));transform:translateY(16px)}
  .ai-panel.floating.on{transform:none}
}

/* ---------- Просмотр страницы из окна сборки ----------
   Рассмотреть, не обрезая: страница целиком, по нажатию — настоящий размер. */
/* ---------- Просмотр страницы учебника ----------
   Здесь нет окна. Белый лист учебника лежал на белой бумаге окна, та — на
   светлом затемнении, и границ самой страницы было не найти. Гаснет всё:
   затемнение глубокое, бумаги под страницей нет, светлое пятно на экране одно —
   сама страница. Шапка и миниатюры лежат прямо на затемнении, поэтому набраны
   светлым по тёмному. */
.mat-view{background:rgba(12,14,18,.86)}
.mat-view .mat-view-modal{width:min(1100px,calc(100vw - 2*var(--s-4)));max-height:92vh;
  display:flex;flex-direction:column;gap:var(--s-3);background:none;box-shadow:none;
  border:none;padding:var(--s-3) 0;position:relative}
.mat-view-head{display:flex;align-items:center;gap:var(--s-2);flex-wrap:wrap;color:#F2F1EE}
.mat-view-head b{font-family:var(--font-head);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40%}
.mat-view-head .small{color:rgba(255,255,255,.6)}
.mat-view-head .icon-btn{color:#F2F1EE}
.mat-view-head .icon-btn:hover{background:rgba(255,255,255,.12)}
/* Страница тянется по высоте окна: ради неё окно и открыли. */
.mat-view-scroll{flex:1 1 auto;min-height:0;overflow:auto;text-align:center}
.mat-view-scroll img{display:inline-block;max-width:100%;max-height:100%;cursor:zoom-in;
  vertical-align:top;border-radius:var(--radius-sm);box-shadow:0 18px 48px rgba(0,0,0,.5)}
/* Стрелки — на краях затемнения по центру высоты, у самих краёв страницы. */
.mat-arrow{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;
  border:none;border-radius:var(--r-pill);background:rgba(255,255,255,.14);color:#F2F1EE;
  font-size:var(--t-lg);cursor:pointer;display:flex;align-items:center;justify-content:center;
  transition:background var(--dur-fast) var(--ease)}
.mat-arrow:hover{background:rgba(255,255,255,.26)}
.mat-arrow.prev{left:calc(-1 * var(--s-5) - 22px)}
.mat-arrow.next{right:calc(-1 * var(--s-5) - 22px)}
@media(max-width:900px){.mat-arrow.prev{left:var(--s-2)}.mat-arrow.next{right:var(--s-2)}}
/* Полоса миниатюр: прыгнуть к нужной странице и поменять порядок тем же
   перетаскиванием, что в самом окне сборки. */
.mat-strip{display:flex;gap:var(--s-2);justify-content:center;flex-wrap:wrap;flex-shrink:0}
.mat-thumb{width:52px;height:64px;padding:0;border:2px solid transparent;border-radius:var(--r-1);
  overflow:hidden;background:none;cursor:pointer;opacity:.6;
  transition:opacity var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)}
.mat-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.mat-thumb:hover{opacity:1}
.mat-thumb.on{opacity:1;border-color:#F2F1EE}
.mat-thumb.dragging{opacity:.35}
.mat-view-scroll img.zoomed{max-width:none;max-height:none;cursor:zoom-out}
.mat-item img{cursor:zoom-in}

/* Флаг у названия языка: 20×14, со скруглением и тонким кантом, чтобы белые
   полосы французского и итальянского не сливались с фоном. */
.flag{display:inline-block;width:20px;height:14px;border-radius:2px;overflow:hidden;vertical-align:-2px;
  box-shadow:0 0 0 1px rgba(0,0,0,.12);flex-shrink:0}
.flag svg{display:block;width:100%;height:100%}
.usel-ic{display:inline-flex;align-items:center;flex-shrink:0}
.usel-btn .usel-ic{margin-right:calc(-1*var(--s-1))}


/* =============== Телефон: кабинет, экран шага, занятие ===============
   Хендофф v3, «Телефон». Порог у платформы один — 640px, второго не заводим.
   Макеты нарисованы в 390; на 320–430 всё держится флексом и процентами. */

/* Сшитые строки без просветов. Один список, а не стопка карточек: между двумя
   строками с зазором глаз ставит границу раздела, которой там нет. */
.grp{display:grid;gap:1px;background:var(--line);border-radius:var(--r-2);overflow:hidden}
.grp>*{background:var(--paper);padding:14px var(--s-4);display:flex;align-items:center;
  justify-content:space-between;gap:var(--s-3);min-height:56px;width:100%;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:inherit;
  border:none;text-align:left;cursor:pointer}
.grp>*:hover{background:var(--surface)}
.grp>.picked{background:var(--surface);box-shadow:inset 3px 0 0 var(--ink)}
.grp-right{font-family:var(--font-body);font-weight:400;font-size:13px;color:var(--muted);
  font-variant-numeric:tabular-nums;white-space:nowrap}

/* Работа к сдаче. На широком экране — строка с действием справа, на телефоне
   карточка с рельсой слева: красная у просроченного, маркер у остального.
   Плашки «просрочено» в строке больше нет — её работу делают рельса и плашка
   в заголовке раздела. */
.todo-card{background:var(--surface);border-radius:var(--r-2);padding:var(--s-3) var(--s-4);
  box-shadow:inset 3px 0 0 var(--marker),var(--sh-1);margin-bottom:var(--s-2);cursor:pointer;
  display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px var(--s-3);align-items:center;
  transition:box-shadow var(--dur-fast) var(--ease)}
.todo-card:hover{box-shadow:inset 3px 0 0 var(--marker),var(--sh-2)}
.todo-card.late{box-shadow:inset 3px 0 0 var(--err),var(--sh-1)}
.todo-card.late:hover{box-shadow:inset 3px 0 0 var(--err),var(--sh-2)}
.tc-title{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);letter-spacing:-.01em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tc-sub{grid-column:1;font-size:var(--t-sm);color:var(--muted)}
.todo-card.late .tc-sub{color:var(--err);font-weight:600}
.tc-go{grid-column:2;grid-row:1 / 3;white-space:nowrap}

/* Плашка «1 просрочено» в заголовке раздела и кнопка «Повторить карточками» —
   только на телефоне: на большом экране просроченное метит своя строка, а до
   словаря есть меню слева. */
.sec-due,.deck-go{display:none}

/* Подсказка над банком слов: слово встаёт в пропуск одним нажатием, и об этом
   надо сказать — само по себе нажатие ничем не подписано. */

/* Лотки телефонных раскладок на широком экране не показываются вовсе. */
.step-head,.step-bar,.step-foot,.step-done,.class-bar{display:none}
.step-head[hidden],.step-bar[hidden],.step-foot[hidden],
.step-done[hidden],.class-bar[hidden]{display:none}
/* На экране шага лист прячется поблочно (class.js: paintStepList), а у этих
   двоих display задан правилом — атрибута hidden им мало. */
.note-insert[hidden],.hw-part[hidden]{display:none}

/* Лист отправки работы и оглавление: содержимое общего листа снизу (openSheet
   в core.js). Свой лист под это не заводим. */
.sheet-t{font-size:var(--t-md);line-height:1.5;color:var(--ink-2);margin-top:var(--s-2)}
.sheet-sum{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);
  font-size:var(--t-md);color:var(--muted);padding:var(--s-3) 0;margin-top:var(--s-3);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.sheet-sum b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.sheet-warn{background:var(--marker-soft);border-radius:var(--r-1);
  padding:14px var(--s-4);margin-top:var(--s-3)}
.sw-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--marker-ink)}
.sw-s{font-size:var(--t-sm);color:var(--marker-ink);opacity:.75;margin-top:3px}
.sw-back{margin-top:var(--s-3)}
.sheet-main{width:100%;justify-content:center;height:52px;margin-top:var(--s-4);
  border-radius:var(--r-1)}
.sheet-later{display:block;width:100%;border:none;background:none;cursor:pointer;
  font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink-2);
  padding:14px 0 var(--s-2)}
.step-row,.flow-row{display:flex;align-items:center;gap:var(--s-3)}
.ex-kind{display:none}   /* тип задания — только над шагом на телефоне */
.step-toc[hidden]{display:none}
.sr-num,.fr-num{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);flex:0 0 22px}
.sr-name,.fr-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sr-st{font-size:var(--t-sm);color:var(--muted);flex:0 0 auto}
/* Пустое задание метим маркером, а не красным: ученик до него не дошёл, это
   не ошибка. */
.sr-st.empty{color:var(--marker-ink);font-weight:600}
.fr-now{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--marker-ink);background:var(--marker-soft);border-radius:var(--r-pill);padding:3px 7px}
.fr-ok{color:var(--ok);font-size:13px}
.flow-row.now{background:var(--marker-soft);box-shadow:inset 3px 0 0 var(--marker)}

@media(max-width:640px){
  /* Тихий текст на тёмном листе внутри светлой страницы. Ни один токен роли
     эту работу не делает: --muted на чернилах не читается. Локально, в блоке
     телефона, а не в :root — роль есть только у этих листов. */
  :root{--plate-muted:#A8A6A0;--sh-plate:0 12px 30px -14px rgba(23,26,33,.5)}

  /* Счётчик несданного у «Домашки». Жёлтый законный: счётчик в меню — третье
     значение маркера. */
  .mn-count{display:inline-block;font-family:var(--font-body);font-variant-numeric:tabular-nums;
    font-size:9px;font-weight:700;color:var(--ink);background:var(--marker);
    border-radius:var(--r-pill);padding:1px 5px;margin-left:5px;vertical-align:1px}

  /* Ближайшее занятие — тёмным листом. Первый экран кабинета открывают ради
     одной строки, и лист отделяет её от всего остального сильнее, чем тень. */
  .next-card{background:var(--c-ink);border-radius:var(--r-2);padding:20px;
    box-shadow:var(--sh-plate)}
  .next-card .eyebrow{color:var(--marker)}
  .next-card .nc-when{color:var(--c-paper);font-size:26px;letter-spacing:-.03em;line-height:1.1}
  .next-card .nc-what,.next-card .small.muted{color:var(--plate-muted)}
  /* Жёлтый ореол на тёмном листе не читается: идущее занятие метит точка
     маркером в eyebrow, она там уже стоит. */
  .next-card.is-live{box-shadow:var(--sh-plate)}
  /* На тёмном листе главное действие светлое — правило v3. */
  .next-card .btn.primary{background:#F2F1EE;color:var(--c-ink);border-radius:var(--r-1);
    padding:15px;font-size:var(--t-lg);width:100%;justify-content:center;margin-top:var(--s-4)}

  /* Просроченное живёт рельсой на карточке и плашкой в заголовке: красная
     полоса поверх экрана забирала первый экран у занятия, а сдавать всё равно
     идут через карточку. */
  .late-line{display:none}
  .sec-due{display:inline-flex;height:auto;padding:3px 7px;font-size:var(--t-label);font-weight:600;
    text-transform:uppercase;letter-spacing:.06em}

  .todo-card{display:block;padding:15px var(--s-4)}
  .tc-title{white-space:normal}
  .tc-sub{margin-top:var(--s-1)}
  .tc-go{width:100%;justify-content:center;margin-top:var(--s-3);
    border-radius:var(--r-1);padding:13px;font-size:var(--t-md)}

  /* Слова с прошлого урока — карточкой: ряд плашек без листа под ним читался
     продолжением заголовка. */
  .deck-card{background:var(--surface);border-radius:var(--r-2);padding:18px;
    box-shadow:var(--sh-1);margin-top:var(--s-3)}
  .deck-card .deck-word,.deck-card .deck-more{font-family:var(--font-head);font-size:var(--t-md);
    font-weight:600;padding:10px var(--s-4)}
  .deck-go{display:flex;width:100%;justify-content:center;background:var(--paper);
    border-radius:var(--r-1);padding:var(--s-3);font-size:var(--t-md);font-weight:600;
    box-shadow:inset 0 0 0 1px var(--line);margin-top:14px}

  /* ---------- Экран шага ----------
     Шапка платформы уступает место шапке работы: наверху — где я и как выйти,
     внизу — что сделать, между ними одно задание. */
  body.step-mode>.topbar,body.step-mode .stu-bar{display:none}
  body.step-mode .class-grid{padding:0 0 96px}
  body.step-mode .class-canvas{padding:0 var(--s-4)}
  /* Лист урока во весь экран, без своей рамки: рамка внутри рамки телефона
     забирает поля у самого задания. Фон снимаем с !important: applyTheme
     (core.js) красит лист строкой в style, и без этого бумага листа
     выглядывала из-под карточки задания полосой. */
  body.step-mode .lesson-sheet{background:none!important;box-shadow:none;border:none;padding:0}
  body.step-mode .card.cls-host{background:none;box-shadow:none;border:none;padding:0}

  .step-head{display:flex;align-items:center;gap:var(--s-3);padding:2px var(--s-4) var(--s-3)}
  .step-close{width:34px;height:34px;flex:0 0 auto;display:flex;align-items:center;
    justify-content:center;border-radius:var(--r-1);background:var(--surface-2);
    color:var(--ink-2);font-size:var(--t-md);text-decoration:none}
  .step-mid{flex:1;min-width:0}
  .step-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-md);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .step-of{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--muted);margin-top:1px}
  /* «Все» открывает оглавление работы — это кнопка, а не подпись, и попадать в
     неё надо не целясь: своя высота и поля по бокам, а не голое слово в 16
     пикселей. */
  .step-all{flex:0 0 auto;border:none;background:none;cursor:pointer;min-height:44px;
    padding:0 var(--s-2);margin-right:calc(var(--s-2) * -1);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-sm);color:var(--marker-ink)}
  /* Полоса хода и словами, и графикой: на 390 она слишком тонкая, чтобы
     читаться одна, а «задание 3 из 12» без неё не показывает остатка. */
  .step-bar{display:flex;gap:3px;padding:0 var(--s-4) 20px}
  .step-bar i{height:4px;border-radius:var(--r-pill)}
  .step-bar .sb-done{background:var(--ink)}
  .step-bar .sb-rest{background:var(--line)}

  .step-foot{position:fixed;left:0;right:0;bottom:0;z-index:50;
    border-top:1px solid var(--line);background:var(--surface);
    padding:var(--s-3) var(--s-4) calc(var(--s-2) + env(safe-area-inset-bottom));
    display:flex;align-items:center;gap:10px}
  .step-back{width:52px;height:52px;flex:0 0 auto;border:none;border-radius:var(--r-1);
    background:var(--surface-2);color:var(--ink-2);font-size:17px;cursor:pointer}
  .step-go{flex:1;height:52px;display:flex;align-items:center;justify-content:center;
    border:none;border-radius:var(--r-1);background:var(--ink);color:var(--paper);
    font-family:var(--font-head);font-size:var(--t-lg);font-weight:600;cursor:pointer;
    text-decoration:none}
  /* Незаполненный шаг: кнопка гаснет, но не запирается — она пропускает
     задание, а не отказывается работать. Модификатор не .empty: так
     называется пустое состояние страницы, и его правило (250 в высоту, место
     под картинку) раздувало кнопку на полэкрана. */
  .step-go.skip{background:var(--surface-2);color:var(--ink-2);
    box-shadow:inset 0 0 0 1px var(--line-2)}

  /* Вариант ответа: белый с кантом, выбранный — сплошной тёмный с галочкой
     маркером. Радиокружок убран, отметку несёт заливка. */
  body.step-mode .opt{background:var(--surface);border:none;border-radius:var(--r-1);
    box-shadow:inset 0 0 0 1px var(--line);padding:var(--s-4);font-size:15.5px;
    line-height:1.4;margin-bottom:9px;min-height:48px}
  body.step-mode .opt .radio{display:none}
  body.step-mode .opt.selected{background:var(--ink);color:var(--paper);box-shadow:none}
  body.step-mode .opt.selected:not(.ok):not(.err)::after{content:'✓';margin-left:auto;
    color:var(--marker);font-size:14px}
  /* Вердикт сильнее выбора: зелёное и красное здесь — данные, и заливка
     выбранного их перекрывать не должна. */
  body.step-mode .opt.ok{background:var(--ok-bg);color:var(--ink);
    box-shadow:inset 0 0 0 1px var(--ok)}
  body.step-mode .opt.err{background:var(--err-bg);color:var(--ink);
    box-shadow:inset 0 0 0 1px var(--err)}

  /* Банк слов — просто ряд чипов над заданием: подложка с пунктиром делала из
     него ещё одну карточку внутри карточки. */
  body.step-mode .pool{border:none;background:none;padding:0;min-height:0;margin:var(--s-3) 0 0}
  body.step-mode .chip{background:var(--surface);border:none;border-radius:var(--r-pill);
    box-shadow:inset 0 0 0 1px var(--line-2);padding:var(--s-3) 18px;font-size:var(--t-lg);
    font-weight:600;min-height:44px}

  /* Квитанция: то же место, тот же адрес, другое состояние. */
  .step-done{display:block;padding:var(--s-5) 0 0}
  .sd-mark{width:52px;height:52px;border-radius:var(--r-pill);background:var(--ok-bg);
    color:var(--ok);display:flex;align-items:center;justify-content:center;font-size:var(--t-h1)}
  .sd-title{font-family:var(--font-head);font-weight:700;font-size:30px;
    letter-spacing:-.03em;margin-top:20px}
  .sd-text{font-size:var(--t-lg);line-height:1.55;color:var(--ink-2);margin-top:10px}
  .sd-sum{background:var(--surface);border-radius:var(--r-2);padding:18px;
    box-shadow:var(--sh-1);margin-top:20px;display:grid;gap:var(--s-2)}
  .sd-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3);
    font-size:var(--t-md)}
  .sd-row span{color:var(--muted)}
  .sd-row b{font-weight:600;font-variant-numeric:tabular-nums}

  /* ---------- Шаговый режим по макетам 12a и 12d ----------
     Разделы занятия на экране шага не видны: шаг — одно задание, и заголовки
     «Урок · Домашка» над ним читались бы ещё одним уровнем. Заметка к заданию
     встаёт под его карточкой. */
  body.step-mode .cls-sec{border:none}
  body.step-mode .cls-sec>.cs-head{display:none}
  body.step-mode .cls-sec>.cs-body{display:flex;flex-direction:column}
  body.step-mode .cls-sec>.cs-body>.step-note{order:2}
  body.step-mode .note-insert{display:none}
  body.step-mode .class-grid{padding-bottom:calc(var(--s-6) * 4)}
  body.step-toc .class-grid{padding-bottom:calc(var(--s-6) * 5)}
  body.step-mode .class-canvas{padding:var(--s-3) var(--s-4) 0}

  .step-head{display:block;position:sticky;top:0;z-index:40;padding:0;background:var(--paper);
    border-bottom:1px solid var(--line)}
  .step-top{display:flex;align-items:center;gap:var(--s-2);min-height:48px;padding:0 var(--s-2) 0 var(--s-4)}
  .step-dot{flex:0 0 auto;width:7px;height:7px;border-radius:var(--r-pill);background:var(--sm-faint)}
  .step-dot.on{background:var(--ok)}
  .step-name{font-size:var(--t-lg);letter-spacing:-.01em}
  .step-more{flex:0 0 auto;width:44px;height:44px;border:none;background:none;cursor:pointer;
    border-radius:var(--r-1);font-size:var(--t-lg);color:var(--ink-2)}
  .step-exit,.step-list{position:relative;flex:0 0 auto;display:inline-flex;align-items:center;height:36px;
    padding:0 var(--s-3);border:1px solid var(--line-2);border-radius:var(--r-1);background:var(--surface);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink);
    text-decoration:none;cursor:pointer}
  .step-exit::after,.step-list::after{content:'';position:absolute;inset:-4px}
  /* «Преподаватель отметил задание» — жёлтым: это пришло от преподавателя.
     Имя не .step-mark: оно занято кружком в списке шагов, и тот делал из
     строки эллипс. Сверху строку отбивает линия шапки, снизу — маркер. */
  .step-where{display:flex;align-items:center;gap:var(--s-3);min-height:44px;padding:0 var(--s-4);
    background:var(--marker-soft);border-top:1px solid var(--line);font-size:var(--t-base);color:var(--marker-ink)}
  .step-head:has(.step-where){border-bottom-color:var(--marker)}
  .step-where span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .step-where-go{flex:0 0 auto;height:36px;padding:0 var(--s-3);border:none;border-radius:var(--r-1);cursor:pointer;
    background:var(--ink);color:var(--paper);font-family:var(--font-head);font-weight:600;font-size:var(--t-base)}
  .step-bar{gap:var(--s-1);padding:var(--s-3) var(--s-4) 0}
  .step-bar i{flex:1;height:4px;border-radius:var(--r-pill);background:var(--line-2)}
  .step-bar i.sb-rest{background:var(--line-2)}
  .step-bar i.sb-past{background:var(--sm-faint)}
  .step-bar i.sb-now{background:var(--ink)}

  /* Карточка задания: номер жетоном, тип меткой, формулировка крупно */
  body.step-mode .card.cls-host{background:var(--surface);border-radius:var(--r-3);padding:var(--s-4);
    box-shadow:var(--sh-2)}
  body.step-mode .ex-head{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2) var(--s-3)}
  body.step-mode .ex-badge{border-radius:var(--r-pill);background:var(--surface-2);padding:var(--s-1) var(--s-3);
    font-size:var(--t-sm);font-weight:600;color:var(--muted)}
  body.step-mode .ex-kind{display:inline;font-size:var(--t-label);font-weight:600;letter-spacing:.12em;
    text-transform:uppercase;color:var(--muted)}
  body.step-mode .ex-instr{flex-basis:100%;order:3;font-weight:700;font-size:var(--t-lesson-h);
    line-height:1.25;letter-spacing:-.02em}
  body.step-mode .step-note{margin-top:var(--s-3)}
  body.step-mode .step-note .sticky.peer::before{content:'От преподавателя';display:block;margin-bottom:var(--s-1);
    font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--marker-ink)}

  .step-foot{flex-direction:column;align-items:stretch;gap:0;background:var(--paper);
    padding:var(--s-2) var(--s-4) calc(var(--s-3) + env(safe-area-inset-bottom))}
  .step-acts{display:flex;align-items:center;gap:var(--s-2)}
  .step-back{background:var(--surface);box-shadow:var(--sh-1)}
  .step-back[disabled]{opacity:.4;cursor:default}
  .step-go{gap:var(--s-2)}
  .step-count{border-radius:var(--r-pill);background:var(--ink-2);padding:0 var(--s-2);
    font-size:var(--t-sm);font-weight:600;line-height:20px}
  .step-cap{margin-top:var(--s-2);text-align:center;font-size:var(--t-sm);color:var(--muted)}

  /* Экран задания — на подложке темнее бумаги: белая карточка на ней читается
     листом, а не рамкой. Оглавление остаётся на бумаге — это страница раздела.
     Подложка одна на рабочие экраны телефона — шаг занятия и конструктор (его
     блок в конце файла). В тёмном хроме и в высоком контрасте подложка — сама
     бумага: карточка там и так светлее её. Стол урока (html.on-lesson body) на
     шаге не действует: листа здесь нет, карточки лежат прямо на хроме, как
     шапка и полоса действия. */
  :root{--work-ground:#EFEDE7}
  html[data-chrome="dark"],html[data-contrast="high"]{--work-ground:var(--c-paper)}
  body.step-mode.step-toc{background:var(--paper)}
  body.step-mode:not(.step-toc),body.step-mode:not(.step-toc) .step-foot{background:var(--work-ground)}

  /* Поля ответа — 16px: iOS увеличивает страницу на любом поле мельче и назад
     не уменьшает. Пропуск — 46 в высоту, как поле в конструкторе. Заполненный
     пропуск нейтральный, серой подложкой с кантом: зелёного нет, пока ответ не
     проверен. Пропуски в таблице не трогаем — в клетке им и так тесно. */
  body.step-mode .gap-text{font-size:var(--t-lg);line-height:2.1}
  body.step-mode .type-gap:not(.tbl-gap){height:46px;padding:0 var(--s-2);border-radius:var(--r-1);
    background:var(--surface-2);border-bottom:2px solid var(--sm-faint);font-family:var(--font-head);
    font-size:var(--t-lg);vertical-align:middle}
  body.step-mode .type-gap:not(.tbl-gap):focus{background:var(--surface);border-bottom-color:var(--ink);
    box-shadow:inset 0 0 0 1px var(--ink)}
  body.step-mode .type-gap.ok{border-bottom-color:var(--ok)}
  body.step-mode .type-gap.err{border-bottom-color:var(--err)}
  body.step-mode .open-area{min-height:148px;padding:var(--s-3);border-color:var(--line-2);
    border-radius:var(--r-1);background:var(--surface);font-size:var(--t-lg);line-height:1.55}
  body.step-mode .open-area:focus{border-color:var(--ink)}
  body.step-mode .frame-area{font-size:var(--t-lg)}

  /* Оглавление домашки (12d) */
  .step-toc{padding:var(--s-1) 0 0}
  .st-title{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);line-height:1.15;
    letter-spacing:-.03em;color:var(--ink)}
  .st-sub{margin-top:var(--s-1);font-size:var(--t-sm);color:var(--muted)}
  .st-list{margin-top:var(--s-3);background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1);overflow:hidden}
  .st-row{display:flex;align-items:center;gap:var(--s-3);width:100%;min-height:60px;padding:0 var(--s-3);
    border:none;border-bottom:1px solid var(--line);background:none;cursor:pointer;text-align:left;color:var(--ink)}
  .st-row:last-child{border-bottom:none}
  .st-num{flex:0 0 auto;font-size:var(--t-sm);font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums}
  .st-main{flex:1;min-width:0;display:flex;flex-direction:column}
  .st-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .st-state{font-size:var(--t-sm);color:var(--muted)}
  .st-ok{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;
    border-radius:var(--r-pill);background:var(--line);color:var(--ink-2);font-size:var(--t-label)}
  .st-go{flex:0 0 auto;font-size:var(--t-lg);color:var(--muted)}
  .step-send{display:flex;flex-direction:column}
  .step-submit{height:52px;border:1px solid var(--line-2);border-radius:var(--r-1);background:none;cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--muted)}
  .step-submit.ready{border-color:var(--ink);background:var(--ink);color:var(--paper)}
  /* Полоса кабинета в оглавлении — та же, что внизу кабинета, и правило у
     пунктов с ней общее (.mobile-nav): ученик уходит по ней в кабинет, и под
     пальцем она не должна там менять ни кегль, ни высоту. Лежит последней —
     нижнего поля у лотка нет, как у настоящей полосы. */
  .step-nav{display:grid;grid-template-columns:repeat(4,1fr);margin:var(--s-3) calc(-1 * var(--s-4)) 0;
    border-top:1px solid var(--line-2)}
  body.step-toc .step-foot{padding-bottom:env(safe-area-inset-bottom)}

  /* ---------- Полоса занятия у ученика ----------
     Панель хода на 390 не встаёт, а вопрос «где мы сейчас» у ученика тот же.
     Её работу делает лист снизу, а полоса — единственное действие внизу. */
  .class-bar{display:flex;align-items:center;gap:10px;position:fixed;left:0;right:0;bottom:0;
    z-index:50;background:var(--surface);border-top:1px solid var(--line);
    padding:var(--s-3) var(--s-4) calc(var(--s-2) + env(safe-area-inset-bottom))}
  .cb-flow{flex:1;height:52px;display:flex;align-items:center;justify-content:center;
    gap:var(--s-2);border:none;border-radius:var(--r-1);background:var(--ink);
    color:var(--paper);font-family:var(--font-head);font-size:var(--t-lg);font-weight:600;
    cursor:pointer}
  .cb-count{font-variant-numeric:tabular-nums;font-size:var(--t-sm);color:var(--marker-ink);
    background:var(--marker-soft);border-radius:var(--r-pill);padding:2px 7px}

  /* ---------- Полоса преподавателя ----------
     Три кнопки: назад, «Показать NN» с названием следующего блока и номер для
     перехода к любому. Главная — средняя, и она же самая широкая: её нажимают
     каждые несколько минут, не глядя. Название под номером мельче — вслепую
     ведут по нему, а глазами сверяются по цифре. */
  .cb-step,.cb-nth{flex:0 0 auto;min-width:52px;height:52px;border:1px solid var(--line-2);
    background:var(--surface);border-radius:var(--r-1);cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink-2);
    font-variant-numeric:tabular-nums}
  .cb-step[disabled]{opacity:.35;pointer-events:none}
  .cb-show{flex:1 1 auto;min-width:0;height:52px;display:flex;flex-direction:column;
    align-items:flex-start;justify-content:center;gap:1px;padding:0 var(--s-3);
    border:none;border-radius:var(--r-1);background:var(--ink);color:var(--paper);
    cursor:pointer;text-align:left;font-family:var(--font-head)}
  .cb-show-n{font-weight:600;font-size:var(--t-md);white-space:nowrap}
  .cb-show-t{font-weight:500;font-size:var(--t-sm);opacity:.72;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Урок кончился — кнопке нечего показывать. Не гасим её, а убираем вовсе:
     тёмная кнопка без действия обещает шаг, которого нет. */
  .cb-show-end{background:none;color:var(--muted);justify-content:center;
    align-items:center;font-weight:500;font-size:var(--t-sm)}
  /* Где ученик, когда он не там же, где мы: в оглавлении это вторая отметка. */
  .flow-row .fr-peer{font-size:var(--t-label);font-weight:600;color:var(--marker-ink);
    background:var(--marker-soft);border-radius:var(--r-pill);padding:2px 7px;flex-shrink:0}

  /* ---------- Что уходит с экрана занятия ----------
     Панель хода, ошибок и домашки на 390 не встаёт колонкой и ложилась над
     листом урока: до самого материала приходилось прокрутить два экрана. Её
     работу делают полоса внизу и «⋯» в шапке.

     Там же прячется ряд кнопок занятия: пять штук в полосе ростом 52 не
     помещались и вставали столбиком вдоль правого края. */
  .class-grid .tpanel{display:none}
  .topbar .cls-acts{display:none}
  .topbar .cls-more{display:inline-flex}
  /* Шапка занятия — своя: у класса нет ни .app, ни .app-main, и общие правила
     телефона до неё не достают. Она разъезжалась на три ряда высотой 141 при
     положенных 52. Полосу «Подтвердите почту» и переключатель темы отсюда
     убираем: занятие идёт сейчас, а почту подтверждают когда-нибудь, и тему
     листа задаёт сам урок. Остаётся то, без чего вести нельзя: выход, часы,
     «⋯» и «Закрыть». */
  body>.topbar:has(.cls-live){flex-wrap:nowrap;gap:var(--s-2);padding:0 var(--s-4)}
  body>.topbar:has(.cls-live) .verify-bar,
  body>.topbar:has(.cls-live) .chrome-toggle{display:none}
  body>.topbar:has(.cls-live) .top-left{min-width:0;overflow:hidden}
  body>.topbar:has(.cls-live) .top-actions{flex:0 0 auto;flex-wrap:nowrap}
  body>.topbar:has(.cls-live) .top-back{max-width:96px;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  /* Шапка задания: номер, задание и «в домашку». На 390 кнопка не сжимается и
     оставляла заданию 85 пикселей — оно вставало столбиком по слову в строке.
     Кнопка уходит под задание: она про то, что с блоком сделать потом, а
     задание читают сейчас. */
  .ex-head{flex-wrap:wrap}
  .ex-head .ex-instr{flex:1 1 auto;min-width:0}
  /* Кнопок в шапке две — «письменно» и «в домашку», — и столбиком по строке на
     каждую они отодвигали сам вопрос на третье место в карточке. Ставим их
     одной строкой: обе короткие и вдвоём умещаются в ширину телефона. */
  .ex-head .hw-add-btn{flex:0 0 auto;justify-content:flex-start;text-align:left;
    margin-top:var(--s-1);margin-left:0}
  .ex-head .hw-add-btn+.hw-add-btn{margin-left:var(--s-2)}
}
/* Выше 640 «⋯» не нужна: все действия занятия стоят в шапке рядом. Правило
   в своём медиазапросе, а не общее: общее стоит в файле ниже телефонного и
   перебивало бы его на любой ширине. */
@media(min-width:641px){.topbar .cls-more{display:none}}

/* Пульс заглушки: одно дыхание на полторы секунды — заметно, что место занято
   ожиданием, и не мельтешит. */
@keyframes skelPulse{0%,100%{opacity:1}50%{opacity:.55}}


/* ---------- Правила телефона ----------

   Из листа «Lessona v3 — телефон», раздел 05. Две вещи там названы числами, и
   обе до сих пор нарушались по всей платформе, а не в одном месте — поэтому и
   лечатся здесь, а не правкой сорока компонентов.

   Кегль. «Ниже 12 на телефоне не опускаемся нигде», а служебный размер
   платформы — 10.5: им набраны надзаголовки, счётчики, подписи под числами. На
   ноутбуке это работает, на 390 читается с трудом. Поднимаем сам токен: одна
   строка чинит все места разом и не даёт им разойтись потом.

   Цель нажатия. «Ничего нажимаемого ниже 44». Кнопки платформы 34 и 28, значки
   28×28 — пальцем в них попадают через раз. Поднимаем минимальную высоту, не
   трогая ширину: ряды остаются рядами, просто в них становится выше.

   Ссылки внутри текста правило не трогает: «Забыли пароль?» посреди абзаца —
   это не элемент управления, и 44 пикселя высоты под ним разорвали бы фразу. */
@media(max-width:640px){
  :root{--t-label:12px}
  .btn,.btn.sm{min-height:44px}
  .icon-btn{width:44px;height:44px}
  .chip{min-height:44px;display:inline-flex;align-items:center}
  /* Шапка ростом 52: кнопка 44 в неё встаёт, но полям в ней остаётся по
     четыре пикселя, и ряд начинает казаться набитым. Там оставляем 36 —
     это всё ещё крупнее прежних 28, и палец попадает. */
  .topbar .btn,.topbar .btn.sm{min-height:36px}
  .topbar .icon-btn{width:36px;height:36px}
  .verify-bar .vb-act{min-height:36px}
  /* Отметка «учу / знаю» в словаре нажимается — значит это кнопка, и мерить её
     надо как кнопку. Плашка .tag ростом 24 годится там, где она только
     называет состояние; здесь ею состояние меняют. */
  .voc-word .tag[onclick]{min-height:36px;padding:0 var(--s-3)}
  /* Тихие кнопки настроек, «← Кабинет» в шапке, «✧ заметка» в жёлобе урока и
     «в словарь» на стикере — все ростом 20–28. Голосом они и должны остаться
     тихими, а вот попадать в них надо пальцем. */
  .quiet-act,.top-back{min-height:36px}
  .note-insert>button,.sticky .svoc{min-height:36px}
  /* Переключатель 34×20 — его размер, а не промах: менять его нельзя, он и
     читается переключателем. Расширяем только место, по которому попадают. */
  .sw-pill::after{content:'';position:absolute;inset:-12px}
  /* Единственный кегль, прописанный числом мимо токенов, — «✓ пройдено» в
     шапке задания. На телефоне и он поднимается до двенадцати. */
  .ex-done{font-size:12px}
  /* «Показать» пароль стоит внутри поля: поле ростом с палец, а слово в нём —
     нет. Даём ему ту же высоту, что у поля, не трогая вид. */
  .pw-word{min-height:36px}
  /* Остальные тихие кнопки страниц: «Скрыть», «Порядок», «ОПУБЛИКОВАН»,
     «в домашку», «Открыть урок». Все ростом 16–25 — голосом тихие, но нажимают
     их так же пальцем. */
  .more-link,.cat-sort,.pub-chip,.hw-add-btn,.rw-ctx-open{min-height:36px}
  /* Конструктор. «Выделить» в рельсе набрано 10.5 и ростом 21 — поднимаем и
     кегль, и высоту. Кружок «+» между карточками остаётся кружком 24: он
     стоит в зазоре между блоками, и раздувать его — значит раздвинуть весь
     урок. Место нажатия расширяем на всю полосу зазора. */
  .rail-pick{font-size:12px;min-height:36px}
  .insert{height:32px}
  .insert button::after{content:'';position:absolute;left:-40px;right:-40px;top:-8px;bottom:-8px}
}

/* Состояние урока уходит из шапки конструктора на телефоне.

   «ЧЕРНОВИК», «Опубликовать», «сохранено» и стрелка отмены стояли в одну
   строку с «← Уроки» четырьмя разными кеглями и переносились на второй ряд —
   шапка читалась мешаниной. Про черновик теперь говорит нижняя полоса, и
   говорит действием: «Опубликовать урок». Отмена живёт в «⋯». Сохранение
   платформа делает сама и молча.

   Правило стоит в конце файла нарочно: `.top-left #pubState` объявлен ниже
   телефонного блока и с тем же весом, а при равном весе выигрывает тот, кто
   позже. */
@media(max-width:640px){
  .bld-top #pubState,.bld-top #saveState,.bld-top #undoBtn{display:none}
}

/* Список людей в операционке с телефона: имя и почта переносятся, а не
   обрезаются многоточием — обрезанная почта это ровно то, по чему человека и
   опознают. Правило в конце файла по той же причине, что и соседнее выше:
   .row .r-title объявлен ниже и с тем же весом. */
@media(max-width:640px){
  .adm-row .r-title,.adm-row .r-sub{white-space:normal;overflow:visible;text-overflow:clip}
}

/* Тост на телефоне встаёт над закреплёнными полосами: нижняя навигация ученика
   и полоса конструктора живут у самого края, и тост ложился поверх кнопки,
   закрывая ровно то, о чём говорил. Поднимаем на их высоту с запасом.

   Правило в конце файла: .toast объявлен выше и с тем же весом. */
@media(max-width:640px){
  /* Ширина по тексту. При left:50% браузер отводит тексту половину экрана, и на
     390 тост ломался на две строки уже на «Занятие снова запланировано». */
  .toast{bottom:calc(84px + env(safe-area-inset-bottom));
    width:max-content;max-width:calc(100vw - 32px)}
}

/* ---------- Кабинет: работа строкой на телефоне (решение 4a) ----------

   Правило стоит в конце файла нарочно: .todo-card объявлен ниже своего
   телефонного раздела и с тем же весом — там он сетка, и flex ей проигрывал,
   строка оставалась в 120 пикселей вместо шестидесяти.

   Жетон говорит объём работы («на девять заданий или на три»), подпись — срок
   и сколько сделано, стрелка заменяет кнопку: нажимается вся строка, а кнопка
   внутри неё была бы вторым способом сделать то же. */
@media(max-width:640px){
  .todo-card{display:flex;align-items:center;gap:var(--s-3);min-height:60px;
    padding:var(--s-2) var(--s-3) var(--s-2) var(--s-2)}
  .tc-num{display:inline-flex;align-items:center;justify-content:center;
    flex:0 0 auto;min-width:38px;height:38px;padding:0 10px;
    border-radius:var(--r-pill);background:var(--surface-2);color:var(--ink);
    font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);
    font-variant-numeric:tabular-nums}
  /* Просроченная работа метит жетон так же, как рельса метит строку: это цвет
     данных — «уже поздно», — и он тут на своём месте. */
  .todo-card.late .tc-num{background:var(--err-bg);color:var(--err)}
  .tc-main{flex:1;min-width:0}
  .todo-card .tc-sub{margin-top:1px;white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis}
  .todo-card .tc-go{display:none}
  .tc-chev{display:block;flex:0 0 auto;width:7px;height:7px;
    border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
    transform:rotate(-45deg)}
}

/* ---------- Конструктор на телефоне: шапка, разделы, строки, шторка блока ----------
   Кадры 5a, 6a, 6b спеки «телефон 640» и решения владельца 13 сентября. На
   широком экране этих узлов не видно: там путь и кнопки справа в шапке, вкладки
   разделов в рельсе и карточка блока, раскрытая на месте. Блок стоит в конце
   файла, чтобы при равном весе перебивать телефонные правила выше. */
.bld-back,.bld-ttl,.bld-more,.bld-sec,.cover-one{display:none}

@media(max-width:640px){
  /* Шапка (5a): «←», название с состоянием, «Как у ученика», «⋯» */
  .bld-top .brand,.bld-top .top-back,.bld-top .top-sep,.bld-top .top-step,.bld-top .top-title{display:none}
  /* 48 и в одну строку, как у шапок по правилу 1a: общее правило вложенных
     страниц (body>.topbar) разрешает панели переноситься и держит поля по
     вертикали, и шапка конструктора выходила в 61. */
  body>.topbar.bld-top{height:48px;min-height:48px;flex-wrap:nowrap;gap:var(--s-1);padding:0 var(--s-1)}
  .bld-top .top-left{flex:1 1 auto;min-width:0;display:flex;flex-wrap:nowrap;align-items:center;gap:var(--s-1)}
  .bld-top .top-mid{display:flex;align-items:center;gap:var(--s-1)}
  .bld-top .bld-more{width:44px;height:44px}
  .bld-back{display:inline-flex;flex:none;align-items:center;justify-content:center;width:44px;height:44px;
    border-radius:var(--r-1);font-size:var(--t-lg);color:var(--ink-2);text-decoration:none}
  .bld-ttl{display:flex;flex-direction:column;min-width:0;line-height:1.25}
  .bld-ttl b{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.02em;color:var(--ink);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .bld-ttl small{font-size:var(--t-sm);color:var(--muted);white-space:nowrap}
  .bld-more{display:inline-flex;flex:none;align-items:center;justify-content:center;width:44px;height:44px;
    font-size:var(--t-lg)}

  /* Обложка (5a): одна кнопка «Обложка» посреди полосы, способ — в шторке */
  .cover-acts{inset:0;align-items:center;justify-content:center}
  .cover-acts>.btn{display:none}
  .cover-acts>.cover-one{display:inline-flex}

  /* Разделы урока — переключателем над списком */
  .bld-sec{display:flex;margin-top:var(--s-3)}
  .bld-sec .seg{display:flex;width:100%}
  .bld-sec .seg>button{flex:1;justify-content:center;min-height:40px;gap:var(--s-1)}
  .bld-sec .seg i{font-style:normal;font-variant-numeric:tabular-nums;color:var(--muted)}

  /* Строки блоков (6a) — одной карточкой: номер жетоном, тип и размер меткой,
     заметки на полях жёлтым жетоном со счётом, название одной строкой */
  .prows{margin-top:var(--s-3);background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .prow{position:relative;display:flex;align-items:center;gap:var(--s-2);min-height:68px;
    padding:var(--s-2) var(--s-1);border-bottom:1px solid var(--line);background:var(--surface);
    cursor:pointer;-webkit-tap-highlight-color:transparent}
  .prow:first-child{border-radius:var(--r-2) var(--r-2) 0 0}
  .prow:last-child{border-bottom:none;border-radius:0 0 var(--r-2) var(--r-2)}
  .prow:only-child{border-radius:var(--r-2)}
  .pgrip{flex:none;display:flex;align-items:center;justify-content:center;width:24px;height:44px;
    color:var(--sm-faint);font-size:var(--t-md);letter-spacing:-.12em;touch-action:none;cursor:grab;
    -webkit-user-select:none;user-select:none}
  .pmain{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--s-1)}
  .pmeta{display:flex;align-items:center;gap:var(--s-2);min-width:0}
  .pchip{flex:none;border-radius:var(--r-pill);background:var(--surface-2);padding:0 var(--s-2);line-height:22px;
    font-size:var(--t-sm);font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums}
  .ptype{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    font-size:var(--t-sm);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
  .pnote{flex:none;display:inline-flex;align-items:center;height:22px;padding:0 var(--s-2);
    border-radius:var(--r-pill);background:var(--marker-soft);color:var(--marker-ink);
    font-size:var(--t-sm);font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}
  .pmark{flex:none;display:inline-flex;align-items:center;color:var(--muted)}
  .pname{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);color:var(--ink);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pmore{flex:none;width:44px;height:44px;color:var(--muted)}
  .prow .bpick{flex:none;margin-right:var(--s-3)}
  .prow.picked{box-shadow:inset 3px 0 0 var(--ink)}
  /* Заметка, оставшаяся строкой (в конце раздела или в режиме выбора), —
     жёлтая: смысл тот же, что у стикера в уроке */
  .prow.is-note{background:var(--note-bg)}
  .prow.is-note .pgrip,.prow.is-note .ptype,.prow.is-note .pname,.prow.is-note .pmore{color:var(--note-ink)}
  .prow.is-note .pchip{background:var(--surface);color:var(--note-ink)}
  .prow.dragging{z-index:2;box-shadow:var(--sh-2)}
  .prow.drop-before{box-shadow:inset 0 2px 0 var(--ink)}
  .prow.drop-after{box-shadow:inset 0 -2px 0 var(--ink)}
  /* Лист урока в редакторе — без своей рамки (5a): обложка и строки лежат
     карточками прямо на подложке, а рамка вокруг них на 390 была карточкой в
     карточке и забирала по 24 пикселя с каждого бока. Фон — с !important:
     applyTheme (core.js) красит лист строкой в style. В виде «Как у ученика»
     лист остаётся листом. */
  .workspace:not(.student-view) .lesson-sheet{background:none!important;border:none;border-radius:0;
    box-shadow:none;padding:0}
  /* Поля экрана — 16 по бокам и 12 сверху, как в 5a: прежние 24 рассчитаны на
     лист в рамке, а рамки больше нет. */
  .workspace:not(.student-view){padding-top:var(--s-3);padding-left:var(--s-4);padding-right:var(--s-4)}
  body:has(>.workspace:not(.student-view)),
  body:has(>.workspace:not(.student-view)) .bld-bar{background:var(--work-ground)}

  /* Шторка блока (6b, 7l): на всю высоту, список виден краем сверху. Слой ниже
     окон (.scrim — 100) и общих шторок: «Сменить тип», «Поправить с ИИ» и «⋯»
     открываются поверх неё. */
  .bs-wrap{z-index:95}
  .bs-wrap .bs-sheet{top:calc(var(--s-6) * 2);max-height:none;padding:0;overflow:hidden;
    display:flex;flex-direction:column}
  .bs-sheet .sheet-grip{flex:none}
  .bs-in{flex:1;min-height:0;display:flex;flex-direction:column}
  .bs-head{flex:none;display:flex;align-items:center;gap:var(--s-2);
    padding:0 var(--s-2) var(--s-2) var(--s-4);border-bottom:1px solid var(--line)}
  .bs-t{flex:1;min-width:0}
  .bs-name{font-family:var(--font-head);font-weight:700;font-size:var(--t-lg);letter-spacing:-.02em;color:var(--ink)}
  .bs-sub{font-size:var(--t-sm);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .bs-more{flex:none;width:44px;height:44px;font-size:var(--t-lg)}
  .bs-done{flex:none;position:relative;height:36px;padding:0 var(--s-3);border:1px solid var(--line-2);
    border-radius:var(--r-1);background:var(--surface);cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink)}
  .bs-done::after{content:'';position:absolute;inset:-4px}
  .bs-body{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;
    padding:var(--s-3) var(--s-4) calc(var(--s-6) + env(safe-area-inset-bottom))}
  .bs-body .beditor{background:none;border:none;border-radius:0;padding:0;box-shadow:none}
  /* Поля — 46 в высоту и 16px (6b): iOS увеличивает страницу на любом поле
     мельче и назад не уменьшает. И все белые с кантом: серая заливка держала
     контраст на оформленной подложке карточки, а шторка сама белая. Правило
     одно на все поля редактора — у вариантов, пар и строк свои обёртки, и
     перечислять их значило бы пропустить следующую. */
  .bs-body .beditor input:not([type=checkbox]):not([type=radio]),.bs-body .beditor select{min-height:46px;
    font-size:var(--t-lg);background:var(--surface);border-color:var(--line)}
  .bs-body .beditor .field textarea,.bs-body .beditor textarea{font-size:var(--t-lg);
    background:var(--surface);border-color:var(--line)}
  /* Заметки на полях в шторке блока — стопкой под заданием (6b), по правилам
     стопки на занятии (.note-stack); нажатие по заметке открывает её правку */
  .bs-notes{margin-top:var(--s-4)}
  .bs-notes .sticky.aside{width:auto;cursor:pointer}
  .sheet-row.danger{color:var(--err)}
}

@media(max-width:360px){
  /* 320 (5a): «Как у ученика» — значком; полоса обложки уходит (дверь к
     картинке — в «⋯» шапки), пока не открыто поле ссылки */
  .bld-top .hdr-seg>button{width:44px;padding:0;justify-content:center;font-size:0}
  .bld-top .hdr-seg>button::before{content:attr(data-ic);font-size:var(--t-lg)}
  .cover:not(.link-open) .cover-pic{display:none}
  /* Обложка на 320 — строкой: название ступенью заголовка, без «УРОК» */
  .cover-edit .t{font-size:var(--t-h1)}
  .cover-set .cs-eyebrow{display:none}
}

/* ---------- Главная преподавателя на телефоне: вторая сверка (2a, 2d, 7a, 7g) ----------
   Первая сверка 12 сентября перенесла порядок ленты и высоты, но не облик:
   занятие осталось белой карточкой широкого экрана с аватаром и тремя строками,
   показания стояли голыми строками на бумаге, первые шаги — строкой без полосы.
   Принятый кадр 2d: страница на подложке темнее бумаги, занятие тёмным листом,
   показания одним поднятым листом, ниже — строки-карточки. */
.now-plate,.d-readouts,.r-one,.bw-lead-s,.bw-self-s{display:none}
@media(max-width:640px){
  body:has(#todayPage){background:var(--work-ground)}

  /* Занятие — тёмный лист (7a): отсчёт дисплейной ступенью, под ним одна строка
     сведений и одно действие. Цвета — из ролей хрома, а не константами: в тёмном
     хроме лист переворачивается целиком и держит тот же контраст. */
  .page .d-now>.now-card{display:none}
  /* Поля листа — 20 и 16 над кнопками: владелец 14 сентября попросил главной
     кнопке «чуть больше воздуха». При 16 со всех сторон и 12 над ней она
     прижималась к подписи и к скруглённому краю. */
  .now-plate{display:block;background:var(--c-ink);color:var(--c-paper);border-radius:var(--r-3);
    padding:calc(var(--s-4) + var(--s-1));box-shadow:var(--sh-2)}
  .np-eyebrow{display:flex;align-items:center;gap:var(--s-2);font-size:var(--t-label);font-weight:600;
    letter-spacing:.12em;text-transform:uppercase;color:var(--marker)}
  .np-eyebrow i{flex:none;width:6px;height:6px;border-radius:var(--r-pill);background:var(--marker)}
  .np-when{margin-top:var(--s-2);font-family:var(--font-head);font-weight:700;font-size:var(--t-d1);
    line-height:1.1;letter-spacing:-.03em;color:var(--c-paper)}
  .np-when::first-letter{text-transform:uppercase}
  .np-meta{margin-top:var(--s-1);font-size:var(--t-base);font-variant-numeric:tabular-nums;
    color:color-mix(in srgb, var(--c-paper) 62%, var(--c-ink))}
  .np-acts{display:flex;gap:var(--s-2);margin-top:var(--s-4)}
  .np-go{flex:1;min-width:0;height:54px;display:flex;align-items:center;justify-content:center;
    border:none;border-radius:var(--r-1);cursor:pointer;text-decoration:none;
    background:color-mix(in srgb, var(--c-paper) 94%, var(--c-ink));color:var(--c-ink);
    font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .np-more{flex:0 0 54px;height:54px;border-radius:var(--r-1);cursor:pointer;background:none;
    border:1px solid color-mix(in srgb, var(--c-paper) 22%, var(--c-ink));
    color:color-mix(in srgb, var(--c-paper) 62%, var(--c-ink));font-size:var(--t-lg)}

  /* Показания — один поднятый лист со строками внутри (2a) */
  .page .d-readouts{display:block}
  .readouts{background:var(--surface);border-radius:var(--r-3);padding:var(--s-1);box-shadow:var(--sh-1)}
  .readouts .readout{position:relative;gap:var(--s-3);min-height:0;padding:var(--s-3);border-radius:var(--r-2)}
  .readouts .readout+.readout::before{content:'';position:absolute;top:0;left:var(--s-3);right:var(--s-3);
    height:1px;background:var(--line)}
  .readouts .ro-num{width:48px;min-width:48px;height:48px;padding:0;font-size:var(--t-h1)}
  .readouts .ro-num:not(.mark){color:var(--ink-2)}

  /* Сборка урока — две кнопки 52, на 390 поровну; вторая белая с тенью, без
     канта: она на подложке, а не на бумаге */
  .page:has(.desk)>.page-head>.btn.ai,.page:has(.desk)>.page-head>.btn:not(.ai){flex:1 1 0;min-width:0;
    min-height:52px;justify-content:center}
  .page:has(.desk)>.page-head>.btn:not(.ai){background:var(--surface);box-shadow:var(--sh-1)}

  /* Первые шаги свёрнутой строкой 56 — белой карточкой с полосой (7g) */
  .steps.folded .steps-row{height:56px;min-height:56px;padding:0 var(--s-3);background:var(--surface);
    border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .steps.folded.open .steps-row{height:auto;padding:0;background:none;box-shadow:none}
  .steps-row .sr-main{flex:1;min-width:0;display:flex;flex-direction:column}
  .steps-row .sr-t{font-size:var(--t-md)}
  .steps-row .sr-bar{display:flex;gap:var(--s-1);margin-top:var(--s-1)}
  .steps-row .sr-bar i{height:4px;border-radius:var(--r-pill);background:var(--line)}
  .steps-row .sr-bar i.on{background:var(--ink)}

  /* Дальше на неделе — надзаголовок над листом и строки 56 с жетоном (2d) */
  .page .week-ahead{background:none;box-shadow:none;border:none;padding:0}
  .week-ahead .panel-head{margin:var(--s-2) 0;font-family:var(--font-body);font-size:var(--t-label);
    font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
  .week-ahead .panel-head .count-plain{display:none}
  .week-ahead .row{min-height:56px;padding:0 var(--s-3);gap:var(--s-3);border:none;
    background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .week-ahead .row+.row{margin-top:var(--s-2)}
  .week-ahead .r-anchor>*{width:34px;height:34px;font-size:var(--t-base)}
  /* Имя и когда — одной строкой (владелец, 14 сентября): по жетону с буквами
     ученика не узнать, а фото есть не у всех. Имя — дверь в карточку ученика и
     забирает высоту строки, чтобы попасть пальцем; остальная строка
     по-прежнему ведёт в расписание. Длинное имя обрезается многоточием, день и
     время — нет. */
  .week-ahead .r-sub{display:none}
  .week-ahead .r-main{display:flex;align-items:center;gap:var(--s-3);align-self:stretch}
  .week-ahead .r-title{display:flex;align-items:center;flex:0 1 auto;min-width:0;overflow:visible}
  .week-ahead .r-title .stu-link{display:block;min-width:0;padding:var(--s-4) 0;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap;font-weight:700}
  .week-ahead .r-one{display:block;flex:none;max-width:60%;margin-left:auto;overflow:hidden;text-overflow:ellipsis;
    font-size:var(--t-base);color:var(--ink-2);white-space:nowrap}
}
/* До 400 — «Урок с ИИ» и «Собрать самому» поровну; шире — «Собрать урок с ИИ»
   и «Самому» по тексту (2d, 414) */
@media(max-width:400px){
  .bw-lead{display:none}
  .bw-lead-s{display:inline}
}
@media(min-width:401px) and (max-width:640px){
  .bw-self{display:none}
  .bw-self-s{display:inline}
  .page:has(.desk)>.page-head>.btn:not(.ai){flex:0 0 auto;padding:0 var(--s-4)}
}
/* 320 (2d): в первый экран держатся занятие и одно показание — подписи у строк
   показаний уходят */
@media(max-width:360px){
  .readouts .ro-s{display:none}
  .readouts .ro-num{width:40px;min-width:40px;height:40px;font-size:var(--t-lg)}
}

@media(max-width:640px){
  /* Лента главной — одним зазором 12 между листами (2d). У блоков оставались
     поля широкого экрана: лист занятия и показания слипались, а между первыми
     шагами и неделей лежало полэкрана пустоты. */
  .app .page:has(.desk){gap:var(--s-3)}
  .app .page:has(.desk)>*,.app .page:has(.desk) section>*{margin-top:0;margin-bottom:0}
  .week-ahead .panel-head{margin:var(--s-1) 0 var(--s-2)}
  /* Поля у пары кнопок одни: при flex-basis 0 ширину делит остаток, а поля
     прибавляются сверху, и у жёлтой с другими полями кнопки выходили разными */
  .page:has(.desk)>.page-head>.btn{padding:0 var(--s-3)}
}
/* 320 (2d): подписи нижней полосы — 12.5, иначе «Расписание» и «Проверка»
   слипаются */
@media(max-width:360px){
  .mobile-nav button,.mobile-nav a,.step-nav a{font-size:var(--t-sm)}
}

/* ---------- Каталог на телефоне: вторая сверка (12e, 14 сентября) ----------
   Первая сверка оставила над списком «ПАПКИ» с чипом на каждую папку и строку
   «Порядок: последняя правка», группы — голыми надзаголовками на бумаге, а
   вторую кнопку внизу — словами. Черновики при этом с телефона не открывались
   вовсе: полку спрятали, а чипа, который обещал её заменить, не было. */
.cat-chips,.cg-n,.cm-plus,.cat-sort-top{display:none}
@media(max-width:640px){
  /* Поиск — простым значком рядом с «⋯», как «+» в шапке расписания */
  .app-main .topbar .cat-find{position:relative;width:36px;height:36px;border:none;background:none;
    box-shadow:none;font-size:var(--t-lg);color:var(--ink-2)}
  .app-main .topbar .top-actions:has(.cat-find)+.top-more{margin-left:0}
  .top-more-body .cat-sort-top{display:flex}

  /* Чипы — строкой под шапкой от края до края, с чертой снизу */
  .app .page:has(.cat-layout)>.page-head{margin-bottom:0}
  .cat-layout{gap:0}
  #folderCol>:not(.cat-chips){display:none}
  .cat-chips{display:flex;gap:var(--s-2);overflow-x:auto;scrollbar-width:none;
    margin:calc(var(--s-3) * -1) calc(var(--s-4) * -1) 0;padding:var(--s-2) var(--s-4);
    border-bottom:1px solid var(--line)}
  .cat-chips::-webkit-scrollbar{display:none}
  .cchip{position:relative;flex:0 0 auto;height:40px;display:inline-flex;align-items:center;gap:var(--s-1);
    padding:0 var(--s-3);border:1px solid var(--line-2);border-radius:var(--r-1);background:none;cursor:pointer;
    font-family:var(--font-head);font-weight:600;font-size:var(--t-base);color:var(--ink);white-space:nowrap}
  .cchip::after{content:'';position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
  .cchip b{font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums}
  .cchip.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
  .cchip.on b{color:color-mix(in srgb, var(--paper) 62%, var(--ink))}
  .fs-row{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3)}
  .fs-row b{font-weight:600;color:var(--muted);font-variant-numeric:tabular-nums}
  .sheet-row.on{color:var(--ink)}

  /* Группы — серой полосой 32 во всю ширину, со счётом. Безымянная группа (порядок
     не по правке) полосы не получает: пустая полоса ничего не делит. */
  .cat-group-head{margin:0 calc(var(--s-4) * -1);padding:0 var(--s-4);min-height:32px;
    align-items:center;background:var(--surface-2)}
  .cat-group-head.later{margin-top:0}
  .cat-group-head .cat-sort{display:none}
  .cat-group-head:has(>.eyebrow:empty){display:none}
  .cg-n{display:inline}

  /* Строки во всю ширину: черта от края до края, как в 12e */
  .cat-main .cat-grid{margin:0 calc(var(--s-4) * -1)}
  .cat-card{padding-left:var(--s-4)}
  .cat-card .cc-acts{right:var(--s-1)}

  /* Внизу — «Собрать урок с ИИ» и квадратный «+», вровень с нижней полосой (52 и
     кант). На 56 между ними оставался просвет, и в нём читался текст строки. */
  .cat-make{bottom:calc(53px + env(safe-area-inset-bottom));padding:var(--s-2) var(--s-4) var(--s-3)}
  .cat-make>.btn.cm-self{flex:0 0 52px;width:52px;padding:0;justify-content:center}
  .cm-self .cm-t{display:none}
  .cm-plus{display:inline;font-size:var(--t-lg);font-weight:400}
}

/* ---------- Кабинет ученика на телефоне: вторая сверка (4a, 14 сентября) ----------
   Первая сверка перенесла порядок и цели, но не облик: шапка без названия и без
   лица, занятие листом с подписью крупнее макета и без точки, работы отдельными
   карточками с рельсой, под ними строка фактов и «Мои уроки 0». Принятый 4a:
   подложка темнее бумаги, занятие тёмным листом, работы одним листом строками с
   жетоном, «Словарь» и «Прогресс» строками со значением. */
.cab-count,.tc-sub-m{display:none}
/* Строки кабинета — только телефону. .cab-more{display:none} выше по файлу
   проигрывал .grp{display:grid} ниже по файлу, и на широком экране под обзором
   стояли «Мои уроки» и «Прогресс», которые есть в меню слева. */
.cab-more.grp{display:none}
@media(max-width:640px){
  body:has(#cabBody){background:var(--work-ground)}
  /* Шапка: название раздела слева, лицо 34 рядом с «⋯» */
  .top-ava .stu-ava{width:34px;height:34px;font-size:var(--t-base);font-weight:600}

  /* Занятие — тёмный лист, как на главной преподавателя (7a): точка маркером у
     надзаголовка, подпись и пояснение одним кеглем. Идущее занятие метит своя
     точка .live — вторая рядом не нужна. */
  .next-card{gap:0;padding:var(--s-4);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  .next-card .eyebrow{gap:var(--s-2);line-height:1.35;letter-spacing:.12em}
  .next-card:not(.is-live) .eyebrow::before{content:'';flex:none;width:6px;height:6px;
    border-radius:var(--r-pill);background:var(--marker)}
  .next-card .nc-when{margin-top:var(--s-2)}
  .next-card .nc-what{margin-top:var(--s-1);font-size:var(--t-sm);line-height:1.36}
  .next-card .nc-actions{margin-top:var(--s-3)}
  .next-card .nc-actions .small{font-size:var(--t-sm);line-height:1.36}

  /* «Сдать» и сколько работ — словами справа, без пилюли и «Вся домашка»:
     домашка целиком — пункт нижней полосы. */
  .sec-todo{margin:var(--s-4) 0 var(--s-2);line-height:1.3}
  .sec-todo>.count-pill,.sec-todo>.more{display:none}
  .cab-count{display:inline;margin-left:auto;font-family:var(--font-body);font-weight:400;
    font-size:var(--t-sm);color:var(--muted);font-variant-numeric:tabular-nums}

  /* Работы — одним листом: строки с жетоном 44 и чертой между ними. Рельсы
     нет: состояние говорят жетон и подпись — жёлтый жетон у новой работы,
     красный у просроченной. */
  .todo-list{padding:var(--s-1);background:var(--surface);border-radius:var(--r-3);box-shadow:var(--sh-1)}
  .todo-list>.todo-card,.todo-list>.todo-card:hover{margin:0;min-height:0;padding:var(--s-3);gap:var(--s-3);
    border-radius:var(--r-2);background:none;box-shadow:none}
  .todo-list>.todo-card+.todo-card{position:relative;border-top:1px solid transparent}
  .todo-list>.todo-card+.todo-card::before{content:'';position:absolute;left:var(--s-3);right:var(--s-3);
    top:-1px;height:1px;background:var(--line)}
  .todo-list .tc-num{min-width:44px;height:44px;padding:0;color:var(--ink-2)}
  .todo-list .todo-card.is-new .tc-num{background:var(--marker-soft);color:var(--marker-ink)}
  .todo-list .tc-title{white-space:nowrap}
  .todo-card .tc-sub:not(.tc-sub-m){display:none}
  .todo-card .tc-sub-m{display:block;margin-top:0}
  .todo-list .tc-chev{width:auto;height:auto;border:none;transform:none;font-style:normal;
    font-size:var(--t-lg);line-height:1;color:var(--muted)}
  .todo-list .tc-chev::before{content:'›'}

  /* Факты уехали в значения строк «Словарь» и «Прогресс» */
  .facts-line{display:none}
  .cab-more.grp{display:grid;gap:0;margin-top:var(--s-3);background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .cab-more>button,.cab-more>button:hover{min-height:56px;padding:0 var(--s-4);gap:var(--s-3);
    background:none;font-size:var(--t-lg);border-bottom:1px solid var(--line)}
  .cab-more>button:last-child{border-bottom:none}
  .cab-more .grp-name{flex:1;min-width:0}
  .cab-more .grp-right{font-size:var(--t-sm)}
  .cab-more .grp-chev{font-style:normal;font-size:var(--t-lg);line-height:1;color:var(--muted)}

  /* Нижняя полоса ученика — кеглем 12.5, как в 4a. Точка «пришло» у «Домашки»
     та же, что у «Проверки» преподавателя (.mobile-nav .mn-dot). */
  /* И полоса кабинета в оглавлении домашки (.step-nav): она делит правило пунктов
     с нижней полосой и должна совпадать с ней. */
  .mobile-nav.is-student button,.mobile-nav.is-student a,.step-nav a{font-size:var(--t-sm)}
}

/* ---------- Ученики на телефоне: вторая сверка (4b, 14 сентября) ----------
   Первая сверка подняла приглашение под список, но оставила переключатель вида
   и число учеников строкой над списком, а список — листом широкого экрана с
   надзаголовками групп и временем со счётом справа, без подписи. Принятый 4b:
   переключатель в шапке, подложка темнее бумаги, ученики строками 68 с лицом,
   уровнем и подписью словами. */
.stu-seg,.stu-phone{display:none}
.stu-seg[hidden]{display:none!important}
@media(max-width:640px){
  body:has(#studentsPage){background:var(--work-ground)}
  /* Переключатель — в шапке, 30 в высоту (правило 1e). Шапка страницы пустеет
     целиком: название стоит в шапке, число учеников видно по списку,
     приглашение — под ним. */
  .app-main .topbar .top-actions>.stu-seg{display:inline-flex}
  .stu-seg{height:30px;margin:0;border-radius:8px}
  .stu-seg button{height:24px;padding:0 var(--s-2);border-radius:6px;font-size:var(--t-sm)}
  .stu-seg button.on{box-shadow:none}
  #studentsPage>.page-head{display:none}

  .stu-list{display:none}
  .stu-phone{display:block}
  .stp-card{padding:var(--s-1);background:var(--surface);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  .stp-card.stp-tail{box-shadow:var(--sh-1)}
  .stp-row{position:relative;display:flex;align-items:center;gap:var(--s-3);padding:var(--s-3);
    border-radius:var(--r-2);cursor:pointer}
  .stp-row+.stp-row{border-top:1px solid transparent}
  .stp-row+.stp-row::before{content:'';position:absolute;left:var(--s-3);right:var(--s-3);
    top:-1px;height:1px;background:var(--line)}
  .stp-row .stu-ava{flex:0 0 44px;width:44px;height:44px;background:var(--surface-2);color:var(--muted);
    font-size:var(--t-base);font-weight:600}
  .stp-main{flex:1;min-width:0}
  .stp-name{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);line-height:1.3;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .stp-lvl{font-size:var(--t-sm);color:var(--muted)}
  .stp-sub{font-size:var(--t-sm);line-height:1.36;color:var(--muted);font-variant-numeric:tabular-nums}
  .stp-chev{flex:none;font-style:normal;font-size:var(--t-lg);line-height:1;color:var(--muted)}
  .stp-row.off .stp-name{color:var(--muted)}
  .stp-head{margin:var(--s-5) 0 var(--s-2);font-size:var(--t-label);font-weight:600;
    letter-spacing:.12em;color:var(--muted)}
  .stp-more{margin-top:var(--s-1)}
  /* Приглашение — в 12 под списком, как между листами */
  .stu-invite{margin-top:var(--s-3)}
}
@media(max-width:360px){
  /* На 320 рядом с названием и «⋯» переключатель не встаёт — он уезжает в
     шторку «⋯» целиком (заметка к 4b). */
  .app-main .topbar .top-actions>.stu-seg{display:none}
  .top-more-body .stu-seg{display:flex;align-self:flex-start;width:auto;min-height:0}
}

/* ---------- Курсы и заготовки на телефоне: вторая сверка (4c, 14 сентября) ----------
   Курсы: строка широкого экрана сжималась в три колонки — знак-рельса, название
   в два слова на строку и «Открыть» сбоку, — а «Новый курс» чёрной кнопкой стоял
   над списком. Принятый 4c: карточка с жетоном 44, полосой со счётом и кнопками
   52 во всю ширину; «Новый курс» — светлой кнопкой под списком. Разметка
   карточки прежняя: .crs-card-main раскладывается сеткой самой карточки.

   Заготовки: пустое состояние по центру с двумя кнопками и примерами абзацами
   стало листом по левому краю и примерами строками (своя разметка в
   snippets.js — тексты у телефона короче). */
.crs-new-m,.sn-empty-m{display:none}
@media(max-width:640px){
  body:has(.crs-list-head),body:has(#snippetsPage){background:var(--work-ground)}

  .crs-list-head{display:none}
  .crs-cards{gap:var(--s-3)}
  /* row-gap:0 — зазор 12 у строки широкого экрана (gap) в сетке лёг бы и между
     рядами, и карточка вырастала на 30 пикселей против макета. */
  .crs-card{display:grid;grid-template-columns:44px minmax(0,1fr) auto;column-gap:var(--s-3);row-gap:0;align-items:center;
    padding:var(--s-4);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  .crs-card:hover{transform:none;box-shadow:var(--sh-2)}
  .crs-card-main{display:contents}
  .crs-mark{grid-column:1;grid-row:1 / span 2;align-self:start;width:44px;height:44px;
    border-radius:var(--r-pill);background:var(--marker)}
  .crs-mark::before,.crs-mark i{display:none}
  .crs-card.draft .crs-mark{background:var(--line)}
  .crs-card-head{grid-column:2 / -1;grid-row:1;align-self:end}
  .crs-card-title{font-weight:600;letter-spacing:-.01em;line-height:1.3}
  .crs-card-sub{grid-column:2 / -1;grid-row:2;align-self:start;margin-top:0;line-height:1.36}
  .crs-card-bar{grid-column:1 / 3;grid-row:3;height:5px;margin-top:var(--s-3)}
  .crs-card-done{grid-column:3;grid-row:3;margin-top:var(--s-3)}
  .crs-card-acts{grid-column:1 / -1;grid-row:4;gap:var(--s-2);margin-top:var(--s-3)}
  .crs-card-acts>.btn{flex:1;min-height:52px;font-size:var(--t-lg)}
  .crs-card-acts>.icon-btn{flex:0 0 52px;width:52px;height:52px;border:1px solid var(--line-2);
    border-radius:var(--r-1);background:none;font-size:var(--t-lg);color:var(--ink-2)}
  .crs-new-m{display:block;margin-top:var(--s-3)}
  .crs-new-m>.btn{width:100%;min-height:52px;font-size:var(--t-lg)}
  /* Светлая кнопка на подложке — тенью, без канта (4c); вес как у общего
     правила вторичных кнопок телефона. */
  .crs-new-m>.btn:not(.primary):not(.ai){box-shadow:var(--sh-1)}
  .crs-new-m>.small{margin-top:var(--s-2);line-height:1.5}

  /* Шапка страницы без счёта заготовок пуста — название стоит в шапке телефона,
     — но держала свой отступ 24 над листом. */
  #snippetsPage>.page-head:not(:has(>.sn-note)){display:none}
  #snippetsPage .sn-empty{display:none}
  .sn-empty-m{display:block}
  .snm-card{padding:var(--s-5);background:var(--surface);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  .snm-t{font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);line-height:1.15;letter-spacing:-.03em}
  .snm-p{margin:var(--s-2) 0 0;font-size:var(--t-md);line-height:1.55;color:var(--ink-2)}
  .snm-go{display:flex;width:100%;min-height:52px;margin-top:var(--s-4);font-size:var(--t-lg)}
  .snm-note{margin-top:var(--s-2);font-size:var(--t-sm);line-height:1.5;color:var(--muted)}
  .snm-head{margin:var(--s-4) 0 var(--s-2);font-size:var(--t-label);font-weight:600;letter-spacing:.12em;color:var(--muted)}
  .snm-list{background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .snm-list>div{display:flex;align-items:center;min-height:56px;padding:0 var(--s-4);font-size:var(--t-md);
    border-bottom:1px solid var(--line)}
  .snm-list>div:last-child{border-bottom:none}
}

/* ---------- Просмотр урока на телефоне: вторая сверка (5b, 7j; 14 сентября) ----------
   Шапка была в две строки: подпись «так это видит ученик» переносилась, рядом
   стояли «Изменить» и «Выйти» кнопками с тенью. Принятый 5b: 48 на бумаге —
   плашка режима, подпись в строку с многоточием, «Изменить» 36 в рамке и «⋯».
   Лист урока не тронут: это содержимое, набранное темой оформления; вокруг
   него — подложка рабочих экранов телефона и поля 16. */
.pb-more{display:none}
@media(max-width:640px){
  body:has(#previewBar){background:var(--work-ground)}
  .preview-bar{min-height:48px;padding:0 var(--s-2) 0 var(--s-4);gap:var(--s-2);background:var(--paper)}
  .preview-bar .pb-label{flex:none;padding:var(--s-1) var(--s-3);font-size:var(--t-sm);letter-spacing:.04em}
  .preview-bar .pb-short{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .preview-bar .pb-seg,.preview-bar .pb-exit{display:none}
  .preview-bar .pb-actions{margin-left:0}
  /* :not(.primary) — ради веса общего правила вторичных кнопок телефона: без
     него к рамке добавлялись его кант и тень. */
  .preview-bar .pb-actions>.btn:not(.primary){min-height:36px;padding:0 var(--s-3);border:1px solid var(--line-2);
    background:none;box-shadow:none;font-size:var(--t-base)}
  .pb-more{display:inline-flex;align-items:center;justify-content:center;flex:none;width:44px;height:44px;
    border:none;background:none;border-radius:var(--r-1);font-size:var(--t-lg);line-height:1;
    color:var(--ink-2);cursor:pointer}
  body:has(#previewBar) .class-grid{padding:var(--s-3) var(--s-4) var(--s-6)}
}

/* ---------- Занятие на телефоне: вторая сверка (3a, 7c; 14 сентября) ----------
   Шапка несла путь «← Главная», жёлтую точку с часами, «⋯» 36 с подложкой и
   «Закрыть»; лист урока — рамкой темы с обложкой, а разделы — строками внутри
   него. Принятый 3a: в шапке точка присутствия, часы и кто в классе, «⋯» 44 и
   «Закрыть» 36 в рамке (7c — две цели, выход не прячут). У преподавателя
   подложка темнее бумаги, раскрытый раздел — листом с серой шапкой-строкой,
   свёрнутые — строками одного листа. Цвета разделов берутся из темы урока:
   переменные applyTheme ставит на лист, а разделы лежат внутри него.

   Полоса внизу по поведению прежняя — «←», «Показать NN» и номер: в 3a
   нарисована полоса ученика «Ход урока», а преподаватель полосой ведёт урок. */
.cls-head-m{display:none}
#csecWork.is-empty{display:none}
@media(max-width:640px){
  body>.topbar:has(.cls-live){padding:0 var(--s-2) 0 var(--s-4)}
  body>.topbar:has(.cls-live) .top-back,body>.topbar:has(.cls-live) .top-sep,
  body>.topbar:has(.cls-live) .top-step,body>.topbar:has(.cls-live) .top-title,
  body>.topbar:has(.cls-live) .cls-live{display:none}
  body>.topbar:has(.cls-live) .top-left{flex:1 1 auto}
  .cls-head-m{display:flex;align-items:center;gap:var(--s-2);min-width:0}
  .chm-dot{flex:0 0 7px;width:7px;height:7px;border-radius:var(--r-pill);background:var(--sm-faint)}
  .cls-head-m.on .chm-dot{background:var(--ok)}
  .chm-txt{display:flex;flex-direction:column;min-width:0}
  .chm-t{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg);letter-spacing:-.01em;line-height:1.3;
    font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--ink)}
  .chm-s{font-size:var(--t-sm);line-height:1.36;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  body>.topbar:has(.cls-live) .cls-more{width:44px;height:44px;background:none;box-shadow:none;
    font-size:var(--t-lg);color:var(--ink-2)}
  body>.topbar:has(.cls-live) .top-actions>.btn:not(.primary){min-height:36px;padding:0 var(--s-3);
    border:1px solid var(--line-2);background:none;box-shadow:none;font-size:var(--t-base)}

  /* Лист преподавателя — без рамки на подложке: разделы сами становятся листами */
  html body:has(.cls-more){background:var(--work-ground)}
  body:has(.cls-more) .class-grid{padding-top:var(--s-3);padding-left:var(--s-4);padding-right:var(--s-4)}
  body:has(.cls-more) .lesson-sheet{background:none!important;border:none;border-radius:0;box-shadow:none;padding:0}
  body:has(.cls-more) #coverClass>.cover{display:none}
  body:has(.cls-more) .cls-sec{border-bottom:none;background:var(--surface)}
  /* row-gap:0 — зазор 12 у строки первого прохода (gap) в сетке лёг бы и между
     названием и подписью. */
  body:has(.cls-more) .cls-sec>.cs-head{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--s-3);
    row-gap:0;align-content:center;min-height:62px;padding:0 var(--s-4)}
  body:has(.cls-more) .cs-head .cs-t{grid-column:1;line-height:1.3}
  body:has(.cls-more) .cs-head .cs-s{grid-column:1;flex:none;text-align:left;line-height:1.5}
  body:has(.cls-more) .cs-head .cs-chev{grid-column:2;grid-row:1 / span 2;width:auto;height:auto;border:none;
    transform:none;font-style:normal;font-size:var(--t-lg);line-height:1;color:var(--muted)}
  body:has(.cls-more) .cs-head .cs-chev::before{content:'›'}
  /* Раскрытый — лист 22: серая шапка-строка и блоки под ней */
  body:has(.cls-more) .cls-sec.open{padding:var(--s-1);border-radius:var(--r-3);box-shadow:var(--sh-2)}
  body:has(.cls-more) .cls-sec.open>.cs-head{min-height:0;padding:var(--s-3) var(--s-4);border-radius:var(--r-2);
    background:var(--surface-2)}
  body:has(.cls-more) .cls-sec.open>.cs-head .cs-chev{transform:rotate(90deg);color:var(--ink-2)}
  body:has(.cls-more) .cls-sec.open>.cs-body{padding:var(--s-3) var(--s-2) var(--s-1)}
  /* Свёрнутые — строками одного листа: черта между ними, скругление у первой и
     последней в ряду, 12 от раскрытого */
  body:has(.cls-more) .cls-sec:not(.open)+.cls-sec:not(.open)>.cs-head{border-top:1px solid var(--line)}
  body:has(.cls-more) .cls-sec:not(.open):first-child,
  body:has(.cls-more) .cls-sec.open+.cls-sec:not(.open){border-top-left-radius:var(--r-2);border-top-right-radius:var(--r-2)}
  body:has(.cls-more) .cls-sec:not(.open):has(+.cls-sec.open),
  body:has(.cls-more) .cls-sec:not(.open):not(:has(~.cls-sec:not(.is-empty))){
    border-bottom-left-radius:var(--r-2);border-bottom-right-radius:var(--r-2)}
  body:has(.cls-more) .cls-sec.open+.cls-sec,body:has(.cls-more) .cls-sec+.cls-sec.open{margin-top:var(--s-3)}
  /* Блок в раскрытом разделе — карточкой с кантом: лист раздела и карточка
     одного цвета, и тень между ними не видна. */
  body:has(.cls-more) .cls-sec .card.cls-host{box-shadow:none;border:1px solid var(--line);border-radius:var(--r-2)}

  /* Полоса — на подложке; «←» и номер — белыми с тенью, как в 3a */
  body:has(.cls-more) .class-bar{background:var(--work-ground);border-top-color:var(--line);
    padding:var(--s-2) var(--s-4) calc(var(--s-3) + env(safe-area-inset-bottom))}
  body:has(.cls-more) .cb-step,body:has(.cls-more) .cb-nth{border:none;background:var(--surface);box-shadow:var(--sh-1)}
}

/* ---------- Тёмный хром: лист занятия не переворачивается (13a; 14 сентября) ----------
   Лист ближайшего занятия на главной преподавателя и в кабинете ученика красится
   ролями хрома наоборот — чернилами по бумаге, — и в тёмном хроме становился
   светлым пятном #F2F1EE во всю ширину первого экрана. Принятый 13a: в тёмной
   теме это такой же тёмный лист с кантом, как остальные, а светлеет одно главное
   действие. У ученика заодно: текст «Войти в класс» в тёмном хроме был цвета её
   же фона. */
@media(max-width:640px){
  html[data-chrome="dark"] .now-plate,html[data-chrome="dark"] .next-card,
  html[data-chrome="dark"] .next-card.is-live{background:var(--c-surface);color:var(--c-ink);box-shadow:var(--sh-1)}
  html[data-chrome="dark"] .np-when,html[data-chrome="dark"] .next-card .nc-when{color:var(--c-ink)}
  html[data-chrome="dark"] .np-meta,html[data-chrome="dark"] .next-card .nc-what,
  html[data-chrome="dark"] .next-card .small.muted{color:var(--c-ink-2)}
  html[data-chrome="dark"] .np-go,html[data-chrome="dark"] .next-card .btn.primary{background:var(--c-ink);color:var(--c-paper)}
  html[data-chrome="dark"] .np-more{border-color:var(--c-line-2);color:var(--c-ink-2)}
}

/* ---------- «Ещё» у преподавателя: служебное — тихим подвалом (14 сентября) ----------
   Владелец: жалоба, операционка, чат и канал — только под «Ещё», и видом
   первоначального подвала — мелко, серым, телеграм самолётиком: «эти кнопки
   меньше и ниже в иерархии». Строками разделов они читались ещё четырьмя
   разделами. В «⋯» шапки у преподавателя их больше нет. Строка подвала — 36 в
   высоту: цель пальца без того, чтобы подвал рос в меню. */
@media(max-width:640px){
  .sheet-body .more-foot{display:flex;flex-direction:column;align-items:flex-start;gap:0;order:0;
    margin-top:var(--s-2);padding:var(--s-2) var(--s-3) 0;border-top:1px solid var(--line)}
  .sheet-body .more-foot .af-tg{gap:0}
  .sheet-body .more-foot .af-link,.sheet-body .more-foot .af-tg a{min-height:36px;display:flex;align-items:center}
  /* Напоминание о почте в «⋯» — строкой со словами: текст «Подтвердите почту» в
     шапке узкого экрана спрятан, и в шторку приезжали только точка и кнопка по
     разным краям. */
  /* flex:none — у полосы в шапке основа 300px по ширине, а в шторке, где узлы
     идут столбиком, та же основа становилась высотой: строка вырастала до 300. */
  .top-more-body .verify-bar{flex:none;flex-wrap:nowrap;align-items:center}
  .top-more-body .verify-bar .vb-text{display:block;flex:1 1 0;min-width:0;white-space:normal;
    font-size:var(--t-sm);color:var(--ink-2)}
}

/* ---------- Карточка ученика на телефоне: своя раскладка (14 сентября) ----------
   Владелец: карточка «всё равно выглядит слишком в духе десктопа», а в ней
   есть «абонемент и его прогресс» — на него и опора. Утром
   панель широкого экрана сжималась стилями — теперь у телефона своя разметка
   (renderProfilePhone в students.js). Своего кадра у карточки нет, язык взят из
   готовых: абонемент тёмным листом с крупным остатком и клетками — кадр
   «Занятия» спеки «телефон» v3; ближайшее — надстрочник с днём и белая карточка
   со временем, оттуда же; «На проверке» — показание главной (2a); разделы —
   строки кабинета (4a); сведения — лист, как разделы настроек (1i). */
@media(max-width:640px){
  body:has(.stc){background:var(--work-ground)}
  .stc{display:flex;flex-direction:column}
  .stc-back{align-self:flex-start;min-height:44px;display:inline-flex;align-items:center;padding:0;border:none;
    background:none;cursor:pointer;font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--ink-2)}

  /* Кто: лицо 64, имя ступенью h1, уровень и «когда заходил», цели плашками */
  .stc-hero{display:flex;align-items:center;gap:var(--s-3);margin-top:var(--s-2)}
  .stc-hero .stu-ava.lg{width:64px;height:64px;font-size:var(--t-h1);background:var(--surface);color:var(--ink-2);
    box-shadow:var(--sh-1)}
  .stc-who{min-width:0}
  .stc-name{margin:0;font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);line-height:1.2;
    letter-spacing:-.02em;overflow-wrap:anywhere}
  .stc-sub{margin-top:var(--s-1);font-size:var(--t-base);color:var(--muted);font-variant-numeric:tabular-nums}
  .stc-goals{display:flex;flex-wrap:wrap;gap:var(--s-2);margin-top:var(--s-3)}
  .stc-goal{position:relative;display:inline-flex;align-items:center;min-height:32px;padding:0 var(--s-3);border:none;
    border-radius:var(--r-pill);background:var(--surface);box-shadow:var(--sh-1);
    font-family:var(--font-body);font-size:var(--t-sm);color:var(--ink-2)}
  .stc-goal.more{cursor:pointer;color:var(--marker-ink)}
  .stc-goal.more::after{content:'';position:absolute;inset:-6px 0}
  .stc-paused{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);margin-top:var(--s-3);
    padding:var(--s-2) var(--s-2) var(--s-2) var(--s-4);border-radius:var(--r-2);background:var(--err-bg);
    font-size:var(--t-base);color:var(--err)}

  /* Абонемент — тёмный лист. Клетки: жёлтым проведённое, красным всё, когда
     занятий не осталось (subTone) — счёт панели широкого экрана. */
  .stc-subs{margin-top:var(--s-5);padding:var(--s-4);border-radius:var(--r-3);background:var(--c-ink);
    color:var(--c-paper);box-shadow:var(--sh-2)}
  .stc-subs-top{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s-3)}
  .stc-eyebrow{font-size:var(--t-label);font-weight:600;letter-spacing:.12em;text-transform:uppercase}
  .stc-eyebrow,.stc-term,.stc-subs-note{color:color-mix(in srgb, var(--c-paper) 62%, var(--c-ink))}
  .stc-term{min-width:0;font-size:var(--t-base);text-align:right;font-variant-numeric:tabular-nums}
  .stc-subs-n{display:flex;align-items:baseline;gap:var(--s-3);margin-top:var(--s-2)}
  .stc-subs-n b{flex:none;font-family:var(--font-head);font-weight:700;font-size:var(--t-d2);line-height:1;
    letter-spacing:-.03em;font-variant-numeric:tabular-nums}
  .stc-subs-n span{min-width:0;font-size:var(--t-lg);color:color-mix(in srgb, var(--c-paper) 80%, var(--c-ink))}
  .stc-subs.is-debt .stc-subs-n b{color:#E88579}
  .stc-cells{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:var(--s-1);margin-top:var(--s-4)}
  .stc-cells i{display:block;height:8px;border-radius:var(--r-pill);background:color-mix(in srgb, var(--c-paper) 16%, var(--c-ink))}
  .stc-cells i.done,.stc-bar>span{background:var(--marker)}
  .stc-cells.low i{background:color-mix(in srgb, #E88579 30%, var(--c-ink))}
  .stc-cells.low i.done,.stc-bar.low>span{background:#E88579}
  .stc-bar{height:8px;margin-top:var(--s-4);border-radius:var(--r-pill);overflow:hidden;
    background:color-mix(in srgb, var(--c-paper) 16%, var(--c-ink))}
  .stc-bar>span{display:block;height:100%}
  .stc-subs-note{margin-top:var(--s-3);font-size:var(--t-base);font-variant-numeric:tabular-nums}
  .stc-subs-note b{font-weight:600;color:var(--marker)}
  .stc-renew{width:100%;height:48px;margin-top:var(--s-3);border-radius:var(--r-1);cursor:pointer;background:none;
    border:1px solid color-mix(in srgb, var(--c-paper) 22%, var(--c-ink));
    font-family:var(--font-head);font-weight:600;font-size:var(--t-md);color:var(--c-paper)}
  .stc-renew.on{border-color:transparent;background:color-mix(in srgb, var(--c-paper) 94%, var(--c-ink));color:var(--c-ink)}

  /* Белые листы: «абонемента нет», ближайшее занятие, разделы, сведения */
  .stc-card,.stc-list{border-radius:var(--r-3);background:var(--surface);box-shadow:var(--sh-1)}
  .stc-card{padding:var(--s-4)}
  .stc-nosub{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);margin-top:var(--s-5);
    padding:var(--s-3) var(--s-3) var(--s-3) var(--s-4)}
  .stc-nosub-t{display:flex;flex-direction:column;min-width:0}
  .stc-nosub-t b{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .stc-nosub-t span{font-size:var(--t-sm);color:var(--muted)}
  .stc-nosub .btn{flex:none;min-height:44px}
  .stc-lab{margin:var(--s-5) 0 var(--s-2);font-size:var(--t-label);font-weight:600;letter-spacing:.1em;
    text-transform:uppercase;color:var(--muted)}
  .stc-lab.mark{color:var(--marker-ink)}
  .stc-when{display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--s-3)}
  .stc-when b{font-family:var(--font-head);font-weight:700;font-size:var(--t-d2);line-height:1.1;letter-spacing:-.03em;
    font-variant-numeric:tabular-nums}
  .stc-when span{font-size:var(--t-lg);color:var(--muted)}
  .stc-none{font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .stc-next-s{margin-top:var(--s-1);font-size:var(--t-base);color:var(--muted)}
  .stc-go{width:100%;min-height:52px;margin-top:var(--s-3);justify-content:center;font-size:var(--t-lg)}
  .stc-go:not(.primary){min-height:48px;font-size:var(--t-md)}
  /* Вторичные кнопки в белых листах — рамкой, без канта с тенью общего
     телефонного правила (вес 0,4,0): иначе кнопка обведена дважды */
  .stc .stc-card>.btn:not(.primary),.stc .stc-fact>.btn:not(.primary){background:none;border-color:var(--line-2);box-shadow:none}
  .stc-more{display:block;width:100%;min-height:44px;margin-top:var(--s-1);border:none;background:none;cursor:pointer;
    font-family:var(--font-body);font-size:var(--t-base);color:var(--ink-2)}
  .readouts.stc-wait{margin-top:var(--s-3)}

  /* Разделы — строки 56: название, значение справа, «›» */
  .stc-list{overflow:hidden}
  .stc-row,.stc-fact{width:100%;margin:0;border:none;border-bottom:1px solid var(--line);background:none;
    font:inherit;text-align:left;text-decoration:none;color:var(--ink)}
  .stc-row:last-child,.stc-fact:last-child{border-bottom:none}
  .stc-row{display:flex;align-items:center;gap:var(--s-3);min-height:56px;padding:0 var(--s-4);cursor:pointer}
  .stc-row:active,a.stc-fact:active,button.stc-fact:active{background:var(--surface-2)}
  .stc-row-t{flex:none;font-family:var(--font-head);font-weight:600;font-size:var(--t-lg)}
  .stc-row-v{flex:1;min-width:0;text-align:right;font-size:var(--t-sm);color:var(--muted);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
  .stc-chev{flex:none;font-style:normal;font-size:var(--t-lg);line-height:1;color:var(--muted)}

  /* Сведения — подпись над значением; у нажимаемых «›» */
  .stc-fact{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--s-3);align-items:center;
    align-content:center;min-height:60px;padding:var(--s-2) var(--s-4)}
  a.stc-fact,button.stc-fact{cursor:pointer}
  .stc-fact-k{grid-column:1;font-size:var(--t-sm);color:var(--muted)}
  .stc-fact-v{grid-column:1;min-width:0;font-size:var(--t-md);overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
  .stc-fact-v.err{color:var(--err)}
  .stc-fact>.stc-chev{grid-column:2;grid-row:1 / span 2}
  .stc-fact-act{grid-column:1 / -1;min-height:44px;margin-top:var(--s-2);justify-content:center}
  .stc-edit{min-height:48px;margin-top:var(--s-3);justify-content:center}

  /* Экран раздела: «← Имя», название ступенью h1, содержимое вкладки листами */
  .stc-title{margin:var(--s-1) 0 var(--s-3);font-family:var(--font-head);font-weight:700;font-size:var(--t-h1);
    line-height:1.2;letter-spacing:-.02em}
  .stc-body .row{gap:var(--s-2) var(--s-3);margin:0 0 var(--s-2);
    padding:var(--s-3) var(--s-4);background:var(--surface);border-radius:var(--r-2);box-shadow:var(--sh-1)}
  .stc-body .row:hover{background:var(--surface);transform:none}
  .stc-body .row>.r-side{flex:1 1 100%;display:flex;flex-wrap:wrap;align-items:center;gap:var(--s-2)}
  /* Название и подпись переносятся: на широком экране строка обрезалась ради
     колонок справа, здесь действия стоят своей строкой. Действия видны всегда —
     наведения у пальца нет, а «✕ снять» уходит к правому краю. */
  .stc-body .row .r-title,.stc-body .row .r-sub{white-space:normal}
  .stc-body .row .r-act{opacity:1;transform:none}
  .stc-body .row>.r-side>.icon-btn:last-child{margin-left:auto}
  .stc-body .eyebrow.stu-part{margin:var(--s-4) 0 var(--s-2)}
  .stc-body .stu-nums{gap:var(--s-2)}
  .stc-body .hw-add{flex-direction:column;align-items:stretch;gap:var(--s-2)}
  .stc-body .hw-add .btn,.stc-body .mrow .btn.ai{min-height:52px;justify-content:center}
  .stc-body .mrow{flex-direction:column;align-items:stretch;border-top:none;padding-top:0}
  .stc-body .card{padding:0 var(--s-4);border-radius:var(--r-3)}
  .stc-body .card>.row{margin:0;padding:var(--s-3) 0;background:none;border-radius:0;box-shadow:none;
    border-bottom:1px solid var(--line)}
  .stc-body .card>.row:last-child{border-bottom:none}
  .stc-body .card>.row>.r-side{flex:0 0 auto;flex-wrap:nowrap}
  .stc-body .sub-card,.stc-body .sn-add{padding:var(--s-4);border-radius:var(--r-3)}
  .stc-body .sub-foot .btn,.stc-body .sn-save,.stc-body .mk-add .btn{min-height:48px}
  .stc-body .sn-item,.stc-body .mk-card{padding:var(--s-3) var(--s-4);border-radius:var(--r-2)}
  /* Пара ошибки — столбиком: в три колонки на 390 обе половины рвались на три строки */
  .stc-body .mk-pair{grid-template-columns:minmax(0,1fr);gap:var(--s-1)}
  .stc-body .mk-arrow{display:none}
  .stc-body textarea,.stc-body .mk-add input{font-size:var(--t-lg)}
  .stc-body .mk-add input{min-height:48px}
  .stc-body .empty{min-height:0;padding:var(--s-6) var(--s-4);border-radius:var(--r-3);background:var(--surface);box-shadow:var(--sh-1)}

  /* Регулярное расписание — белым листом; название и имя уже в шапке экрана */
  .stc-form{padding:var(--s-4);border-radius:var(--r-3);background:var(--surface);box-shadow:var(--sh-1)}
  .stc-form .sp-head{justify-content:flex-start;margin-bottom:var(--s-3)}
  .stc-form .sp-head>div:first-child{display:none}
  .stc-form input[type="time"]{min-height:46px;font-size:var(--t-lg)}
  .stc-form .btn{min-height:48px}

  /* Тёмный хром: лист абонемента — тёмный с кантом, светлеет одно главное
     действие, как у ближайшего занятия на главной (13a) */
  html[data-chrome="dark"] .stc-subs{background:var(--c-surface);color:var(--c-ink);box-shadow:var(--sh-1)}
  html[data-chrome="dark"] .stc-eyebrow,html[data-chrome="dark"] .stc-term,html[data-chrome="dark"] .stc-subs-note,
  html[data-chrome="dark"] .stc-subs-n span{color:var(--c-ink-2)}
  html[data-chrome="dark"] .stc-cells i:not(.done),html[data-chrome="dark"] .stc-bar{background:color-mix(in srgb, var(--c-ink) 14%, var(--c-surface))}
  html[data-chrome="dark"] .stc-cells.low i:not(.done){background:color-mix(in srgb, #E88579 30%, var(--c-surface))}
  html[data-chrome="dark"] .stc-renew{border-color:var(--c-line-2);color:var(--c-ink)}
  html[data-chrome="dark"] .stc-renew.on{border-color:transparent;background:var(--c-ink);color:var(--c-paper)}
}
