/* Bakasana — компоненты. Ни одного значения числом: всё из tokens.css.
   Правило: новый элемент интерфейса сначала появляется здесь и на странице
   кита (/kit), и только потом на живой странице. Иначе через месяц у нас
   снова три разных кнопки и четыре карточки. */

/* ── кнопки ────────────────────────────────────────────────────────
   Пилюли — фирменная черта проекта, идёт с боевого сайта.
   Четыре вида, и этого достаточно: главное действие, мягкое, контурное, тихое. */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  padding: 0 var(--sp-5);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: none;
  font: inherit; font-size: var(--fs-base); font-weight: 600;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease),
              color var(--dur-2) var(--ease),
              opacity var(--dur-1) var(--ease);
}
.btn-primary { background: var(--ink); color: var(--on-ink); }
/* Под курсором — ТЁМНАЯ бирюза (--accent-ink), а не бирюза бренда: белый текст на #48bbc0 давал 2,30 : 1 при норме
   4,5 (замер 01.10.26, слово Pet «давай попробуем изменить»). Светлая бирюза остаётся кольцу фокуса и выбранному.
   В тёмной теме --accent-ink светлый, а текст кнопки тёмный — контраст там высокий в обе стороны. */
@media (hover: hover) { .btn-primary:hover { background: var(--accent-ink); color: var(--on-ink); } }
.btn-soft { background: var(--accent-soft); color: var(--accent-ink); }
@media (hover: hover) { .btn-soft:hover { background: var(--accent-ink); color: var(--on-ink); } }
.btn-ghost { border-color: var(--hairline); color: var(--ink); }
@media (hover: hover) { .btn-ghost:hover { border-color: var(--ink); } }
.btn-quiet { color: var(--text-dim); padding: 0 var(--sp-3); }
@media (hover: hover) { .btn-quiet:hover { color: var(--ink); } }
.btn-sm { min-height: var(--tap-sm); font-size: var(--fs-sm); padding: 0 var(--sp-4); }
.btn-wide { width: 100%; }
.btn[disabled], .btn.is-busy { opacity: .45; pointer-events: none; }
.btn .ic { flex: none; }

/* ── поля ─────────────────────────────────────────────────────────── */
.field { display: block; margin-bottom: var(--sp-4); }
.field > span { display: block; font-size: var(--fs-sm); color: var(--text-dim); margin-bottom: var(--sp-1); }
/* 🚩 Перечисляем ИСКЛЮЧЕНИЯ, а не типы полей. Здесь стоял список — text, email, tel,
   search, password — и `number` в него просто не попал: поле цены выходило 177x21
   при кегле 13 против 293x44 при 16 у соседей (замер 09.09.26 на форме каталога).
   То есть палец мимо, и iOS зумит страницу на фокусе. Список участников отстаёт молча
   на первом же новом типе — денилист безопаснее (правило из памяти проекта). */
input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=file]):not([type=range]):not([type=color]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]),
select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit; font-size: var(--fs-base);
  transition: border-color var(--dur-2) var(--ease);
}
textarea { min-height: calc(var(--tap) * 2); line-height: var(--lh-base); resize: vertical; }
@media (hover: hover) { input:hover, select:hover, textarea:hover { border-color: var(--text-dim); } }

/* Фокус на поле: рамка ОДНА — та, что у поля и так есть, она перекрашивается,
   а вокруг мягкое гало. Раньше поверх рамки рисовался ещё и контур с отступом,
   и на поле с ошибкой человек видел три линии разом: красную, зазор и бирюзовую
   (замечено Pet на ките 29.08.26). Гало не смещает раскладку и не спорит с ошибкой. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.field.is-err input, .field.is-err textarea, .field.is-err select { border-color: var(--err); }
.field.is-err input:focus-visible, .field.is-err textarea:focus-visible, .field.is-err select:focus-visible {
  border-color: var(--err);
  box-shadow: 0 0 0 3px var(--err-soft);
}

/* У кнопок, чипов и ссылок своей рамки нет — там контур и остаётся. */
.btn:focus-visible, .chip:focus-visible, .icon-btn:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* `.field > .field-err` — потому что `.field > span` сильнее одного класса и красил ошибку в серый подписи (замер 16.10). */
.field-err, .field > .field-err { display: block; margin-top: var(--sp-1); margin-bottom: 0; font-size: var(--fs-sm); color: var(--err); }

/* Поле кода из письма: цифры крупно и вразрядку — их часто читают с чужого экрана. */
.code-input { font-size: var(--fs-lg); font-weight: 600; letter-spacing: .22em; text-align: center; }

/* Поиск: иконка внутри поля, а не рядом — так поле остаётся одной целью нажатия. */
.search { position: relative; }
.search .ic { position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%); color: var(--text-dim); pointer-events: none; }
/* 🪤 Общее правило полей перечисляет ИСКЛЮЧЕНИЯ десятью :not([type=…]) и весит (0,10,1) —
   любой классовый селектор ему проигрывает, и отступ под иконку молча терялся: иконка ложилась
   на текст (поймал Pet в поиске раздела «Медиа» 20.09.26). Здесь !important осознанно. */
.search input { padding-left: calc(var(--sp-3) * 2 + 20px) !important; }

/* ── чипы-фильтры ──────────────────────────────────────────────────
   Мгновенный фильтр медиатеки. Выключенный чип — не серый и не блёклый:
   выключенных на экране большинство, и они не должны выглядеть сломанными. */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--tap-sm);
  padding: 0 var(--sp-4);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface-soft);
  color: var(--text);
  font: inherit; font-size: var(--fs-sm);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
@media (hover: hover) { .chip:hover { background: var(--surface-sunk); } }
.chip.is-on { background: var(--ink); color: var(--on-ink); }
@media (hover: hover) { .chip.is-on:hover { background: var(--accent); } }
.chip b { font-weight: 400; opacity: .55; }
/* Страховка: приглушённый текст внутри ВКЛЮЧЁННОГО чипа наследует его цвет, а не серый темы —
   иначе счётчик «266» на чёрном чипе пропадает (поймал Pet 20.09.26 в разделе «Медиа»). */
.chip.is-on .muted { color: inherit; opacity: .55; }
/* Иконка направления в чипе: цвет от текста, поэтому во включённом чипе она белеет сама.
   flex: none — иначе на узком экране fleх сжимает её в овал. */
.chip > svg { flex: none; opacity: .75; margin-left: calc(var(--sp-1) * -1); }
.chip.is-on > svg { opacity: 1; }
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Ряд чипов, который на узком экране не переносится, а скроллится вбок:
   переносить четырнадцать направлений в три строки — значит съесть пол-экрана. */
.chips-scroll {
  display: flex; gap: var(--sp-2);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: var(--sp-1);
  margin: 0 calc(var(--gutter) * -1);
  padding-left: var(--gutter); padding-right: var(--gutter);
}
.chips-scroll::-webkit-scrollbar { display: none; }

/* Рельса: тот же ряд чипов, но со стрелками для мыши и затемнением у краёв.
   На телефоне ряд листают пальцем и подсказка не нужна; на компьютере ряд просто
   обрывался у края, и было не видно, что там ещё семь значений. */
.chips-rail { position: relative; }
.chips-rail .chips-scroll { scroll-behavior: smooth; }
/* Центр — по ЧИПУ, а не по ряду: у ряда снизу 4 px (--sp-1) под полосу, и на 50 % высоты стрелка стояла на 2 px ниже
   чипов (поймал Pet 28.09, замер в Chromium и WebKit). Сдвиг — половина разницы полей ряда; под пальцем поля
   симметричны (см. блок «палец») и сдвиг обнуляется. */
.rail-btn {
  position: absolute; top: calc(50% - var(--rail-shift, calc(var(--sp-1) / 2))); transform: translateY(-50%); z-index: 1;
  display: none; align-items: center; justify-content: center;
  width: var(--tap-sm); height: var(--tap-sm);
  border: 1px solid var(--hairline); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--ink);
  cursor: pointer;
  transition: border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}
@media (hover: hover) { .rail-btn:hover { border-color: var(--ink); } }
/* Стекла на стрелках НЕТ — пробовали 28.09 (идея Pet) и сняли в тот же вечер: над ВЫБРАННЫМ (чёрным) чипом стекло
   давало мутно-серое пятно, а затухание края рельсы размазывало его в сторону (ТГ 499, снимок A/B
   _lab/shots/rail-ab.png). Стекло хорошо на фото, не на тёмных плоских заливках. */
.rail-btn[data-rail="prev"] { left: calc(var(--gutter) * -1 + var(--sp-1)); }
.rail-btn[data-rail="next"] { right: calc(var(--gutter) * -1 + var(--sp-1)); }
.chips-rail.has-prev .rail-btn[data-rail="prev"],
.chips-rail.has-next .rail-btn[data-rail="next"] { display: inline-flex; }
/* Затемнение у края — намёк, что ряд продолжается. Маской, а не плашкой:
   плашка перекрыла бы чип и мешала бы по нему попасть. */
.chips-rail.has-next .chips-scroll {
  mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
}
.chips-rail.has-prev.has-next .chips-scroll {
  mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent);
}
.chips-rail.has-prev:not(.has-next) .chips-scroll {
  mask-image: linear-gradient(to right, transparent, #000 48px);
}
@media (max-width: 767px) {
  .rail-btn { display: none !important; }
}

/* ── бейджи ───────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-0) var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
  color: var(--text-dim);
  font-size: var(--fs-xs); font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
}
.badge-accent { background: var(--accent-soft); color: var(--accent-ink); }
.badge-live   { background: var(--err-soft);    color: var(--err); }
.badge-ok     { background: var(--ok-soft);     color: var(--ok); }
.badge-warn   { background: var(--warn-soft);   color: var(--warn); }

/* <picture> — прозрачная обёртка: раскладку задаёт <img> внутри, как и раньше.
   Без этого picture стал бы инлайновой коробкой и сломал object-fit у обложек. */
picture { display: contents; }

/* ── карточки ─────────────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--sp-5);
}
.card-flat { border: 0; background: var(--surface-soft); }

/* Карточка записи — главный элемент витрины. Обложка, тип, название до трёх
   строк, преподаватель, длительность, цена. Название обрезаем по строкам,
   а не по буквам: в каталоге есть заголовки на девять слов с санскритом. */
.rec {
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease),
              background-color var(--dur-2) var(--ease);
}
@media (hover: hover) { .rec:hover { border-color: var(--text-dim); background: var(--surface-raised); box-shadow: var(--shadow-raise); } }

/* ── Поведение карточки — «комбо» из лабы G (D-0177, 01.10.26): отклик + появление + тон записи.
   Вид не меняется, меняется только движение и состояния. Движение — только тому, кто не просил «меньше движения»,
   наведение — только там, где есть настоящий курсор. «Кнопку с карточкой» не берём: тон и так красит кнопку. */

/* ОТКЛИК. Подъём и сжатие — только transform; остальное — те же свойства и те же 200 мс. */
@media (prefers-reduced-motion: no-preference) {
  .rec {
    transition: transform var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease),
                box-shadow var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
  }
  .rec .btn {
    transition: transform var(--dur-1) var(--ease), background-color var(--dur-2) var(--ease),
                border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease), opacity var(--dur-1) var(--ease);
  }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .rec:hover { transform: translateY(-2px); }
  /* Подъём уводит нижний край из-под неподвижного курсора: на нижних 2 px карточка теряла бы наведение и падала
     обратно, и так по кругу. Пока она поднята — невидимая нижняя кромка в 4 px. Для кромки .rec не режет выходящее
     за край, поэтому углы обложки режет сама обложка: вид тот же (радиус минус рамка). */
  .rec { position: relative; overflow: visible; }
  .rec > .rec-cover { overflow: hidden; border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0; }
  .rec:hover::after { content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 4px; }
}
/* Нажатие: карточка садится (.98, вход 120 мс, возврат 200), кнопка внутри — .97: карточка одна ссылка.
   🪤 Стоит ПОСЛЕ подъёма: вес селекторов равный, и раньше подъём перебивал сжатие (замер 01.10: −2 px на нажатии). */
@media (prefers-reduced-motion: no-preference) {
  .rec:active:not(:has(.rec-fav:active)) { transform: scale(.98); transition-duration: var(--dur-1); }
  .rec:active:not(:has(.rec-fav:active)) .btn { transform: scale(.97); }
}
.rec:active:not(:has(.rec-fav:active)) { border-color: var(--text-dim); box-shadow: none; }
/* Фокус клавишей — без анимации, кольцо тёмной бирюзой: --accent на белом даёт 2,3 : 1 при пороге 3.
   Фокус теперь на ссылке-заголовке, кольцо — на всей карточке (правило у .rec-link ниже). */

/* ТОН ЗАПИСИ. Под курсором карточка берёт мягкий тон своей обложки (`--rec-h` из accent_hue ставит _rec.php),
   подпись — тоном (серое на цветном не оставляем), кнопка — линией тона. Правило одного края: заливка и тень,
   граница прозрачная. Стоит ПОСЛЕ :active — на нажатии граница остаётся прозрачной, уходит только тень. */
.rec-meta { transition: color var(--dur-2) var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .rec:hover { background: var(--rec-soft); border-color: transparent; }
  .rec:hover .rec-meta { color: var(--rec-ink); }
  .rec:hover .btn-soft:not(:hover) { background: var(--rec-line); color: var(--rec-ink); }
}

/* ПОЯВЛЕНИЕ. Первый экран собирается один раз: проявление со сдвигом 8 px, шаг 50 мс, не больше восьми ступеней.
   Класс .rec-in ставит ui.js в <head> — ДО первой отрисовки, поэтому вспышки готовой карточки нет. Без скрипта и
   при «меньше движения» класса нет — карточки стоят готовыми. Через 1,2 с класс снимается: фильтр и сортировка
   медиатеки, вставив карточку заново, каскад не повторяют. На перелёте обложки (D-0169) класс снимается сразу. */
@keyframes rec-in { from { opacity: 0; transform: translateY(8px); } }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(-n+8) { animation: rec-in var(--dur-3) var(--ease) backwards; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(2) { animation-delay: 50ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(3) { animation-delay: 100ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(4) { animation-delay: 150ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(5) { animation-delay: 200ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(6) { animation-delay: 250ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(7) { animation-delay: 300ms; }
.rec-in :is(.grid-recs, .recs-rail) > .rec:nth-child(8) { animation-delay: 350ms; }
/* Пропорция обложки берётся из токена: она квадратная (замер по всем 120 картинкам
   витрины). Обрезаем по центру — у двух вертикальных исключений так теряется меньше. */
.rec-cover {
  position: relative;
  aspect-ratio: var(--cover);
  background: var(--surface-soft);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-dim);
}
.rec-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Пока обложка едет — мягкое мерцание вместо пустой рамки. Обложки лежат на боевом
   сайте и весят под сотню килобайт: замер 29.08.26 — 70–90 КБ и полторы-две секунды
   на картинку. Место под неё держит aspect-ratio, поэтому список не дёргается.
   Класс снимает скрипт по событию load, а не таймером. */
.rec-cover.is-wait { animation: sk 1.4s ease-in-out infinite; }
.rec-cover.is-wait img { opacity: 0; }
.rec-cover img { transition: opacity var(--dur-2) var(--ease); }
.rec-cover .badge { position: absolute; left: var(--sp-2); top: var(--sp-2); background: var(--surface); }
/* «Стекло» на обложке (идея Pet 28.09): поверхность на 70 % + размытие того, что под ней. Текст — --ink, не --text-dim:
   худший случай — чёрный участок обложки, фон выходит ≈ #b3b3b3, и серый текст там провалился бы (2.3:1), а --ink ≈ 7:1.
   Без размытия в браузере и при «меньше прозрачности» в системе — сплошная поверхность, как было. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .rec-cover .badge:not(.badge-live) {
    background: color-mix(in srgb, var(--surface) var(--glass, 55%), transparent);   /* 70 → 55: Pet 28.09 «проявить картинку» */
    -webkit-backdrop-filter: var(--glass-filter, blur(10px) saturate(1.3)); backdrop-filter: var(--glass-filter, blur(10px) saturate(1.3));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--surface) 45%, transparent);
    color: var(--ink);
  }
}
/* Тёмная тема: стекло прозрачнее (Pet 28.09: «можно даже чуть прозрачнее»), а то, что под ним, ПРИТУШЕНО яркостью —
   иначе на светлых обложках тёмное стекло светлело, и светлый текст проваливался (замер 55 %: 12 плашек из 120 < 4.5). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --glass: 40%; --glass-filter: blur(10px) saturate(1.3) brightness(.55); }
}
:root[data-theme="dark"] { --glass: 40%; --glass-filter: blur(10px) saturate(1.3) brightness(.55); }
@media (prefers-reduced-transparency: reduce) {
  .rec-cover .badge:not(.badge-live) { background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
.rec-body { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); flex: 1 0 auto; }
.rec-title {
  font-family: var(--font-head);
  font-size: var(--fs-md); font-weight: 700; line-height: var(--lh-snug);
  letter-spacing: -.01em;
  color: var(--ink);
  margin: 0;
  /* Три строки (Pet 27.10, замер медиатеки): в две не влезали 12 из 132 названий на телефоне и 26 на ПК, в три — 1 и 6. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* Карточка — блок, ссылка — заголовок, растянутый на всю карточку (c70): так сердечко стоит поверх, а не внутри ссылки. */
.rec { position: relative; }
.rec-link { color: inherit; text-decoration: none; }
.rec-link::after { content: ''; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.rec-link:focus-visible { outline: none; }
.rec:has(.rec-link:focus-visible) { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
/* Сердечко (c70): в левом верхнем углу обложки (кнопка — ребёнок карточки, обложка сверху, угол тот же), выше растяжки
   ссылки. Ростом и скруглением — как плашка вида рядом (Pet 27.10: «размером как бейджик»), --fav-h; плашка — правее. */
.rec { --fav-h: 26px; }
.rec-fav { position: absolute; left: var(--sp-2); top: var(--sp-2); z-index: 2; display: grid; place-items: center;
           width: var(--fav-h); height: var(--fav-h); padding: 0; border: 0; border-radius: var(--radius-sm); cursor: pointer;
           background: var(--surface); color: var(--ink);
           transition: transform var(--dur-1) var(--ease), color var(--dur-2) var(--ease); }
.rec-fav svg { width: 16px; height: 16px; }
.rec-fav::before { content: ''; position: absolute; inset: -9px; }   /* палец попадает с запасом: 44 px */
.rec-fav svg { transition: fill var(--dur-2) var(--ease); }
.rec-fav.is-on { color: var(--accent-ink); }
.rec-fav.is-on svg { fill: currentColor; }
.rec-fav:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
@media (hover: hover) { .rec-fav:hover { color: var(--accent-ink); } }
@media (prefers-reduced-motion: no-preference) { .rec-fav:active { transform: scale(.88); } }
.rec-fav ~ .rec-cover .badge:not(.badge-promo) { left: calc(var(--sp-2) + var(--fav-h) + 6px); }
/* Стекло — как у плашки вида рядом (Pet 27.10): та же дымка, размытие и кромка; без размытия — сплошная поверхность. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .rec-fav {
    background: color-mix(in srgb, var(--surface) var(--glass, 55%), transparent);
    -webkit-backdrop-filter: var(--glass-filter, blur(10px) saturate(1.3)); backdrop-filter: var(--glass-filter, blur(10px) saturate(1.3));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--surface) 45%, transparent);
  }
}
@media (prefers-reduced-transparency: reduce) {
  .rec-fav { background: var(--surface); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
.rec-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); font-size: var(--fs-xs); color: var(--text-dim); }
.rec-meta span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.rec-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-3); margin-top: auto; padding-top: var(--sp-2); }
.rec-foot .btn { white-space: nowrap; }
.rec-price { font-family: var(--font-head); font-size: var(--fs-lg); font-weight: 700; color: var(--ink); letter-spacing: -.01em; }
.rec-price small { font-family: var(--font); font-size: var(--fs-xs); font-weight: 400; color: var(--text-dim); }
/* Акция (c68): старая цена мелко над новой — две строки в высоту кнопки, карточка не растёт (Pet 27.10). */
.rec-price.is-promo { display: grid; line-height: 1; gap: 2px; color: var(--warn); }
.rec-price.is-promo s { font-family: var(--font); font-size: var(--fs-xs); font-weight: 400; color: var(--text-dim); letter-spacing: 0; }
.rec-was { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 6px; }
.rec-code { font-family: var(--font); font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em; color: var(--warn); }
/* Код акции — плашкой на обложке справа, в тёплом тоне кнопки «Акция» медиатеки. */
.rec-cover .badge.badge-promo { left: auto; right: var(--sp-2); background: var(--warn); color: var(--surface); font-weight: 600; }

/* Сетка каталога: на узком — одна колонка, дальше растёт сама.
   Ступенек по ширине нет — только один структурный флип в шапке. */
.grid-recs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--sp-4);
}

/* ── шапка и подвал ────────────────────────────────────────────────
   Шапка липкая: в медиатеке длинная лента, и человек не должен листать
   вверх, чтобы вернуться к поиску. Тень появляется только при прокрутке. */
.site-header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
  /* Поля по вертикали меньше, а логотип крупнее: шапка была высокой и пустоватой,
     бренд в ней терялся (замечание Pet 29.08.26). */
  padding: var(--sp-2) 0;
  padding-top: max(var(--sp-2), env(safe-area-inset-top));
  transition: transform var(--dur-3) var(--ease);
}
/* Уезжает вверх, когда листают вниз, и возвращается от первого движения вверх:
   на телефоне шапка съедает седьмую часть экрана, а нужна не всё время. */
.site-header.is-away { transform: translateY(-100%); }
.site-header .wrap { display: flex; align-items: center; gap: var(--sp-3); }
.site-header .spacer { flex: 1; }
/* Логотип дизайнера вставлен разметкой и красится currentColor — на тёмной теме
   становится светлым сам, без второй картинки и без фильтров. */
.brand { display: inline-flex; align-items: center; color: var(--ink); text-decoration: none; line-height: 0; }
.brand .logo { display: block; height: 32px; width: auto; }
/* Бренд всегда одного тона — цвета заголовков, где бы ни стоял. */
.logo, .logo-mark { color: var(--ink); }
@media (max-width: 767px) {
  .brand .logo { height: 26px; }
}
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--tap); height: var(--tap);
  border: 0; border-radius: var(--radius-pill);
  background: none; color: var(--ink);
  cursor: pointer;
  transition: background-color var(--dur-2) var(--ease);
}
@media (hover: hover) { .icon-btn:hover { background: var(--surface-soft); } }

/* В тумблере лежат обе иконки, показана та, которая предлагает переключиться:
   днём — луна, ночью — солнце. Так кнопка говорит о действии, а не о состоянии. */
.ic-sun { display: none; }
.ic-moon { display: inline-block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ic-sun { display: inline-block; }
  :root:not([data-theme="light"]) .ic-moon { display: none; }
}
:root[data-theme="dark"] .ic-sun { display: inline-block; }
:root[data-theme="dark"] .ic-moon { display: none; }
:root[data-theme="light"] .ic-sun { display: none; }
:root[data-theme="light"] .ic-moon { display: inline-block; }
.site-footer {
  border-top: 1px solid var(--hairline);
  padding: var(--sp-5) 0;
  padding-bottom: max(var(--sp-5), env(safe-area-inset-bottom));
  margin-top: var(--sp-8);
  color: var(--text-dim); font-size: var(--fs-sm);
}

/* ── шторка снизу ──────────────────────────────────────────────────
   Мобильный способ показать фильтры: диалог по центру на телефоне
   неудобен — до верхних кнопок не достаёт большой палец. */
.sheet-overlay {
  position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: var(--z-sheet);
  background: var(--overlay);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-3) var(--ease);
}
.sheet-overlay.is-open { opacity: 1; pointer-events: auto; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-sheet) + 1);
  max-height: 85vh; overflow-y: auto;
  background: var(--surface-raised);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-sheet);
  padding: var(--sp-4) var(--gutter);
  padding-bottom: max(var(--sp-5), env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform var(--dur-3) var(--ease);
}
.sheet.is-open { transform: translateY(0); }
/* Шторка — стекло (Pet 28.09: «чтобы просвечивала медиатеку»): все шторки одним правилом — фильтры, меню, фрагмент.
   Под ней и так затемнение (--overlay), поэтому 82 % поверхности хватает, чтобы текст в шторке читался без оговорок. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .sheet { background: color-mix(in srgb, var(--surface-raised) 82%, transparent);
           -webkit-backdrop-filter: blur(20px) saturate(1.3); backdrop-filter: blur(20px) saturate(1.3); }
}
@media (prefers-reduced-transparency: reduce) {
  .sheet { background: var(--surface-raised); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
.sheet-grip { width: 36px; height: 4px; border-radius: var(--radius-pill); background: var(--surface-sunk); margin: 0 auto var(--sp-4); }
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-4); }

/* ── сообщения ────────────────────────────────────────────────────── */
.note { border-radius: var(--radius); padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-4); font-size: var(--fs-sm); }
.note-ok   { background: var(--ok-soft);     color: var(--ok); }
.note-err  { background: var(--err-soft);    color: var(--err); }
.note-warn { background: var(--warn-soft);   color: var(--warn); }
.note-info { background: var(--accent-soft); color: var(--accent-ink); }

.toast {
  position: fixed; left: 50%; bottom: var(--sp-6); z-index: var(--z-toast);
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-pill);
  background: var(--ink); color: var(--on-ink);
  font-size: var(--fs-sm);
  box-shadow: var(--shadow-raise);
}

/* ── пустое состояние ─────────────────────────────────────────────── */
.empty { text-align: center; padding: var(--sp-8) var(--sp-4); color: var(--text-dim); }
.empty .ic { color: var(--surface-sunk); margin-bottom: var(--sp-3); }
.empty h3 { color: var(--ink); margin-bottom: var(--sp-2); }

/* ── скелетон загрузки ────────────────────────────────────────────── */
.sk { background: var(--surface-sunk); border-radius: var(--radius-sm); animation: sk 1.4s ease-in-out infinite; }
.sk-line { height: 12px; margin-bottom: var(--sp-2); }
.sk-cover { aspect-ratio: 16 / 9; border-radius: var(--radius); }
@keyframes sk { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }

/* ── полоса доступа ────────────────────────────────────────────────
   «Доступ открыт до 12 сентября» — в кабинете это главный факт карточки. */
.meter { height: 6px; border-radius: var(--radius-pill); background: var(--surface-sunk); overflow: hidden; }
.meter i { display: block; height: 100%; background: var(--accent); border-radius: inherit; }
.meter.is-low i { background: var(--warn); }

/* ── аккордеон (программа курса) ──────────────────────────────────── */
.acc { border-top: 1px solid var(--hairline); }
.acc summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: var(--tap);
  padding: var(--sp-3) 0;
  cursor: pointer;
  list-style: none;
  font-weight: 600; color: var(--ink);
}
.acc summary::-webkit-details-marker { display: none; }
.acc summary .ic { color: var(--text-dim); transition: transform var(--dur-2) var(--ease); flex: none; }
.acc[open] summary .ic { transform: rotate(180deg); }
.acc-body { padding: 0 0 var(--sp-4); color: var(--text); }

/* ── плавное раскрытие аккордеонов — КАНОН (слово Pet 28.09) ─────────────
   Все <details> витрины (фильтры, вопросы, уроки курса) раскрываются высотой и проявлением, а не щелчком.
   Чистый CSS: ::details-content + interpolate-size (Chromium 131+). Где этого нет (Safari сейчас) — открывается
   мгновенно, как раньше: правило с незнакомым псевдоэлементом браузер просто отбрасывает. JS не нужен.
   overflow-clip-margin — чтобы невидимая область пальца у чипов (::after, 5 px) не обрезалась по краю. */
:root { interpolate-size: allow-keywords; }
details.acc::details-content, details.faq-item::details-content, details.rp-lesson::details-content {
  block-size: 0; opacity: 0; overflow-y: clip; overflow-clip-margin: 6px;
  transition: block-size var(--dur-3) var(--ease), opacity var(--dur-3) var(--ease),
              content-visibility var(--dur-3) allow-discrete;
}
details.acc[open]::details-content, details.faq-item[open]::details-content, details.rp-lesson[open]::details-content {
  block-size: auto; opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  details.acc::details-content, details.faq-item::details-content, details.rp-lesson::details-content { transition: none; }
}

/* ── тонкие утилиты. Их намеренно мало: раскладка живёт в компонентах ── */
.row   { display: flex; align-items: center; gap: var(--sp-3); }
.stack { display: flex; flex-direction: column; gap: var(--sp-3); }
.between { justify-content: space-between; }
.narrow { max-width: 420px; margin: 0 auto var(--sp-8); }   /* верх — у main (28.09) */

@media (max-width: 767px) {
  .narrow { margin: 0 auto var(--sp-5); }   /* верх — у main (28.09) */
  .grid-recs { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
}

/* Человеку, который просил систему не анимировать, ничего не двигаем. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* 🚩 Гасим переходы на один кадр при смене темы — иначе часть элементов остаётся
   в старом цвете. Поймано замером в браузере: у карточки записи есть
   transition: border-color, и её граница после переключения оставалась светлой,
   пока элемент чем-нибудь не тронешь (у .card без transition всё темнело сразу).
   Заодно страница не перетекает цветами полсекунды — переодевание должно быть
   мгновенным, а не «плавным». Класс вешает и снимает тумблер в layout. */
.no-anim, .no-anim *, .no-anim *::before, .no-anim *::after {
  transition: none !important;
}

/* ── медиатека ─────────────────────────────────────────────────────
   Панель поиска и сортировки, быстрые чипы, полоска выбранного.
   Раскладка живёт здесь; значения — в токенах. */
/* Верх --sp-5, как отступ .page на всех прочих страницах: с --sp-6 медиатека отходила
   от шапки на 32 px против 24 у главной — те самые «лишние десять на глаз» (Pet 09.09,
   замер: 32 против 24 и на телефоне, и на ПК). */
.med-head { margin: 0 0 var(--sp-4); }   /* верх — у main (28.09) */
/* Ширину абзаца не режем: на широком экране обрывок в две строки посреди пустоты
   читается как недоделка (решение Pet 29.08.26). */

.med-bar { display: flex; gap: var(--sp-2); align-items: center; margin-bottom: var(--sp-3); }
.med-search { flex: 1; min-width: 0; }
.med-sort {
  width: auto; min-height: var(--tap); flex: none;
  padding-right: var(--sp-4);
}
/* Сортировка своим списком (initCombos, 28.09) — там, где мышь: обёртка встаёт на место селекта, кнопка не прыгает
   по ширине при смене пункта (под самый длинный — «Популярные за всё время»), список не уже своего самого длинного пункта. */
.med-bar .combo { flex: none; }
.med-bar .combo-btn { width: auto; min-width: 15.5em; }   /* под «Популярные за всё время» (27.10) */
.med-bar .combo-list { right: auto; min-width: 100%; width: max-content; }
.med-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--ink); color: var(--on-ink);
  font-size: var(--fs-xs); font-weight: 600;
}
.med-quick { margin-bottom: var(--sp-3); }
.med-picked { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.med-total { margin: 0 0 var(--sp-4); }

/* Шторка фильтров: на телефоне во всю ширину снизу, на широком — по центру,
   но всё той же шторкой. Второй раскладки не заводим, пока она не понадобилась. */
.med-sheet { max-width: 640px; margin: 0 auto; }
/* На ПК шире (Pet 28.09): у асан и преподавателей по десятку чипов — в 640 они шли столбиком по три. */
@media (min-width: 1024px) { .med-sheet { max-width: min(920px, calc(100vw - 96px)); } }
.med-sheet .acc:first-of-type { border-top: 0; }
.med-in-group { display: block; margin-bottom: var(--sp-3); }
/* Низ шторки прижат к САМОМУ краю: нижний отступ шторки отдан ему (padding-bottom: 0 у шторки), иначе липкий низ
   вставал над этим отступом, и чипы асан ехали полосой ПОД кнопкой «Показать» (поймал по скрину Pet 28.09). */
.med-sheet { padding-bottom: 0; }
.med-sheet-foot {
  position: sticky; bottom: 0;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0 max(var(--sp-4), env(safe-area-inset-bottom));
  margin-top: var(--sp-4);
  background: var(--surface-raised);
  border-top: 1px solid var(--hairline);
}
/* Низ — во всю ширину шторки, заподлицо с её стеклом (ТГ 504: был белым прямоугольником уже шторки — стекло в стекле
   размывает уже белый фон самой шторки, и низ выходил сплошной вставкой с жёсткими краями). Поля шторки отдаём ему
   отрицательным отступом, фон — тот же тон шторки чуть плотнее, чтобы список под ним читался как «продолжается». */
.med-sheet-foot { margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter); }
/* Второй заход того же вечера (Pet: «всё равно слишком контрастная»): низ без своей плашки и без черты — список
   мягко уходит под кнопки затуханием 16 px, дальше тон шторки. Своё размытие снято: стекло в стекле и давало вставку. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .med-sheet-foot {
    border-top: 0;
    background: linear-gradient(to bottom, transparent, color-mix(in srgb, var(--surface-raised) 88%, transparent) var(--sp-4));
  }
}
/* «Сбросить»: пока выбирать нечего — приглушена и неактивна (правило скилла disabled-states: 0.38–0.5), выбрано —
   обведённая кнопка со счётчиком «Сбросить · N»: видно, что и сколько она снимет. */
.med-reset:disabled { opacity: .4; cursor: default; }
.med-reset.is-armed { border-color: var(--ink); color: var(--ink); font-variant-numeric: tabular-nums; }
@media (prefers-reduced-transparency: reduce) {
  .med-sheet-foot { background: var(--surface-raised); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
.med-sheet-foot .btn-wide { flex: 1; }

@media (max-width: 767px) {
  /* На телефоне поиск занимает строку целиком, а кнопка фильтров и сортировка
     делят вторую пополам: три строки подряд съедали экран до первой карточки. */
  .med-bar { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-2); }
  .med-search { grid-column: 1 / -1; }
  .med-sort { width: 100%; }
  .med-bar .btn { width: 100%; }
  /* С акцией (Pet 27.10): «Фильтры» и «Акция» пополам, сортировка строкой ниже во всю ширину — без просветов.
     Без акции — как было: фильтры и сортировка пополам. */
  .med-bar.has-promo :is(.med-sort, .combo) { grid-column: 1 / -1; }
}
/* Поиск и «Акция» в шторке — одной строкой над осями. */
.med-sheet-top { display: flex; gap: var(--sp-2); align-items: center; margin-bottom: var(--sp-3); }
.med-sheet-top .search { flex: 1; min-width: 0; }
@media (max-width: 767px) {
  /* Шторка выше (Pet 27.10): в ней теперь поиск и акция, оси свёрнуты — раскрытой осям нужно место. */
  .med-sheet { max-height: 92vh; max-height: 92dvh; }
}
/* «Акция» — видна, пока акция идёт (Pet 27.10: «чтоб было заметно»): тёплая рамка, включённая — залита. */
.med-promo { flex: none; border-color: color-mix(in oklch, var(--warn) 55%, transparent); color: var(--warn); }
.med-promo b { font-weight: 400; opacity: .7; }
.med-promo.is-on { background: var(--warn); border-color: var(--warn); color: var(--surface); }
@media (hover: hover) { .med-promo:hover { border-color: var(--warn); } }

/* Значение фильтра, которое в текущей выборке ничего не даст. Не прячем — список
   не должен прыгать под пальцем, — но гасим и не даём нажать. */
.chip.is-off { opacity: .35; pointer-events: none; }

/* ── подвал ────────────────────────────────────────────────────────
   Значения сняты с боевого (mhtml от Pet), а не подобраны на глаз: радиус 50
   по внешним углам, внутренний стык прямой — две панели читаются как один блок;
   светлая панель #e9e9e7, заголовок соцсетей 30.
   Ширина — холст страницы (--content), как у всего остального: во всю ширину окна
   подвал на широком мониторе спорил с контентом (решение Pet 03.09.26). На боевом
   он тоже во всю ширину, но там и контент без холста. */
.site-footer {
  border-top: 0;
  padding: 0 0 var(--sp-6);
  padding-bottom: max(var(--sp-6), env(safe-area-inset-bottom));
  margin-top: var(--sp-8);
  color: var(--text);
}
.foot-wide { width: 100%; max-width: var(--content); margin: 0 auto; padding: 0 var(--gutter); }

.foot-panels { display: grid; grid-template-columns: minmax(0, 2.6fr) minmax(0, 1fr); }
.foot-main {
  background: var(--foot-main); color: var(--foot-main-fg);
  border-radius: var(--foot-radius) 0 0 var(--foot-radius);
  padding: var(--sp-7) var(--sp-6);
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-6);
}
.foot-main .logo { color: var(--foot-main-fg); }
.foot-brand { display: inline-flex; margin-bottom: var(--sp-5); }
/* Логотип в подвале вдвое крупнее шапки: здесь ему есть где стоять, и подвал —
   последнее, что видит человек (Pet 03.09.26). На телефоне чуть меньше. */
.foot-brand .logo { height: 76px; }
@media (max-width: 767px) { .foot-brand .logo { height: 56px; } }
.foot-nav { display: flex; flex-direction: column; gap: var(--sp-2); }
.foot-nav a {
  color: var(--foot-main-fg); font-size: var(--fs-sm);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: rgba(255, 255, 255, .4);
}
@media (hover: hover) { .foot-nav a:hover { text-decoration-color: var(--accent); } }
.foot-legal { font-size: var(--fs-xs); line-height: 1.8; opacity: .8; }
.foot-legal p { margin: 0 0 var(--sp-4); }
.foot-legal a { color: var(--foot-main-fg); }

.foot-social {
  background: var(--foot-soft);
  border-radius: 0 var(--foot-radius) var(--foot-radius) 0;
  padding: var(--sp-7) var(--sp-6);
  display: flex; flex-direction: column; justify-content: center; gap: var(--sp-4);
}
.foot-social h3 {
  margin: 0; color: var(--ink);
  font-size: 30px; text-transform: uppercase; letter-spacing: .02em;   /* замер с боевого */
}
.foot-soc { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: 0; }
.foot-soc a { color: var(--ink); display: inline-flex; }
@media (hover: hover) { .foot-soc a:hover { color: var(--accent); } }
/* Пометка про Meta: звёздочка у значка и мелкая сноска под рядом (Pet 26.10). */
.foot-soc sup { font-size: 12px; line-height: 1; margin-left: 1px; align-self: flex-start; }
.foot-note { margin: 0; font-size: var(--fs-xs); line-height: 1.35; color: var(--text-dim); max-width: 36ch; }

.foot-pay { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--sp-5); margin-top: var(--sp-6); }
.foot-pay img { height: 24px; width: auto; }
.foot-pay-systems { height: 18px !important; max-width: 100%; }

@media (max-width: 767px) {
  /* На телефоне панели встают стопкой и скругляются сверху и снизу — как на боевом. */
  .foot-panels { grid-template-columns: minmax(0, 1fr); }
  .foot-main {
    grid-template-columns: minmax(0, 1fr); gap: var(--sp-5);
    border-radius: var(--foot-radius) var(--foot-radius) 0 0;
    padding: var(--sp-6) var(--sp-5);
  }
  .foot-social {
    border-radius: 0 0 var(--foot-radius) var(--foot-radius);
    padding: var(--sp-6) var(--sp-5);
  }
}

/* Ссылка входа в шапке — того же роста, что иконки рядом. */
.head-link { min-height: var(--tap); font-size: var(--fs-sm); }
/* «Править» в шапке — команде с планшета и ПК; на телефоне шапке тесно, правят с компьютера. */
.head-edit { display: none; }
@media (min-width: 600px) { .head-edit { display: inline-flex; } }

/* ── разделы в шапке ──────────────────────────────────────────────
   На ПК ссылки стоят строкой рядом с логотипом, бургера нет; на телефоне
   строка прячется, разделы живут в шторке за бургером (решение Pet 03.09.26).
   Один брейк 768, как во всём ките. */
.site-nav { display: flex; align-items: center; gap: var(--sp-1); margin-left: var(--sp-3); }
.site-nav-link {
  display: inline-flex; align-items: center; min-height: var(--tap);
  padding: 0 var(--sp-3); border-radius: var(--radius-pill);
  color: var(--text); text-decoration: none; font-size: var(--fs-sm);
  transition: background-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
@media (hover: hover) { .site-nav-link:hover { background: var(--surface-soft); color: var(--ink); } }
/* Где вы сейчас — подчерк цветом акцента, а не заливка: заливка спорила бы с чипами. */
.site-nav-link.is-here { color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent); border-radius: 0; }
@media (hover: hover) { .site-nav-link.is-here:hover { background: none; } }
.only-mobile { display: none; }
@media (max-width: 767px) {
  .only-mobile { display: inline-flex; }
  .only-desktop { display: none; }
}

/* ── страница с заголовком ────────────────────────────────────────────
   Отступ от шапки — один на всех, классом, а не инлайном в каждом шаблоне:
   каждая новая страница забывала его заново (кабинет и управление 03.09.26,
   поймал Pet глазами). SUPERSEDE 28.09: отступ теперь у main — одно число на все страницы (base.css). */
.page { }   /* отступ под шапкой переехал на main (28.09); класс оставлен — на нём висят вложенные правила */

/* ── кабинет и управление ─────────────────────────────────────────── */
.cab-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.cab-top h1 { margin: 0 0 var(--sp-1); }
/* Библиотека (D-0081): три группы, карточки те же, что в медиатеке. */
.lib-tools { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.lib-search { flex: 1; min-width: 220px; }
/* Группы «Занятий» — каждая в рамке (Pet 27.10), над первыми двумя — «Мои доступы». */
.lib-section { margin: 0 0 var(--sp-3); }
.lib-group { margin-top: var(--sp-4); padding: var(--sp-5); border: 1px solid var(--hairline); border-radius: var(--radius-lg); background: var(--surface); }
.lib-group:first-of-type { margin-top: 0; }
@media (max-width: 639px) { .lib-group { padding: var(--sp-4) var(--sp-3); } }
.lib-head { margin-bottom: var(--sp-3); }
.lib-head :is(h2, h3) { margin: 0 0 var(--sp-1); font-size: var(--fs-lg); }
.lib-head :is(h2, h3) b { font-weight: 400; font-size: var(--fs-md); margin-left: var(--sp-1); }
.lib-head p { margin: 0; }
/* Состояние доступа на карточке вместо цены. */
.rec-note { font-size: var(--fs-xs); color: var(--ok); line-height: var(--lh-snug); }
.rec-note.is-off { color: var(--text-dim); }
/* Просмотр на карточке записи: сцена и текущий урок. */
.player[data-stage] { cursor: pointer; }
/* Сцена — во всю ширину своей колонки и по левому краю, как кнопки под ней и ряд уроков.
   Потолок по высоте с центрированием (пробовал 04.09.26) ужимал ТОЛЬКО видео: кнопки и ряд
   оставались во всю ширину, и левые края разъезжались — поймал Pet глазами, замером это
   не ловится, потому что каждый блок по отдельности «правильный». Ряд, если не помещается
   на низком экране, доводится прокруткой в play(), а не сжатием кадра. */
.player.is-live { aspect-ratio: 16 / 9; background: #000; }
.player.is-live img { display: none; }
.rp-watch .rp-price { color: var(--ok); }
.rp-watch-row { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin: var(--sp-2) 0 0; }
/* Текущий урок курса — полоса у заголовка, не у всего тела: на одиночном уроке полоса
   вдоль абзаца читалась как артефакт (поймал Pet 03.09.26).
   Полоса рисуется отдельным слоем, а не тенью внутрь: inset-тень берёт геометрию summary
   вместе с его отступами, поэтому висела хвостами сверху и снизу (18 и 20 px замером) и
   прижималась к пилюле вплотную — зазор был ровно 0. На телефоне, где заголовок переносится
   на три строки, она вдобавок перечёркивала и номер урока, и название (поймал Pet 04.09.26).
   Слой привязан к содержимому и вынесен левее его на шаг сетки. */
.rp-lesson.is-now > summary { position: relative; }
.rp-lesson.is-now > summary::before {
  content: ""; position: absolute; left: calc(var(--sp-3) * -1);
  top: var(--sp-4); bottom: var(--sp-4);
  width: 3px; border-radius: 2px; background: var(--accent);
}
.rp-lesson.is-now > summary .rp-lesson-title { color: var(--accent-ink); }
/* Пока играет — сцена занимает всю ширину плашки, а текст и карточка доступа встают
   под ней в две колонки. Прежняя раскладка задумывалась как «сцена шире, покупка справа»,
   но места в сетке никому не назначала: `.rp-side` растягивался на всю строку, и авто-раскладка
   сбрасывала карточку доступа в третий ряд — справа от видео оставалась дыра в 384 px
   (замер 04.09.26, поймал Pet глазами). Теперь у каждого блока своя клетка, и видео шире
   на треть: 1248 px против 896 на холсте 1456. На телефоне колонка и так одна. */
@media (min-width: 1100px) {
  .rp-hero.is-watching { grid-template-columns: minmax(0, 1fr) minmax(0, 320px); }
  .rp-hero.is-watching .rp-media    { grid-column: 1 / -1; grid-row: 1; }
  .rp-hero.is-watching .rp-side     { grid-column: 1;      grid-row: 2; }
  .rp-hero.is-watching .rp-buy-col  { grid-column: 2;      grid-row: 2; }
}
.rp-media-actions .btn-ghost { flex: 0 0 auto; }
/* Заказ в истории: дата, номер и способ, сумма справа; состав списком. */
.order-head { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.order-sum { margin-left: auto; font-family: var(--font-head); font-weight: 700; color: var(--ink); }
.order-items { margin: var(--sp-2) 0 0; padding-left: 1.2em; }
.order-items li { margin: var(--sp-1) 0; }
/* Телефон (Pet 27.10): всё по левому краю — сумма строкой под номером, названия без точек списка. */
@media (max-width: 599px) {
  .order-sum { margin-left: 0; flex-basis: 100%; }
  .order-items { list-style: none; padding-left: 0; }
}
/* Заказы сеткой (Pet 27.10): на ПК по три в ряд, на планшете по два, на телефоне — столбиком во всю ширину. */
@media (min-width: 768px) { .order-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .order-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* minmax(0, 1fr), а не голый 1fr: у голого нижняя граница — min-content содержимого,
   и колонка распирается ИМ, а не экраном. На /admin/roles/ таблица «Команда» задала
   треку 472,6 px в коробке 343 — страница ехала вправо на 114 (замер 09.09.26).
   Так написаны все сетки кита; эта и ещё восемь были исключением. */
.cab-grid { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1fr); margin-top: var(--sp-5); }
@media (min-width: 768px) { .cab-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }

/* Разделы внутри управления — чипы, как фильтры в медиатеке. */
.subnav { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-5); }
.admin-tile { display: block; color: inherit; text-decoration: none; }
.admin-tile .ic { color: var(--accent-ink); margin-bottom: var(--sp-2); }
.admin-tile h2 { margin: 0 0 var(--sp-1); }
.admin-tile p { margin: 0; }
@media (hover: hover) { a.admin-tile:hover { border-color: var(--ink); } }
.admin-tile.is-soon { opacity: .6; }

/* ── форма записи в управлении (19.09.26, D-0107) ──────────────────────────
   Чип с галкой внутри: тот же .chip, что фильтр медиатеки, только держит состояние
   через свой checkbox — форма отправляет его сама, скрипт не нужен. */
.chip-check { position: relative; cursor: pointer; }
.chip-check input { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.chip-check:has(input:checked) { background: var(--ink); color: var(--on-ink); }
@media (hover: hover) { .chip-check:has(input:checked):hover { background: var(--accent); } }
.chip-check:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Строка с галкой в форме: галка и подпись — одна цель нажатия. */
.check-line { display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); cursor: pointer; }
.check-line input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--accent); flex: none; }
.check-line-lg { font-size: var(--fs-lg); font-weight: 600; }
/* Повторяемые строки: уроки и программа. Порядок = порядок в списке; переставляются кнопками. */
.rows [data-rows-list] { display: flex; flex-direction: column; gap: var(--sp-3); }
.row-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--sp-3); align-items: start;
  padding: var(--sp-3); border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface-soft);
}
.row-item.is-del { opacity: .45; }
.row-fields { display: grid; gap: var(--sp-3); grid-template-columns: minmax(0, 1fr); }
.row-fields .field { margin: 0; }
.row-fields .field-wide { grid-column: 1 / -1; }
@media (min-width: 768px) { .row-fields { grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1.4fr); } }
.row-tools { display: flex; flex-direction: column; gap: var(--sp-1); }
.acc-inline summary { cursor: pointer; color: var(--accent-ink); }
.acc-inline p { margin: var(--sp-2) 0 0; }
/* Старый текст под полем: подсказка, а не второе поле — свёрнута, раскрывается по слову. */
.old-text { margin: calc(-1 * var(--sp-2)) 0 var(--sp-4); font-size: var(--fs-sm); }
.old-text p { color: var(--text); }
/* Колонки формы: на телефоне одна, на ПК две или три. Голый 1fr в сетке
   тянется под содержимое (замер 09.09.26) — только minmax(0, 1fr). */
.form-cols { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1fr); }
.form-cols .field { margin: 0; }
.form-cols > * { min-width: 0; }
@media (min-width: 768px) {
  .form-cols-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .form-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.cat-form .card { margin-bottom: var(--sp-4); }
.cat-form .field .field { margin-bottom: 0; }
.cat-form-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-4) 0 0; }
/* Обложка: картинка слева, управление справа; на телефоне столбиком. */
.cover-box { display: flex; gap: var(--sp-4); align-items: flex-start; flex-wrap: wrap; }
.cover-box img { width: 180px; height: 180px; object-fit: cover; border-radius: var(--radius); background: var(--surface-soft); display: block; }
.cover-ctl { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
/* Выбранная, ещё не загруженная обложка — пунктиром: файл уйдёт с формой (Pet 24.10). */
.cover-box img.cover-pending { outline: 2px dashed var(--accent-ink); outline-offset: 2px; }
/* Замечания списком в плашке «Сохранено» (Pet 24.10: «пищит 2 замечания — а какие?»). */
.note-list { margin: var(--sp-1) 0 0; padding-left: 1.2em; font-size: var(--fs-sm); }
.note-list a { color: inherit; text-decoration: underline; }
/* Тон обложки кружком: тот же тон, что берёт плашка записи (`--rec-h`, D-0177); нет — бирюза бренда. */
.hue-dot { display: inline-block; width: 1em; height: 1em; border-radius: 50%; vertical-align: -.15em; margin-right: var(--sp-1);
  background: oklch(0.72 0.13 var(--rec-h, 190)); border: 1px solid var(--hairline); }
.hue-dot.is-none { background: var(--surface-soft); }
/* Урок без разбора: программа на странице будет пустой — пусть редактор это видит (#379, 24.10). */
.lc-nosum { color: var(--warn); }
/* Разбор урока (c20): галка «по ролику», свёрнутый разбор как есть, свой разбор — поля и асаны тегами. */
.lc-razbor { display: grid; gap: var(--sp-2); }
.lc-own > .field { margin-top: var(--sp-2); }
.tags-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: var(--sp-1) 0; }
.chip-tag { display: inline-flex; align-items: center; gap: 4px; padding-right: 4px; }
.chip-x { border: 0; background: none; color: inherit; cursor: pointer; font: inherit; line-height: 1; padding: 0 4px; opacity: .7; }
.chip-x:hover, .chip-x:focus-visible { opacity: 1; }
input[type="file"] { font: inherit; font-size: var(--fs-sm); max-width: 100%; }
/* Счётчик длины у подписи поля: число вместо абзаца про норму. */
.counter { font-variant-numeric: tabular-nums; margin-left: var(--sp-2); }
.counter.is-out { color: var(--warn); }
/* Чек-лист готовности к витрине: зелёное сделано, красное не пускает, жёлтое желательно. */
.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.checklist li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.checklist .ic { flex: none; }
.checklist .is-ok   { color: var(--ok); }
.checklist .is-bad  { color: var(--err); }
.checklist .is-warn { color: var(--warn); }
/* Служебная таблица: имя слева, значение справа. */
.svc { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); margin-top: var(--sp-4); }
.svc th, .svc td { padding: var(--sp-2) var(--sp-3); border-top: 1px solid var(--hairline); text-align: left; vertical-align: top; }
.svc th { color: var(--text-dim); font-weight: 400; width: 12em; white-space: nowrap; }
.wrap-any { word-break: break-all; }
/* ── медиа и место (D-0109) ──────────────────────────────────────────────
   Полоса места: сегменты по частям, тон каждого — из OKLCH по кругу, светлота и хрома
   общие, поэтому полоса читается и в тёмной теме. */
.meter { display: flex; height: 14px; border-radius: var(--radius-pill); overflow: hidden; background: var(--surface-sunk); }
.meter > i { display: block; height: 100%; min-width: 2px; }
.meter-legend { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); font-size: var(--fs-sm); }
.meter-legend li { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.meter-legend > li > i { width: 10px; height: 10px; border-radius: 3px; flex: none; align-self: center; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
/* Плитки здоровья: число крупно, подпись мелко; цвет числа — состояние. */
.stat-grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.stat { padding: var(--sp-3) var(--sp-4); border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface-soft); min-width: 0; }
.stat b { display: block; font-size: var(--fs-lg); font-weight: 600; line-height: var(--lh-snug); word-break: break-word; }
.stat span { display: block; font-size: var(--fs-sm); color: var(--text-dim); margin-top: var(--sp-1); }
.stat.is-ok b   { color: var(--ok); }
.stat.is-warn b { color: var(--warn); }
.stat.is-bad b  { color: var(--err); }
/* 🪤 Превью в таблице: у колонки нет своей ширины, авто-раскладка ужимает её, а базовое
   img { max-width: 100% } даёт картинке схлопнуться до ширины ячейки при высоте 64 — на ПК
   уже 1440 выходили полоски 32×64, на телефоне 0×64 (поймал Pet 20.09.26). Колонке — ширина,
   картинке — снятый потолок. */
.media-table td:first-child, .media-table th:first-child { width: 64px; min-width: 64px; padding-right: var(--sp-2); }
.media-table .media-thumb, .media-table picture img { width: 64px; height: 64px; max-width: none; object-fit: cover; border-radius: var(--radius); display: block; background: var(--surface-soft); }
.media-table td.nowrap { white-space: nowrap; }
.media-table .media-src { color: var(--text-dim); font-size: var(--fs-xs); word-break: break-all; }
.media-table tr.is-hidden { display: none; }
/* Увеличение по клику: превью — кнопка, картинка — в нативном диалоге поверх страницы. */
.zoom-btn { display: block; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: var(--radius); }
.zoom-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
dialog.zoom { border: 0; padding: 0; background: transparent; max-width: min(92vw, 1080px); cursor: zoom-out; }
dialog.zoom::backdrop { background: var(--overlay); }
dialog.zoom img { display: block; max-width: 92vw; max-height: 84vh; border-radius: var(--radius); background: var(--surface); }
dialog.zoom p { margin: var(--sp-2) 0 0; text-align: center; color: var(--on-ink); font-size: var(--fs-sm); }
dialog.zoom a { color: var(--on-ink); }
/* Телефон: таблица из шести колонок не читается — строка становится карточкой: превью слева,
   справа где используется, размер и вес строкой, действия внизу (канон «таблицы 3+ колонок → карточки»). */
/* Селекторы с .rights.media-table: правила таблицы прав стоят в файле НИЖЕ и при равной
   специфичности перебивали карточку (линии между ячейками, центровка, ширина 7em). */
@media (max-width: 767px) {
  .rights.media-table, .rights.media-table tbody { display: block; overflow: visible; }
  .rights.media-table thead { display: none; }
  .rights.media-table tr { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: var(--sp-1) var(--sp-3); padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline); }
  .rights.media-table tr.is-hidden { display: none; }
  .rights.media-table td, .rights.media-table td.c { display: block; border: 0; padding: 0; width: auto; min-width: 0; text-align: left; white-space: normal; }
  .rights.media-table td:first-child { grid-row: 1 / span 5; }
  .rights.media-table td:empty { display: none; }
  .rights.media-table td form { justify-content: flex-start !important; margin-top: var(--sp-1); }
}

/* Журнал правок: когда · кто · что, ниже строки «было → стало». */
.hist { list-style: none; margin: 0; padding: 0; }
.hist li { padding: var(--sp-2) 0; border-bottom: 1px solid var(--hairline); font-size: var(--fs-sm); }
.hist li:last-child { border-bottom: 0; }
.hist time { color: var(--text-dim); }
.hist .diff { display: block; color: var(--text); padding-left: var(--sp-3); }
.hist .diff s { color: var(--text-dim); }
/* Таблица прав: строки — действия, столбцы — роли. */
.rights { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.rights th, .rights td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--hairline); text-align: left; vertical-align: top; }
.rights th { color: var(--text-dim); font-weight: 400; }
.rights .c { text-align: center; width: 7em; }
/* Карточки, идущие прямой чередой друг под другом. Своих полей у `.card` нет — в сетках
   расстояние задаёт `gap`, и подряд стоящие карточки слипались в одну простыню (замер
   20.09: зазор 0 px). Правило узкое, только для прямых детей страницы: карточка внутри
   сетки прямым ребёнком не является, и её раскладку это не трогает. */
.page > .card + .card,
.page > .card + .stat-row,
.page > .stat-row + .card { margin-top: var(--sp-4); }

/* Плитки итогов и пара блоков в ряд — у страниц статистики своя сетка: `cab-grid`
   рассчитан на крупные плитки кабинета и на широком экране ломает четвёрку на 2×2. */
.stat-row { display: grid; gap: var(--sp-3); margin: var(--sp-4) 0 var(--sp-5);
            grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); }
.stat { border: 1px solid var(--hairline); border-radius: var(--radius-2, 14px); padding: var(--sp-4); }
.stat b { display: block; font-size: var(--fs-lg); line-height: 1.15; }
.stat span { color: var(--text-dim); font-size: var(--fs-sm); }

/* ── графика: полосы и столбики ────────────────────────────────────────────
   Библиотек нет: нужны четыре примитива, и все рисуются разметкой (D-0117).
   🪤 Заливка полосы — БЛОЧНАЯ, иначе высота дорожки её не касается и полоса пуста.
   🪤 У колонки месяца высота 100 % прописана здесь: проценты у столбика внутри
   считаются от РОДИТЕЛЯ, а от `auto` они дают ноль. */
.chart-bars { display: grid; gap: var(--sp-1); }
.chart-bar { display: grid; grid-template-columns: minmax(0, 17em) 1fr minmax(0, 12em);
             gap: var(--sp-3); align-items: center; font-size: var(--fs-sm); }
.chart-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chart-bar-track { background: var(--hairline); border-radius: var(--radius-pill);
                   height: 14px; overflow: hidden; }
.chart-bar-fill { display: block; height: 100%; background: var(--ink);
                  border-radius: var(--radius-pill); }
.chart-bar-fill.is-soft { background: var(--text-dim); opacity: .45; }
.chart-bar-value { text-align: right; color: var(--text-dim); white-space: nowrap; }

.chart-wrap { display: block; }
.chart-top { margin: 0; text-align: right; font-size: var(--fs-xs); color: var(--text-dim); }
.chart-readout { margin: var(--sp-2) 0 0; font-size: var(--fs-sm); min-height: 1.5em; }
.chart-months { display: flex; align-items: flex-end; gap: 6px; height: 180px;
                padding-top: var(--sp-2); }
/* Пустой месяц — не «ничего не нарисовали», а «в этом месяце ноль»: даём тонкую засечку,
   иначе провал читается как отсутствие данных. */
.chart-month.is-empty i { height: 2px !important; background: var(--hairline); }
.chart-month:hover i, .chart-month:focus-visible i { opacity: .78; }
.chart-month:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.chart-month { flex: 1; height: 100%; min-width: 0; display: flex; flex-direction: column;
               justify-content: flex-end; align-items: center; gap: 4px; }
.chart-month i { display: block; width: 100%; background: var(--ink); border-radius: 4px 4px 0 0; }
.chart-month.is-flag i { background: var(--accent); }
.chart-month u { font-style: normal; text-decoration: none; font-size: 10px;
                 color: var(--text-dim); white-space: nowrap; }
@media (max-width: 640px) {
  .chart-bar { grid-template-columns: minmax(0, 8em) 1fr minmax(0, 8em); gap: var(--sp-2); }
  .chart-months { height: 130px; gap: 3px; }
  .chart-month u { font-size: 9px; }
}

/* Шапка-сортировка: заголовок колонки — ссылка, но выглядеть он должен заголовком,
   а не синей строкой. Подсказка появляется под курсором — и только там, где курсор
   вообще есть: на телефоне :hover залипает после нажатия (D-0098). */
.rights th a { color: inherit; text-decoration: none; }
.rights th[aria-sort] a { color: var(--ink); }
@media (hover: hover) {
  .rights th a:hover { text-decoration: underline; text-underline-offset: 3px; }
}
.rights input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--accent); }
.rights .badge { margin-left: var(--sp-1); }
/* Шире экрана — едет ВНУТРИ себя. Правило висит на самой таблице, а не на обёртке
   в разметке: обёртку дали двум таблицам из пяти, и обе страницы без неё разъезжались
   на телефоне — /admin/roles/ на 114 px, /kit на 59 (замер 09.09.26). Третья, у
   преподавателей, ждала своей очереди: она рисуется, только когда кому-то открыт курс.
   Обёртки в шаблонах остаются — они теперь просто никогда не переполняются.
   Только на телефоне: на ПК display:block отнял бы у таблицы width:100%. */
@media (max-width: 767px) {
  .rights { display: block; overflow-x: auto; }
}

/* ── поиск из шапки ────────────────────────────────────────────────
   Панель выезжает под шапкой и живёт на всех страницах: искать человек может
   откуда угодно, а не только из медиатеки. */
/* Панель живёт ВНУТРИ шапки: раньше она стояла в конце страницы и sticky держал её
   там, где она в потоке, — то есть под подвалом (поймал Pet 31.08.26).
   Раскрывается поверх содержимого, а не раздвигает его: страница под поиском
   не должна прыгать вниз, пока человек печатает. */
.site-header { position: sticky; }
/* Поиск встаёт НА МЕСТО шапки, а не под неё (Pet 27.10: «строка поиска становится шапкой», без подёргивания):
   те же поля, что у шапки, — строка поля ложится ровно туда, где была строка логотипа; содержимое шапки
   под ним прячется (.is-searching), подсказки растут вниз той же панелью. */
.search-panel {
  position: absolute; top: 0; left: 0; right: 0;
  border-bottom: 1px solid var(--hairline);
  background: var(--surface-raised);
  box-shadow: var(--shadow-raise);
  padding: var(--sp-2) 0;
  padding-top: max(var(--sp-2), env(safe-area-inset-top));
  max-height: 85vh; overflow-y: auto;
}
.site-header.is-searching > .wrap { visibility: hidden; }
.search-panel:not([hidden]) .search-panel-inner { animation: search-in var(--dur-2) var(--ease); }
@keyframes search-in { from { opacity: 0; transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) { .search-panel:not([hidden]) .search-panel-inner { animation: none; } }
.search-hits:empty { display: none; }
.search-hits:not(:empty) { padding-bottom: var(--sp-2); }
/* Стекло (Pet 28.09, ТГ 506) — как у шторок: 82 % поверхности + размытие; под ним и так затемнение (.search-dim). */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .search-panel { background: color-mix(in srgb, var(--surface-raised) 82%, transparent);
                  -webkit-backdrop-filter: blur(20px) saturate(1.3); backdrop-filter: blur(20px) saturate(1.3); }
}
@media (prefers-reduced-transparency: reduce) {
  .search-panel { background: var(--surface-raised); -webkit-backdrop-filter: none; backdrop-filter: none; }
}
/* Затемнение под панелью: взгляд остаётся на поиске, а не на каталоге за ним. */
.search-dim {
  position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: calc(var(--z-header) - 1);
  background: var(--overlay);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-3) var(--ease);
}
.search-dim.is-open { opacity: 1; pointer-events: auto; }
.search-panel-inner { display: flex; align-items: center; gap: var(--sp-2); }
.search-panel-field { flex: 1; min-width: 0; }
.search-hits { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-2); }
/* Пока панель открыта, шапка не уезжает при прокрутке — иначе поле убегает из-под пальца. */
.site-header:has(.search-panel:not([hidden])) { transform: none !important; }
.search-hit {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2); border-radius: var(--radius);
  color: inherit; text-decoration: none;
}
.search-hit:focus-visible { background: var(--surface-soft); }
@media (hover: hover) { .search-hit:hover { background: var(--surface-soft); } }
.search-hit img {
  width: 72px; height: 72px;            /* квадрат, как обложки каталога */
  object-fit: cover; border-radius: var(--radius); flex: none; background: var(--surface-soft);
}
.search-hit b { font-weight: 600; font-size: var(--fs-base); display: block; line-height: var(--lh-snug); }
.search-hit span { font-size: var(--fs-sm); color: var(--text-dim); }
.search-hit { padding: var(--sp-2) var(--sp-3); }
.search-note { font-size: var(--fs-xs); color: var(--text-dim); padding: var(--sp-2); }

/* Подсказки при печати — словами, без чисел: счёт подсказки и счёт поиска
   считаются по разным правилам, и цифры рядом расходились бы с выдачей. */
.search-tips { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding: var(--sp-2) var(--sp-2) var(--sp-3); }

/* Подсказки под полем поиска медиатеки. Пока они на экране, ряд быстрых фильтров
   прячется: два ряда пилюль подряд читаются как один список, и человек не понимает,
   где фильтр, а где подсказка (замечание Pet 31.08.26). */
.med-tips { align-items: center; margin-bottom: var(--sp-3); }
.med-tips-label { font-size: var(--fs-sm); color: var(--text-dim); margin-right: var(--sp-1); }
.chip-tip { background: transparent; border-color: var(--hairline); color: var(--text); }
@media (hover: hover) { .chip-tip:hover { background: var(--surface-soft); border-color: var(--text-dim); } }
.chip-tip .ic { color: var(--text-dim); }

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

   Три заливки: тихая (подложка бренда), акцентная (тон записи) и белая. */
.plate {
  border-radius: var(--radius-lg);
  padding: var(--sp-6) var(--sp-5);
  background: var(--surface-soft);
}
.plate-accent { background: var(--rec-soft); }
.plate-plain  { background: var(--surface); border: 1px solid var(--hairline); }
.plate + .plate { margin-top: var(--sp-4); }
@media (min-width: 768px) { .plate { padding: var(--sp-7) var(--sp-6); } }

/* Заголовок секции — с тонкой чертой в акцентном тоне вместо номера.
   Номера тут не годятся: разделы карточки не последовательность. */
.plate-head { display: flex; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.plate-head h2 { font-size: var(--fs-xl); margin: 0; }
.plate-head .plate-note { font-size: var(--fs-sm); color: var(--text-dim); }

/* ── крошки ────────────────────────────────────────────────────────
   Не украшение: с них человек возвращается в медиатеку с тем же фильтром,
   которым сюда пришёл, и по ним же робот видит место страницы в разделе. */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-dim); margin: 0 0 var(--sp-4);   /* верх — у main (28.09) */
}
.crumbs a { color: var(--text-dim); text-decoration: none; }
@media (hover: hover) { .crumbs a:hover { color: var(--ink); text-decoration: underline; } }
.crumbs-here { color: var(--ink); }

/* ── плеер и обложка занятия ───────────────────────────────────────
   Два кадра, и это не украшение. У видео кадр 16:9, а обложки занятий
   дизайнер рисует КВАДРАТОМ и ставит в них надписи: вписанная в 16:9
   обрезкой, обложка теряет собственный текст (поймано замером в браузере
   01.09.26 — у «Абдоминальных поз» срезало половину заголовка).
   Поэтому в шапке карточки стоит квадрат, а фрагмент играет отдельно,
   уже в своём кадре. */
.player {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--radius); background: var(--surface-soft);
  display: flex; align-items: center; justify-content: center;
}
.player img, .player iframe { position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%; border: 0; }
.player img { object-fit: cover; }
.player-cover { aspect-ratio: var(--cover); }
.player-cover img { object-fit: contain; }
/* Кнопка воспроизведения — только в КАДРЕ ВИДЕО, кругом по центру.
   На обложку не кладём ничего. Проверено двумя заходами 01.09.26: круг по центру
   ложился на лицо преподавателя, подпись слева-снизу — на надпись дизайнера,
   а пилюля в правом нижнем углу на телефоне (обложка 290 px) накрыла половину
   заголовка «НОГИ В РУКИ». Обложка — постер, у него свой текст; действие
   живёт строкой под ней (.rp-media-actions). */
.player-play {
  position: relative; width: var(--sp-8); height: var(--sp-8); border: 0;
  border-radius: var(--radius-pill); background: var(--surface); color: var(--ink);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  cursor: pointer; font: inherit; font-weight: 600; font-size: var(--fs-sm);
  box-shadow: var(--shadow-raise); transition: transform var(--dur-2) var(--ease);
}
@media (hover: hover) { .player-play:hover { transform: scale(1.04); } }
.player-play:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rp-media-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }
/* Переключатель уроков под сценой. Пока курс играл, перейти на другой урок можно было
   только через «Программу» внизу — а она после нажатия увозила обратно наверх, к сцене,
   и с самого экрана просмотра выхода не было (поймал Pet 04.09.26). Ряд — канонные чипы
   (.chip / .chip.is-on), своего тут только отступ: новый компонент ради этого не нужен.
   У одиночного урока ряда нет — переключать нечего. */
.rp-track { margin-top: var(--sp-3); scroll-margin-bottom: var(--sp-4); }
.rp-media-actions .btn { flex: 1; }

/* ── строка фактов ─────────────────────────────────────────────────
   Уроков, времени, срок доступа. Иконка красится тоном записи — это тот
   самый «акцент в теле»: он подсвечивает мелочь, а не заливает экран. */
.facts { display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6); }
.fact { display: flex; align-items: flex-start; gap: var(--sp-2); }
.fact .ic { color: var(--rec-tint); flex: none; margin-top: var(--sp-0); }
.fact span { display: flex; flex-direction: column; line-height: var(--lh-snug); }
.fact b { font-family: var(--font-head); font-size: var(--fs-md); color: var(--ink); font-weight: 700; }
.fact small { font-size: var(--fs-xs); color: var(--text-dim); }

/* ── липкая полоса покупки ─────────────────────────────────────────
   Приезжает, когда блок покупки уехал вверх за экран. Сторож — прямой
   замер на каждой прокрутке, а не подписка на пересечение: подписка
   ловит ПЕРЕХОД и застревает, если экран прыгнул мимо него (замерено
   01.09.26: после мгновенного возврата наверх полоса оставалась висеть). */
/* Вид — из эскиза «Полёт» (Pet 26.10): плавающая панель с размытым фоном. Широкий экран — по центру, с обложкой
   и названием; телефон — во всю ширину снизу со скруглёнными верхними углами, только срок, цена и кнопка. */
.buybar {
  position: fixed; z-index: var(--z-header); left: 50%; bottom: max(16px, env(safe-area-inset-bottom));
  width: min(760px, calc(100% - 32px)); display: flex; align-items: center; gap: var(--sp-3);
  padding: 10px 10px 10px 12px; border-radius: 22px; border: 1px solid var(--hairline);
  /* Стекло, как у шторки фильтров (Pet 26.10), но прозрачнее: под панелью нет затемнения, и 82 % читалось сплошной плашкой.
     Текст держит размытие 20 px. Без поддержки размытия и при «меньше прозрачности» — сплошной фон. */
  background: color-mix(in srgb, var(--surface-raised) 62%, transparent); box-shadow: var(--shadow-sheet);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  transform: translate(-50%, calc(100% + 40px)); opacity: 0; visibility: hidden;
  transition: transform 460ms var(--ease), opacity 300ms var(--ease), visibility 0s linear 460ms;
}
.buybar.is-up { transform: translate(-50%, 0); opacity: 1; visibility: visible; transition-delay: 0s; }
.buybar-cover { width: 48px; height: 48px; border-radius: 12px; overflow: hidden; flex: none; object-fit: cover; display: block; }
.buybar-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.buybar-t { min-width: 0; flex: 1; display: grid; }
.buybar-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buybar-who { font-weight: 400; color: var(--text-dim); }
.buybar-t small { font-size: var(--fs-xs); color: var(--text-dim); }
.buybar-price { font-family: var(--font-head); font-size: var(--fs-lg); color: var(--ink); font-weight: 700; white-space: nowrap; }
.buybar .btn { flex: none; }
@media (max-width: 767px) {
  /* На телефоне под панелью чаще текст, чем обложки: на 62 % он спорил со сроком (замер 26.10) — плотнее, но стекло видно.
     Одна строка, как в «Полёте»: срок слева, крупная цена у кнопки (Pet 26.10: «куцо смотрится»). */
  .buybar { left: 0; right: 0; bottom: 0; width: auto; border-radius: 22px 22px 0 0; border-bottom: 0;
    padding: 12px 16px max(12px, env(safe-area-inset-bottom)); transform: translateY(calc(100% + 20px));
    background: color-mix(in srgb, var(--surface-raised) 76%, transparent); gap: var(--sp-3); }
  .buybar-t small { font-size: 15px; line-height: 1.25; color: var(--text); }
  .buybar-price { font-size: 1.35rem; }
  .buybar.is-up { transform: none; }
  .buybar-cover, .buybar-title { display: none; }
  .buybar .btn { min-width: 112px; }
  /* «Что нового» не прячется под панелью: поднимается над ней. */
  body:has(.buybar.is-up) .news-bubble { bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) { .buybar { transition: none; } }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .buybar { background: var(--surface-raised); } }
@media (prefers-reduced-transparency: reduce) { .buybar { background: var(--surface-raised); -webkit-backdrop-filter: none; backdrop-filter: none; } }

/* ── карточка записи: раскладка страницы ───────────────────────────
   Холст 1360 занимают КОЛОНКИ, а не длинные строки: обложка, сведения
   и блок покупки стоят рядом. Растянуть абзац на всю ширину нельзя —
   строка выходит под двести знаков; но и жать страницу в середину
   незачем, поэтому ширину съедает раскладка. */
.rec-page { padding-bottom: var(--sp-8); }

.rp-hero { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr) minmax(0, 320px); gap: var(--sp-6); align-items: start; }
@media (max-width: 1099px) { .rp-hero { grid-template-columns: minmax(0, 360px) minmax(0, 1fr); } .rp-buy-col { grid-column: 1 / -1; } }
@media (max-width: 767px)  { .rp-hero { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); } }

.rp-side { display: flex; flex-direction: column; gap: var(--sp-4); }
.rp-badges { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.rp-title { font-size: var(--fs-2xl); line-height: var(--lh-tight); margin: 0; text-wrap: balance; }
.rp-sub { font-size: var(--fs-md); color: var(--text); line-height: var(--lh-base); margin: 0; max-width: 54ch; }

/* Преподаватели идут сеткой: у курса их бывает четверо, столбиком они занимали
   пол-экрана при пустой колонке справа. Колонок столько, сколько влезает; `min()`
   в minmax обязателен — без него единственная колонка на телефоне не сожмётся. */
.rp-teachers { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); gap: var(--sp-3) var(--sp-4); }
.rp-teacher { display: flex; align-items: center; gap: var(--sp-3); text-decoration: none; color: var(--text); min-width: 0; }
.rp-teacher .rp-teacher-name { min-width: 0; }
.rp-teacher-name b, .rp-teacher-name small { overflow-wrap: anywhere; }
.rp-ava {
  width: var(--sp-8); height: var(--sp-8); flex: none; border-radius: var(--radius-pill);
  object-fit: cover; background: var(--surface); display: inline-flex;
  align-items: center; justify-content: center; overflow: hidden;
  font-family: var(--font-head); font-weight: 700; font-size: var(--fs-sm); color: var(--rec-ink);
}
/* Чёрно-белым фото делает ТЕМА, а не файл: в базе и в медиа лежит цветной оригинал,
   он нужен для промо и писем, где портрет живёт по своим правилам (решение Pet 04.09.26).
   Так же снимается и обратное решение: убрать фильтр — одна строка, перезаливать нечего. */
/* <picture> внутри аватара обязан иметь размер: иначе ленивый <img> внутри него остаётся
   нулевой ширины, браузер считает его невидимым и НЕ ГРУЗИТ НИКОГДА — на странице отзывов
   все восемь фото так и стояли пустыми (замер 05.09.26: currentSrc пуст, naturalWidth 0).
   На карточке записи это обходили lazy=false; здесь лечится причина, для всех аватаров. */
.rp-ava picture { display: block; width: 100%; height: 100%; }
.rp-ava img { width: 100%; height: 100%; object-fit: cover; display: block; filter: grayscale(1); }
.rp-teacher-name { display: flex; flex-direction: column; line-height: var(--lh-snug); }
.rp-teacher-name b { color: var(--ink); font-weight: 600; }
.rp-teacher-name small { font-size: var(--fs-xs); color: var(--text-dim); }
@media (hover: hover) { .rp-teacher:hover small { color: var(--rec-ink); } }

.rp-buy {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5); border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--rec-line);
}
.rp-price { font-family: var(--font-head); font-size: var(--fs-xl); font-weight: 700; color: var(--ink); }
/* Акция у покупки (c68): старая цена зачёркнута рядом, новая — тёплым тоном акции; под ценой — код и «Скопировать». */
.rp-price.is-promo { color: var(--warn); }
.rp-price.is-promo s { font-family: var(--font); font-size: var(--fs-md); font-weight: 400; color: var(--text-dim); }
.rp-promo { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-3); flex-wrap: wrap;
            padding: var(--sp-3); border-radius: var(--radius); background: color-mix(in oklch, var(--warn) 10%, var(--surface));
            font-size: var(--fs-sm); color: var(--text); }
.rp-promo b { color: var(--ink); letter-spacing: .02em; }
.buybar-price.is-promo { color: var(--warn); }
.rp-buy-note { font-size: var(--fs-xs); color: var(--text-dim); margin: 0; }

/* Программа. Внутри урока текст слева, разбор справа: так холст занят,
   а строка остаётся читаемой. На узком — друг под другом. */
.rp-lesson { border-top: 1px solid var(--hairline); }
.rp-lesson:first-of-type { border-top: 0; }
.rp-lesson > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-4) 0; cursor: pointer; list-style: none; min-height: var(--tap);
}
.rp-lesson > summary::-webkit-details-marker { display: none; }
/* Клавиатура: summary и кнопка на обложке не попадали под общее правило фокуса,
   и человек с клавиатуры не видел, где стоит. */
.rp-lesson > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }
/* Отдельный урок: одного пункта аккордеон не делает — тело показано сразу. */
.rp-lesson-single { padding-top: var(--sp-2); }
.rp-lesson > summary .ic { color: var(--text-dim); transition: transform var(--dur-2) var(--ease); flex: none; }
.rp-lesson[open] > summary .ic { transform: rotate(180deg); }
.rp-lesson-head { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; flex-wrap: wrap; }
.rp-lesson-no {
  font-family: var(--font-head); font-weight: 700; font-size: var(--fs-sm);
  color: var(--rec-ink); background: var(--rec-soft); border-radius: var(--radius-pill);
  padding: var(--sp-0) var(--sp-3); flex: none;
}
.rp-lesson-title { font-family: var(--font-head); font-size: var(--fs-md); font-weight: 700; color: var(--ink); }
.rp-lesson-time { font-size: var(--fs-xs); color: var(--text-dim); }

.rp-lesson-body { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--sp-6); padding-bottom: var(--sp-5); }
@media (max-width: 899px) { .rp-lesson-body { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); } }
.rp-lesson-body p { margin: 0 0 var(--sp-4); line-height: var(--lh-base); }

.rp-aside { display: flex; flex-direction: column; gap: var(--sp-4); }
/* Подпись-метка, а не заголовок раздела: шрифт текста, как у .rp-axis h3. Была h4 (базовое правило h1–h3 её не трогало);
   став h3 ради порядка уровней, взяла шрифт заголовка — замер 28.09 поймал, вернули вид прежним. */
.rp-aside h3 {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-dim); margin: 0 0 var(--sp-2); font-family: var(--font); font-weight: 600; line-height: inherit;
}
.rp-aside ul { margin: 0; padding-left: var(--sp-4); }
.rp-aside li { margin-bottom: var(--sp-2); font-size: var(--fs-sm); line-height: var(--lh-base); }
.rp-inline { font-size: var(--fs-sm); color: var(--text); line-height: var(--lh-base); margin: 0; }

.rp-axes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-4); }
.rp-axis h3 {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-dim); margin: 0 0 var(--sp-3); font-family: var(--font); font-weight: 600;
}
a.chip { text-decoration: none; }

.rp-terms { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--sp-4); }
.rp-term {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-5); border-radius: var(--radius); background: var(--surface);
}
.rp-term .ic { color: var(--rec-tint); }
.rp-term b { font-family: var(--font-head); font-size: var(--fs-md); color: var(--ink); font-weight: 700; }
.rp-term span { font-size: var(--fs-sm); color: var(--text-dim); line-height: var(--lh-base); }

/* Шторка с роликом. Ширину ограничиваем, а не отдаём во весь экран: кадр 16:9
   от полутора тысяч пикселей выше самого экрана, и низ ролика уезжает под сгиб —
   человеку приходится скроллить, чтобы увидеть картинку (поймал Pet 01.09.26).
   Кадр держится пропорцией и не вылезает за высоту окна. */
.rec-sheet { max-width: 960px; margin: 0 auto; max-height: 92vh; overflow-y: auto; }
.rec-sheet .player { width: 100%; aspect-ratio: 16 / 9; max-height: 64vh; }
.rec-sheet p { max-width: 62ch; }

/* ── главная: лента блоков ─────────────────────────────────────────
   Страница — стопка плашек из page_blocks. Раскладку каждого типа задаёт
   его компонент; сама лента только держит ритм и отступы. */
/* 🪤 Боковые поля — те же, что у холста (--gutter): короткая запись padding с нулём
   по бокам перебивала поля .wrap, плашки главной выходили 1360 вместо 1312 и на
   телефоне прилипали к краям экрана. Подвал при этом стоял верно, и казалось,
   что он уже (поймал Pet 03.09.26). */
.home { display: flex; flex-direction: column; gap: var(--sp-4); padding: 0 var(--gutter) var(--sp-8); }   /* верх — у main (28.09) */
.home .plate + .plate { margin-top: 0; }
.plate-head { flex-wrap: wrap; }
/* Ссылка «все» стои́т СПРАВА, когда помещается рядом с заголовком, и уходит под него
   ПО ЛЕВОМУ краю, когда не помещается. Делает это одно свойство: при space-between пара
   на строке расходится по краям, а одиночка на своей строке прижимается к началу.
   Ради этого убран `margin-left: auto` — авто-отступ гонит вправо и одиночку тоже,
   отчего длинный заголовок оставлял ссылку висеть справа с дырой слева (поймал Pet 09.09
   на телефоне; его вопрос был «рвать title или переделать канон по левой стороне» —
   не нужно ни то, ни другое, поведение само зависит от того, поместилось или нет).
   Нацелено через :has — у голов с `.plate-note` (кит, отзывы, карточка) подпись должна
   стоять сразу за заголовком, а не улетать к правому краю. */
.plate-head:has(.plate-more) { justify-content: space-between; }
.plate-more {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-sm); color: var(--accent-ink); text-decoration: none; white-space: nowrap;
}
@media (hover: hover) { .plate-more:hover { text-decoration: underline; } }

/* обложка: единственный h1, крупный кегль раздела */
.hm-hero { padding-top: var(--sp-7); padding-bottom: var(--sp-7); }
/* Шрифт заголовка — на КЛАССЕ, а не только на теге h1: в ките обложка показана через <p> (второй h1 на странице
   нельзя), и там заголовок рисовался текстовым шрифтом — поймал Pet 28.09. Правило держит тот, кто им назван. */
.hm-hero-title { font-family: var(--font-head); font-weight: 700; color: var(--ink); letter-spacing: -.015em;
                 font-size: var(--fs-display); line-height: var(--lh-tight); margin: 0; max-width: 16ch; text-wrap: balance; }
.hm-hero-sub { font-size: var(--fs-md); color: var(--text); line-height: var(--lh-base); margin: var(--sp-4) 0 0; max-width: 54ch; text-wrap: balance; }
/* Дескриптор — одной строкой от 768 px (Pet 28.10; замер: влезает в колонку на 768…1440 без прокрутки), на телефоне — ровный перенос. */
@media (min-width: 768px) { .hm-hero-sub { max-width: none; white-space: nowrap; } }
.hm-hero-actions { margin-top: var(--sp-5); }
@media (min-width: 768px) { .hm-hero { padding-top: var(--sp-8); padding-bottom: var(--sp-8); } }
/* Знак в обложке (Pet 27.10): телефон — над заголовком, ПК — слева, высотой в две строки заголовка, текст сдвинут вправо. */
.hm-hero-mark { display: block; color: var(--ink); line-height: 0; margin-bottom: var(--sp-4); }
.hm-hero-mark .crane { width: 56px; height: 56px; overflow: visible; }
@media (min-width: 768px) {
  .hm-hero-head { display: flex; align-items: center; gap: var(--sp-5); }
  .hm-hero-mark { margin: 0; flex: none; }
  .hm-hero-mark .crane { --h: calc(var(--fs-display) * var(--lh-tight) * 2); width: var(--h); height: var(--h); }
}

/* ── Небо обложки (слово Pet 01.10.26, мотив «Полёта» из лабы C) ──────────────────────────────────────
   Переливы в тоне плашки (--rec-h), оранжевое солнце и клин журавлей из знака — оранжевый с голубым взят
   у иллюстрации проекта 2020 года. Слои: небо (z −2) → стекло (z −1, светлая дымка там, где текст) → текст.
   Двигается только transform: ни лейаута, ни перерисовки фона. backdrop-filter на всю плашку не ставим —
   размытие поверх движущегося неба пересчитывалось бы каждый кадр; «стекло» — дымка, отблеск и кромка. */
.hm-sky {
  position: relative; isolation: isolate; overflow: hidden;
  --sky-a: oklch(0.86 0.09 var(--rec-h) / .95);   /* перелив в тоне плашки */
  --sky-b: oklch(0.84 0.08 235 / .70);             /* голубой иллюстрации */
  --sky-c: oklch(0.91 0.07 75 / .65);              /* тёплый отсвет солнца */
  --sky-sun-core: oklch(0.90 0.12 80);
  --sky-sun-rim:  oklch(0.76 0.17 50);
  --sky-halo:     oklch(0.82 0.13 62 / .38);
  --sky-bird:     oklch(0.30 0.035 var(--rec-h) / .82);
  --sky-sheen:    color-mix(in oklch, white 38%, transparent);
  --sky-edge:     color-mix(in oklch, white 65%, transparent);
  box-shadow: inset 0 0 0 1px var(--sky-edge);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hm-sky {
    --sky-a: oklch(0.46 0.09 var(--rec-h) / .75); --sky-b: oklch(0.42 0.08 240 / .60); --sky-c: oklch(0.52 0.10 60 / .40);
    --sky-sun-core: oklch(0.82 0.12 72); --sky-sun-rim: oklch(0.64 0.15 44); --sky-halo: oklch(0.66 0.14 50 / .22);
    --sky-bird: oklch(0.93 0.03 var(--rec-h) / .78); --sky-sheen: color-mix(in oklch, white 7%, transparent);
    --sky-edge: color-mix(in oklch, white 9%, transparent);
  }
}
:root[data-theme="dark"] .hm-sky {
  --sky-a: oklch(0.46 0.09 var(--rec-h) / .75); --sky-b: oklch(0.42 0.08 240 / .60); --sky-c: oklch(0.52 0.10 60 / .40);
  --sky-sun-core: oklch(0.82 0.12 72); --sky-sun-rim: oklch(0.64 0.15 44); --sky-halo: oklch(0.66 0.14 50 / .22);
  --sky-bird: oklch(0.93 0.03 var(--rec-h) / .78); --sky-sheen: color-mix(in oklch, white 7%, transparent);
  --sky-edge: color-mix(in oklch, white 9%, transparent);
}
.hm-sky-art { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -2; pointer-events: none; }
.hm-sky-art > * { position: absolute; }
.hm-sky-glow { aspect-ratio: 1; border-radius: 50%; will-change: transform; animation: hm-drift 14s ease-in-out infinite alternate; }
.hm-sky-glow-1 { width: 72%; left: 32%; top: -55%; background: radial-gradient(closest-side, var(--sky-a), transparent); }
.hm-sky-glow-2 { width: 58%; right: -18%; bottom: -62%; background: radial-gradient(closest-side, var(--sky-b), transparent);
                 animation-duration: 17s; animation-delay: -6s; }
.hm-sky-glow-3 { width: 46%; left: 8%; bottom: -58%; background: radial-gradient(closest-side, var(--sky-c), transparent);
                 animation-duration: 12s; animation-delay: -3s; }
/* Солнце — СВЕЧЕНИЕ, а не диск (Pet 01.10: «выглядит как шарик, оттягивает внимание»; сперва был шар 230 px,
   потом 120 px в углу — всё равно мяч). Как в «Полёте»: тёплое пятно света без края, клин уходит в него. */
/* Правки Pet 01.10: 11:40 — ореол размытее и тише; 11:47 — снова круглый (эллипс читался овалом) и ОДИН: пятно света
   объёмной сцены убрано, в тёмной теме два ореола ложились друг на друга. Этот — единственный во всех режимах. */
.hm-sky-sun {
  width: 50%; aspect-ratio: 1; right: -9%; top: -62%; border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in oklch, var(--sky-sun-core) 58%, transparent) 0%,
                              color-mix(in oklch, var(--sky-sun-rim) 24%, transparent) 34%,
                              color-mix(in oklch, var(--sky-sun-rim) 9%, transparent) 64%, transparent 100%);
  animation: hm-sun 10s ease-in-out infinite alternate;
}
.hm-sky-flock { right: 15%; top: 6%; width: 50%; height: 90%; color: var(--sky-bird); animation: hm-glide 16s ease-in-out infinite alternate;
                transition: opacity 1.2s var(--ease); }
/* Объёмный клин (sky3d.js): проявляется, когда сцена поднялась, — SVG-клин уходит. */
.hm-sky-canvas { top: 0; left: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 1.4s var(--ease); }
.hm-sky.gl-on .hm-sky-canvas { opacity: 1; }
.hm-sky.gl-on .hm-sky-flock { opacity: 0; }
.hm-sky-bird { animation: hm-bob 4.2s ease-in-out infinite alternate; animation-delay: calc(var(--i) * -.37s); }
.hm-sky-sheen {
  inset: 0 -60%; background: linear-gradient(105deg, transparent 32%, var(--sky-sheen) 46%, transparent 60%);
  animation: hm-sheen 19s ease-in-out infinite alternate;
}
/* Стекло: светлая дымка тоном плашки там, где текст, — небо видно сквозь, текст читается. */
.hm-sky::before {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(90deg, color-mix(in oklch, var(--rec-soft) 84%, transparent) 0%,
                                     color-mix(in oklch, var(--rec-soft) 58%, transparent) 40%, transparent 66%);
}
@keyframes hm-drift { to { transform: translate3d(-8%, 7%, 0) scale(1.12); } }
@keyframes hm-sun   { to { transform: translateY(7%) scale(1.06); } }
@keyframes hm-glide { to { transform: translate3d(-3%, -5%, 0); } }
@keyframes hm-bob   { to { transform: translateY(-4px); } }
@keyframes hm-sheen { from { transform: translateX(-18%); } to { transform: translateX(18%); } }
.hm-sky.is-still :is(.hm-sky-glow, .hm-sky-sun, .hm-sky-flock, .hm-sky-bird, .hm-sky-sheen) { animation-play-state: paused; }

/* Пауза — тихая (Pet 28.09: «тише, но оставить»), видна скрипту: без него нажимать нечем. 36 на глаз, 44 под пальцем. */
.hm-sky-pause {
  position: absolute; right: var(--sp-3); bottom: var(--sp-3); width: 36px; height: 36px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; padding: 0; cursor: pointer;
  border: 1px solid color-mix(in oklch, var(--ink) 14%, transparent);
  background: color-mix(in oklch, var(--surface) 55%, transparent); color: var(--text-dim); opacity: .72;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  transition: opacity var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.hm-sky-pause[hidden] { display: none; }
.hm-sky-pause::after { content: ''; position: absolute; inset: -4px; }
@media (hover: hover) { .hm-sky-pause:hover { opacity: 1; color: var(--ink); } }
.hm-sky-pause:focus-visible { opacity: 1; outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.hm-sky-pause-ico { width: 10px; height: 12px; border-left: 3px solid currentColor; border-right: 3px solid currentColor; }
.hm-sky.is-still .hm-sky-pause-ico { border: 0; background: currentColor; clip-path: polygon(15% 0, 100% 50%, 15% 100%); }

@media (max-width: 767px) {
  /* Телефон: небо над заголовком — клин и солнце сверху, дымка снизу вверх. */
  .hm-sky { padding-top: calc(var(--sp-6) + 104px); }
  .hm-sky-flock { width: 66%; height: 120px; top: 10px; right: 20%; }
  .hm-sky-sun { width: 90%; right: -30%; top: -22%; }
  .hm-sky-glow-1 { width: 120%; left: 10%; top: -60%; }
  .hm-sky::before { background: linear-gradient(0deg, color-mix(in oklch, var(--rec-soft) 86%, transparent) 0%,
                                                       color-mix(in oklch, var(--rec-soft) 60%, transparent) 58%, transparent 82%); }
}
@media (prefers-reduced-motion: reduce) {
  .hm-sky :is(.hm-sky-glow, .hm-sky-sun, .hm-sky-flock, .hm-sky-bird, .hm-sky-sheen) { animation: none; }
  .hm-sky-pause { display: none; }
}

/* промо: заголовок, срок словами, кнопка справа */
.hm-promo-in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-4) var(--sp-6); }
.hm-promo-in h2 { margin: 0; font-size: var(--fs-xl); }
.hm-promo-note { font-size: var(--fs-sm); color: var(--rec-ink); margin: 0 0 var(--sp-1); font-weight: 600; }
/* Текст акции — во всю ширину рядом с кнопкой, а не узкой колонкой (Pet 27.10: «не сужать, пусть дотягивается»). */
.hm-promo-in > div { flex: 1 1 28rem; min-width: 0; }
.hm-promo-text { margin: var(--sp-2) 0 0; max-width: 90ch; }

/* ряд подборки: на широком — сетка каталога, на телефоне — лента вбок со снапом,
   как ряд чипов в медиатеке: иначе восемь карточек столбиком — это восемь экранов.

   Лента вылетает до КРАЯ ПЛАШКИ (её поле — --sp-5), а не до поля страницы: раньше
   обрыв шёл на восемь пикселей раньше края и читался как граница, а не как
   «дальше есть» (поймал Pet 03.09.26). Плюс затемнение у края, пока есть куда
   листать, — тот же приём, что у ряда чипов в медиатеке. */
@media (max-width: 767px) {
  /* scroll-padding обязателен рядом с padding: без него снап тянет первую карточку
     к самому краю прокрутки, и лента при загрузке уже отъехала на ширину поля. */
  .recs-rail { scroll-padding: 0 var(--sp-5); }
  .recs-rail {
    display: flex; gap: var(--sp-3); overflow-x: auto; scroll-snap-type: x mandatory;
    margin: 0 calc(var(--sp-5) * -1); padding: 0 var(--sp-5) var(--sp-2);
    scrollbar-width: none;
  }
  .recs-rail::-webkit-scrollbar { display: none; }
  .recs-rail > .rec { flex: 0 0 76%; scroll-snap-align: start; }

  .rail-wrap.has-next > [data-rail-track] {
    mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent);
  }
  .rail-wrap.has-prev.has-next > [data-rail-track] {
    mask-image: linear-gradient(to right, transparent, #000 40px, #000 calc(100% - 56px), transparent);
  }
  .rail-wrap.has-prev:not(.has-next) > [data-rail-track] {
    mask-image: linear-gradient(to right, transparent, #000 40px);
  }
}

/* Лента в одну линию на ЛЮБОЙ ширине — личная подборка (c46, Pet 27.10: «и на ПК, и на телефоне в одну линию, чтобы
   места не занимать»). Механика та же, что у ленты телефона (initRail: has-prev/has-next, затухание у края), на ПК — стрелки.
   Лента вылетает до края плашки или карточки: --edge — их поле. */
.rail-line { position: relative; }
.recs-line {
  --edge: var(--sp-5);
  display: flex; gap: var(--sp-4); overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth; scrollbar-width: none;
  margin: 0 calc(var(--edge) * -1); padding: 0 var(--edge) var(--sp-2); scroll-padding: 0 var(--edge);
}
@media (min-width: 768px) { .plate .recs-line { --edge: var(--sp-6); } }
.recs-line::-webkit-scrollbar { display: none; }
.recs-line > .rec { flex: 0 0 calc((100% - 3 * var(--sp-4)) / 4); min-width: 0; scroll-snap-align: start; }
@media (max-width: 1023px) { .recs-line > .rec { flex-basis: calc((100% - 2 * var(--sp-4)) / 3); } }
@media (max-width: 767px) { .recs-line { gap: var(--sp-3); } .recs-line > .rec { flex-basis: 76%; } }
.rail-line.has-next > .recs-line { mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent); }
.rail-line.has-prev.has-next > .recs-line { mask-image: linear-gradient(to right, transparent, #000 40px, #000 calc(100% - 56px), transparent); }
.rail-line.has-prev:not(.has-next) > .recs-line { mask-image: linear-gradient(to right, transparent, #000 40px); }
/* Стрелки — по середине обложки, а не карточки: под ними текст, по нему целятся пальцем и глазом. */
.rail-line .rail-btn { top: 28%; }
.rail-line .rail-btn[data-rail="prev"] { left: calc(var(--sp-3) * -1); }
.rail-line .rail-btn[data-rail="next"] { right: calc(var(--sp-3) * -1); }
.rail-line.has-prev .rail-btn[data-rail="prev"],
.rail-line.has-next .rail-btn[data-rail="next"] { display: inline-flex; }

/* плитка направлений по «Полёту» (Pet 27.10): больше записей — крупнее плитка (два первых — на две колонки),
   крупное число, полоска — доля от самого большого направления. Ведёт в медиатеку с фильтром. */
.hm-dirs { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.hm-dirs > :nth-child(-n+2) { grid-column: span 2; }
@media (min-width: 700px) { .hm-dirs { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.hm-dir {
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-4); height: 100%; min-height: 132px; min-width: 0;
  padding: var(--sp-4) var(--sp-4) var(--sp-3); border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--hairline); text-decoration: none; color: var(--ink);
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.hm-dirs > :nth-child(-n+2) .hm-dir { min-height: 150px; }
@media (hover: hover) { .hm-dir:hover { border-color: var(--text-dim); background: var(--surface-raised); box-shadow: var(--shadow-raise); } }
/* Название переносится только по пробелам («Скручивани / я» — поймал Pet 01.09.26 при overflow-wrap: anywhere). */
.hm-dir-top { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.hm-dir b { font-family: var(--font-head); font-size: var(--fs-md); font-weight: 700; line-height: var(--lh-snug); overflow-wrap: normal; hyphens: manual; }
.hm-dir-n { display: flex; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-dim); white-space: nowrap; }
.hm-dir-n strong { font-family: var(--font-head); font-weight: 700; font-size: clamp(28px, 1.2vw + 18px, 38px); line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.hm-dir-bar { display: block; height: 4px; border-radius: 4px; background: var(--surface-sunk); overflow: hidden; }
.hm-dir-bar i { display: block; height: 100%; border-radius: inherit; transform-origin: left; transform: scaleX(var(--r, 1));
                background: linear-gradient(90deg, var(--accent), var(--accent-ink)); }
/* Иконка приглушена до подписи — плитка про слово, иконка помогает узнать. */
.hm-dir-ic svg { flex: none; color: var(--text-dim); }
@media (hover: hover) { .hm-dir-ic:hover svg { color: var(--accent-ink); } }
/* Узкий телефон: одна колонка — строка «название · число», полоска под ней. */
@media (max-width: 519px) {
  .hm-dirs { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
  .hm-dirs > :nth-child(-n+2) { grid-column: auto; }
  .hm-dir, .hm-dirs > :nth-child(-n+2) .hm-dir { min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--sp-2) var(--sp-3); padding: var(--sp-3) var(--sp-4); }
  .hm-dir-bar { grid-column: 1 / -1; }
  .hm-dir-n strong { font-size: 24px; }
}

/* ── вопрос-ответ ────────────────────────────────────────────────────
   Раскрытие на <details>: работает без скрипта, ищется поиском по странице
   (браузер сам раскрывает найденное) и доступно с клавиатуры. */
.faq { display: flex; flex-direction: column; }
.faq-item { border-bottom: 1px solid var(--hairline); }
.faq-item:first-child { border-top: 1px solid var(--hairline); }
.faq-item > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  min-height: var(--tap); padding: var(--sp-4) 0;
  font-family: var(--font-head); font-size: var(--fs-md); font-weight: 700; color: var(--ink);
  cursor: pointer; list-style: none;
  transition: color var(--dur-2) var(--ease);
}
.faq-item > summary::-webkit-details-marker { display: none; }
@media (hover: hover) { .faq-item > summary:hover { color: var(--accent-ink); } }
.faq-item > summary svg { flex: none; color: var(--text-dim); transition: transform var(--dur-2) var(--ease); }
.faq-item[open] > summary svg { transform: rotate(180deg); }
/* 🚩 КАНОН АККОРДЕОНА (слово Pet 09.09): текст ответа идёт во всю ширину строки вопроса,
   меры у него нет. Обоснование то же, по которому список забрал ширину: строка вопроса —
   это граница блока, и ответ, обрывающийся раньше неё, читается как недоверстанный,
   а не как забота о мере. Было 68ch, потом 96ch — обе оставляли дыру до шеврона. */
.faq-answer { padding: 0 0 var(--sp-5); max-width: none; color: var(--text); }
.faq-answer p { margin: 0 0 var(--sp-3); }
.faq-answer p:last-child { margin-bottom: 0; }
/* Блок вопросов на главной — две колонки на ПК (слово Pet 28.09): ответ ~70 знаков в строке (скилл: 60–75), дыры до
   шеврона нет — канон аккордеона выше в силе, просто колонка уже. На телефоне — одна колонка, второй список следом. */
@media (min-width: 1024px) {
  .faq-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--sp-7); align-items: start; }
}
@media (max-width: 1023px) {
  .faq-cols > .faq + .faq > .faq-item:first-child { border-top: 0; }   /* стык двух списков — без двойной черты */
}
.faq-more { margin: var(--sp-5) 0 0; }

/* Частые вопросы на главной — по «Полёту» (Pet 27.10): слева плашка-вступление со знаком у края (на ПК держится,
   пока листаешь), справа — вопросы карточками; плюс в кружке поворачивается в крестик и заливается. */
.hm-faq { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1000px) {
  .hm-faq { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: start; gap: var(--sp-5); }
  .hm-faq-intro { grid-column: span 4; }   /* по верху списка, без прилипания (Pet 27.10) */
  .hm-faq-list { grid-column: span 8; }
}
.hm-faq-intro {
  position: relative; overflow: hidden; display: grid; gap: var(--sp-3); justify-items: start;
  padding: clamp(22px, 3vw, 36px) clamp(22px, 3vw, 36px) 96px; border-radius: var(--radius-lg); background: var(--surface); box-shadow: inset 0 0 0 1px var(--hairline);
}   /* низ с запасом — знак сидит в углу под текстом, а не на нём (Pet 27.10) */
.hm-faq-intro h2 { margin: 0; font-size: var(--fs-2xl); line-height: var(--lh-tight); }
.hm-faq-intro p { margin: 0; color: var(--text-dim); }
.hm-faq-intro > :not(.hm-faq-mark) { position: relative; z-index: 1; }
.hm-faq-mark { position: absolute; right: -64px; bottom: -92px; opacity: .09; color: var(--ink); pointer-events: none; }
.hm-faq-mark svg { width: 180px; height: 180px; }
.hm-faq-list { display: grid; gap: var(--sp-2); }
.hm-qa, .hm-qa:first-child { border: 0; border-radius: var(--radius); background: var(--surface); box-shadow: inset 0 0 0 1px var(--hairline); }
.hm-qa > summary { min-height: 60px; padding: var(--sp-4) var(--sp-5); border-radius: var(--radius); }
.hm-qa > summary svg, .hm-qa[open] > summary svg { transform: none; color: inherit; }
.hm-qa-ic { flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
            background: var(--surface-sunk); color: var(--text-dim); transition: transform var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease); }
.hm-qa[open] .hm-qa-ic { transform: rotate(45deg); background: var(--ink); color: var(--on-ink); }
/* Ответ — на всю ширину карточки вопроса (Pet 27.10: «текст на 100 %»). */
.hm-qa .faq-answer { padding: 0 var(--sp-5) var(--sp-5); }
/* Под курсором — лёгкий тон акцента, а не цвет плашки: на мягкой плашке карточка становилась «прозрачной» (Pet 27.10). */
@media (hover: hover) { .hm-qa > summary:hover { background: color-mix(in oklch, var(--surface) 90%, var(--accent)); } }

/* На странице вопросов заголовок и подводка живут по общим правилам документа,
   а список идёт во всю ширину плашки. */
.faq-page .faq { margin-top: var(--sp-5); }

/* преподаватели по «Полёту» (Pet 27.10): на ПК сетка по девять, лишние — за плиткой «Все преподаватели»;
   под курсором — плашка в тоне сайта и кольцо акцентом. Телефон: лента в две строки, листается вбок, все сразу. */
.hm-people {
  list-style: none; display: grid; grid-auto-flow: column; grid-template-rows: repeat(2, auto);
  grid-auto-columns: calc((100% - 20px) / 3.3); gap: var(--sp-1) var(--sp-2); overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity; scrollbar-width: none;
  /* До края ПЛАШКИ (её поле --sp-5), как лента карточек: с полем страницы (--gutter, на телефоне 16) лента
     обрывалась на 8 px раньше края, а снап без scroll-padding прижимал лица к самому краю (Pet 27.10: «прилипает»). */
  margin: 0 calc(var(--sp-5) * -1); padding: var(--sp-1) var(--sp-5) var(--sp-2); scroll-padding: 0 var(--sp-5);
}
.hm-people::-webkit-scrollbar { display: none; }
.hm-people > li { scroll-snap-align: start; min-width: 0; }
@media (min-width: 700px) {
  .hm-people { grid-auto-flow: row; grid-template-rows: none; grid-template-columns: repeat(auto-fill, minmax(122px, 1fr));
               overflow: visible; margin: 0; padding: 0; gap: var(--sp-3); }
  [data-teachers]:not(.is-open) .hm-people > .is-extra { display: none; }
}
@media (min-width: 1100px) { .hm-people { grid-template-columns: repeat(9, minmax(0, 1fr)); } }
@media (max-width: 699px) { .hm-person-all-li { display: none; } }
[data-teachers].is-open .hm-person-all-li { display: none; }
.hm-person {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--sp-2); width: 100%; height: 100%;
  padding: var(--sp-3) var(--sp-2); border: 0; border-radius: var(--radius); background: none; font: inherit; cursor: pointer;
  text-decoration: none; color: var(--text); transition: background-color var(--dur-2) var(--ease);
}
.hm-person .rp-ava { width: 84px; height: 84px; box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--hairline);
                     transition: transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); }
.hm-person b { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); line-height: var(--lh-snug); }
.hm-person small { font-size: var(--fs-xs); color: var(--text-dim); white-space: nowrap; }
.hm-person-all-ic { width: 84px; height: 84px; border-radius: 50%; display: grid; place-items: center; flex: none;
                    background: var(--ink); color: var(--on-ink); transition: transform var(--dur-2) var(--ease); }
@media (hover: hover) {
  .hm-person:hover { background: var(--accent-soft); }
  .hm-person:hover .rp-ava { transform: scale(1.05); box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--accent); }
  .hm-person-all:hover .hm-person-all-ic { transform: rotate(-45deg); }
}
@media (max-width: 699px) { .hm-person { padding: var(--sp-3) 2px; } }

/* текст */
.hm-text-p { max-width: 68ch; line-height: var(--lh-base); }

/* Предпросмотр команды на главной: выключенный блок команде виден, но обведён пунктиром — без подписей
   (правило Pet 26.10: подпись рядом с превью читается как текст для ученика). Плашка с номером — только у блока главной.
   На страницах эфира пунктирных превью «только команде» больше нет (Pet 28.10): там команда видит то же, что купивший. */
.hm-off { position: relative; outline: 2px dashed var(--warn); outline-offset: 6px; border-radius: var(--radius-lg); }
.hl-card.is-draft { outline: 2px dashed var(--warn); outline-offset: 6px; }   /* черновик эфира у команды, без бейджа */
.hm-off > .badge { position: absolute; top: calc(var(--sp-3) * -1); left: var(--sp-5); background: var(--warn-soft); color: var(--warn); z-index: 1; }

/* ── меню на широком экране: панель слева, а не шторка снизу ────────
   Шторка снизу — телефонный приём: на Full HD она растягивается на 1900 px ради
   трёх ссылок, на 2K выглядит нелепо (Pet 03.09.26). На широком экране тот же
   элемент выезжает слева под бургером панелью 320 px; механика и разметка те же. */
@media (min-width: 768px) {
  .sheet[data-menu-sheet] {
    top: 0; bottom: 0; left: 0; right: auto;
    width: 320px; max-height: none;
    border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
    box-shadow: var(--shadow-raise);
    transform: translateX(-100%);
  }
  .sheet[data-menu-sheet].is-open { transform: translateX(0); }
  .sheet[data-menu-sheet] .sheet-grip { display: none; }
}

/* ── Документ (D-0092): оферта, политика, «О проекте» — длинный текст. ────────────────
   Мера строки ~72 знака: шире читается заметно хуже, поэтому текст не растягивается
   на всю плашку даже там, где место есть. Заголовки разделов с якорями; оглавление
   появляется от четырёх разделов и на широком экране стоит справа, липнет к верху. */
/* Без класса .page: его padding-top (32) складывался с верхним отступом крошек (24) —
   от шапки до контента выходило 56 против 24 на главной и карточке (поймал Pet 05.09.26).
   Документ дышит как карточка записи: крошки задают шаг сами. */
.doc-page .crumbs { margin-bottom: var(--sp-4); }
/* 🚩 Кегль и мера листа держатся на САМОМ .doc, а не на обёртке — иначе страница,
   забывшая обёртку, молча проваливается в старую болезнь: 72ch при 16 px дают 573 px,
   ровно то число, из-за которого кегль 05.09 и переехал на контейнер. Так вернулась
   страница вопросов, заведённая 08.09 без `.doc-solo` (поймал Pet 09.09 — «наш
   классический баг, который так и тянется»). Обёртка теперь добавляет ОГЛАВЛЕНИЕ,
   а не канон текста. */
.doc { min-width: 0; font-size: var(--fs-md); }   /* мера строки — на детях, см. ниже */
.doc-title { font-size: var(--fs-2xl); line-height: var(--lh-tight); margin: 0 0 var(--sp-3); text-wrap: balance; }
.doc-meta { font-size: var(--fs-sm); color: var(--text-dim); margin: 0 0 var(--sp-5); }
.doc-lead { font-size: var(--fs-md); line-height: var(--lh-base); margin: 0 0 var(--sp-5); }
.doc-lead p { margin: 0 0 var(--sp-3); }
.doc h2 { font-family: var(--font-head); font-size: var(--fs-lg); line-height: var(--lh-tight); margin: var(--sp-7) 0 var(--sp-3); scroll-margin-top: 88px; }
.doc h3 { font-family: var(--font-head); font-size: var(--fs-md); line-height: var(--lh-snug); margin: var(--sp-5) 0 var(--sp-2); scroll-margin-top: 88px; }
.doc-title + h2, .doc-meta + h2, .doc-lead + h2 { margin-top: var(--sp-4); }
.doc p { margin: 0 0 var(--sp-4); line-height: var(--lh-base); }
.doc ul, .doc ol { margin: 0 0 var(--sp-4); padding-left: 1.4em; }
.doc li { margin: var(--sp-1) 0; line-height: var(--lh-base); }
.doc a { color: var(--accent-ink); }
.doc strong { color: var(--ink); }
.doc-figure { display: block; margin: var(--sp-4) 0 var(--sp-5); border-radius: var(--radius); overflow: hidden; }
.doc-figure img, .doc-figure picture { display: block; width: 100%; height: auto; }
/* Вставка-баннер (views/widgets) — сама ссылка: `.doc a` перекрашивал её заголовок в цвет ссылок текста
   (снимок 30.09: «Все уроки…» бирюзой вместо чёрного из одобренного превью). Цвет — свой, из вставки. */
.doc .bpfly { color: var(--bpfly-ink); }
.doc-grid { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: var(--sp-7); align-items: start; }
.doc-toc { position: sticky; top: 88px; font-size: var(--fs-sm); }
.doc-toc-title { margin: 0 0 var(--sp-2); font-family: var(--font-head); font-weight: 700; color: var(--ink); }
.doc-toc ol { margin: 0; padding-left: 1.2em; color: var(--text-dim); }
.doc-toc li { margin: var(--sp-1) 0; line-height: var(--lh-snug); }
.doc-toc a { color: var(--text); text-decoration: none; }
@media (hover: hover) { .doc-toc a:hover { color: var(--accent-ink); } }
@media (max-width: 899px) {
  .doc-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  /* На телефоне оглавления нет (слово Pet): якоря в тексте остаются, прокрутки хватает. */
  .doc-toc { display: none; }
}

/* ── Отзывы (D-0092): карточка = цитата + кто говорит. Речь чужая, печатается как есть;
   год стоит отдельным полем, чтобы отзыв 2020-го читался как история, а не как обещание. */
.reviews-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-4); }
/* ── Отзывы: слайдер (D-0100) ───────────────────────────────────────────
   Механика взята у мипиповского донора `ПК_продукт/reviews/slider.html` — методом,
   не кодом: там тёмный «рельс» и розовый бренд Тильды, у нас свой кит.
   Суть донора: дорожка на scroll-snap с НАТИВНОЙ прокруткой — свайп пальцем работает
   сам, ничего не эмулируем; страница за раз ровно одна; под дорожкой стрелки, точки
   и счётчик, и все трое синхронны прокрутке, а не только кликам.

   Почему не `initRail`: у него механика непрерывной ленты (едет на 0,8 экрана,
   стрелки гаснут по краям). Здесь страница ровно одна, и нужны точки со счётчиком.

   Что чинит (замер 09.09.26): сеткой на телефоне восемь отзывов давали 6356 px
   подряд — восемь экранов одинаковых блоков; на ПК ряд из трёх равнялся по самой
   длинной карточке, разнобой высот 167 px. */
.rev-track {
  display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
}
.rev-track::-webkit-scrollbar { display: none; }
.rev-slide { min-width: 100%; scroll-snap-align: start; }

/* Карточка на весь слайд: слева — кто говорит, справа — речь. Речи достаётся ~105
   знаков в строке, это принятая мера сайта. Порядок в разметке остаётся смысловым
   (цитата, потом подпись) — местами их меняет сетка, а не DOM. */
/* `align-content: start` обязателен вместе с `height: 100%`: дорожка тянет все карточки
   до высоты самой длинной, а лишнюю высоту сетка раздаёт между авторядами. У длинного
   отзыва её съедает текст, у короткого она уходит В ШАПКУ — замер 09.09.26: ряд «кто»
   259,75 px при содержимом 214, то есть 62 px пустоты между подписью и речью (поймал Pet
   на телефоне). Ряды по содержимому, остаток — внизу карточки. */
.rev-slide .review { display: grid; grid-template-columns: minmax(0, 260px) minmax(0, 1fr); gap: var(--sp-6); align-items: start; align-content: start; height: 100%; }
.rev-slide .review-text { grid-column: 2; grid-row: 1; }
.rev-slide .review-who  { grid-column: 1; grid-row: 1; flex-direction: column; align-items: flex-start; gap: var(--sp-3); }

.rev-nav { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-4); }
.rev-arrows { display: flex; gap: var(--sp-2); }
.rev-arrows .icon-btn:disabled { opacity: .3; cursor: default; }
.rev-dots { display: flex; flex-wrap: wrap; justify-content: center; gap: 0; }
/* Точка рисуется псевдоэлементом, а кнопка вокруг неё — зона нажатия: 8 px сама точка
   и 24 кнопка (норма 2.5.8), на пальце 32. Восемь по 32 — 256 px, влезает в плашку
   телефона (293). Больше девяти — перенесутся, `wrap` на это и стои́т. */
.rev-dot {
  width: 24px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.rev-dot::before {
  content: ''; width: 8px; height: 8px; border-radius: var(--radius-pill);
  background: var(--hairline); transition: background-color var(--dur-2) var(--ease);
}
.rev-dot.is-on::before { background: var(--accent); }
.rev-count { font-size: var(--fs-sm); color: var(--text-dim); font-variant-numeric: tabular-nums; }

@media (pointer: coarse) {
  .rev-dot { width: 32px; height: 32px; }
  /* На самых узких телефонах восемь по 32 (256) не влезают в плашку 238 и уходят
     во второй ряд. 28 — всё ещё выше нормы 24, и ряд остаётся один. */
  @media (max-width: 360px) { .rev-dot { width: 28px; height: 28px; } }
  /* Стрелки — для мыши. На пальце их работу делает свайп, а место они занимают. */
  .rev-arrows { display: none; }
}

@media (max-width: 767px) {
  /* Лицо сверху, речь под ним: человек видит, кто говорит, до того как читать
     (так же в доноре). Меняет местами сетка — разметка остаётся смысловой. */
  .rev-slide .review { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
  /* Аватар вровень с ИМЕНЕМ, а не по центру блока: роль занимает до шести строк,
     и центрированный портрет повисал на 47 px ниже верха (замер 09.09.26). */
  .rev-slide .review-who  { grid-column: 1; grid-row: 1; flex-direction: row; align-items: flex-start; }
  .rev-slide .review-text { grid-column: 1; grid-row: 2; }
}
.review { display: flex; flex-direction: column; gap: var(--sp-4); margin: 0; padding: var(--sp-5); background: var(--surface); border-radius: var(--radius); }
.review-text { margin: 0; line-height: var(--lh-base); flex: 1; }
.review-who { display: flex; align-items: center; gap: var(--sp-3); }
.review-by { display: flex; flex-direction: column; min-width: 0; }
.review-name { font-family: var(--font-head); font-weight: 700; color: var(--ink); }
.review-role { font-size: var(--fs-xs); color: var(--text-dim); line-height: var(--lh-snug); }

/* Каждый элемент урока ведёт в каталог (D-0093): асаны в строке — ссылки в фильтр,
   части тела — чипы-ссылки в поиск. Ссылка в строке подчёркнута волоском, а не цветом:
   строка из двадцати асан синим читалась бы как одно пятно. */
.rp-inline a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--hairline); }
@media (hover: hover) { .rp-inline a:hover { color: var(--accent-ink); border-color: var(--accent-ink); } }
a.chip { text-decoration: none; color: var(--text); }
@media (hover: hover) { a.chip:hover { color: var(--ink); } }

/* ── Лист документа (D-0094). Мера строки 72 знака верна, но лист не должен растягиваться
   на всю плашку: текст слева, оглавление у правого края — между ними дыра, и это тот же
   класс дефекта, что с видео на карточке (поймал Pet). Лист — узкая плашка по центру,
   оглавление рядом с текстом. Отзывы (сетка) этим правилом не ограничены. */
/* SUPERSEDE того же дня: узкий лист Pet отверг — плашка документа во всю ширину контейнера,
   как у остальных страниц («а что с контейнером?»). Дыру убираем не сужением плашки,
   а расстановкой ВНУТРИ: текст 18 px (мера 72 знака при этом сама вырастает до ~650 px),
   оглавление сразу за ним, пара стоит по центру плашки — поля симметричны и читаются
   как поля листа, а не как пустота сбоку. Без оглавления колонка просто по центру. */
.doc-sheet { max-width: var(--content); }
.doc-sheet-solo { max-width: var(--content); }
/* Кегль отсюда переехал на сам .doc (см. выше). Причина, по которой он тут стоял, ушла
   вместе с колонкой minmax(0, 72ch): трек давно `1fr`, и от шрифта сетки уже ничего
   не считается. Обёртке остаётся её работа — расстановка текста и оглавления. */
.doc h2 { font-size: var(--fs-xl); }
.doc h3 { font-size: var(--fs-lg); }
/* Вторая поправка Pet: текст стыкуется с ЛЕВЫМ краем плашки, как на всех страницах, оглавление
   уходит к правому, а текст забирает всё между ними — ширина колонки выросла в полтора раза.
   Мера строки здесь ~100 знаков: длиннее книжной нормы, но это решение владельца — глаз ждёт
   один и тот же левый край на каждой странице сайта. Без оглавления колонка тоже от левого края,
   с потолком 96 знаков, чтобы абзац «О проекте» не тянулся через весь экран. */
/* 🚩 Мера строки живёт на ДЕТЯХ листа, а не на нём самом. У картинки меры чтения нет,
   и держать её в текстовой колонке — тот же класс дефекта («широкий контейнер + узкая
   мера = дыра справа»), что уже выходил у видео на карточке, у листа документа и у вопросов.
   Замер 09.09.26 на `/about/`: карта и баннер стояли 859 в плашке 1312 — 389 px пустоты
   справа от каждой картинки, при том что исходники есть в 1080.

   Перечисляем ИСКЛЮЧЕНИЕ, а не участников: список «кому мера положена» отстал бы молча
   на первом же новом типе блока ([[feedback_list_exclusions_not_inclusions]] в памяти).

   🪤 Мера здесь НЕ в `ch`, и это не небрежность: `ch` считается от кегля САМОГО элемента,
   и у заголовка «96 знаков» выходят шире, чем у текста. Замер 09.09.26: абзац при 18 px
   дал 859, а h2 при 26 px — 1238, то есть заголовок вылезал во всю плашку. В этом же файле
   про ту же ловушку уже была записка — про колонку сетки; она стои́т и на детях.
   Поэтому мера — одна длина на весь лист: 54rem ≈ 96 знаков при кегле листа 18 px. */
.doc { --doc-measure: 54rem; }
.doc > * { max-width: var(--doc-measure); }
.doc-figure { max-width: none; }
.doc-grid .doc > * { max-width: none; }   /* в сетке ширину задаёт колонка, не мера */
.doc-grid .doc { max-width: none; }
/* Сторож на сам класс ошибки: если .doc и .plate оказались ОДНИМ элементом, мера строки
   на нём сузит саму плашку, а не текст — так 08.09 и вышло у страницы вопросов, и она
   повисла узкой колонкой при пустой правой трети экрана. Плашка всегда во всю ширину
   контейнера (канон Pet 05.09); мера строки живёт ВНУТРИ неё, на .doc в обвязке. */
.plate.doc { max-width: none; }

/* ── страница вопросов — единственное исключение из меры листа (слово Pet 09.09) ──
   Её содержание не сплошной текст, а СПИСОК строк, и строка кликается целиком:
   узкая колонка оставляла 421 px пустоты справа от плашки — третий выход того же
   класса дефекта, что видео на карточке и лист документа (D-0094).
   Поэтому ширину забирает список, а мера остаётся ровно там, где текст ЧИТАЮТ —
   на лиде и на ответе. */
.faq-page { max-width: none; }
.faq-page .doc-lead { max-width: 96ch; }
/* 🚩 Аккордеон — ВТОРОЕ исключение из меры, рядом с картинкой. Когда мера переехала
   с листа на его детей (D-0101), она накрыла и `.faq`: список снова сел на 864 в плашке
   1246, то есть отменил решение того же дня о полной ширине. Замер это показывал —
   строка вопроса стояла 859 — и был пропущен: я смотрел на ширину ЛИСТА, а не строки.
   🔑 Проверять надо то поле, которое меняли, а не соседнее с ним. */
.faq-page .faq { max-width: none; }
.doc-grid { grid-template-columns: minmax(0, 1fr) 280px; gap: var(--sp-8); justify-content: stretch; }
/* Диапазон, а не «до 1099»: без нижней границы это правило стояло в файле ПОСЛЕ мобильного
   и перебивало его — на телефоне сетка не схлопывалась, оглавление вставало рядом с текстом
   (поймал Pet 05.09.26). */
@media (min-width: 900px) and (max-width: 1099px) { .doc-grid { grid-template-columns: minmax(0, 1fr) 220px; gap: var(--sp-7); } }

/* мобильный документ — ПОСЛЕДНИМ в файле: базовое правило .doc-grid дописывалось позже
   первого мобильного и перебивало его тем же весом — на телефоне оставались две колонки
   (второй раз за день ловим порядок каскада, 05.09.26). Одна колонка, текст во всю плашку. */
@media (max-width: 899px) {
  .doc-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  .doc-grid .doc, .doc-solo .doc { max-width: none; }
  .doc-toc { display: none; }
}

/* ── палец ─────────────────────────────────────────────────────────
   Зона нажатия — свойство УКАЗАТЕЛЯ, а не ширины экрана: у планшета шире 768
   палец тот же. Поэтому здесь единственное место в ките, где брейк не 768,
   а `pointer: coarse`. Сам размер не новый: --tap: 44px лежит в токенах
   с самого начала и уже стои́т в одиннадцати местах — до подвала, логотипа
   и «Все новинки» он просто не дошёл (замер 09.09.26: соцсети 24x24,
   ссылки документов 22 px высоты).
   Ссылки ВНУТРИ фразы (почта, телефон, автоссылки документа) намеренно не трогаем:
   растянуть строку текста нельзя, и норма их не требует.
   Блок стои́т ПОСЛЕДНИМ намеренно — он только поднимает высоту, ничего
   не перекрашивая, и должен быть последним словом. */
@media (pointer: coarse) {
  .foot-nav a { display: flex; align-items: center; min-height: var(--tap); }
  /* Зазор тут --sp-1, а не --sp-4: пять кнопок по 44 с зазором 16 просят 284 px,
     а панель подвала на телефоне 360 даёт 280 — и Vimeo уходил на вторую строку
     один (поймал Pet на своём телефоне 09.09). С 4 px ряд просит 236 и влезает
     даже на 320. Глазу зазор не меньше прежнего: 24-я иконка стои́т в коробке 44. */
  .foot-soc { gap: var(--sp-1); }
  .foot-soc a { min-width: var(--tap); min-height: var(--tap); align-items: center; justify-content: center; }
  .crumbs a { display: inline-flex; align-items: center; min-height: var(--tap); }
  .brand { min-height: var(--tap); }
  /* Ссылке «все» высоту пальца даём ОБЛАСТЬЮ нажатия, а не строкой: min-height растил
     плашку на 22 px и делал перенос вдвое заметнее. Сам перенос не отсюда — он был
     всегда: замер на 360 даёт заголовок 241 + ссылка 114 + зазор 12 = 367 в коробке 278,
     на одной строке они не помещаются ни при каком кегле. */
  .plate-more { position: relative; }
  .plate-more::after { content: ''; position: absolute; inset: -11px -8px; }
  /* Компактные 36 (--tap-sm) под пальцем добираем до 44 тем же приёмом — ОБЛАСТЬЮ, вид не меняется
     (лаба 27.09, правило скилла touch-target-size: «extend hit area beyond visual bounds»; замер:
     чипы асан и осей на карточке, «Посмотреть фрагмент», фильтры медиатеки — 36 px).
     По 4 px вверх и вниз: зазор рядов чипов 8 — соседние области сходятся встык, не налезая.
     🪤 -5, а не -4: абсолютный ::after отсчитывается от ВНУТРЕННЕЙ границы (padding box), а у чипа
     и кнопки рамка 1 px — с -4 выходило 42, и замер попаданием мимо нижнего края это поймал. */
  .chip, .btn-sm { position: relative; }
  .chip::after, .btn-sm::after { content: ''; position: absolute; inset: -5px 0; }
  /* Ряд с прокруткой вбок режет и вертикаль (overflow-x: auto делает auto и по y) — область чипа
     обрезалась, замер: 0 из 8 в медиатеке. Даём ряду 4 px сверху изнутри и забираем их отрицательным
     полем: вёрстка не сдвигается, область влезает целиком (снизу 4 px у ряда уже были). */
  .chips-scroll { padding-top: var(--sp-1); margin-top: calc(var(--sp-1) * -1); }
  .chips-rail { --rail-shift: 0px; }   /* поля ряда стали 4/4 — стрелке сдвиг не нужен */
}

/* Перенос неизбежен (арифметика выше) — делаем его аккуратным, а не случайным:
   зазор между заголовком и ссылкой меньше. Правило по ШИРИНЕ, а не по указателю:
   не помещается оно из-за ширины. Последним в файле — чтобы ничто не перебило. */
@media (max-width: 767px) {
  .plate-head { gap: var(--sp-2); }
}

/* Портрет практики (D-0126): две ромашки рядом на ПК, одна под другой на телефоне.
   Асаны — чипы, которые ничего не открывают: палец-курсор у них врал бы. */
.portrait-grid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 900px) { .portrait-grid { grid-template-columns: 1fr 1fr; } }
.chip.is-static { cursor: default; }
/* Заголовки внутри портрета шли впритык к предыдущим полосам и читались как их часть. */
.portrait-h { margin: var(--sp-5) 0 var(--sp-2); }

/* 🪤 Подписи ромашки живут в координатах SVG: поле 640x470 на экране 390 px сжимается
   вдвое, и 12 px превращаются в 6,7 — «балансы на руках» не читается вовсе. Поднять шрифт
   в самой ромашке нельзя: та же геометрия рисует отчёты, где поле во всю ширину и подписи
   в самый раз. Поэтому на узком экране те же числа показываем полосами. */
.portrait-wide { display: none; }
@media (min-width: 700px) {
  .portrait-wide { display: block; }
  .portrait-narrow { display: none; }
}

/* 🪤 На телефоне трёх колонок у полосы не остаётся: при 390 px дорожка сжималась до 70 px
   и переставала что-либо показывать, а подпись резалась на «живот и диафр…». Ниже 480 px
   дорожка уходит ПОД подпись и получает всю ширину. */
@media (max-width: 480px) {
  .chart-bar { grid-template-columns: 1fr auto; grid-template-areas: "label value" "track track";
               gap: 2px var(--sp-2); }
  .chart-bar-label { grid-area: label; white-space: normal; }
  .chart-bar-value { grid-area: value; }
  .chart-bar-track { grid-area: track; }
}

/* ── «Практика» по эскизу D лабы (слово Pet 30.09.26) ───────────────────────
   Из эскиза — каркас, полосы, раскрытие и движение; тема, шрифты и карточки — наши.
   Заливка одна на всё: полосы портрета, срок доступа, уроки записи.
   🔑 Заливка едет СДВИГОМ (translateX), а не шириной и не scaleX: ширину анимировать дорого,
   а scaleX плющит скруглённый конец полосы. Полоса во всю дорожку, видна её часть — конец остаётся круглым.
   Без JS и при «меньше движения» класса .is-anim нет — полосы стоят готовыми (ставит initFills в ui.js). */
.prac-card h2 { margin-top: 0; }
.prac-sub { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-md); }
.prac-sub-note { font-family: var(--font); font-weight: 400; margin-left: var(--sp-2); }

.pbar-track { display: block; height: 10px; background: var(--surface-sunk); border-radius: var(--radius-pill); overflow: hidden; }
.pbar-fill { display: block; width: 100%; height: 100%; background: var(--accent-ink); border-radius: var(--radius-pill);
             transform: translateX(calc((var(--p, 1) - 1) * 100%)); }
.pbar-fill.is-warn { background: var(--warn); }
[data-fills].is-anim .pbar-fill { transform: translateX(-100%); }
[data-fills].is-anim.is-in .pbar-fill { transform: translateX(calc((var(--p, 1) - 1) * 100%));
             transition: transform 800ms cubic-bezier(.22, .8, .24, 1); transition-delay: calc(var(--i, 0) * 40ms); }
@media (prefers-reduced-motion: reduce) {
  [data-fills].is-anim .pbar-fill { transform: translateX(calc((var(--p, 1) - 1) * 100%)); transition: none; }
}
/* Счётные сегменты: один сегмент — одно занятие (шкала блока не больше двенадцати). Режем дорожку маской,
   заливка под ней та же. */
.pbar-track.is-seg {
  -webkit-mask-image: repeating-linear-gradient(to right, #000 0, #000 calc(100% / var(--n) - 2px), transparent calc(100% / var(--n) - 2px), transparent calc(100% / var(--n)));
          mask-image: repeating-linear-gradient(to right, #000 0, #000 calc(100% / var(--n) - 2px), transparent calc(100% / var(--n) - 2px), transparent calc(100% / var(--n)));
}

/* Строка портрета — раскрывается: «из чего это число». Высота строки — палец (--tap). */
.pbars { display: grid; gap: 2px; margin-top: var(--sp-3); }
.pbar > summary { display: grid; grid-template-columns: minmax(0, 12em) minmax(0, 1fr) 2.2em 16px; align-items: center;
                  gap: var(--sp-3); min-height: var(--tap); padding: 0 var(--sp-2); margin: 0 calc(var(--sp-2) * -1);
                  border-radius: var(--radius-sm); cursor: pointer; list-style: none; font-size: var(--fs-sm); }
.pbar > summary::-webkit-details-marker { display: none; }
.pbar > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) { .pbar > summary:hover { background: var(--surface-soft); } }
/* Подпись переносится, а не режется: «наклоны и вытяжения вперёд» в колонке 12em обрывалась многоточием. */
.pbar-label { line-height: 1.25; overflow-wrap: anywhere; }
.pbar-value { text-align: right; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.pbar-chev { color: var(--text-dim); transition: transform var(--dur-2) var(--ease); }
.pbar[open] .pbar-chev { transform: rotate(180deg); }
.pbar-list { list-style: none; margin: 0; padding: var(--sp-1) 0 var(--sp-3); display: grid; gap: var(--sp-2); }
.pbar-list li { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px var(--sp-3);
                padding-left: var(--sp-3); border-left: 2px solid var(--hairline); font-size: var(--fs-sm); }
details.pbar::details-content { block-size: 0; opacity: 0; overflow-y: clip;
  transition: block-size var(--dur-3) var(--ease), opacity var(--dur-3) var(--ease), content-visibility var(--dur-3) allow-discrete; }
details.pbar[open]::details-content { block-size: auto; opacity: 1; }
@media (prefers-reduced-motion: reduce) { details.pbar::details-content { transition: none; } .pbar-chev { transition: none; } }

/* «Где вы сейчас»: запись, на которой остановились. Весь блок — ссылка, как карточка записи. */
.pnow { display: grid; grid-template-columns: 168px minmax(0, 1fr); gap: var(--sp-4); align-items: center;
        color: inherit; text-decoration: none; border-radius: var(--radius); }
.pnow-cover { border-radius: var(--radius-sm); overflow: hidden; }
.pnow-when { margin: 0 0 var(--sp-1); }
.pnow-title { margin: 0 0 var(--sp-1); font-size: var(--fs-md); }
.pnow-lesson { margin: 0 0 var(--sp-3); font-size: var(--fs-sm); color: var(--text-dim);
               display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.pnow-segs { display: flex; gap: 4px; max-width: 420px; margin: var(--sp-3) 0; }
.pseg { flex: 1; height: 6px; background: var(--surface-sunk); border-radius: var(--radius-pill); overflow: hidden; }
.pseg.is-now { height: 10px; margin-top: -2px; }
@media (hover: hover) { .pnow:hover .pnow-title { text-decoration: underline; text-underline-offset: 3px; } }
/* На «Занятиях» блок стоит сам, без карточки вокруг — рамку даём ему. */
.cab-now { margin-bottom: var(--sp-5); }
/* Верх «Занятий» (Pet 27.10): баннер личной подборки — заливкой бирюзы, как плашка акции на главной; на ПК рядом с поиском
   по своим записям, по половине. Баннер целиком — ссылка, «Смотреть» внутри — её вид, а не вторая кнопка. */
/* Между баннером подборки и поиском — тот же воздух, что над баннером (Pet 27.10: «выделить воздухом»). */
.cab-lead { display: grid; gap: var(--sp-5); margin-bottom: var(--sp-5); }
@media (min-width: 960px) { .cab-lead.is-pair { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; } }
.cab-lead .lib-tools { margin-bottom: 0; }
/* На ПК поиск рядом с баннером — в такой же рамке и того же роста (Pet 27.10); на телефоне рамки нет. */
@media (min-width: 960px) {
  .cab-lead.is-pair .lib-tools { padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-2); min-height: 64px;
                                 border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface); flex-wrap: nowrap; }
}
.cab-picks { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); min-height: 64px;
             border-radius: var(--radius); background: var(--rec-soft); color: var(--ink); text-decoration: none;
             transition: background-color var(--dur-2) var(--ease); }
.cab-picks b { flex: 1; min-width: 0; font-family: var(--font-head); font-size: var(--fs-md); line-height: var(--lh-snug); }
.cab-picks-ic { display: grid; place-items: center; width: 40px; height: 40px; flex: none; border-radius: 50%;
                background: var(--surface); color: var(--accent-ink); }
.cab-picks .btn { flex: none; }
@media (hover: hover) { .cab-picks:hover { background: color-mix(in oklch, var(--rec-soft) 80%, var(--accent)); } }
.prac-picks-note { margin: calc(var(--sp-2) * -1) 0 var(--sp-4); }
/* «Приложение на телефон» (c44): иконка приложения, две строки и кнопка; рамкой, как карточки кабинета. */
.cab-app { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); min-height: 64px;
           border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface); }
.cab-app[hidden] { display: none; }
.cab-app-ic { flex: none; width: 44px; height: 44px; border-radius: 11px; box-shadow: 0 0 0 1px var(--hairline); }
.cab-app-txt { flex: 1; min-width: 0; display: grid; gap: 2px; }
.cab-app-txt b { font-family: var(--font-head); font-size: var(--fs-md); line-height: var(--lh-snug); color: var(--ink); }
.cab-app-txt small { font-size: var(--fs-sm); color: var(--text-dim); }
.cab-app .btn { flex: none; }
.cab-app-x { flex: none; margin-right: calc(var(--sp-2) * -1); }
/* Телефон (Pet 27.10, скрин): иконка и текст в ряд, крестик в углу, кнопка ниже — по левому краю текста, как у плашки канала. */
@media (max-width: 599px) {
  .cab-app { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; grid-template-areas: "ic txt x" ". go go";
             align-items: start; gap: var(--sp-2) var(--sp-3); padding: var(--sp-4); }
  .cab-app[hidden] { display: none; }
  .cab-app-ic { grid-area: ic; }
  .cab-app-txt { grid-area: txt; }
  .cab-app .btn { grid-area: go; justify-self: start; }
  .cab-app-x { grid-area: x; margin: calc(var(--sp-2) * -1) calc(var(--sp-2) * -1) 0 0; }
}
.cab-app { margin-bottom: var(--sp-5); }
.cab-now .pnow { padding: var(--sp-4); border: 1px solid var(--hairline); background: var(--surface); }

/* Открытые записи со сроком: полоса — сколько осталось от окна доступа. */
/* Колонки одной ширины у всех строк: с `auto` у подписи дорожки начинались вразнобой (снимок 30.09). */
.pterms { display: grid; gap: 2px; max-width: 860px; }
.prac-card > .pbars { max-width: 640px; }   /* одиночный список (преподаватели) — не во всю карточку */
.pterm { display: grid; grid-template-columns: minmax(0, 1fr) minmax(80px, 220px) 16.5em; gap: var(--sp-3);
         align-items: center; min-height: var(--tap); padding: 0 var(--sp-2); margin: 0 calc(var(--sp-2) * -1);
         border-radius: var(--radius-sm); color: inherit; text-decoration: none; font-size: var(--fs-sm); }
@media (hover: hover) { .pterm:hover { background: var(--surface-soft); } }
.pterm-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pterm-left { color: var(--text-dim); white-space: nowrap; text-align: right; }

/* Практика по дням: числа и календарь. Уровень дня — и цветом, и РАЗМЕРОМ квадрата (не только цветом). */
.pstats { display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-6); margin: 0 0 var(--sp-4); }
.pstat b { display: block; font-family: var(--font-head); font-size: var(--fs-xl); line-height: 1.15; color: var(--ink);
           font-variant-numeric: tabular-nums; }
.pstat span { font-size: var(--fs-sm); color: var(--text-dim); }
.pcal-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
.pcal-in { display: inline-block; }
.pcal-head, .pcal-grid { display: grid; grid-auto-flow: column; grid-auto-columns: 16px; gap: 3px; }
.pcal-head { height: 18px; font-size: 11px; color: var(--text-dim); }
.pcal-head span { white-space: nowrap; }
.pcal-w { display: grid; grid-template-rows: repeat(7, 16px); gap: 3px; }
.pcal-d { display: block; width: 16px; height: 16px; border-radius: 4px; background: var(--surface-sunk); }
.pcal-d.l1 { background: var(--accent-ink); box-shadow: inset 0 0 0 5px var(--surface-sunk); }
.pcal-d.l2 { background: var(--accent-ink); box-shadow: inset 0 0 0 3.5px var(--surface-sunk); }
.pcal-d.l3 { background: var(--accent-ink); box-shadow: inset 0 0 0 2px var(--surface-sunk); }
.pcal-d.l4 { background: var(--accent-ink); }
.pcal-readout { margin: var(--sp-2) 0 var(--sp-3); min-height: 1.5em; }

@media (max-width: 599px) {
  /* Телефон (Pet 27.10): обложка и название — рядом и одного роста (название не длиннее трёх строк, стоит по центру
     обложки); полоска уроков и кнопка — ниже, на всю ширину, кнопку удобно нажать. Обложку не обрезаем: на ней текст. */
  .pnow { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); grid-template-areas: "cover text" "segs segs" "btn btn";
          gap: var(--sp-3); align-items: center; }
  .pnow-body { display: contents; }
  .pnow-cover { grid-area: cover; }
  .pnow-text { grid-area: text; }
  .pnow-title { display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; margin: 0; }
  .pnow-lesson { margin: var(--sp-1) 0 0; -webkit-line-clamp: 1; line-clamp: 1; }
  .pnow-segs { grid-area: segs; max-width: none; margin: 0; }
  .pnow-btn { grid-area: btn; width: 100%; justify-content: center; min-height: var(--tap); }
  .pterm { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title title" "track left"; gap: 4px var(--sp-3);
           padding-block: var(--sp-2); }
  .pterm-title { grid-area: title; white-space: normal; }
  .pterm .pbar-track { grid-area: track; }
  .pterm-left { grid-area: left; }
}
@media (max-width: 480px) {
  .pbar > summary { grid-template-columns: minmax(0, 1fr) auto 16px; grid-template-areas: "label value chev" "track track track";
                    gap: 4px var(--sp-2); padding-block: var(--sp-2); }
  .pbar-label { grid-area: label; white-space: normal; }
  .pbar-value { grid-area: value; }
  .pbar-chev { grid-area: chev; }
  .pbar > summary .pbar-track { grid-area: track; }
}

/* ── Страницы входа: форма и стена обложек (эскиз E лабы в нашем каноне, слово Pet 30.09.26) ──────────
   Из эскиза — раскладка в две половины, плывущая стена, ячейки кода, подсказка почты. Цвета, шрифты,
   карточка формы и кнопки — наши. Стена — украшение: без неё страница та же (телефон без JS — лента,
   при «меньше движения» всё стоит). Движется только transform. */
.lg { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
.lg-form { width: 100%; max-width: 420px; margin: 0 auto; }
.lg-visual { display: none; }
.lg-strip-wrap { position: relative; margin: 0 calc(var(--gutter) * -1); }
.lg-strip { height: 84px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 76%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 12%, #000 76%, transparent 100%); }
.lg-row { display: flex; width: max-content; padding: 10px 0; animation: lg-x 150s linear infinite; will-change: transform; }
.lg-row picture, .lg-row > img { flex: none; display: block; width: 64px; height: 64px; margin-right: 10px;
  border-radius: var(--radius); overflow: hidden; background: var(--surface-sunk); }
.lg-row img, .lg-col img { display: block; width: 100%; height: 100%; object-fit: cover; filter: saturate(.62); }
@keyframes lg-x    { to { transform: translate3d(-50%, 0, 0); } }
@keyframes lg-up   { to { transform: translate3d(0, -50%, 0); } }
@keyframes lg-down { from { transform: translate3d(0, -50%, 0); } to { transform: translate3d(0, 0, 0); } }

/* Пауза — тихая, но есть (WCAG 2.2.2). Работает скриптом, поэтому без него кнопки нет. */
.lg-pause { position: absolute; display: none; place-items: center; width: var(--tap); height: var(--tap); padding: 0;
  border-radius: 50%; border: 1px solid var(--hairline); background: var(--surface); color: var(--text-dim); cursor: pointer; }
.lg.is-js .lg-pause { display: inline-grid; }
.lg-pause .lg-i-play { display: none; }
.lg-pause[aria-pressed="true"] .lg-i-play { display: block; }
.lg-pause[aria-pressed="true"] .lg-i-pause { display: none; }
.lg-strip-wrap .lg-pause { right: var(--gutter); top: 20px; }
@media (hover: hover) { .lg-pause:hover { color: var(--ink); border-color: var(--text-dim); } }

@media (min-width: 960px) {
  /* Отступ до подвала — как под шапкой (32): у окна со стеной чёткие края, и канонные 64 перед подвалом
     читались перекосом (глаз Pet 30.09; первая версия добавляла ещё 64 сверху и давала 128 против 32). */
  .lg { grid-template-columns: minmax(360px, 440px) minmax(0, 1fr); gap: var(--sp-7); align-items: center;
        margin-bottom: calc(var(--sp-6) - var(--sp-8)); }
  .lg-form { max-width: none; margin: 0; }
  .lg-strip-wrap { display: none; }
  .lg-visual { display: block; position: relative; height: clamp(460px, calc(100svh - 240px), 640px);
    border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-soft); isolation: isolate; }
  .lg-wall { position: absolute; inset: -14% -12%; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px;
    transform: rotate(-6deg); }
  .lg-col { will-change: transform; animation: lg-up 190s linear infinite; }
  .lg-col:nth-child(2) { animation-name: lg-down; animation-duration: 230s; animation-delay: -60s; }
  .lg-col:nth-child(3) { animation-duration: 210s; animation-delay: -120s; }
  .lg-col:nth-child(4) { animation-name: lg-down; animation-duration: 250s; animation-delay: -30s; }
  .lg-col picture, .lg-col > img { display: block; aspect-ratio: 1 / 1; margin: 0 0 16px; border-radius: var(--radius);
    overflow: hidden; background: var(--surface-sunk); }
  /* Вуаль — в цвет панели: снизу плотная под подпись, поверх всей стены — лёгкая, чтобы пёстрые обложки не спорили с формой. */
  .lg-veil { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1; pointer-events: none;
    background: linear-gradient(0deg, var(--surface-soft) 0%, color-mix(in srgb, var(--surface-soft) 78%, transparent) 30%, transparent 66%),
                color-mix(in srgb, var(--surface-soft) 24%, transparent); }
  .lg-cap { position: absolute; z-index: 2; left: var(--sp-6); right: 96px; bottom: var(--sp-6); color: var(--ink); }
  .lg-cap p { margin: var(--sp-3) 0 0; max-width: 22ch; font-family: var(--font-head); font-weight: 700; font-size: var(--fs-xl);
    line-height: 1.2; text-wrap: balance; }
  .lg-visual .lg-pause { z-index: 2; right: var(--sp-5); bottom: var(--sp-5); }
}
@media (prefers-reduced-motion: reduce) {
  .lg-row, .lg-col { animation: none !important; }
  .lg .lg-pause { display: none !important; }
}

/* Подсказка под полем почты: опечатка в домене, русская раскладка. Пустая — места не занимает. */
.field-hint { display: block; margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--text-dim); }
.field-hint:empty { display: none; }
.field-hint b { color: var(--ink); }
.linkbtn { padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--accent-ink); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px; min-height: var(--tap-sm); }

/* Код из шести цифр: одно настоящее поле поверх шести ячеек (ставит initOtp; без JS — обычное поле).
   🪤 !important — не лень: общее правило полей собрано из десяти :not() и тяжелее любого класса (0,10,1). */
.otp { display: block; position: relative; }
/* Ячейки — во всю ширину формы, как кнопка под ними: с потолком 340 справа оставалась пустота (снимок Pet 30.09). */
.otp.is-on { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sp-2); border-radius: var(--radius); }
.otp-cell { display: flex; align-items: center; justify-content: center; height: 56px; min-width: 0;
  border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface);
  font-family: var(--font-head); font-weight: 700; font-size: var(--fs-xl); line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.otp-cell.is-active { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.otp-cell.is-active:empty::after { content: ''; width: 2px; height: 24px; border-radius: 1px; background: var(--ink);
  animation: otp-blink 1.1s steps(1) infinite; }
@keyframes otp-blink { 50% { opacity: 0; } }
.otp.is-on input { position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100% !important; height: 100% !important; min-height: 0 !important; margin: 0;
  padding: 0 0 0 12px !important; border: 0 !important; outline: none; background: transparent !important; color: transparent !important;
  caret-color: transparent; -webkit-text-fill-color: transparent; font-size: 16px !important; letter-spacing: 1em; text-align: left;
  cursor: text; -webkit-appearance: none; appearance: none; }
.otp.is-on input::placeholder { color: transparent; }
.otp.is-on input::selection { background: transparent; }
.otp.is-on:focus-within { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .otp-cell.is-active:empty::after { animation: none; } }

/* ── Письма (D-0138): реестр и карточка ─────────────────────────────────────
   Правка середины письма — поля contenteditable; подстановки — плашками, которые
   не правятся по букве. Сцена превью светлая в обеих темах: письмо в почте светлое. */
.mail-reg .mail-grp td { padding-top: var(--sp-4); font-size: var(--fs-xs); letter-spacing: .06em;
                         text-transform: uppercase; color: var(--text-dim); border-bottom: 0; }
.mail-reg .mail-no { font-weight: 600; color: var(--accent-ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mail-reg tr.is-later td { color: var(--text-dim); }
.mail-toggle { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; margin: var(--sp-4) 0 0; }
.mail-grid { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1fr); align-items: start; margin-top: var(--sp-4); }
@media (min-width: 1100px) { .mail-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
/* Колонка сетки — minmax(0, 1fr): неявная `auto` растягивалась по переключателю из пяти видов, и на
   телефоне карточка P01 выезжала вбок на 20 px (замер WebKit 375, 23.09.26). */
.mail-editor, .mail-preview { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); align-content: start; }
.mail-editor .field { margin: 0; }
.mail-edit { min-height: var(--tap); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--hairline); border-radius: var(--radius);
             background: var(--surface); color: var(--ink); line-height: var(--lh-base); outline: none; overflow-wrap: anywhere; }
.mail-edit:focus-visible { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.mail-block { display: grid; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--radius); border: 1px dashed var(--hairline); }
.mail-block-box { background: var(--surface-soft); border-color: transparent; }
.mail-block-small .mail-edit { font-size: var(--fs-sm); color: var(--text-dim); }
.mail-locked { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border-radius: var(--radius);
               background: var(--surface-soft); color: var(--text-dim); font-size: var(--fs-sm); }
.mail-var { display: inline-flex; align-items: center; gap: 4px; padding: 0 var(--sp-2); border-radius: 999px; background: var(--accent-soft);
            color: var(--accent-ink); font-size: .9em; font-weight: 600; white-space: nowrap; user-select: all; }
.mail-var.is-locked { box-shadow: inset 0 0 0 1px var(--accent); }
.mail-btn-row, .mail-code-row { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; }
.mail-edit-btn { min-width: 12rem; font-weight: 600; }
.mail-gates { display: grid; gap: var(--sp-1); padding: var(--sp-3); border-radius: var(--radius); background: var(--surface-soft); font-size: var(--fs-sm); }
.mail-gate { display: flex; gap: var(--sp-2); align-items: flex-start; }
.mail-gate > svg { flex: none; margin-top: 3px; }
.mail-gate.is-ok { color: var(--ok); }
.mail-gate.is-bad { color: var(--err); }
.mail-gate span { color: var(--text); }
.mail-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.mail-pv-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-2); align-items: center; }
.mail-pv-title { font-size: var(--fs-lg); margin: 0; }
.mail-seg { display: inline-flex; border: 1px solid var(--hairline); border-radius: 999px; overflow: hidden; }
.mail-seg button { font: inherit; font-size: var(--fs-sm); font-weight: 600; min-height: var(--tap-sm); padding: 0 var(--sp-3);
                   border: 0; background: transparent; color: var(--text-dim); cursor: pointer; }
.mail-seg button[aria-pressed="true"] { background: var(--ink); color: var(--on-ink); }
.mail-seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mail-inbox { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius); background: var(--surface-soft); overflow-wrap: anywhere; }
.mail-pv-stage { background: #eceae6; border-radius: var(--radius); padding: var(--sp-3); overflow: hidden; }
.mail-pv-fit { margin: 0 auto; overflow: hidden; }
.mail-pv-frame { display: block; width: 600px; height: 900px; border: 0; background: #ffffff; transform-origin: 0 0; }
.mail-vars { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
/* Номер записи или учётки — бейджем, который выделяется целиком одним щелчком (просьба Pet 23.09): двойной щелчок
   по голому числу в Chrome на Windows прихватывал пробел справа, и в таблицу сверки уезжало «123 ». */
.idnum { display: inline-block; padding: 0 6px; border-radius: 6px; background: var(--surface-soft); color: var(--text);
         font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; user-select: all; -webkit-user-select: all;
         cursor: text; line-height: 1.6; }
.idnum-cap { font-size: var(--fs-xs); color: var(--text-dim); margin-right: 2px; }
/* Колонка номера — без переноса (Pet 23.09: «WP» и номер разъезжались на две строки, а соседней колонке есть запас). */
.idcol { white-space: nowrap; width: 1%; }

/* Письмо о покупке (D-0141): блоки позиции повторяются на каждую — отмечены полосой слева. */
.mail-block.is-repeat { box-shadow: inset 3px 0 0 var(--accent); }
.mail-block-show { color: var(--accent-ink); }
.mail-edit-link { min-width: 12rem; font-weight: 600; }
.mail-pv-views { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); align-items: center; }
.mail-pv-views .mail-seg { max-width: 100%; overflow-x: auto; }
.mail-pv-views .mail-seg button { white-space: nowrap; }
.mail-pv-product { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); flex: 1 1 16rem; min-width: 0; margin: 0; }
.mail-pv-product select { flex: 1 1 12rem; min-width: 0; max-width: 100%; }

/* ── Эфир: блок покупки под лендингом (D-0150) ──────────────────────────────────
   Лендинг курса — чужая вёрстка, а блок покупки — наш: плашка тона записи (как у карточки),
   слева расписание, справа цена и кнопка. На узком — друг под другом, кнопка под рукой. */
.live-buy { padding: var(--sp-7) 0; scroll-margin-top: 80px; }
.live-buy-card {
  display: grid; gap: var(--sp-5); grid-template-columns: minmax(0, 1fr);
  padding: var(--sp-5); border-radius: var(--radius-lg); background: var(--rec-soft);
}
@media (min-width: 900px) { .live-buy-card { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); padding: var(--sp-7); } }
.live-buy-info { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.live-buy-kicker { margin: 0; font-size: var(--fs-sm); color: var(--rec-ink); font-weight: 600; letter-spacing: .02em; }
.live-buy-title { margin: 0; font-size: var(--fs-2xl); line-height: var(--lh-tight); text-wrap: balance; }
.live-buy-who { margin: 0; color: var(--text-dim); }
.live-sched { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.live-sched li { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius); background: var(--surface); border: 1px solid var(--rec-line); }
.live-sched-when { font-family: var(--font-head); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.live-sched-what { font-size: var(--fs-sm); color: var(--text); }
.live-sched li.is-passed { opacity: .6; }
.live-buy-pay {
  display: flex; flex-direction: column; gap: var(--sp-3); align-self: start;
  padding: var(--sp-5); border-radius: var(--radius); background: var(--surface); border: 1px solid var(--rec-line);
}
/* На ПК плашка с ценой — по высоте левой части, содержимое по центру (Pet 27.10: «равнозначно с левой частью»). */
@media (min-width: 900px) { .live-buy-pay { align-self: stretch; justify-content: center; } }
.live-price-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-3); }
.live-price { font-family: var(--font-head); font-size: var(--fs-xl); font-weight: 700; color: var(--ink); }
.live-price-ok { color: var(--ok); }
.live-price-old { color: var(--text-dim); font-size: var(--fs-md); }
.live-buy-early { margin: 0; font-size: var(--fs-sm); color: var(--rec-ink); font-weight: 600; }
.live-buy-note { margin: 0; font-size: var(--fs-xs); color: var(--text-dim); }

/* ── Главная: предстоящие и идущие эфиры (D-0150; карточка по «Полёту» — Pet 01.10.26, раскладка — Pet 27.10) ─────
   Плашка в ритме главной с заголовком сверху; эфиры — карточками в треть ширины рядом (на планшете по два, на телефоне
   по одному). Обложка КВАДРАТНАЯ и целиком: на ней текст дизайнера, обрезать нельзя. Обложки нет — иконка на плашке тона. */
.hl-grid { display: grid; gap: var(--sp-5); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 640px) { .hl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .hl-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.hl-card {
  display: flex; flex-direction: column; overflow: hidden;
  border-radius: var(--radius-lg); background: var(--rec-soft); color: var(--text);
}
/* Фон — цвет края обложки (media_edge_color): карточка читается одним целым с картинкой (Pet 01.10).
   Тёмная тема: тёмная поверхность с оттенком края — светлый бежевый там слепил бы. */
.hl-card.has-edge { background: var(--hl-bg); }
/* Стекло поверх всей карточки — и картинки, и фона (Pet 01.10, 11:45: «небольшой стеклянный эффект»): диагональный
   блик, светлая кромка и мягкая тень. Слой прозрачен для нажатий. backdrop-filter не нужен — под стеклом своё же. */
.hl-card { position: relative; --hl-glint: rgba(255, 255, 255, .26); --hl-rim: rgba(255, 255, 255, .55);
           box-shadow: 0 14px 34px -18px rgba(30, 30, 20, .28); }
.hl-card::after {
  content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(118deg, var(--hl-glint) 0%, transparent 34%, transparent 66%,
                                      color-mix(in srgb, var(--hl-glint) 45%, transparent) 100%);
  box-shadow: inset 0 1px 0 var(--hl-rim), inset 0 0 0 1px color-mix(in srgb, var(--hl-rim) 55%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hl-card { --hl-glint: rgba(255, 255, 255, .07); --hl-rim: rgba(255, 255, 255, .14); box-shadow: none; }
}
:root[data-theme="dark"] .hl-card { --hl-glint: rgba(255, 255, 255, .07); --hl-rim: rgba(255, 255, 255, .14); box-shadow: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hl-card.has-edge { background: color-mix(in oklch, var(--hl-bg) 14%, var(--surface)); }
}
:root[data-theme="dark"] .hl-card.has-edge { background: color-mix(in oklch, var(--hl-bg) 14%, var(--surface)); }
.hl-media {
  /* width: 100% обязательна: WebKit не растягивает элемент сетки с aspect-ratio — без неё 0×0
     (память reference_webkit_image_tile_collapse). top/left вместо inset — iOS до 14.5 его не знает. */
  position: relative; display: grid; place-items: center; width: 100%; aspect-ratio: 1; align-self: start;
  /* Подложка — цвет самой карточки (край обложки или тон), а не светлая своя: на обратном ходе увеличения картинка
     на долю пикселя отставала от низа, и светлая подложка давала белую полоску (Pet 27.10). */
  background: transparent; color: var(--rec-tint); overflow: hidden;
}
.hl-media picture, .hl-media img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.hl-media img { transition: transform var(--dur-3) var(--ease); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) { .hl-card:hover .hl-media img { transform: scale(1.03); } }
.hl-media .badge { position: absolute; left: var(--sp-3); top: var(--sp-3); }
.hl-body {
  display: flex; flex-direction: column; gap: var(--sp-3); flex: 1; min-width: 0;
  padding: var(--sp-5) var(--sp-5) var(--sp-6);
}
.hl-status { margin: 0; display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); font-weight: 600; color: var(--rec-ink); }
/* Точка «в эфире» дышит; у записи эфира — ровная и тихая. */
.hl-dot { position: relative; width: 8px; height: 8px; border-radius: 50%; background: var(--ok); flex: none; }
.hl-dot::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; border-radius: 50%; background: inherit; animation: hl-ping 1.8s var(--ease) infinite; }
.is-after .hl-dot { background: var(--text-dim); }
.is-after .hl-dot::after { animation: none; }
@keyframes hl-ping { 0% { transform: scale(1); opacity: .7; } 100% { transform: scale(2.6); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hl-dot::after { animation: none; } }
/* Под обложкой — только цена со сроком и кнопка (Pet 27.10): кто, когда и сколько уроков — на самой обложке.
   Цена, под ней кнопка — слева, одной колонкой (слово Pet 01.10: кнопка ближе к тексту, а не у дальнего края). */
.hl-foot { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3); margin-top: auto; }
.hl-price-row { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.hl-pill { padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: 600;
           background: color-mix(in oklch, var(--surface) 78%, transparent); color: var(--text-dim); box-shadow: inset 0 0 0 1px var(--hairline); }
.hl-term { margin: 0; font-size: var(--fs-sm); color: var(--text-dim); }
.hl-price { font-family: var(--font-head); font-weight: 700; font-size: var(--fs-xl); line-height: var(--lh-tight); color: var(--ink); }

/* ── Страница ученика эфира (D-0150) ───────────────────────────────────────────
   Расписание столбиком: урок сегодня — плашкой тона и яркой кнопкой Zoom, прошедший — тише.
   Канал эфира — заметной полосой сверху (слово Pet 23.09). */
.live-me { display: flex; flex-direction: column; gap: var(--sp-5); padding-bottom: var(--sp-8); }
.live-me-head { display: flex; flex-direction: column; gap: var(--sp-2); }
.live-me-head h1 { margin: 0; text-wrap: balance; }
.live-me-text { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
/* Шапка — в той же рамке, что карточки уроков ниже (Pet 27.10): один язык на странице. */
.live-me-head.has-cover { flex-direction: row; align-items: center; gap: var(--sp-5); padding: var(--sp-4);
                          border-radius: var(--radius); background: var(--surface); border: 1px solid var(--hairline); }
.live-me-cover { position: relative; flex: none; width: 180px; height: 180px; border-radius: var(--radius-lg); overflow: hidden;
                 background: var(--surface-soft); box-shadow: var(--shadow-raise); }
.live-me-cover picture, .live-me-cover img { position: absolute; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 639px) {
  /* Телефон: обложка крупнее (Pet 27.10), заголовок на ступень меньше — иначе он съедает экран в пять строк. */
  /* Pet 27.10, вечер: обложка — на всю ширину рамки, под ней строкой «Эфир в Zoom · даты», преподаватель, заголовок. */
  .live-me-head.has-cover { flex-direction: column; gap: var(--sp-3); align-items: stretch; padding: var(--sp-3); }
  .live-me-cover { width: 100%; height: auto; aspect-ratio: var(--cover); border-radius: var(--radius); }
  .live-me-head .live-buy-who { order: 1; }
  .live-me-head h1 { order: 2; }
  .live-me-head .note { order: 3; }
  .live-me-head.has-cover h1 { font-size: var(--fs-lg); line-height: var(--lh-snug); }
}
.live-me-channel {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius); background: var(--rec-soft); color: var(--rec-ink); text-decoration: none;
  border: 1px solid var(--rec-line);
}
.live-me-channel-txt { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.live-me-channel b { color: var(--ink); }
.live-me-channel small { font-size: var(--fs-sm); color: var(--text-dim); }
.live-me-channel-ic { flex: none; display: grid; color: #2aabee; }   /* фирменный голубой Telegram — знак узнают по цвету */
.live-me-channel .btn { flex: none; }
/* Телефон (Pet 27.10): знак и текст в ряд, кнопка ниже — по левому краю текста. */
@media (max-width: 599px) {
  .live-me-channel { flex-wrap: wrap; padding: var(--sp-4); }
  .live-me-channel-txt { flex-basis: calc(100% - 40px - var(--sp-3)); }
  .live-me-channel .btn { margin-left: calc(40px + var(--sp-3)); }
}
.live-me-stage { position: relative; width: 100%; max-width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius); overflow: hidden; background: #000; scroll-margin-top: 90px; }
.live-me-stage iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; }
.live-me-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.live-me-item {
  display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius); background: var(--surface); border: 1px solid var(--hairline);
}
.live-me-item.is-today { background: var(--rec-soft); border-color: var(--rec-line); }
.live-me-item.is-now { border-color: var(--rec-tint); }
.live-me-when { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3);
                font-family: var(--font-head); font-weight: 700; color: var(--rec-ink); font-variant-numeric: tabular-nums; }
.live-me-when .badge { font-family: var(--font); font-weight: 600; }
.live-me-item.is-passed .live-me-when { color: var(--text-dim); }
.live-me-title { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-snug); }
.live-me-act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin: var(--sp-2) 0; }   /* воздух у кнопки — Pet 28.10 */
.live-me-sum { margin-top: var(--sp-2); }
/* Умное оглавление урока (c73): табличка в рамке (Pet 28.10) — слева раздел, справа время светло-зелёной пилюлей,
   как «Смотреть запись». Нажимается вся строка — цель крупнее; нажал — плеер перескочил. */
.live-me-toc { margin-top: var(--sp-5); }
.live-me-toc h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-base); }
.live-me-toc ol { list-style: none; margin: 0; padding: 0; border: 1px solid var(--hairline); border-radius: var(--radius); overflow: hidden; }
.live-me-toc li + li { border-top: 1px solid var(--hairline); }
.live-me-toc button {
  display: flex; gap: var(--sp-3); align-items: center; justify-content: space-between; width: 100%; padding: 10px var(--sp-4);
  border: 0; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.live-me-toc time {
  flex: none; padding: 4px 12px; border-radius: var(--radius-pill); background: var(--accent-soft); color: var(--accent-ink);
  font-variant-numeric: tabular-nums; font-weight: 600; font-size: var(--fs-sm, 0.875rem);
}
@media (hover: hover) {
  .live-me-toc button:hover { background: var(--surface-soft); }
  .live-me-toc button:hover time { background: var(--accent-ink); color: var(--on-ink); }
}
.live-me-toc button:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
/* Раздел, который идёт в плеере сейчас: подложка и залитая пилюля, полоска слева — как у текущего урока в записи. */
.live-me-toc button.is-now { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent-ink); font-weight: 600; }
.live-me-toc button.is-now time { background: var(--accent-ink); color: var(--on-ink); }
.live-me-sum h3 { margin: 0 0 var(--sp-1); font-size: var(--fs-base); }
.live-me-sum p { margin: 0; }
.live-me-gift h2, .live-me-info h2 { font-size: var(--fs-lg); margin: 0 0 var(--sp-3); }
/* «Как всё устроено» — в рамке, как карточки уроков (Pet 28.10: без неё блок висел отдельно от страницы). */
.live-me-info { padding: var(--sp-4) var(--sp-5); border-radius: var(--radius); background: var(--surface); border: 1px solid var(--hairline); }
.live-me-info ul { margin: 0; padding-left: 1.2em; display: flex; flex-direction: column; gap: var(--sp-2); color: var(--text); }

/* Полоска продления на странице ученика (D-0151): у записей, в окне продления; плашкой тона, кнопка справа. */
.live-me-renew {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3) var(--sp-5);
  padding: var(--sp-4) var(--sp-5); border-radius: var(--radius); background: var(--rec-soft); border: 1px solid var(--rec-line);
}
.live-me-renew > div:first-child { flex: 1 1 22rem; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.live-me-renew b { font-family: var(--font-head); color: var(--ink); }
.live-me-renew p { margin: 0; }
.live-me-renew-act { display: flex; flex-direction: column; gap: var(--sp-1); }

/* Ключи и доступы (D-0152): строка на сервис — заголовок с хвостом ключа, форма замены в строку. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.keys-list { display: flex; flex-direction: column; gap: var(--sp-3); }
/* Группы ключей (Pet 26.10): заголовок-строка сворачивает свои карточки. */
.keys-grp { display: flex; flex-direction: column; gap: var(--sp-3); }
.keys-grp > summary { display: flex; align-items: baseline; gap: var(--sp-3); cursor: pointer; list-style: none;
                      padding: var(--sp-3) var(--sp-4); border-radius: var(--radius); background: var(--surface-soft); }
.keys-grp > summary::-webkit-details-marker { display: none; }
.keys-grp > summary::before { content: '▸'; color: var(--text-dim); transition: transform var(--dur-2) var(--ease); }
.keys-grp[open] > summary::before { transform: rotate(90deg); }
.keys-grp[open] > summary { margin-bottom: var(--sp-1); }
.keys-grp-title { font-family: var(--font-head); font-weight: 700; font-size: var(--fs-lg); }
.keys-how { margin-top: var(--sp-1); }
.keys-how summary { cursor: pointer; color: var(--accent-ink); width: max-content; }
.keys-how p { margin: var(--sp-2) 0 0; max-width: 100ch; line-height: var(--lh-base); }
.keys-row { display: flex; flex-direction: column; gap: var(--sp-2); }
.keys-row h2 { font-size: var(--fs-lg); margin: 0; }
.keys-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--sp-2) var(--sp-4); }
.keys-head > div { min-width: 0; flex: 1 1 20rem; }
.keys-head p { margin: var(--sp-1) 0 0; }
.keys-head .badge { font-variant-numeric: tabular-nums; }
.keys-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }

/* Каталог: плашка «Создать» вверху (Pet 23.09) — выделена тоном акцента, кнопки справа, на узком — под текстом. */
.cat-create { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3) var(--sp-5);
  background: var(--accent-soft); border-color: transparent; margin-bottom: var(--sp-4); }
.cat-create h2 { margin: 0; font-size: var(--fs-lg); }
.cat-create p { margin: var(--sp-1) 0 0; }
.cat-create-btns { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* ── Карточка эфира (D-0154): разделы по порядку работы, группы — цветом номера, липкая панель справа ──────
   Цвет не «полосой на карточке», а номером раздела: зелёный — содержание, тёплый — деньги и сроки,
   синий — публикация. На телефоне панель уходит вниз, «Сохранить» — полосой у нижнего края. */
.lc-shell { display: grid; gap: var(--sp-4); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1100px) { .lc-shell { grid-template-columns: minmax(0, 1fr) 300px; } }
.lc-main { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.cat-form.lc-shell .card { margin-bottom: 0; }
.lc-sec h2 { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); font-size: var(--fs-lg); }
.lc-n { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums; background: var(--g-soft, var(--accent-soft)); color: var(--g-ink, var(--accent-ink)); flex: none; }
.lc-sec[data-group="a"] { --g-soft: var(--ok-soft, #e1f1e6); --g-ink: var(--ok); }
.lc-sec[data-group="b"] { --g-soft: var(--warn-soft, #f7ecdc); --g-ink: var(--warn); }
.lc-sec[data-group="c"] { --g-soft: var(--accent-soft); --g-ink: var(--accent-ink); }
.lc-sec { scroll-margin-top: 90px; }
.lc-cols-cover { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 768px) { .lc-cols-cover { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); } }
.lc-row { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 768px) { .lc-row { grid-template-columns: minmax(0, 1.3fr) minmax(0, .5fr) minmax(0, 1.2fr); } .lc-row .lc-wide { grid-column: 1 / -1; } }
/* Подарок участникам — подсписок раздела «Занятия» (Pet 26.09): название и ролик в строку. */
.lc-sub { font-size: var(--fs-md); margin: var(--sp-4) 0 var(--sp-1); display: flex; gap: var(--sp-2); align-items: baseline; }
@media (min-width: 768px) { .lc-gift { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); } }
/* Адрес страницы: домен серым перед полем — видно, что это кусок ссылки (Pet 26.09). */
.addr { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-1); }
.addr-host { color: var(--text-dim); font-size: var(--fs-sm); white-space: nowrap; }
.addr input { flex: 1 1 12rem; min-width: 0; }
.lc-inline { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-1); }
.lc-inline input { flex: 1 1 7rem; min-width: 0; }
.lc-fold summary { cursor: pointer; list-style-position: inside; }
.lc-side { display: flex; flex-direction: column; gap: var(--sp-3); }
/* Липнет у самого верха (Pet 24.09): шапка сайта при прокрутке вниз уезжает, место свободно. */
@media (min-width: 1100px) { .lc-side { position: sticky; top: var(--sp-4); } }
.lc-ready h2 { font-size: var(--fs-md); margin: 0 0 var(--sp-2); }
.lc-ready .checklist a { color: inherit; text-decoration: none; border-bottom: 1px dotted currentColor; }
.lc-ready .check-line-lg { margin-top: var(--sp-3); }
.lc-save { display: flex; flex-direction: column; gap: var(--sp-2); }
@media (max-width: 1099px) {
  .lc { padding-bottom: 88px; }
  .lc-save { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20; flex-direction: row; align-items: center;
    padding: var(--sp-3) var(--gutter) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
    background: var(--surface); border-top: 1px solid var(--hairline); box-shadow: var(--shadow-raise); }
  .lc-save .btn-wide { flex: 1 1 auto; width: auto; }
}
.lc-ready .checklist li { align-items: flex-start; }
.lc-ready .checklist li > span { min-width: 0; }
.lc-del { align-self: flex-start; color: var(--err); }

/* ── Страница продажи в цветах лендинга (Pet 26.09) ─────────────────────────────────────────────
   Токены сайта подменяет палитра лендинга (<style> в layout, live_landing_skin_css); здесь — только то,
   что токенами не выражено: кнопка покупки акцентом лендинга и его радиусом, заголовки его шрифтом,
   плашка покупки его радиусом, шапка на его фоне. Тумблера темы нет: лендинг нарисован под светлую. */
.lp-skin [data-theme-toggle] { display: none; }
.lp-skin .site-header { background: var(--bg); }
.lp-skin .live-buy { --rec-soft: var(--surface-soft); --rec-ink: var(--lp-accent, var(--accent-ink)); --rec-line: var(--hairline); }
.lp-skin .live-buy-card { border-radius: var(--lp-radius-card, var(--radius-lg)); }
.lp-skin .live-buy-title, .lp-skin .live-price, .lp-skin .live-sched-when { font-family: var(--lp-font-head, var(--font-head)); }
.lp-skin .live-buy-title { font-weight: 300; color: var(--ink); }
.lp-skin .live-buy .btn-primary { background: var(--lp-accent, var(--ink)); color: #fff; border-radius: var(--lp-radius-btn, var(--radius-pill));
  text-transform: uppercase; letter-spacing: .06em; font-weight: 700; }
@media (hover: hover) { .lp-skin .live-buy .btn-primary:hover { background: var(--lp-accent-hover, var(--lp-accent, var(--ink))); } }

/* ── Выбор преподавателей в карточке (шаг 3, Pet 26.09): выбранные сверху, поиск, «+ Новый» ── */
.tp-chips:not(:has(.chip:not([hidden]))) { display: none; }
.tp-tools { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); }
.tp-search { flex: 1 1 14rem; min-width: 0; }
.tp-new { margin-top: var(--sp-3); padding: var(--sp-3); border: 1px dashed var(--hairline); border-radius: var(--radius); }
.tp-new[hidden] { display: none; }
.tp-new-hint { grid-column: 1 / -1; }
[data-tp-all][aria-pressed="true"] { background: var(--surface-soft); }

/* ── Справочник преподавателей (шаг 3, Pet 26.09): сетка карточек, правка — во всплывающем окне ── */
.tt-head { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; justify-content: space-between; margin-bottom: var(--sp-3); }
.tt-list { display: grid; gap: var(--sp-2); grid-template-columns: minmax(0, 1fr); }
.tt-card { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: var(--sp-3); align-items: start; width: 100%;
  text-align: left; font: inherit; color: inherit; cursor: pointer; scroll-margin-top: 90px; }
.tt-photo { display: grid; place-items: center; color: var(--text-dim); width: 64px; height: 64px; }
.tt-photo img { width: 100%; height: 100%; object-fit: contain; filter: grayscale(1); }
.tt-name { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.tt-name b { font-family: var(--font-head); font-size: var(--fs-lg); line-height: var(--lh-tight); }
.tt-card.is-off .tt-name b { color: var(--text-dim); }
/* «Править» — кнопкой по канону (Pet 26.09: серая подпись читалась «никакой»); нажимается вся карточка. */
.tt-edit { align-self: flex-start; margin-top: var(--sp-2); pointer-events: none; }
/* Наведение — по канону, а не своё (Pet 26.09: «ховера нет, каноны дрейфуют»): карточка как .rec, «Править» как .btn-soft.
   Первая версия ставила кнопке ТЕ ЖЕ цвета, что у неё и так есть, — эффекта было ноль. */
.tt-card { transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
@media (hover: hover) {
  .tt-card:hover { border-color: var(--text-dim); background: var(--surface-raised); box-shadow: var(--shadow-raise); }
  .tt-card:hover .tt-edit { background: var(--accent); color: var(--on-ink); }
}
.tt-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* ПК — сетка в три колонки, карточка пополам: фото слева без плашки, текст справа у верхнего края, имя крупнее. */
@media (min-width: 1000px) {
  .tt-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .tt-card { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-4); }
  .tt-card .tt-photo { width: 100%; height: auto; aspect-ratio: 1 / 1; }
  .tt-card .tt-name b { font-size: var(--fs-xl); }
}
/* Окно правки: поверх затемнённого фона; щелчком мимо и Esc не закрывается — только «Отмена» или «Сохранить». */
dialog.tt-dlg { border: 0; border-radius: var(--radius-lg, 16px); padding: var(--sp-5); width: min(92vw, 560px);
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-raise); }
dialog.tt-dlg::backdrop { background: var(--overlay); }
.tt-dlg h2 { margin: 0 0 var(--sp-3); font-size: var(--fs-xl); }
.tt-dlg-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.tt-dlg-head h2 { margin: 0; }
.tt-dlg-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-4); }

/* ── Выдача доступа (шаг 4, D-0154) ── */
.acc-search { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }
.acc-search input { flex: 1 1 18rem; min-width: 0; }
.acc-table tr.is-dim td { color: var(--text-dim); }
.acc-table td form { margin: 0; }

/* ── Выбор со списком (Pet 26.09): свой вместо браузерного — по ширине поля, в цветах сайта ── */
.combo { position: relative; }
.combo-native { position: absolute; left: 0; bottom: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.combo-btn { width: 100%; min-height: var(--tap); padding: var(--sp-2) calc(var(--sp-3) + 20px) var(--sp-2) var(--sp-3);
  border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface); color: var(--ink);
  font: inherit; font-size: var(--fs-base); text-align: left; cursor: pointer; position: relative;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: border-color var(--dur-2) var(--ease); }
.combo-btn::after { content: "▾"; position: absolute; right: var(--sp-3); top: 50%; transform: translateY(-50%); color: var(--text-dim); }
@media (hover: hover) { .combo-btn:hover { border-color: var(--text-dim); } }
.combo-btn:focus-visible, .combo-btn[aria-expanded="true"] { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.combo-list { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 40; margin: 0; padding: var(--sp-1);
  list-style: none; max-height: min(320px, 50vh); overflow-y: auto; background: var(--surface-raised, var(--surface));
  border: 1px solid var(--hairline); border-radius: var(--radius); box-shadow: var(--shadow-raise); }
.combo-list li { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); cursor: pointer; color: var(--ink); font-size: var(--fs-sm); }
.combo-list li > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-list li > small { flex: none; color: var(--text-dim); font-size: var(--fs-xs); }
@media (hover: hover) { .combo-list li[data-i]:hover { background: var(--surface-soft); } }
.combo-list li.is-on { background: var(--accent-soft); color: var(--accent-ink); }
.combo-list li[aria-disabled="true"] { color: var(--text-dim); cursor: default; }
.combo-list .combo-empty { color: var(--text-dim); cursor: default; }

/* ── оформление покупки и статус после кассы (D-0161) ─────────────────── */
/* Номер заказа — строкой под заголовком. Надзаголовка капсом здесь больше нет (запрет штампов, D-0170). */
.buy-order { margin: calc(var(--sp-2) * -1) 0 0; }
.buy-card { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); }
.buy-price { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-3); font-size: var(--fs-xl); font-weight: 700; }
.buy-price .muted { font-size: var(--fs-sm); font-weight: 400; }
/* Промокод (D-0181): старая цена зачёркнута тем же кеглем, что новая, только тише; поле и «Применить» — одной строкой. */
.buy-price .buy-price-was { font-size: inherit; font-weight: 400; }
.buy-promo { margin-bottom: 0; }
.buy-promo-row { display: flex; gap: var(--sp-2); }
.buy-promo-row input { flex: 1; min-width: 0; text-transform: uppercase; }
.buy-promo-row input::placeholder { text-transform: none; }
/* «Применён» — состояние, а не выключенная кнопка: зелёным и без серости (Pet 27.10). */
.buy-promo-btn:disabled { opacity: 1; cursor: default; color: var(--ok); background: color-mix(in oklch, var(--ok) 12%, var(--surface)); border-color: transparent; }

/* Фокус-вид оформления и «Оплачено» (c18/c19, Pet 24.10: «ничто не отвлекает»): вместо шапки — логотип и путь назад,
   вместо подвала — строка документов, реквизитов и значков оплаты (их требует касса рядом с оплатой). */
.focus-head { background: var(--surface); border-bottom: 1px solid var(--hairline); }
/* Pet 26.10: путь назад — слева, логотип — справа; шапка ниже ростом, контент поднимается. */
.focus-head .wrap { display: flex; align-items: center; gap: var(--sp-4); min-height: 52px; }
.focus-head .brand { margin-left: auto; }
/* Шапка и подвал — по краям контента оформления, а не по ширине сайта: крошка стоит ровно над заголовком. */
.focus-head .wrap, .focus-foot .wrap { max-width: 1040px; }
.focus-back { order: -1; display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm);
              color: var(--text-dim); text-decoration: none; }
.focus-back:hover { color: var(--ink); }
.focus-foot { margin-top: var(--sp-8); padding: var(--sp-5) 0 var(--sp-6); border-top: 1px solid var(--hairline);
              font-size: var(--fs-xs); color: var(--text-dim); }
.focus-foot .wrap { display: grid; gap: var(--sp-3); }
.focus-foot p { margin: 0; }
.focus-docs { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); }
.focus-docs a { color: inherit; }
.focus-pay { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-5); }
.focus-pay img { height: 18px; width: auto; }
/* Оформление на широком — две колонки: слева что покупаешь, справа оплата; на телефоне — столбиком в том же порядке. */
/* Pet 26.10: левая и правая карточки одной высоты, обложка квадратная, как в каталоге; цена — главное число страницы. */
.buy-wrap { max-width: 1040px; padding-top: var(--sp-4); }
.buy-wrap h1 { margin: 0 0 var(--sp-4); }
.buy-grid { display: grid; gap: var(--sp-5); align-items: stretch; }
@media (min-width: 860px) { .buy-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--sp-6); } }
.buy-what, .buy-pay { display: grid; gap: var(--sp-3); margin: 0; align-content: start; }
.buy-pay .buy-price { font-size: var(--fs-display); line-height: 1.05; }
.buy-pay .buy-price .muted { flex-basis: 100%; }
.buy-what h2 { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-tight); text-wrap: balance; }
.buy-cover { border-radius: var(--radius); overflow: hidden; aspect-ratio: 1; background: var(--surface-soft); }
.buy-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.buy-meta { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: 0; font-size: var(--fs-sm); color: var(--text-dim); }
.buy-meta span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.buy-pay form { display: grid; gap: var(--sp-3); }
.buy-pay .field { margin-bottom: 0; }
.buy-legal { margin: 0; font-size: var(--fs-xs); color: var(--text-dim); }
/* Две кассы (c12, c63): переключатель «Россия / Другие страны», одна кнопка, под ней способы выбранной стороны. */
.pay-side { display: grid; gap: var(--sp-3); }
@media (max-width: 767px) { .pay-side { margin-top: var(--sp-4); } }   /* на телефоне переключатель липнул к промокоду (Pet 26.10) */
.pay-seg { display: grid; grid-template-columns: 1fr 1fr; padding: 4px; border-radius: var(--radius-pill); background: var(--surface-sunk); }
.pay-seg label { position: relative; cursor: pointer; }
.pay-seg input { position: absolute; opacity: 0; top: 0; right: 0; bottom: 0; left: 0; margin: 0; cursor: pointer; }
.pay-seg span { display: block; text-align: center; padding: 8px 10px; border-radius: var(--radius-pill); font-weight: 600; color: var(--text-dim);
  transition: background .15s, color .15s; }
.pay-seg input:checked + span { background: var(--surface); color: var(--text); box-shadow: var(--shadow-raise); }
.pay-seg input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.pay-marks { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.pay-marks img, .pay-otp { box-sizing: content-box; height: 16px; width: auto; padding: 6px 9px; border-radius: 6px; background: #1d1d1f; }
.pay-otp { display: inline-flex; align-items: center; gap: 6px; color: #fff; font-size: 12px; font-weight: 600; line-height: 1; }
.pay-otp img { height: 16px; padding: 0; background: none; }
.pay-side:has(input[value="stripe"]:checked) .pay-marks[data-side="robokassa"],
.pay-side:not(:has(input[value="stripe"]:checked)) .pay-marks[data-side="stripe"] { display: none; }
/* «Оплачено» (c19): одна большая кнопка к занятию и строка про письмо и срок — тот же фокус-вид. */
/* «Оплачено» (c19) — та же сетка, что у оформления: слева что куплено, справа срок крупно и кнопка к занятию. */
.buy-wrap .buy-order { margin: calc(var(--sp-3) * -1) 0 var(--sp-4); }
.paid-until { margin: 0; font-size: var(--fs-2xl); line-height: var(--lh-tight); text-wrap: balance; }
.paid-go { margin-top: var(--sp-3); }
/* Справа текста мало, а высота — по обложке слева: на широком срок и кнопка стоят посередине карточки, не прилипают к верху. */
@media (min-width: 860px) { .paid-box { align-content: center; } }

/* Записи акции в карточке промокода: инструменты одной лентой, список — своей прокруткой, чтобы карточка не уезжала. */
.cp-pick { margin-top: var(--sp-3); }
.cp-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2); }
.cp-tools input[type="search"] { flex: 1 1 14rem; min-width: 0; }
.cp-tools select { flex: 0 1 auto; max-width: 100%; }
.cp-list { list-style: none; margin: 0; padding: var(--sp-1) var(--sp-3); max-height: 28rem; overflow-y: auto;
           border: 1px solid var(--hairline); border-radius: var(--radius); }
.cp-list .check-line { align-items: flex-start; padding: var(--sp-1) 0; }
.cp-list .check-line input { margin-top: 2px; }

/* 404 (c62): знак крупно, под ним заголовок, поиск по медиатеке и одна кнопка. */
.nf { max-width: 520px; margin: 0 auto var(--sp-8); text-align: center; }
.nf-mark { display: flex; justify-content: center; margin-bottom: var(--sp-6); }
.nf-mark svg { width: min(240px, 56vw); height: auto; overflow: visible; }
.crane .fig path { fill: currentColor; }
/* Журавль из эскиза «Журнал» (Pet 26.10): контур рисуется, заливается, потом один взмах — на 404 и в заставке ролика «Что нового». */
@media (prefers-reduced-motion: no-preference) {
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane .fig path { stroke: currentColor; stroke-width: .45; stroke-linejoin: round; stroke-dasharray: 1 1; stroke-dashoffset: 1;
    fill-opacity: 0; animation: c-draw 1.6s cubic-bezier(.65, 0, .35, 1) forwards, c-fill .8s ease-out 1.55s forwards; }
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane .f2 path { animation-delay: .16s, 1.7s; }
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane .f3 path { animation-delay: .32s, 1.85s; }
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane .f4 path { animation-delay: .48s, 2s; }
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane .fig { animation: c-flap 1.25s cubic-bezier(.33, 0, .2, 1) 2.75s both; }
  :is(.nf-mark, .reel .sc.on, .doc-motto, .hm-hero-mark) .crane { animation: c-rise 1.25s cubic-bezier(.33, 0, .2, 1) 2.75s both; }
  @keyframes c-draw { to { stroke-dashoffset: 0; } }
  @keyframes c-fill { to { fill-opacity: 1; stroke-opacity: 0; } }
  @keyframes c-flap { 0% { transform: translate(0, 0); } 38% { transform: translate(var(--dx), var(--dy)); } 100% { transform: translate(0, 0); } }
  @keyframes c-rise { 0% { transform: none; } 38% { transform: translateY(-3%) rotate(-3deg); } 100% { transform: none; } }
}
.nf h1 { margin: 0 0 var(--sp-2); text-wrap: balance; }
.nf .muted { margin: 0 0 var(--sp-5); text-wrap: pretty; }
.nf-find { margin-bottom: var(--sp-4); text-align: left; }
.nf-go { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--sp-2) var(--sp-4); margin: 0; }
@media (max-width: 767px) { .nf { margin-bottom: var(--sp-6); } .nf-mark { margin-bottom: var(--sp-5); } }
/* На широком (Pet 26.10): пополам — знак слева, текст, поиск и кнопка справа по левому краю. */
@media (min-width: 860px) {
  .nf { max-width: 960px; display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: var(--sp-7); text-align: left;
        margin-top: var(--sp-6); }
  .nf-mark { margin: 0; }
  .nf-mark svg { width: min(320px, 100%); }
  .nf-go { justify-content: flex-start; }
}

/* ── «Что нового» после переезда (c56) ──────────────────────────────────────────
   Кругляшок внизу слева → окно с роликом; карточка в кабинете. «Понятно» ставит html.news-seen — прячет всё сразу. */
.news-seen .news-bubble, .news-seen .news-card { display: none !important; }

.news-bubble { position: fixed; left: max(16px, env(safe-area-inset-left, 0px)); bottom: max(16px, env(safe-area-inset-bottom, 0px)); z-index: 40;
  display: inline-flex; align-items: center; gap: var(--sp-2); padding: 6px; border: 0; border-radius: var(--radius-pill);
  background: var(--ink); color: var(--on-ink); font: inherit; font-weight: 600; cursor: pointer; box-shadow: var(--shadow-raise); }
.news-bubble-mark { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; }
.news-bubble-txt { padding-right: var(--sp-3); }
/* Знак по умолчанию цвета чернил (.logo-mark) — на тёмном круге его не видно. */
.news-bubble .logo-mark, .reel .note .av .logo-mark { color: var(--on-ink); }
@media (max-width: 767px) { .news-bubble-txt { display: none; } }
@media (hover: hover) { .news-bubble:hover { background: var(--accent-ink); } }
@media (prefers-reduced-motion: no-preference) {
  .news-bubble-mark svg { animation: news-turn 1.4s cubic-bezier(.33, 0, .2, 1) 1.2s both; }
  @keyframes news-turn { from { transform: rotate(-90deg); opacity: 0; } to { transform: none; opacity: 1; } }
}

/* Ролик — вплотную к краям окна (Pet 27.10: белые поля по бокам смотрелись рамкой). Ширина окна — от высоты экрана,
   чтобы ролик 9:16 и строка кнопок под ним влезли без прокрутки. */
.news-dlg { border: 0; padding: 0 0 var(--sp-3); border-radius: 22px; background: var(--surface); color: var(--text); overflow: hidden;
  width: min(400px, calc(100vw - 24px), calc((100dvh - 110px) * 9 / 16)); max-height: calc(100dvh - 24px); box-shadow: var(--shadow-sheet); }
.news-dlg .reel { width: 100%; border-radius: 0; }
.news-dlg .news-ctl { padding-inline: var(--sp-3); }
.news-dlg::backdrop { background: var(--overlay); }
.news-x { position: absolute; top: 8px; right: 8px; z-index: 2; }
.news-ctl { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); }
.news-ctl .btn-primary { margin-left: auto; }
.news-dots { display: flex; gap: 5px; flex: none; }
.news-ctl .btn-quiet { padding-inline: var(--sp-2); }
.news-dots button { width: 8px; height: 8px; border: 0; padding: 0; border-radius: 50%; background: var(--hairline); cursor: pointer; }
.news-dots button.on { background: var(--ink); }

/* Ролик: всё внутри меряется в --u = 1/360 ширины сцены — ставит reel.js. */
/* Фон — две размытые капли, голубая и тёплая, из иллюстрации 2020 года (Pet 27.10: «облагородить фон»). Плывут сдвигом
   background-position, а не transform: фон тогда идёт по часам страницы и в записи видео не убегает вперёд. */
.reel { --u: 1px; position: relative; width: min(100%, calc((100dvh - 150px) * 9 / 16)); aspect-ratio: 9 / 16; overflow: hidden;
  border-radius: 16px; margin-inline: auto;
  --reel-b: oklch(0.86 0.07 235 / .55); --reel-c: oklch(0.90 0.08 70 / .60);
  background:
    radial-gradient(closest-side, var(--reel-b), transparent) 0 0 / 130% 75% no-repeat,
    radial-gradient(closest-side, var(--reel-c), transparent) 100% 100% / 120% 70% no-repeat,
    var(--bg);
  animation: reel-drift 18s ease-in-out infinite alternate; }
@keyframes reel-drift {
  from { background-position: -30% -15%, 130% 115%, 0 0; }
  to   { background-position: 40% 20%, 60% 75%, 0 0; }
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .reel { --reel-b: oklch(0.42 0.08 240 / .55); --reel-c: oklch(0.50 0.10 60 / .35); }
}
:root[data-theme="dark"] .reel { --reel-b: oklch(0.42 0.08 240 / .55); --reel-c: oklch(0.50 0.10 60 / .35); }
.reel .sc { position: absolute; top: 0; right: 0; bottom: 0; left: 0; padding: calc(40 * var(--u)) calc(28 * var(--u)); display: flex; flex-direction: column;
  justify-content: center; gap: calc(18 * var(--u)); opacity: 0; pointer-events: none;
  transform: translateX(calc(28 * var(--u))) scale(.98); transition: opacity .5s, transform .6s cubic-bezier(.2, .7, .2, 1); }
.reel .sc.on { opacity: 1; transform: none; }
.reel .sc.off { transform: translateX(calc(-28 * var(--u))) scale(.98); }
.reel .cap { font-family: var(--font-head); font-size: calc(30 * var(--u)); line-height: 1.12; font-weight: 700; margin: 0; text-wrap: balance; }
.reel .sub { margin: 0; color: var(--text-dim); font-size: calc(17 * var(--u)); line-height: 1.35; }
.reel .ui { background: var(--surface); border: 1px solid var(--hairline); border-radius: calc(16 * var(--u)); padding: calc(16 * var(--u));
  box-shadow: var(--shadow-raise); }
.reel .rise { transform: translateY(calc(24 * var(--u))); opacity: 0; transition: transform .7s cubic-bezier(.2, .7, .2, 1), opacity .7s; }
.reel .sc.on .rise { transform: none; opacity: 1; }
.reel .sc.on .d2 { transition-delay: .35s; } .reel .sc.on .d3 { transition-delay: .7s; } .reel .sc.on .d4 { transition-delay: 1.05s; }
.reel .sc.on .d5 { transition-delay: 2.3s; }
.reel .sc-mark { align-items: center; text-align: center; }
.reel .sc-mark .crane { width: calc(170 * var(--u)); height: auto; overflow: visible; color: var(--ink); }
.reel .url { font-weight: 600; letter-spacing: .02em; }
.reel .pill { display: inline-flex; align-items: center; border-radius: var(--radius-pill); padding: calc(6 * var(--u)) calc(12 * var(--u));
  background: var(--ink); color: var(--on-ink); font-weight: 600; font-size: calc(13 * var(--u)); white-space: nowrap; }
.reel .pill.soft { background: var(--surface-soft); color: var(--text); border: 1px solid var(--hairline); }
.reel .cont { display: grid; grid-template-columns: calc(84 * var(--u)) 1fr; gap: calc(12 * var(--u)); align-items: center; }
.reel .cov { aspect-ratio: 1; border-radius: calc(10 * var(--u)); overflow: hidden; background: linear-gradient(135deg, var(--accent-soft), var(--surface-sunk)); }
.reel .cont div > b { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.reel :is(.cov, .pk i) img { width: 100%; height: 100%; object-fit: cover; display: block; }
.reel .cont b, .reel .note b { display: block; font-size: calc(15 * var(--u)); line-height: 1.25; }
.reel .cont small, .reel .note small { color: var(--text-dim); font-size: calc(13 * var(--u)); }
.reel .bar { height: calc(6 * var(--u)); border-radius: 3px; background: var(--hairline); margin-top: calc(8 * var(--u)); overflow: hidden; }
.reel .bar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width 2.2s ease-out .9s; }
.reel .sc.on .bar i { width: 62%; }
.reel .cal-cap { display: flex; justify-content: space-between; font-size: calc(13 * var(--u)); color: var(--text-dim); margin-bottom: calc(8 * var(--u)); }
.reel .cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: calc(6 * var(--u)); }
.reel .cal i { aspect-ratio: 1; border-radius: calc(6 * var(--u)); background: var(--surface-sunk); transition: background .3s; }
.reel .sc.on .cal i.x { background: var(--accent); }
.reel .sc.on .cal i { transition-delay: calc(.9s + var(--k, 0) * .06s); }
.reel .axis { display: grid; grid-template-columns: 1fr 1.1fr; gap: calc(10 * var(--u)); align-items: center; font-size: calc(14 * var(--u));
  padding: calc(5 * var(--u)) 0; }
.reel .axis i { height: calc(8 * var(--u)); border-radius: 4px; background: var(--accent); width: 0; transition: width 1.4s ease-out 1s; }
.reel .sc.on .axis i { width: var(--w); }
.reel .teach { display: flex; align-items: center; gap: calc(8 * var(--u)); padding: calc(12 * var(--u)) calc(16 * var(--u)); }
.reel .av-i { width: calc(36 * var(--u)); height: calc(36 * var(--u)); border-radius: 50%; background: var(--accent-soft); color: var(--accent-ink);
  display: grid; place-items: center; font-size: calc(12 * var(--u)); font-weight: 600; flex: none; }
.reel .teach-cap { margin-left: calc(4 * var(--u)); font-size: calc(14 * var(--u)); color: var(--text-dim); }
.reel .live-row { display: flex; justify-content: space-between; align-items: center; gap: calc(8 * var(--u)); padding: calc(10 * var(--u)) 0;
  border-bottom: 1px solid var(--hairline); font-size: calc(14 * var(--u)); }
.reel .live-row:last-child { border-bottom: 0; }
.reel .note { display: grid; grid-template-columns: calc(36 * var(--u)) 1fr; gap: calc(10 * var(--u)); align-items: start; }
.reel .note .av { width: calc(36 * var(--u)); height: calc(36 * var(--u)); border-radius: 50%; background: var(--ink); color: var(--on-ink);
  display: grid; place-items: center; }
.reel .note .av svg { width: 62%; height: auto; }
.reel .q { display: flex; align-items: center; gap: calc(8 * var(--u)); border: 1px solid var(--hairline); border-radius: var(--radius-pill);
  padding: calc(10 * var(--u)) calc(14 * var(--u)); font-size: calc(15 * var(--u)); }
.reel .q svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); color: var(--text-dim); }
.reel .caret { display: inline-block; width: 1px; height: 1.1em; background: var(--text); animation: news-blink 1s steps(1) infinite; }
@keyframes news-blink { 50% { opacity: 0; } }
.reel .hits { display: grid; gap: calc(8 * var(--u)); margin-top: calc(12 * var(--u)); }
.reel .hit { display: flex; align-items: center; gap: calc(10 * var(--u)); font-size: calc(14 * var(--u)); opacity: 0;
  transform: translateY(calc(8 * var(--u))); transition: opacity .4s, transform .4s; }
.reel .hit.in { opacity: 1; transform: none; }
.reel .hit i { width: calc(44 * var(--u)); height: calc(44 * var(--u)); border-radius: calc(8 * var(--u)); background: var(--surface-sunk); flex: none;
  overflow: hidden; }
.reel .hit img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Палец: точка с кругом там, где «нажимают» (Zoom, переключатель темы). Момент — --at от начала сцены.
   Видимость — цветом и тенью, а не opacity/transform: так нажатие и в записи видео приходится ровно на свой кадр. */
.reel .pill, .reel .th-tg { position: relative; }
.reel .tap { position: absolute; left: 62%; top: 58%; width: calc(26 * var(--u)); height: calc(26 * var(--u)); margin: calc(-13 * var(--u)) 0 0 calc(-13 * var(--u));
  border-radius: 50%; background: rgba(34, 34, 34, 0); box-shadow: 0 0 0 0 rgba(34, 34, 34, 0); pointer-events: none; }
.reel .sc.on .tap { animation: reel-tap 1.1s ease-out var(--at, 1s) both; }
@keyframes reel-tap {
  0%   { background: rgba(34, 34, 34, 0);   box-shadow: 0 0 0 0 rgba(34, 34, 34, 0); }
  25%  { background: rgba(34, 34, 34, .32); box-shadow: 0 0 0 0 rgba(34, 34, 34, .28); }
  40%  { background: rgba(34, 34, 34, .45); box-shadow: 0 0 0 calc(4 * var(--u)) rgba(34, 34, 34, .22); }
  100% { background: rgba(34, 34, 34, 0);   box-shadow: 0 0 0 calc(22 * var(--u)) rgba(34, 34, 34, 0); }
}

/* Вход по коду: цифры встают по одной, потом «Вы в кабинете». */
.reel .login { display: grid; gap: calc(12 * var(--u)); }
.reel .fld small { display: block; font-size: calc(12 * var(--u)); color: var(--text-dim); margin-bottom: calc(4 * var(--u)); }
/* Сцена крупнее остальных по элементам (Pet 27.10: сверху и снизу пусто) — поля и клетки кода в полтора раза. */
.reel .login { gap: calc(18 * var(--u)); padding: calc(20 * var(--u)); }
.reel .fld small { font-size: calc(14 * var(--u)); margin-bottom: calc(6 * var(--u)); }
.reel .fld > span { display: block; border: 1px solid var(--hairline); border-radius: calc(12 * var(--u)); padding: calc(14 * var(--u)) calc(16 * var(--u));
  font-size: calc(18 * var(--u)); }
.reel .code { display: grid; grid-template-columns: repeat(6, 1fr); gap: calc(7 * var(--u)); }
.reel .code i { display: grid; place-items: center; aspect-ratio: 1 / 1.3; border: 1.5px solid var(--hairline); border-radius: calc(12 * var(--u));
  font-style: normal; font-size: calc(26 * var(--u)); font-weight: 600; transition: border-color .2s; }
.reel .code b { color: transparent; transition: color .15s; }
.reel .sc.on .code i { border-color: var(--accent); transition-delay: calc(1.3s + var(--k) * .22s); }
.reel .sc.on .code b { color: var(--ink); transition-delay: calc(1.3s + var(--k) * .22s); }
.reel .login-ok { display: flex; align-items: center; gap: calc(8 * var(--u)); font-size: calc(15 * var(--u)); font-weight: 600; color: transparent;
  transition: color .3s; }
.reel .login-ok svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); }
.reel .sc.on .login-ok { color: var(--accent-ink); transition-delay: 2.9s; }

/* Скорость: новая полоска полная почти сразу, старая ползёт в 9,5 раза медленнее (2,8 с против 26,7 с, замер 26.10). */
.reel .speed { display: grid; gap: calc(14 * var(--u)); }
.reel .sp-row { display: grid; grid-template-columns: 1fr auto; gap: calc(6 * var(--u)) calc(10 * var(--u)); font-size: calc(14 * var(--u)); }
.reel .sp-row b { font-variant-numeric: tabular-nums; }
.reel .sp-bar { grid-column: 1 / -1; height: calc(10 * var(--u)); border-radius: 5px; background: var(--surface-sunk); overflow: hidden; }
.reel .sp-bar i { display: block; height: 100%; width: 0; border-radius: inherit; }
/* Анимацией, а не переходом: в записи видео (виртуальное время) переход ширины срабатывал сразу целиком (27.10). */
.reel .is-new .sp-bar i { background: var(--accent); }
.reel .is-old .sp-bar i { background: var(--text-dim); }
.reel .is-old { color: var(--text-dim); }
@keyframes reel-fill { from { width: 0; } to { width: 100%; } }
.reel .sc.on .is-new .sp-bar i { animation: reel-fill .5s ease-out 1.2s both; }
.reel .sc.on .is-old .sp-bar i { animation: reel-fill 4.8s linear 1.2s both; }

/* Личная подборка под «Продолжить». */
.reel .picks-cap { margin: 0 0 calc(10 * var(--u)); font-size: calc(14 * var(--u)); font-weight: 600; }
.reel .picks-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: calc(8 * var(--u)); }
/* Обложки квадратные, подпись — ровно две строки у всех трёх: карточки стоят в линию (Pet 27.10: «разъехались»). */
.reel .pk { display: grid; grid-template-rows: auto calc(2 * 1.25em); gap: calc(6 * var(--u)); font-size: calc(12 * var(--u)); line-height: 1.25; }
.reel .pk i { aspect-ratio: 1; border-radius: calc(8 * var(--u)); overflow: hidden; background: var(--surface-sunk); }
/* Избранное (c70): две карточки, у первой нажимают сердечко — заливается; счётчик вкладки 2 → 3. Только цветом — ровно
   ложится в запись видео. */
.reel .favs { display: grid; gap: calc(14 * var(--u)); }
.reel .fv-row { display: grid; grid-template-columns: 1fr 1fr; gap: calc(10 * var(--u)); }
.reel .fv { position: relative; display: grid; gap: calc(6 * var(--u)); }
.reel .fv > i { aspect-ratio: 1; border-radius: calc(10 * var(--u)); overflow: hidden; background: var(--surface-sunk); }
.reel .fv > i img { width: 100%; height: 100%; object-fit: cover; display: block; }
.reel .fv s { display: block; height: calc(7 * var(--u)); border-radius: 4px; background: var(--hairline); text-decoration: none; }
.reel .fv s + s { width: 60%; }
.reel .fv-h { position: absolute; left: calc(8 * var(--u)); top: calc(8 * var(--u)); display: grid; place-items: center;
  width: calc(30 * var(--u)); height: calc(30 * var(--u)); border-radius: calc(8 * var(--u)); background: rgba(255, 255, 255, .85); color: #222; }
.reel .fv-h svg { width: calc(18 * var(--u)); height: calc(18 * var(--u)); fill: transparent; transition: fill .25s, color .25s; }
.reel .fv.is-on .fv-h svg { fill: currentColor; color: var(--accent-ink); }
.reel .sc.on .fv.is-new .fv-h svg { fill: var(--accent-ink); color: var(--accent-ink); transition-delay: 1.45s; }
.reel .fv-tab { display: inline-flex; align-items: center; gap: calc(8 * var(--u)); justify-self: start; padding: calc(8 * var(--u)) calc(14 * var(--u));
  border-radius: var(--radius-pill); background: var(--ink); color: var(--on-ink); font-size: calc(15 * var(--u)); font-weight: 600; }
.reel .fv-tab svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); fill: currentColor; }
.reel .fv-tab b { display: grid; font-variant-numeric: tabular-nums; }
.reel .fv-tab em { grid-area: 1 / 1; font-style: normal; transition: color .2s; }
.reel .fv-tab em + em { color: transparent; }
.reel .sc.on .fv-tab em:first-child { color: transparent; transition-delay: 1.6s; }
.reel .sc.on .fv-tab em + em { color: var(--on-ink); transition-delay: 1.6s; }
.reel .pk span { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* Тёмная тема: два одинаковых мини-экрана, тёмный раскрывается кругом от переключателя. Цвета свои — сцена одинакова
   при любой теме сайта. clip-path рисуется по часам страницы — в видео раскрытие тоже на своём месте. */
/* Мини-экран темы — шире полей сцены и выше (Pet 27.10: «растянуть плашку»). */
.reel .theme-demo { position: relative; height: calc(440 * var(--u)); margin-inline: calc(-14 * var(--u)); }
.reel .th { position: absolute; inset: 0; border-radius: calc(16 * var(--u)); padding: calc(14 * var(--u)); display: grid; grid-template-rows: auto 1fr;
  gap: calc(12 * var(--u)); box-shadow: var(--shadow-raise); }
.reel .th-light { background: #ffffff; color: #222222; border: 1px solid #e6e3dd; --th-card: #f5f4f1; }
.reel .th-dark { background: #1a1a19; color: #f7f5f1; border: 1px solid #333330; --th-card: #2b2b29;
  clip-path: circle(0 at calc(100% - 26 * var(--u)) calc(28 * var(--u))); transition: clip-path 1s cubic-bezier(.6, 0, .3, 1); }
.reel .sc.on .th-dark { clip-path: circle(150% at calc(100% - 26 * var(--u)) calc(28 * var(--u))); transition-delay: 1.5s; }
.reel .th-head { display: flex; justify-content: space-between; align-items: center; }
.reel .th-logo svg { width: calc(22 * var(--u)); height: auto; }
.reel .th .logo-mark { color: inherit; }   /* знак по умолчанию цвета чернил сайта — в мини-экране берёт цвет своей темы */
.reel .th-tg { display: grid; place-items: center; width: calc(30 * var(--u)); height: calc(30 * var(--u)); border-radius: 50%; border: 1px solid currentColor; }
.reel .th-tg svg { width: calc(16 * var(--u)); height: calc(16 * var(--u)); }
.reel .th-cards { display: grid; grid-template-columns: 1fr 1fr; align-content: start; gap: calc(8 * var(--u)); min-height: 0; }
/* Мини-карточки (Pet 27.10: «квадратики обыграть», потом «обложки один к одному»): квадратная обложка и две строки-штриха
   названия, в цветах своей темы. */
.reel .th-cards i { display: grid; gap: calc(6 * var(--u)); padding: calc(6 * var(--u)) calc(6 * var(--u)) calc(10 * var(--u));
  border-radius: calc(10 * var(--u)); background: var(--th-card); }
.reel .th-cards b { aspect-ratio: 1; border-radius: calc(6 * var(--u)); overflow: hidden; }
.reel .th-cards img { width: 100%; height: 100%; object-fit: cover; display: block; }
.reel .th-cards s { display: block; height: calc(6 * var(--u)); border-radius: 3px; background: currentColor; opacity: .55; text-decoration: none; }
.reel .th-cards s + s { width: 60%; opacity: .3; }

@media (prefers-reduced-motion: reduce) {
  .reel { animation: none; }
  .reel .sc, .reel .rise, .reel .bar i, .reel .cal i, .reel .axis i, .reel .hit, .reel .code i, .reel .code b, .reel .login-ok,
  .reel .sp-bar i, .reel .th-dark { transition: none; }
  .reel .sc.on .sp-bar i { animation: none; width: 100%; }
  .reel .sc.on .tap { animation: none; }
}

/* Карточка в кабинете: над «Продолжить», пункты в две колонки на широком. */
.news-card { border: 1px solid var(--hairline); border-radius: 16px; padding: var(--sp-5); background: var(--surface-soft); margin-bottom: var(--sp-5); }
.news-card h2 { margin: 0 0 var(--sp-1); font-size: var(--fs-xl, 1.3rem); text-wrap: balance; }
.news-card > p { margin: 0 0 var(--sp-4); }
.news-card ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
@media (min-width: 760px) { .news-card ul { grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-6); } }
.news-card li { display: grid; grid-template-columns: 40px 1fr; gap: var(--sp-3); align-items: start; }
.news-card li i { width: 40px; height: 40px; border-radius: 12px; background: var(--accent-soft); color: var(--accent-ink);
  display: grid; place-items: center; font-style: normal; font-weight: 600; }
.news-card li b { display: block; font-weight: 600; }
.news-card li span { color: var(--text-dim); font-size: var(--fs-sm); }
.news-card-go { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-5); }

/* Команда (Pet 26.10): журавль слева, заголовок и вступление справа; люди — карточки в две колонки на широком. */
.team-head { display: grid; gap: var(--sp-5); align-items: center; margin-bottom: var(--sp-6); }
.team-head .doc-title { margin-top: 0; }
.team-mark { margin: 0; }
.team-mark svg { width: min(200px, 48vw); }
@media (min-width: 860px) {
  .team-head { grid-template-columns: 240px minmax(0, 1fr); gap: var(--sp-7); }
  .team-mark svg { width: 220px; }
}
.team { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
@media (min-width: 860px) { .team { grid-template-columns: 1fr 1fr; gap: var(--sp-5); } }
.team-card { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: var(--sp-4); align-items: start;
  padding: var(--sp-5); border: 1px solid var(--hairline); border-radius: 16px; background: var(--surface); }
.team-ava { width: 72px; height: 72px; border-radius: 50%; overflow: hidden; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-ink); font-family: var(--font-head); font-weight: 700; font-size: 1.4rem; }
.team-ava img { width: 100%; height: 100%; object-fit: cover; display: block; }
.team-name { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-tight); }
.team-role { margin: 2px 0 var(--sp-2); color: var(--text-dim); font-size: var(--fs-sm); }
.team-text { margin: 0; }

/* «О проекте» (Pet 26.10): справа от истории — девиз с журавлём, текст обтекает слева и сохраняет свою меру. */
.doc-motto { text-align: center; margin: 0 0 var(--sp-5); }
.doc-motto .crane { width: 150px; height: auto; overflow: visible; color: var(--ink); }
.doc-motto-text { font-family: var(--font-head); font-weight: 700; font-size: var(--fs-2xl); line-height: var(--lh-tight); color: var(--ink);
  margin: var(--sp-4) 0 var(--sp-1) !important; text-wrap: balance; }
.doc-motto-sub { color: var(--text-dim); font-size: var(--fs-sm); margin: 0 !important; }
@media (min-width: 1100px) {
  .doc-motto { float: right; width: 320px; margin: var(--sp-2) 0 var(--sp-5) var(--sp-7); }
  .doc-motto .crane { width: 200px; }
}
.doc-motto ~ h2, .doc-motto ~ .doc-figure { clear: both; }
/* На телефоне девиз и журавль команды — по левому краю, как текст, и с воздухом после заголовка (Pet 26.10). */
@media (max-width: 1099px) { .doc-motto { text-align: left; margin-top: var(--sp-5); } }
@media (max-width: 859px) { .team-mark { justify-content: flex-start; } .team-head { margin-top: var(--sp-2); } }
/* Шапка «Команды» на телефоне (Pet 28.10): журавль — около 40 % слева, заголовок и вступление справа, а не друг под другом. */
@media (max-width: 859px) {
  .team-head { grid-template-columns: 40% minmax(0, 1fr); gap: var(--sp-4); }
  .team-mark svg { width: 100%; height: auto; }
  .team-head .doc-lead { font-size: var(--fs-sm); }
}

/* Уведомление о cookie (Pet 26.10): карточка в правом нижнем углу на широком, во всю ширину снизу на телефоне. */
.cookie-note { position: fixed; z-index: calc(var(--z-header) + 2); right: max(16px, env(safe-area-inset-right, 0px));
  bottom: max(16px, env(safe-area-inset-bottom, 0px)); width: min(420px, calc(100% - 32px));
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  border-radius: 16px; border: 1px solid var(--hairline); background: var(--surface-raised); box-shadow: var(--shadow-sheet); }
.cookie-note[hidden] { display: none; }
.cookie-note p { margin: 0; font-size: var(--fs-sm); line-height: 1.4; }
.cookie-note a { color: var(--accent-ink); }
.cookie-note .btn { flex: none; }
.cookie-ask .news-bubble { display: none !important; }
@media (max-width: 767px) {
  .cookie-note { left: 12px; right: 12px; width: auto; bottom: max(12px, env(safe-area-inset-bottom, 0px)); }
}

/* «Оплачено» (Pet 26.10): срок и кнопка — наверху, под ними три похожих занятия плитками. */
.paid-box:has(.paid-more) { align-content: start; }
.paid-more { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--hairline); }
.paid-more h2 { margin: 0 0 var(--sp-3); font-size: var(--fs-md); }
.paid-more ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.paid-more a { display: grid; gap: var(--sp-2); text-decoration: none; color: var(--text); }
.paid-more-cover { aspect-ratio: 1; border-radius: var(--radius); overflow: hidden; background: var(--surface-soft); }
.paid-more-cover img, .paid-more-cover picture { width: 100%; height: 100%; object-fit: cover; display: block; }
.paid-more-title { font-size: var(--fs-sm); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
@media (hover: hover) { .paid-more a:hover .paid-more-title { color: var(--accent-ink); } }
/* Перечёркнутая цена после промокода (Pet 26.10): справа от новой, вдвое мельче и чуть прозрачнее — не спорит с ценой к оплате. */
.buy-pay .buy-price .buy-price-was { order: 1; flex-basis: auto; font-size: .5em; opacity: .8; }
.buy-pay .buy-price > .muted:not(.buy-price-was) { order: 2; }
/* Карточка команды (Pet 26.10): кружок и имя с ролью — строкой по центру по вертикали, текст ниже на всю ширину. */
.team-card { grid-template-areas: "ava who" "text text"; align-items: center; row-gap: var(--sp-3); }
.team-ava { grid-area: ava; }
.team-who { grid-area: who; min-width: 0; }
.team-who .team-role { margin-bottom: 0; }
.team-text { grid-area: text; }
/* Фото команды (Pet 28.10): на телефоне кружок крупнее — 100 вместо 72; на ПК фото — своя колонка слева во всю высоту
   карточки, скруглённый прямоугольник внутри её формы, имя, роль и текст — справа. */
.team-card { grid-template-columns: 100px minmax(0, 1fr); }
.team-ava { width: 100px; height: 100px; font-size: 1.9rem; }
@media (min-width: 860px) {
  .team-card { grid-template-columns: 168px minmax(0, 1fr); grid-template-rows: auto 1fr; grid-template-areas: "ava who" "ava text";
    align-items: start; column-gap: var(--sp-5); row-gap: var(--sp-2); }
  .team-ava { width: 100%; height: 100%; min-height: 168px; align-self: stretch; border-radius: 12px; font-size: 2.4rem; }
  .team-ava img { object-position: 50% 30%; }
}

/* Плавающая «Фильтры» в медиатеке (Pet 26.10): стекло, как у панели покупки; выплывает снизу по центру, когда строка поиска уехала. */
.med-float { position: fixed; z-index: var(--z-header); left: 50%; bottom: max(16px, env(safe-area-inset-bottom, 0px));
  display: inline-flex; align-items: center; gap: var(--sp-2); padding: 12px 20px; border-radius: var(--radius-pill);
  border: 1px solid var(--hairline); font: inherit; font-weight: 600; color: var(--text); cursor: pointer;
  background: color-mix(in srgb, var(--surface-raised) 72%, transparent); box-shadow: var(--shadow-sheet);
  -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
  transform: translate(-50%, calc(100% + 40px)); opacity: 0; visibility: hidden;
  transition: transform 420ms var(--ease), opacity 260ms var(--ease), visibility 0s linear 420ms; }
.med-float.is-up { transform: translate(-50%, 0); opacity: 1; visibility: visible; transition-delay: 0s; }
@media (prefers-reduced-motion: reduce) { .med-float { transition: none; } }
@media (prefers-reduced-transparency: reduce) { .med-float { background: var(--surface-raised); -webkit-backdrop-filter: none; backdrop-filter: none; } }
