/* ============================================================================
   СУПРЕМУМ · practice-paper.css — дельта слоя «Тушь и бумага» для практики
   ============================================================================
   ЗАЧЕМ. Движок практики (practice.js, practice-ui.js) и его оформление
   practice.css остаются прежними: раздел переезжает последним, чтобы правка
   палитры не задела тренажёр посреди генерации тем. Этот файл — тонкая
   накладка сверху, показывающая, как тема практики выглядит в новом облике.

   ПОРЯДОК ПОДКЛЮЧЕНИЯ на странице темы (его ставит {{SKIN}} в шаблоне):
       supremum.css · app-shell.css · practice.css   (прежний слой)
       sup-fonts.css · sup-tokens-paper.css · sup-compat.css · этот файл

   Токены идут ПОСЛЕ supremum.css намеренно: у обоих объявления в :root,
   и побеждает последний. Правила же прежнего слоя остаются, поэтому здесь
   гасится ровно то, что противоречит новому облику, и ничего больше.

   ИМЕНА КЛАССОВ ЗДЕСЬ — ТОЛЬКО ТЕ, ЧТО ДВИЖОК ДЕЙСТВИТЕЛЬНО СОЗДАЁТ.
   Ревизия 07.09.2026 нашла в этом файле 14 селекторов, которых нет ни
   в practice.js, ни в practice-ui.js, ни в шаблоне страницы (.task-card,
   .level-card, .topic-card, .pr-panel, .task-question, .task-explain,
   .verdict-ok, .verdict-err, .is-correct, .is-wrong, .pr-stat-value,
   .lvl-badge, .task-counter, .pr-streak, .pr-timer, .viz-block) — правила
   выглядели работающими и не делали ничего. Мёртвый селектор неотличим
   от опечатки в живом, поэтому «на всякий случай» здесь не держат:
   перед добавлением имени — грепнуть его по assets\practice*.js.

   Включается на теме списком PAPER_SKIN в tools\gen_practice_pages.py.
   Когда раздел переедет целиком, файл вливается в practice.css и исчезает.

   Проверки:
       python tools\build_checks\check_css.py
       python tools\redesign\check_paper_vars.py
   ============================================================================ */


/* ── 0. ПОЧЕМУ ЗДЕСЬ БОЛЬШЕ НЕТ ВОЗВРАТА ТОКЕНОВ ────────────────────────────
   До 07.09.2026 здесь стоял блок html[data-theme="dark"], переводивший 12
   имён (--accent, --text, --bg, --muted, --green/--red/--amber/--blue,
   --glass*, --shadow) на токены слоя. Он лечил симптом: слой токенов для
   базовой тональности объявлялся селектором [data-theme="dark"] (0,1,0)
   и проигрывал палитре v1 из supremum.css (html[data-theme="dark"], 0,1,1),
   поэтому 5–6 класс, витрина и кабинет в тёмной теме молча откатывались
   на индиго (замер: --accent = rgb(129,140,248)).

   Починено в генераторе (tools\design_system\palette.py): все шесть блоков
   тональность × тема выровнены на html:root:where(…) — ровно (0,1,1) у всех,
   различающее убрано в :where(). Заодно поднят мост sup-compat.css (:root →
   html:root): он тоже проигрывал v1 в тёмной теме, из-за чего --muted,
   --green, --red, --amber, --blue откатывались на v1 во ВСЕХ трёх
   тональностях, а не только в бумажной (замер 07.09.2026: 12 откатов).

   Замер после починки: 0 откатов в шести сочетаниях. Возврат снят.
   Если он когда-нибудь понадобится снова — это признак, что специфичность
   слоя опять разъехалась, и чинить надо генератор, а не этот файл. */


/* ── 1. ЛИСТ ───────────────────────────────────────────────────────────────
   Три радиальных пятна из глассморфизма убираются: в бумажной системе фон —
   ровный лист, а глубину задают фактура и границы, а не подсветка. */

/* БАЗОВЫЙ КЕГЛЬ. Стандарт проекта — 20px (--fs-root). В каноне его ставит
   sup-base.css строкой html { font-size: var(--fs-root) }, но на страницу
   практики sup-base НЕ подключается и подключён не будет: он несёт 46 КБ
   компонентов с теми же именами (.card, .btn, .input, .rubric, .tab-btn),
   что уже красит practice.css, и лёг бы поверх движка. Замер 07.09.2026
   показал у такого подключения 8 лишних переопределений сверх нужного
   (.rubric уезжает в моноширинный, .pr-input теряет рамку 2px→1px,
   кнопка «Проверить» растёт 49→57px, у h1 появляется тректинг −0.36px) —
   ни одно из них не заказано и не проверено.

   Поэтому включаем ровно то, ради чего сюда шли, — тем самым способом,
   который описан как штатная точка включения в theory-paper.css §4/4.
   Без этой строки страница остаётся на браузерных 16px, и вместе с ней
   уезжает ВСЁ, что считается от rem: --fs-md (кегль самого body ниже),
   --fs-xs, --measure (мера строки была 558px вместо 698).

   Тренажёр от подъёма не страдает: карточка задачи живёт в .pr-scope
   с абсолютными 20px, дерево тем — в .pr-tree с абсолютными 20px, а
   холсты и viewBox движок задаёт в px (в practice.css, practice-kit.js
   и модулях задач нет ни одной rem-геометрии). Меняются только шапка,
   крошки, подвал и мера строки — замер это подтвердил: 12 элементов,
   все структурные, косметических расхождений ноль.

   Эта строка ДУБЛИРУЕТ правило sup-base.css. Если правило в базе изменится,
   менять надо и здесь; когда раздел переедет целиком и этот файл вольётся
   в practice.css — строка уходит вместе с ним. */
html { font-size: var(--fs-root); }

body {
  font-family: var(--font-body);
  font-size: var(--fs-md);
  line-height: var(--lh-md);
  font-synthesis: none;
  background-image: none;
  background-color: var(--bg);
  color: var(--text);
}

h1, h2, h3, h4, .pr-head h1, .ui-dialog-title, .pr-summary h2 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: var(--fw-display);
  color: var(--text-strong);
}

/* Вся математика идёт через KaTeX, и оба правила §4 дизайн-системы обязаны
   стоять на КАЖДОЙ странице с формулами. Без .cyrillic_fallback кириллица
   в \text{} молча уезжает в Times New Roman: класс KaTeX объявляет, но нигде
   не определяет. На страницах практики он не был определён вовсе — theory.css
   сюда не подключается. */
.katex { font-size: 0.98em; }
.cyrillic_fallback { font-family: var(--font-body); }


/* ── 2. ЦИФРЫ ──────────────────────────────────────────────────────────────
   Показания, счётчики и номера — моношрифт из токенов и табличные цифры:
   иначе строка «Задача 7 из 12» дёргается при смене значения, а колонки
   номеров тем в дереве не выстраиваются. Вес Plex Mono только 500. */
.task-num,
.qs-value,
.tc-num,
.pr-chapter .ch-num,
.pr-gap-step > .n,
.pr-para-list li.pr-topic .n,
.pr-xp-float,
.pr-input,
#pr-step-n,
.ui-tab .tab-count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-mono);
  font-feature-settings: 'zero' 0;
}

/* Смешанные строки (число + слово) моношрифт не получают — только табличные
   цифры, чтобы не прыгала правая колонка. */
.sum-row, .tt-row, .rk-top, .wk-top, .rev-next, .qs-label, .pr-source {
  font-variant-numeric: tabular-nums;
}


/* ── 3. СЛОИ: СТЕКЛО ТОЛЬКО В НАВИГАЦИИ ────────────────────────────────────
   Правило слоя (docs\design-system.md §2): размытие живёт в навигационном
   слое, а под учебным текстом подложка плотная. Причина не вкусовая — на
   полупрозрачном фоне контраст текста зависит от того, что оказалось под ним,
   и замер перестаёт что-либо гарантировать.

   practice.css кладёт .ui-card на стекло с blur(14px) — под ЛЮБОЕ содержимое,
   включая условие задачи и разбор. Здесь стекло с них снимается. */
.pr-main .ui-card,
.pr-topic-card,
.ui-dialog {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-raised);
}

/* Плотное (--solid) — там, где ученик задерживается: карточка задачи,
   шапка темы с описанием, разбор, итоги. Непрозрачность 1.0, то есть
   заведомо выше порога 0.88 для листа. */
.pr-main .ui-card.pr-card,
.pr-main .ui-card.pr-head,
.pr-main .ui-card.pr-summary,
.pr-main .ui-accordion,
.ui-dialog {
  background: var(--solid);
}

/* Дерево тем — навигация: единственное место, где стекло остаётся. */
#pr-tree.ui-card {
  background: var(--glass);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

/* Три обязательных фолбэка стекла (§2). На узком экране backdrop-filter даёт
   подтверждённые рывки прокрутки на бюджетном Android, поэтому там стекла
   не бывает вовсе — независимо от настроек.

   Ручного переключателя «Стекло / Плотно» больше нет нигде на сайте, поэтому
   и правила под класс .no-glass здесь не осталось: класс некому поставить,
   а правило, которое ничто не включает, неотличимо от сломанного.
   Единственное имя в файле, которого не ставит движок, — .cyrillic_fallback:
   его печатает сам KaTeX во время работы. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  #pr-tree.ui-card { background: var(--solid); }
}
@media (prefers-reduced-transparency: reduce) {
  #pr-tree.ui-card {
    -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--solid);
  }
}
@media (max-width: 720px) {
  #pr-tree.ui-card {
    -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--solid);
  }
}

/* Вложенное на плотном даётся заливкой --sunken, а не вторым стеклом:
   стекло на стекле запрещено (§9). Заодно уходит зависимость от --accent-soft,
   который в тёмной теме перебивался индиго v1. */
.pr-text.condition,
.pr-oda,
.pr-hint-panel,
.pr-reflect,
.pr-gap-step,
.sum-stop,
.ui-accordion-head:hover {
  background: var(--sunken);
}


/* ── 4. МЕРА СТРОКИ ────────────────────────────────────────────────────────
   Условие задачи, разбор и подсказка — самый длинный текст на странице.
   Без ограничения на широком экране строка уходит за 90 знаков, и глаз
   теряет начало следующей.

   min(…, 100%) обязателен: 34.9rem при базе 20px — это 698px, и голый
   max-width распирал бы окно 390px (грабля §11.4 дизайн-системы). */
.pr-head .sub,
.pr-text,
.pr-oda-body,
.pr-solution,
.pr-step-text,
.pr-why-body,
.pr-examples,
.pr-hint-panel,
.pr-canvas-hint,
.pr-reflect,
.pr-verdict.soft,
.sum-note,
.sum-advice,
.ui-dialog-sub,
.pr-tree-note {
  max-width: min(var(--measure), 100%);
  line-height: var(--lh-md);
}

/* Чертёж и элементы ответа мерой не ограничиваются — им нужна вся ширина. */
.pr-svg, .pr-answer, .pr-choices, .pr-order, .pr-multi { max-width: 100%; }


/* ── 5. ВЕРДИКТЫ И СОСТОЯНИЯ ОТВЕТА ────────────────────────────────────────
   Все значения — через смысловые роли (--ok/--err/--warn и их -soft/-fg),
   ни одного собственного цвета. В practice.css заливки состояний записаны
   литералами палитры v1 (rgba(5,150,105,.12) и rgba(220,38,38,.10)) —
   изумруд и алый, чужие бумаге; они бы остались на новом слое как есть.

   Цвет нигде не единственный носитель (§3): у «верно» стоит знак ✓ из
   разметки движка, у обоих вердиктов — слово и цветная черта слева,
   у вариантов ответа — граница, а не только заливка. */
.pr-verdict {
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4);
  border-left: 3px solid transparent;
  font-weight: var(--fw-semi);
}
.pr-verdict.ok {
  color: var(--ok-fg);
  background: var(--ok-soft);
  border-left-color: var(--ok);
}
.pr-verdict.soft {
  color: var(--err-fg);
  background: var(--err-soft);
  border-left-color: var(--err);
}
/* Знак «не сошлось». У «верно» движок печатает <span class="tick">✓</span>,
   у «не сошлось» знака нет вовсе — носителями остаются цвет и слово, а цвет
   в одиночку не носитель (§3). Движок общий и не правится, поэтому знак
   ставится здесь. Это ЗНАК, а не эмодзи: как и ✓, он несёт вердикт.
   Формулировка движка про шаг, а не про способности, — не трогается. */
.pr-verdict.soft::before {
  content: "\2717\00a0";
  color: var(--err);
  font-weight: var(--fw-bold);
}

/* НАЙДЕНО ЗАМЕРОМ. Заливки состояний в наборе токенов идут с непрозрачностью
   .10–.13, и на тёмной теме разница между «нейтрально» и «верно» падает ниже
   1.1 по контрасту к подложке — ученик заливку просто не видит. Поэтому
   состояние несут ДВА признака сразу: заливка (слабая) и граница в 2px
   смысловым цветом (сильная). Граница считается по --ok/--err/--warn,
   у которых контраст к подложке проверен генератором палитры. */
.pr-choice.ok, .pr-opt.ok, .pr-cmp.ok, .pr-input.ok {
  background: var(--ok-soft);
  border: 2px solid var(--ok);
  color: var(--ok-fg);
}
.pr-choice.bad, .pr-opt.bad, .pr-cmp.bad, .pr-input.bad {
  background: var(--err-soft);
  border: 2px solid var(--err);
  color: var(--err-fg);
}
.pr-opt.missed {
  background: var(--warn-soft);
  border: 2px dashed var(--warn);
  color: var(--warn-fg);
}
.pr-opt.on {
  background: var(--sunken);
  border-color: var(--accent);
  color: var(--text-strong);
}

/* Полоса уровней. НАЙДЕНО ЗАМЕРОМ: подпись неактивного уровня стояла на
   --muted поверх подложки --accent-soft, и в тёмных графите и газете контраст
   падал до 3.41 и 3.57 — ниже порога 4.5. Подложка переводится на --sunken
   (утопленное, а не тонированное акцентом), подпись — на основной план текста,
   а активный уровень отличается ещё и весом, то есть не одним цветом. */
.pr-levels.ui-tabs { background: var(--sunken); }
.pr-levels .ui-tab { color: var(--text); font-weight: var(--fw-normal); }
.pr-levels .ui-tab.active {
  background: var(--surface);
  color: var(--text-strong);
  font-weight: var(--fw-semi);
  box-shadow: var(--shadow-raised);
}
.pr-levels .ui-tab.locked, .pr-levels .ui-tab:disabled { color: var(--text-soft); }

/* Шапка главы в дереве тем — ВТОРОЕ такое же место, найденное тем же замером:
   --muted поверх подложки --accent-soft. В тёмной теме контраст 4.27 (базовая),
   4.25 (графит) и 4.31 (газета) при пороге 4.5. Лечится так же, как полоса
   уровней: подложка утопленная, а не тонированная акцентом, подпись — на
   основной план текста. Полоска слева остаётся акцентной: она и различает
   главы, и там цвет несёт смысл, а не красит текст. */
.pr-chapter-head {
  background: var(--sunken);
  color: var(--text);
}

/* Бейджи ступени и режима — те же роли; в practice.css у них литералы v1. */
.ui-badge { background: var(--sunken); color: var(--text); border-radius: var(--radius-xs); }
.ui-badge.success { background: var(--ok-soft); color: var(--ok-fg); border: 1px solid var(--ok); }
.ui-badge.warn    { background: var(--warn-soft); color: var(--warn-fg); border: 1px solid var(--warn); }
.ui-badge.danger  { background: var(--err-soft); color: var(--err-fg); border: 1px solid var(--err); }
.ui-badge.outline { background: transparent; color: var(--text-soft); border: 1px solid var(--border-strong); }

/* Полоса подхода: сегменты тонкие (6px), заливка .13 на них не читалась бы
   вовсе — здесь смысловой цвет берётся в полную силу. */
.task-progress .seg      { background: var(--n-3); }
.task-progress .seg.ok   { background: var(--ok); }
.task-progress .seg.fail { background: var(--err); }
.task-progress .seg.now  { background: var(--accent); }
.task-progress .seg.gift { background: var(--warn); }

/* Точки состояния темы в дереве. Форма уже различает «частично» (полукруг)
   от «готово» (заливка) и «слабо» (обводка) — цвет только дублирует. */
.pr-dot        { background: var(--n-3); border: 1px solid var(--border-strong); }
.pr-dot.part   { background: linear-gradient(90deg, var(--warn) 50%, transparent 50%); border-color: var(--warn); }
.pr-dot.done   { background: var(--ok); border-color: var(--ok); }
.pr-dot.weak   { background: var(--err); border-color: var(--err); }
.pr-dot.review { background: var(--warn); border-color: var(--warn); }

/* Вспышка «верно» и пульс «пора повторить» в practice.css записаны литералами
   изумруда и янтаря v1 — переопределяем целиком, keyframes переобъявлением
   заменяются. Вспышка спокойная: успех отмечается, а не празднуется. */
@keyframes prFlash {
  0%   { box-shadow: 0 0 0 0 var(--ok-soft); }
  30%  { box-shadow: 0 0 0 4px var(--ok); }
  100% { box-shadow: var(--shadow-raised); }
}
@keyframes prPulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--warn-soft); }
  70%      { box-shadow: 0 0 0 6px transparent; }
}

.pr-predict-fb.hit { border-left-color: var(--ok); }


/* ── 6. АКЦЕНТ И ПОДПИСЬ НА НЁМ ────────────────────────────────────────────
   НАЙДЕНО ЗАМЕРОМ. supremum.css и practice.css пишут подпись на акценте
   как color:#fff. В светлой бумаге акцент — тёмные чернила, и белое читается;
   в тёмной акцент — светлый мел (#e8e5de), и белым по белому не видно ничего:
   кнопка «Проверить» и активная тема в дереве пропадали. Подпись обязана
   инвертироваться вместе с акцентом — для этого в наборе есть --accent-fg. */
.btn-primary, .btn-login,
.ui-chip.active,
.pr-para-list li.active,
.pr-para-list li.pr-topic.active,
.pr-para-list li.pr-topic.active .n {
  color: var(--accent-fg);
}
.pr-para-list li.active .pr-dot {
  background: var(--accent-fg);
  border-color: var(--accent-fg);
}

/* Тонируется акцентом только главное действие (§3). «Подсказка», «Не знаю»,
   шаги разбора остаются нейтральными. */
.btn-primary { background: var(--accent); box-shadow: none; border-radius: var(--radius-md); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-ghost {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
}
.btn-ghost:hover { background: var(--sunken); border-color: var(--accent-line); }

.pr-head .rubric, .pr-sol-title { color: var(--text-soft); }
.pr-text b, .pr-examples b, .pr-solution .frm { color: var(--text-strong); }


/* ── 7. ФОРМА ──────────────────────────────────────────────────────────────

   ШРИФТ ЭЛЕМЕНТОВ УПРАВЛЕНИЯ. НАЙДЕНО ЗАМЕРОМ: <button> и <input> шрифт
   НЕ наследуют — браузер даёт им свой (в Chromium это Arial 13.3px).
   practice.css пишет font-family:inherit точечно, в восьми правилах
   (.ui-accordion-head, .ui-chip, .pr-input, .pr-choice, .pr-opt, .pr-cmp,
   .pr-order-item и соседи), а кому не написал — тот и остался на чужом
   шрифте. Замер 07.09.2026 на бумажной теме: кнопка «Проверить» (.btn-primary
   / #pr-check) — Arial 17px/700, «Пропустить» (#pr-skip) — Arial 17px/600,
   переключатель темы (.theme-btn) — Arial 22px. Самый заметный элемент
   страницы шёл не тем шрифтом, что вся остальная страница.

   В каноне это лечит sup-base.css строкой input, button, textarea, select
   { font: inherit }. Полный сброс сюда не годится: он снёс бы и кегль,
   и вес, которые practice.css выставляет каждому элементу отдельно
   (.btn-primary 700, .pr-input 500, .ui-tab 600). Поэтому бьём точечно
   по семейству — размер и вес остаются за practice.css.

   Своё семейство у элемента правило не отнимает: объявление в правиле
   класса сильнее правила по имени тега, поэтому моноширинные поля и цифры
   (.pr-input, .qs-value, .task-num, .ui-badge) остаются моноширинными.
   Замер после правки это подтвердил.

   РАДИУСЫ.
   В practice.css 14 разных радиусов; дизайн-система разрешает 5 и капсулу.
   Карточка и слой ui-* уже переведены мостом (--ui-radius, --ui-radius-card),
   здесь добираются литералы, оставшиеся в правилах. */
button, input, textarea, select { font-family: inherit; }

.ui-tab, .pr-input, .pr-choice, .pr-opt, .pr-cmp,
.pr-order-item, .pr-order-slot, .pr-hint-panel, .pr-oda,
.pr-gap-step, .pr-reflect, .sum-stop, .ui-chip, .due-item {
  border-radius: var(--radius-sm);
}
.pr-para-list li, .pr-para-list a.clickable { border-radius: var(--radius-sm); }
/* Сцена чертежа (16px) и полоса условия (14px) — последние два значения
   вне шкалы. После правки на странице остаются 6 · 10 · 12 · 18, круг
   у точки состояния и капсула: пять ступеней плюс капсула, как в §5. */
.pr-svg { border-radius: var(--radius-md); }
.pr-text.condition { border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.ui-badge, .pr-predict .pp-btn { border-radius: var(--radius-xs); }
.ui-progress, .ui-progress > .bar, .wk-dot, .task-progress .seg {
  border-radius: var(--radius-pill);
}


/* ── 8. РАЗМЕР ЦЕЛИ ────────────────────────────────────────────────────────
   Все интерактивные цели ≥ 44px (§7.2, условие приёмки 4). Замер до правки:
   .ui-tab уровней — 37px по высоте, то есть промах пальцем на телефоне
   гарантирован. Малой кнопке хватает добора зоны, менять кегль не нужно. */
.ui-tab,
.pr-choice, .pr-opt, .pr-cmp, .pr-order-item,
.pr-input, .btn-primary, .btn-ghost,
.ui-accordion-head, .pr-back, .theme-btn, .ui-chip,
.pr-step-nav .btn-ghost, .pr-predict .pp-btn {
  min-height: var(--tap);
}
.pr-back, .theme-btn { display: inline-flex; align-items: center; }
/* Кнопки шагов и предсказания остаются визуально небольшими: высоту добирает
   зона, а не кегль. */
.pr-step-nav .btn-ghost, .pr-predict .pp-btn { display: inline-flex; align-items: center; }

/* Дерево тем замером не покрывалось: .pr-tree стоит на абсолютных 20px, и
   подъём корневого кегля до него не доходит. Замер 07.09.2026: строка темы
   36.9px, ссылка «← Весь каталог» 22.3px — обе ниже 44. Ссылка каталога
   единственная в блоке, поэтому ей хватает добора зоны; строке темы добор
   идёт вместе с центровкой, иначе точка состояния повисает у верхнего края.
   Кегль ни там, ни там не меняется. */
.pr-para-list a.clickable {
  min-height: var(--tap);
  align-items: center;
}
.pr-tree-back {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}


/* ── 9. ЧЕРТЁЖ ─────────────────────────────────────────────────────────────
   Рамку, сетку и штрих ученика движок красит ИНЛАЙНОМ на SVG-узле
   (practice.js, initCanvasDrawing), а инлайновое объявление сильнее любого
   селектора — отсюда !important, единственный в файле. Рамка стояла на
   --glass-border: после моста это --border с непрозрачностью .11–.15,
   то есть пунктир поля построения почти не виден. Берём --border-strong. */
#pr-canvas-border { stroke: var(--border-strong) !important; }
#pr-canvas-grid   { stroke: var(--rule) !important; }
#pr-ink-path      { stroke: var(--accent) !important; }


/* ── 10. ДВИЖЕНИЕ ──────────────────────────────────────────────────────────
   Подскок translateY был навешан разом на кнопки, карточки, варианты ответа
   и плитки — когда движется всё, движение перестаёт что-либо означать (§6).
   Наведение меняет заливку и границу. */
.btn-primary:hover, .btn-ghost:hover, .btn-login:hover,
.pr-choice:hover, .pr-cmp:hover, .pr-topic-card:hover, .due-item:hover {
  transform: none;
}
.pr-choice:hover:not(:disabled),
.pr-cmp:hover:not(:disabled),
.pr-order-item:hover:not(:disabled) {
  background: var(--sunken);
  border-color: var(--accent-line);
}
.pr-topic-card:hover {
  background: var(--glass-hover);
  border-color: var(--accent-line);
  box-shadow: var(--shadow-raised);
}

/* Видимый фокус обязателен: ответ вводят с клавиатуры, и место ввода
   должно быть заметно без наведения мышью. */
:focus-visible {
  outline: var(--ring-width) solid var(--ring);
  outline-offset: var(--ring-offset);
}

/* Ученик может попросить систему убрать анимацию. Просьбу выполняем —
   выключаем, а не замедляем; элемент остаётся видимым. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   РАСКЛАДКА СТРАНИЦЫ ТЕМЫ — решение Анатолия 07.09.2026
   ══════════════════════════════════════════════════════════════════════════
   Вариант В «Тихая шапка» (статистика полосой, уровни сегмент-контролом,
   служебное занимает мало экрана) + из варианта Б «чертёж сбоку» (от 1100px
   карточка задачи делится на две колонки). Демо: _lab/paper/urovni/.

   Все правила ниже адресуются через html.sup-paper — признак, который ставит
   генератор на страницы со скином (tools/gen_practice_pages.py). Поведение,
   которого нельзя добиться стилями, — в practice-paper.js. Ни одно правило
   не переставляет узлы: движок находит их по id и пересобирает по частям.

   Замер до правки (1440×800, m5-naturalnye-i-drobi): карточка начиналась
   на 657-й точке от верха, ширина колонки задачи 690px, кеглей на странице 19.
   ────────────────────────────────────────────────────────────────────────── */


/* ── 11. РЕЖИМ ФОКУСА ─────────────────────────────────────────────────────
   Тема практики — режим фокуса, без сайдбара приложения (site-blueprint §5.8;
   демо urovni/ показывалось без него). Причина не только вкусовая: с сайдбаром
   272px и деревом тем 270px колонке задачи на 1440px оставалось 690px, и
   делить карточку на две колонки было негде. Выход из темы остаётся тремя
   путями: крошки «Практика», «← Вся практика» в шапке, «← Весь каталог»
   под деревом.

   С 13.09.2026 (ревизия навигации, шаг 2) сайдбара у темы нет вовсе, а не
   спрятанного: навигацию сайта над страницей рисует site-nav.js — на
   компьютере она есть, как и на всех остальных страницах. Правило
   `#appnav { display: none }` снято, прятать больше нечего. */
.sup-paper .shell-content { margin-left: 0; }
.sup-paper .shell-inner { max-width: 1380px; margin-inline: auto; }


/* ── 12. ТИХАЯ ШАПКА ──────────────────────────────────────────────────────
   Шапка темы: одна карточка с рубрикой, заголовком и ссылкой на теорию,
   вытянутая в строку. Подзаголовок-правило из реестра здесь НЕ показывается:
   тот же текст движок печатает в «Порядке действий» под задачей — раскрытым
   на уровнях 1–2 и свёрнутым на 3–4, где ученик восстанавливает его сам.
   Дублировать его в шапке значит подсказывать там, где по методике нельзя. */
.sup-paper .pr-head {
  padding: var(--sp-4) var(--sp-5);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "top top" "h1 link";
  align-items: center;
  column-gap: var(--sp-5);
  row-gap: var(--sp-2);
}
.sup-paper .pr-head-top { grid-area: top; margin-bottom: 0; }
.sup-paper .pr-head h1 { grid-area: h1; font-size: var(--fs-xl); line-height: 1.2; }
.sup-paper .pr-head .sub { display: none; }
.sup-paper .pr-head .theory-link {
  grid-area: link;
  margin-top: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  white-space: nowrap;
}
/* НАЙДЕНО СНИМКОМ 09.09.2026 (iframe 390px). Заголовок и ссылка стоят
   в одной строке сетки, ссылка — nowrap и шириной auto (≈208px). На 390px
   заголовку остаётся ≈110px, а слово «Взаимно» шире, и оно вылезало
   из своей колонки прямо под кнопку «Повторить теорию»: строки заголовка
   читались сквозь неё. Замером это не ловится — колонки не пересекаются,
   пересекается содержимое. На узком экране шапка становится в столбик. */
@media (max-width: 720px) {
  .sup-paper .pr-head {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "top" "h1" "link";
    justify-items: start;
    row-gap: var(--sp-3);
  }
  .sup-paper .pr-head .theory-link { white-space: normal; }
}

.sup-paper .pr-main, .sup-paper .pr-wrap { gap: var(--sp-4); }

/* Статистика полосой: пять показаний в одну строку, разделённые чертой,
   вместо пяти карточек. Подпись и число — на одной линии. */
.sup-paper .pr-quickstats {
  gap: 0;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--sunken);
  overflow: hidden;
}
.sup-paper .pr-quickstats .qs-tile {
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  min-height: var(--tap);
  background: transparent;
  border: 0;
  border-left: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.sup-paper .pr-quickstats .qs-tile:first-child { border-left: 0; }
.sup-paper .pr-quickstats .qs-value { margin-top: 0; }

/* Уровни сегмент-контролом: одна капсула, а не сетка вкладок на всю ширину.
   practice.css задаёт .pr-levels как grid в 2–4 колонки шириной 100% —
   здесь это гасится, и счётчик «Задача N из M» встаёт в ту же строку. */
.sup-paper .pr-levels.ui-tabs,
.sup-paper .pr-levels.ui-tabs:has(.ui-tab:nth-child(3):last-child),
.sup-paper .pr-levels.ui-tabs:has(.ui-tab:nth-child(2):last-child) {
  display: flex;
  flex-wrap: wrap;
  width: auto;
  flex: 1 1 auto;
  gap: 0;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--sunken);
}
.sup-paper .pr-levels .ui-tab {
  flex: 1 1 auto;
  justify-content: center;
  border: 0;
  border-radius: 0;
  border-left: 1px solid var(--border);
  box-shadow: none;
  gap: var(--sp-2);
}
.sup-paper .pr-levels .ui-tab:first-child { border-left: 0; }
.sup-paper .pr-levels .ui-tab.active { box-shadow: none; background: var(--surface); }
.sup-paper .task-head { gap: var(--sp-3) var(--sp-4); }

/* Компас у «Порядка действий» — эмодзи в псевдоэлементе practice.css. */
.sup-paper .pr-oda > summary::before { content: none; }

/* ЗАМЕР 09.09.2026. Карточка задачи — сетка с gap 18px, а practice.css
   вдобавок даёт «Порядку действий» margin-bottom:14px. Два механизма
   отступа подряд дают 32px там, где заказано 18, и именно эти 14 пикселей
   выносили Разминку с четырьмя вариантами ответа за экран: 774px при
   пороге 760. Отступ здесь один — тот, что у сетки. */
.sup-paper .pr-card > .pr-oda { margin-bottom: 0; }

/* Пустая ячейка подсказки не должна занимать строку сетки (см. раздел 13). */
.sup-paper #pr-hint-slot:empty { display: none; }

/* Значок из спрайта (practice-paper.js вклеивает assets/icons.svg). */
.pp-ico {
  width: 1em; height: 1em;
  flex-shrink: 0;
  vertical-align: -0.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.sup-paper .theme-btn .pp-ico { width: 1.15em; height: 1.15em; }
.sup-paper .ui-tab .pp-ico { width: .9em; height: .9em; }
/* Боковая колонка и палитра поиска: значок вместо эмодзи (см. dressShell).
   .ic в app-shell.css — строчный контейнер под символ, значку нужен блок,
   иначе он садится на базовую линию и уезжает вниз на пиксель-два. */
.sup-paper .sb-item .ic,
.sup-paper .sb-search .ic { display: flex; align-items: center; justify-content: center; }
.sup-paper .sb-item .ic .pp-ico,
.sup-paper .sb-search .ic .pp-ico { width: 1.05rem; height: 1.05rem; vertical-align: 0; }
.sup-paper .cmdk-input-row > .pp-ico { width: 1.05rem; height: 1.05rem; color: var(--muted); }

/* Ползунок модели: полоса 16px — цель ниже 44px. Высота добирается зоной,
   сам ползунок остаётся тонким. */
.sup-paper .pr-svg input[type="range"] { min-height: var(--tap); }
/* Чипы «−»/«+» в моделях: 41px по ширине (замер m5-naturalnye-i-drobi). */
.sup-paper .ui-chip { min-width: var(--tap); justify-content: center; }
/* Кнопка бокового меню на телефоне: 42×42 в app-shell.css — на два пикселя
   ниже порога цели (замер 09.09.2026 через iframe 390px). */
.sup-paper .nav-burger { min-width: var(--tap); min-height: var(--tap); }


/* ── 13. ЧЕРТЁЖ СБОКУ (от 1100px) ─────────────────────────────────────────
   Карточка с чертежом/моделью делится на две колонки: слева порядок
   действий, условие, ответ, вердикт и кнопки; справа — чертёж, липкий
   к верху. Так карточка помещается в экран 800px высотой (условие приёмки
   18: интерактив без внутренней прокрутки).

   БЕЗ ПЕРЕСТАНОВКИ УЗЛОВ. Дети .pr-card идут в порядке движка: .task-head,
   #pr-progress, [.pr-oda], .pr-text, [.pr-svg], .pr-answer, [#pr-hint-slot],
   [.pr-feedback], .pr-actions. Все, кроме чертежа, — в первую колонку по
   порядку; чертёж — во вторую, со строки 3 до конца. Строк объявлено 8 + одна
   растяжимая: если чертёж выше суммы строк левой колонки, лишнее уходит
   в последнюю строку, а не размазывается между условием и кнопками.
   Межстрочный зазор сетки — ноль, ритм задают поля детей: у пустых строк
   сетки зазоры остались бы, и карточка росла бы на пустоте. */
@media (min-width: 1100px) {
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) {
    grid-template-columns: minmax(0, 11fr) minmax(0, 10fr);
    grid-template-rows: repeat(8, auto) minmax(0, 1fr);
    column-gap: var(--sp-6);
    row-gap: 0;
    align-items: start;
  }
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) > * { grid-column: 1; min-width: 0; }
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) > * + * { margin-top: var(--sp-4); }
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) > .pr-svg {
    grid-column: 2;
    grid-row: 3 / 10;
    position: sticky;
    top: calc(var(--sn-h, 0px) + var(--sp-5));
    align-self: start;
    margin-top: var(--sp-4);
  }
  /* Полоса уровней и полоса подхода — во всю ширину карточки, над обеими
     колонками: в левой колонке (≈470px) четыре уровня переносились
     на вторую строку. */
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) > .task-head,
  .sup-paper .pr-card:has(> .pr-svg:not(:empty)) > #pr-progress { grid-column: 1 / -1; }

  /* ── «Порядок действий» сбоку, когда чертежа нет ─────────────────────────
     ЗАМЕР 09.09.2026, 20 вариантов × 4 уровня × 6 тем. Условие приёмки —
     карточка ≤ 760px при 1440×800. Не выполнялось на уровнях без чертежа:
     Разминка 10 из 20 вариантов у двух тем (максимум 817), Практика 7 из 40
     у двух тем (максимум 783). Из чего складывался максимум: раскрытый
     «Порядок действий» 163–194px + список из четырёх вариантов ответа
     293–297px — и то и другое узкой колонкой в одну стопку.

     Свернуть схему нельзя: на уровнях 1–2 она раскрыта по методике
     (Гальперин, ООД даётся ДО действия, а не выводится пробами; practice.js,
     odaHtml). Значит, её надо не убирать, а перестать ставить НАД ответом:
     тем же приёмом, что и чертёж, — во вторую колонку, липкой к верху.
     Схема при этом видна не «до», а «всё время», что для ООД не хуже.

     Условие приёмки после правки — в отчёте ниже по замеру. */
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) {
    grid-template-columns: minmax(0, 13fr) minmax(0, 8fr);
    grid-template-rows: repeat(8, auto) minmax(0, 1fr);
    column-gap: var(--sp-6);
    row-gap: 0;
    align-items: start;
  }
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) > * {
    grid-column: 1; min-width: 0;
  }
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) > * + * {
    margin-top: var(--sp-4);
  }
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) > .pr-oda {
    grid-column: 2;
    grid-row: 3 / 10;
    position: sticky;
    top: calc(var(--sn-h, 0px) + var(--sp-5));
    align-self: start;
    margin-top: var(--sp-4);
  }
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) > .task-head,
  .sup-paper .pr-card:has(> .pr-oda[open]):not(:has(> .pr-svg:not(:empty))) > #pr-progress {
    grid-column: 1 / -1;
  }
}


/* ── 14. ШКАЛА КЕГЛЕЙ ─────────────────────────────────────────────────────
   Норма §4: не больше 8 кеглей на страницу. practice.css считает всё в em
   от 20px базы .pr-scope с коэффициентами .68/.72/.74/.78/.8/.82/.85/.86/
   .88/.9/.92/.95/.98/1.1 — замер 07.09.2026 дал 19 разных кеглей на странице
   темы. Здесь всё сводится к пяти ступеням токенов:

       --fs-xs  15.5   подписи показаний, рубрика, дерево тем, бейджи, счётчик
       --fs-sm  17.5   кнопки, уровни, подсказки, разбор, крошки, подвал
       --fs-md  20     условие, ответ, варианты, порядок действий, вердикт
       --fs-lg  23     показания, заголовок итогов
       --fs-xl  ≈27    заголовок темы

   Кегль ВНУТРИ холста (#pr-svg: модель, чертёж, подписи) не трогается:
   его задают модули задач, и по стандарту мелкий шрифт допустим только там.
   Формулы KaTeX меряются от кегля родителя (.katex 0.98em, раздел 1). */

/* xs */
.sup-paper .qs-label,
.sup-paper .qs-value small,
.sup-paper .pr-head .rubric,
.sup-paper .pr-tree .course-note,
.sup-paper .pr-chapter-head,
.sup-paper .pr-para-list li,
.sup-paper .pr-para-list li.pr-sec-head,
.sup-paper .pr-tree-note,
.sup-paper .pr-tree-back,
.sup-paper .ui-badge,
.sup-paper .ui-tab .tab-count,
.sup-paper .task-num,
.sup-paper .pr-sol-title,
.sup-paper .pr-field label,
.sup-paper .pr-order-slot .ph,
.sup-paper .ui-tooltip,
.sup-paper .pr-gap-step > .n,
.sup-paper .pr-empty .dim,
.sup-paper .sum-row.rev .rev-next {
  font-size: var(--fs-xs);
}

/* sm */
.sup-paper .pr-back,
.sup-paper .pr-tree h2,
.sup-paper .pr-head .theory-link,
.sup-paper .ui-tab,
.sup-paper .ui-chip,
.sup-paper .ui-accordion-head,
.sup-paper .btn-ghost,
.sup-paper .btn-primary,
.sup-paper .pr-actions .btn-primary,
.sup-paper .pr-actions .btn-ghost,
.sup-paper .pr-step-nav .btn-ghost,
.sup-paper .sum-actions .btn-primary,
.sup-paper .sum-actions .btn-ghost,
.sup-paper .pr-canvas-hint,
.sup-paper .pr-hint-panel,
.sup-paper .pr-examples,
.sup-paper .pr-solution,
.sup-paper .pr-verdict.soft,
.sup-paper .pr-predict,
.sup-paper .pr-predict .pp-btn,
.sup-paper .pr-predict-fb,
.sup-paper .pr-oda > summary,
.sup-paper .pr-order-item,
.sup-paper .pr-order-step,
.sup-paper .pr-opt,
.sup-paper .pr-source,
.sup-paper .pr-xp-float,
.sup-paper .pr-why,
.sup-paper .sum-row,
.sup-paper .sum-note,
.sup-paper .sum-advice,
.sup-paper .sum-stop,
.sup-paper .ui-dialog-sub,
.sup-paper .ui-toast .t-title,
.sup-paper .ui-toast .t-sub,
.sup-paper .pr-empty p,
.sup-paper .shell-topbar .crumbs,
.sup-paper footer.site {
  font-size: var(--fs-sm);
}

/* md */
.sup-paper .pr-text,
.sup-paper .pr-oda-body,
.sup-paper .pr-choice,
.sup-paper .pr-input,
.sup-paper .pr-unit,
.sup-paper .pr-cmp,
.sup-paper .pr-verdict,
.sup-paper .pr-gap-step,
.sup-paper .pr-reflect,
.sup-paper .pr-text table,
.sup-paper .pr-empty h3 {
  font-size: var(--fs-md);
}

/* lg */
.sup-paper .qs-value,
.sup-paper .pr-summary h2,
.sup-paper .ui-dialog-title,
.sup-paper .rk-title {
  font-size: var(--fs-lg);
}

/* Полоса уровней на узком экране practice.css уменьшает до .72em —
   на слое ступеней меньше xs нет. */
@media (max-width: 620px) {
  .sup-paper .pr-levels .ui-tab { font-size: var(--fs-xs); }
}

/* Телефон: база 18px, как у витрины (paper.css) и в §4 дизайн-системы —
   при 20px на 390px мера падает ниже 30 знаков. */
@media (max-width: 720px) {
  html.sup-paper { font-size: 18px; }
  /* Минимум текста вне холста — 15.5px абсолютных: при базе 18px ступень xs
     (0.775rem = 13.9px) проваливает пол, поэтому xs поднимается явно —
     то же правило, что в paper.css. */
  html.sup-paper, html.sup-paper[data-tone] { --fs-xs: 0.8612rem; }
}

/* Эмодзи-заставки итогов, диалога и пустого состояния: practice-paper.js
   вычищает символ, пустой блок с кеглем 2.6rem оставлял бы дыру. */
.sup-paper .sum-emoji,
.sup-paper .ui-dialog-emoji,
.sup-paper .pr-empty .e-icon { display: none; }

/* «Почему именно так?» на шаге разбора: в practice.css у врезки нет формы,
   только эмодзи в псевдоэлементе. Форма — как предложено в демо urovni.css §7. */
.sup-paper .pr-why {
  margin-top: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--sunken);
}
.sup-paper .pr-why > summary {
  padding: var(--sp-2) var(--sp-4);
  min-height: var(--tap);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-semi);
  color: var(--text);
  opacity: 1;
}
.sup-paper .pr-why > summary::before { content: '?'; color: var(--text-soft); font-family: var(--font-mono); }
.sup-paper .pr-why-body { margin-top: 0; padding: 0 var(--sp-4) var(--sp-4); border-left: 0; color: var(--text); }
.sup-paper .pr-reflect-q { font-weight: var(--fw-semi); color: var(--text-strong); opacity: 1; }

/* «Порядок действий»: цель ≥ 44px (замер демо: 41.3px). */
.sup-paper .pr-oda > summary { min-height: var(--tap); display: flex; align-items: center; opacity: 1; }

/* Крошки пути: цель 28px и перенос на телефоне (app-shell.css — flex без
   переноса, на 390px распирал страницу). */
.sup-paper .shell-topbar, .sup-paper .shell-topbar-right { flex-wrap: wrap; }
.sup-paper .shell-topbar .crumbs { min-width: 0; }
.sup-paper .shell-topbar .crumbs a { min-height: var(--tap); display: inline-flex; align-items: center; }
.sup-paper footer.site a { min-height: var(--tap); display: inline-flex; align-items: center; }
