/* ============================================================
   Оживление кабинета ученика.

   Файл подключается только на страницах ученика и гостя: в панели
   преподавателя (.shell) анимаций нет — там работают со списками
   и проверкой, и подпрыгивающие карточки там мешают, а не радуют.

   Всё здесь необязательное. Без файла (и без motion.js) страницы
   выглядят и работают ровно как раньше — ни один эффект не несёт
   смысла, который нельзя прочитать глазами.
   ============================================================ */

:root{
  /* Быстрый старт, мягкое торможение — движение читается как отклик,
     а не как проигрывание ролика. */
  --mo-e:cubic-bezier(.22,.8,.28,1);
  --mo-fast:.13s; --mo:.2s; --mo-slow:.38s;
  --mo-lift:0 6px 16px -10px rgba(28,19,48,.55);
}

/* ============ кнопки ============ */
/* overflow скрывает круг «чернил» от клика, position — его якорь. */
.btn{position:relative;overflow:hidden;
  transition:background var(--mo),border-color var(--mo),color var(--mo),
             transform var(--mo-fast) var(--mo-e),box-shadow var(--mo)}
.btn:hover{transform:translateY(-1px);box-shadow:var(--mo-lift)}
/* Нажатие короче наведения: рука ждёт мгновенной реакции на палец. */
.btn:active{transform:translateY(0) scale(.97);box-shadow:none;transition-duration:.06s}
.btn-primary:hover{box-shadow:0 8px 18px -9px rgba(76,29,149,.8)}
.btn-ok:hover{box-shadow:0 8px 18px -9px rgba(15,157,88,.7)}
.btn-danger-fill:hover{box-shadow:0 8px 18px -9px rgba(220,38,38,.7)}
/* Призрачная кнопка живёт в шапке рядом с именем: подъём там читается
   как дрожание строки, оставляем только заливку. */
.btn-ghost:hover{transform:none;box-shadow:none}
.btn[disabled]{transform:none;box-shadow:none}

/* Круг от точки клика. Размер и координаты ставит motion.js. */
.mo-ripple{position:absolute;border-radius:50%;pointer-events:none;background:currentColor;
  opacity:.2;transform:scale(0);animation:moRipple .5s var(--mo-e) forwards}
@keyframes moRipple{to{transform:scale(1);opacity:0}}

/* Форма ушла на сервер: кнопку гасим, чтобы не отправили второй раз. */
.btn.is-busy{pointer-events:none;opacity:.8}
.btn.is-busy::before{content:"";width:14px;height:14px;flex:none;border-radius:50%;
  border:2px solid currentColor;border-right-color:transparent;animation:moSpin .6s linear infinite}
@keyframes moSpin{to{transform:rotate(360deg)}}

/* Скопировали код привязки бота: галочка заметнее смены надписи. */
.btn.is-copied{background:var(--ok-soft);border-color:#bfe5cf;color:var(--ok)}
.btn.is-copied::before{content:"✓";font-weight:700;animation:moPop .3s var(--mo-e)}
@keyframes moPop{0%{transform:scale(.4)}60%{transform:scale(1.18)}100%{transform:scale(1)}}

/* ============ шапка и навигация ============ */
/* У активного пункта своя заливка, ему подчёркивание не нужно — линия
   растёт из центра только под тем, куда ведут мышь. */
.nav a{position:relative}
.nav a::after{content:"";position:absolute;left:11px;right:11px;bottom:3px;height:2px;border-radius:2px;
  background:var(--accent-2);opacity:0;transform:scaleX(.3);transition:transform var(--mo) var(--mo-e),opacity var(--mo)}
.nav a:hover::after{opacity:.6;transform:scaleX(1)}
.nav a.active::after,.nav .btn::after{content:none}
.brand .logo{transition:transform .3s var(--mo-e)}
.brand:hover .logo{transform:rotate(-8deg) scale(1.07)}
.tabs a{transition:background var(--mo),color var(--mo),transform var(--mo-fast)}
.tabs a:hover{transform:translateY(-1px)}

/* ============ карточки, строки, плитки ============ */
/* Подъёма у карточки во всю ширину нет — она бы качала половину экрана.
   Тень углубляется только там, куда можно нажать. */
.card{transition:box-shadow .24s,border-color .24s,transform .24s var(--mo-e)}
.card:has(a):hover{border-color:#ddd6ee;
  box-shadow:0 1px 2px rgba(28,19,48,.05),0 16px 34px -20px rgba(28,19,48,.45)}
/* Карточка тренажёра размером с плитку — её поднимаем целиком. */
.trainer-card:hover{transform:translateY(-3px)}
.trainer-icon{transition:transform .25s var(--mo-e)}
.trainer-card:hover .trainer-icon{transform:scale(1.12) rotate(-6deg)}

.lesson-row .ico{transition:transform var(--mo) var(--mo-e),background var(--mo),color var(--mo)}
.lesson-row:hover .ico{transform:scale(1.12)}
.lesson-row .t{transition:transform var(--mo) var(--mo-e)}
.lesson-row:hover .t{transform:translateX(3px)}
.lesson-row.locked:hover .t{transform:none}   /* закрытый урок никуда не ведёт */

/* Плашка урока: та же реакция на наведение, что и у строки, плюс поворот
   стрелки — он и показывает, что плашка раскрывается. */
.lesson .ico{transition:transform var(--mo) var(--mo-e),background var(--mo),color var(--mo)}
.lesson>summary:hover .ico{transform:scale(1.12)}
.lesson .t{transition:transform var(--mo) var(--mo-e)}
.lesson>summary:hover .t{transform:translateX(3px)}
.lesson.locked>summary:hover .t{transform:none}
.lesson-plan .ln .n{transition:transform var(--mo) var(--mo-e),background var(--mo)}
.lesson-plan a.ln:hover .n{transform:scale(1.1)}

/* Раскрытие плашки: высоту тянет app.css, здесь — проявление содержимого.
   Строки состава выезжают лесенкой, по 25 мс друг за другом: взгляд успевает
   пройти список сверху вниз, а не получает его разом. Дальше восьмой задержку
   не наращиваем — ждать раскрытия урока из полутора десятков шагов дольше,
   чем он раскрывается, незачем. */
.lesson[open]>.lesson-body{animation:moLessonOpen .34s var(--mo-e) both}
@keyframes moLessonOpen{from{opacity:0}to{opacity:1}}

/* Строка состава не просто проявляется, а сходит сверху — так список
   читается как выехавший из-под шапки, а не как включённый свет. */
.lesson[open] .lesson-plan li{animation:moLessonStep .42s var(--mo-e) both}
@keyframes moLessonStep{from{opacity:0;transform:translateY(-9px)}to{opacity:1;transform:none}}
.lesson[open] .lesson-plan li:nth-child(1){animation-delay:.04s}
.lesson[open] .lesson-plan li:nth-child(2){animation-delay:.078s}
.lesson[open] .lesson-plan li:nth-child(3){animation-delay:.116s}
.lesson[open] .lesson-plan li:nth-child(4){animation-delay:.154s}
.lesson[open] .lesson-plan li:nth-child(5){animation-delay:.192s}
.lesson[open] .lesson-plan li:nth-child(6){animation-delay:.23s}
.lesson[open] .lesson-plan li:nth-child(7){animation-delay:.268s}
.lesson[open] .lesson-plan li:nth-child(n+8){animation-delay:.306s}
.lesson[open] .lesson-go{animation:moLessonStep .42s var(--mo-e) .28s both}

/* Раздел раскрывается так же, как урок, только лесенкой идут не строки
   состава, а сами плашки уроков. */
.unit .t{transition:transform var(--mo) var(--mo-e)}
.unit>summary:hover .t{transform:translateX(3px)}
.unit[open]>.unit-body{animation:moLessonOpen .34s var(--mo-e) both}
.unit[open]>.unit-body>.lesson{animation:moLessonStep .42s var(--mo-e) both}
.unit[open]>.unit-body>.lesson:nth-child(1){animation-delay:.04s}
.unit[open]>.unit-body>.lesson:nth-child(2){animation-delay:.078s}
.unit[open]>.unit-body>.lesson:nth-child(3){animation-delay:.116s}
.unit[open]>.unit-body>.lesson:nth-child(4){animation-delay:.154s}
.unit[open]>.unit-body>.lesson:nth-child(5){animation-delay:.192s}
.unit[open]>.unit-body>.lesson:nth-child(n+6){animation-delay:.23s}

.steps-nav li a .n{transition:transform var(--mo) var(--mo-e),background var(--mo)}
.steps-nav li a:hover .n{transform:scale(1.1)}
.steps-nav li a:hover .b{color:var(--accent)}

tbody tr{transition:background .16s}
.lb-row{transition:background .16s}
.lb-row:hover{background:var(--surface-2)}
.lb-pod{transition:transform .25s var(--mo-e),box-shadow .25s}
.lb-pod:hover{transform:translateY(-3px)}

.ach{transition:transform var(--mo) var(--mo-e),box-shadow var(--mo),opacity var(--mo),
     background var(--mo),border-color var(--mo)}
.ach.on:hover{transform:translateY(-2px);box-shadow:0 10px 22px -14px rgba(28,19,48,.6)}
.ach-icon{transition:transform .25s var(--mo-e)}
.ach.on:hover .ach-icon{transform:scale(1.15) rotate(-5deg)}

.mcal-day:hover{transform:translateY(-2px);box-shadow:0 6px 14px -10px rgba(28,19,48,.6)}
.mcal-day{transition:background .12s,border-color .12s,transform var(--mo-fast) var(--mo-e),box-shadow var(--mo-fast)}
.cal-col i{transition:transform .12s var(--mo-e)}
.cal-col i:hover{transform:scale(1.35)}

/* ============ формы и задания ============ */
/* Видно, в каком задании стоит курсор: в длинном ДЗ это заметно помогает. */
form[data-autosave] .q:focus-within{border-color:#c6bce0;box-shadow:0 0 0 3px var(--accent-soft)}
form[data-autosave] .opt:has(input:checked){border-color:var(--accent);background:var(--accent-soft)}
.opt:active{transform:scale(.995)}
.chem-key:hover{transform:translateY(-1px)}
/* Последняя минута на работу: цифры дышат — на них смотрят краем глаза. */
.hw-tile.danger b{animation:pulse 1s ease-in-out infinite}

/* ============ появление блоков ============ */
/* Классы ставит motion.js и снимает после проигрывания, чтобы на странице
   не оставалось лишних transform: они ломают position:sticky у потомков.
   Скрытие висит на body.mo — класс тоже от скрипта, поэтому без JS
   страница показывается целиком, а не остаётся пустой. */
body.mo .mo-pre{opacity:0}
body.mo .mo-in{animation:moRise var(--mo-slow) var(--mo-e) both}
@keyframes moRise{from{opacity:0;transform:translateY(10px)}}

/* Карточке со списком уроков достаётся только проявление: выезжают плашки
   внутри неё, и если бы ехала ещё и она, они ехали бы дважды. */
body.mo .mo-in.mo-flat{animation-name:moFade}

/* Цифры считаются от нуля — без этого плитка дёргается по ширине. */
.stat .v,.lb-mini-nums b{font-variant-numeric:tabular-nums}

/* ============ разбор ошибок ============ */
/* Разобранное задание уезжает вниз списка. Короткое затухание на время
   переезда: без него карточка скачет через полстраницы рывком. */
.review-q.review-moving{opacity:.2;transform:scale(.99);
  transition:opacity var(--mo) ,transform var(--mo) var(--mo-e)}

/* ============ переход между страницами ============ */
/* Кросс-документные переходы: где браузер не умеет (Firefox), правило
   просто игнорируется. Только растворение, без разъезжающихся блоков —
   поверх него ещё выезжают карточки, и двойное движение утомляет. */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
}
::view-transition-old(root){animation:moFade .14s linear reverse}
::view-transition-new(root){animation:moFade .2s var(--mo-e)}
@keyframes moFade{from{opacity:0}}

/* ============ бережный режим ============ */
/* Система просит убрать движение — убираем всё: и добавленное здесь,
   и разминку с конфетти. Состояния при этом сохраняются, просто
   переключаются мгновенно. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .btn:hover,.btn:active,.trainer-card:hover,.lesson-row:hover .t,.lesson>summary:hover .t,.mcal-day:hover,
  .lb-pod:hover,.ach.on:hover,.tabs a:hover{transform:none}
  .mo-pre{opacity:1!important}
  .mo-ripple{display:none}
}
