/* ============================================================================
   СУПРЕМУМ · sup-base.css — слой 2: база и компоненты
   ============================================================================
   Требует sup-tokens.css (слой 1) — подключается ПЕРЕД этим файлом.
   Ни одного значения мимо токенов: цвет, кегль, отступ, радиус, длительность
   берутся только через var(). Это проверяет линтер сборки.

   ИМЕНА КЛАССОВ ЗДЕСЬ НЕ НОВЫЕ. Они повторяют то, что уже стоит в разметке
   512 страниц теории (.card, .definition, .highlight, .memo, .mistake,
   .viz-block, .tab-btn, .btn, .topic-nav, .theory-col …). Благодаря этому
   готовая страница получает новое оформление БЕЗ ПРАВКИ РАЗМЕТКИ — достаточно
   заменить подключаемый CSS. Переименовывать классы здесь нельзя: это тут же
   отрежет 512 страниц от системы.

   ПРИНЦИП: цвет несёт смысл, а не украшает.
   Каркас нейтральный, крупных окрашенных плоскостей нет. Возвышение даёт
   граница, а не тень и не размытие. Насыщенный цвет только там, где значит.
   ============================================================================ */

/* ── СБРОС ─────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  font-size: var(--fs-root);
  -webkit-text-size-adjust: 100%;
  /* Страница не скроллится по горизонтали никогда. На боевом pricing.html
     контент разъезжался до 778px при вьюпорте 360 — вот от чего страховка. */
  overflow-x: clip;
}

body {
  min-height: 100vh;
  overflow-x: clip;
  font-family: var(--font-body);
  font-size: var(--fs-md);
  line-height: var(--lh-md);
  font-weight: var(--fw-normal);
  font-synthesis-weight: var(--font-synthesis);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, video, canvas { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
table { border-collapse: collapse; }
ul[class], ol[class] { list-style: none; padding: 0; }
p, h1, h2, h3, h4, li, dt, dd { overflow-wrap: break-word; }

/* ── ФАКТУРА: миллиметровка вместо градиентных пятен ───────────────────────
   Раньше на body лежали три радиальных градиента (и в theory.css, и в
   supremum.css) — самый узнаваемый штамп ИИ-вёрстки. Здесь фактура из мира
   предмета: клетка, затухающая к низу по mask-image, чтобы не спорить
   с чертежом. Рисуется на ::before, а не на background самого body: так она
   не прокручивается вместе с длинным текстом и не мешает печати. */

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-line) 0 1px, transparent 1px 100%),
    linear-gradient(to bottom, var(--grid-line) 0 1px, transparent 1px 100%);
  background-size: var(--grid-step) var(--grid-step);
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / .55), transparent 62%);
  mask-image: linear-gradient(to bottom, rgb(0 0 0 / .55), transparent 62%);
}

/* Раздел, которому нужна мелкая клетка — как в тетради по математике */
.texture-fine::before { background-size: var(--grid-step-fine) var(--grid-step-fine); }
.texture-none::before { display: none; }

/* ── ТИПОГРАФИКА ───────────────────────────────────────────────────────── */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-optical-sizing: auto;
  color: var(--text-strong);
  text-wrap: balance;
}
h1 { font-size: var(--fs-3xl); line-height: var(--lh-3xl); letter-spacing: -.012em; }
h2 { font-size: var(--fs-2xl); line-height: var(--lh-2xl); letter-spacing: -.008em; }
h3 { font-size: var(--fs-xl);  line-height: var(--lh-xl); }
h4 { font-size: var(--fs-lg);  line-height: var(--lh-lg); }

p { text-wrap: pretty; }

/* Ссылка узнаётся подчёркиванием, а не только цветом: при дальтонизме цвет
   ссылки от текста не отличить. Отступ подчёркивания — чтобы не резало буквы. */
a {
  color: var(--text-strong);
  text-decoration-line: underline;
  text-decoration-color: var(--accent-line);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: text-decoration-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
a:hover { text-decoration-color: var(--accent); }

/* Числа, координаты, показания приборов. tabular-nums обязательно: без него
   цифры в живом показании дёргаются по ширине при каждом изменении. */
.mono, .num, .readout-v, code, kbd, samp {
  font-family: var(--font-mono);
  font-weight: var(--fw-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
}

/* Рубрикатор над заголовком: «ГЛАВА 3 · § 22». Номер параграфа живёт здесь,
   а не внутри названия темы — внутри он ломал разбивку строк заголовка. */
.rubric {
  font-family: var(--font-mono);
  font-weight: var(--fw-mono);
  font-size: var(--fs-xs);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-soft);
}

.lead { font-size: var(--fs-lg); line-height: var(--lh-lg); color: var(--text-soft); }
.meta { font-size: var(--fs-xs); line-height: var(--lh-xs); color: var(--text-soft); }
.measure { max-width: var(--measure); }

/* Подпись бренда: подчёркивание ручкой учителя. Только витрина — на учебных
   страницах красный обязан значить ошибку и ничего больше. */
.pen-mark {
  position: relative;
  white-space: nowrap;
}
.pen-mark::after {
  content: "";
  position: absolute;
  left: -.06em; right: -.06em; bottom: -.16em;
  height: .13em;
  border-radius: var(--radius-pill);
  background: var(--pen);
  /* Неровный край: линия нарисована рукой, а не векторным редактором */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
  transform: rotate(-.35deg);
}

/* ── ДОСТУПНОСТЬ ───────────────────────────────────────────────────────── */

a, button, summary, [role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--ring-width) solid var(--ring);
  outline-offset: var(--ring-offset);
  border-radius: var(--radius-xs);
}

.skip-link {
  position: absolute;
  left: var(--sp-4); top: -100px;
  z-index: calc(var(--z-header) + 10);
  padding: var(--sp-3) var(--sp-6);
  background: var(--accent); color: var(--accent-fg);
  font-weight: var(--fw-semi); text-decoration: none;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-link:focus { top: 0; }

.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;
}

/* Любая цель — не меньше 44×44, даже если значок 16px */
.tap, .icon-btn {
  min-width: var(--tap); min-height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

/* ── ЗНАЧКИ ────────────────────────────────────────────────────────────── */

.icon {
  width: 1em; height: 1em;
  flex-shrink: 0; pointer-events: none;
  stroke: currentColor; fill: none; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round;
}
.icon-lg { width: 1.4em; height: 1.4em; }

/* ── ПРИМИТИВЫ РАСКЛАДКИ ───────────────────────────────────────────────── */

.wrap {
  width: 100%; max-width: var(--page-max);
  margin-inline: auto; padding-inline: var(--page-pad);
}
.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--flow, var(--sp-4)); }
.cluster {
  display: flex; flex-wrap: wrap;
  gap: var(--gap, var(--sp-3)); align-items: center;
}
.grid-auto {
  display: grid; gap: var(--gap, var(--sp-4));
  grid-template-columns: repeat(auto-fit, minmax(min(var(--col, 260px), 100%), 1fr));
}
/* Грид-потомок по умолчанию не сжимается уже содержимого — корень переполнений */
.grid-auto > *, .wrap > * { min-width: 0; }

/* Широкое содержимое прокручивается внутри себя, а не ломает страницу */
.scroll-x {
  overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

/* ── ШАПКА ─────────────────────────────────────────────────────────────── */

header.page-header, header.site, .sup-header {
  position: sticky; top: 0;
  z-index: var(--z-header);
  display: flex; align-items: center; gap: var(--sp-4);
  min-height: var(--hdr, 64px);
  padding: var(--sp-2) var(--page-pad);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  /* Никакого backdrop-filter: когда «стекло» у всего, иерархии нет.
     Шапка непрозрачна — под ней текст, его не должно быть видно насквозь. */
}

.logo {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: var(--tap);   /* это ссылка на главную — значит тач-цель */
  text-decoration: none; color: var(--text-strong);
}
.logo-mark {
  width: 40px; height: 40px; flex-shrink: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px;
  font-family: var(--font-display);
  font-weight: var(--fw-display); font-size: .8rem; line-height: 1;
  color: var(--accent-fg); background: var(--accent);
  border-radius: var(--radius-sm);
}
/* Черта под «sup» — та же ручка учителя, что в подписи бренда */
.logo-mark::after {
  content: ""; width: 22px; height: 2px;
  border-radius: var(--radius-pill); background: var(--pen);
}
.logo-name {
  display: block;
  font-family: var(--font-display); font-weight: var(--fw-display);
  font-size: var(--fs-lg); letter-spacing: .1em; line-height: 1.1;
}
.logo-sub {
  display: block;
  font-size: var(--fs-xs); color: var(--text-soft); letter-spacing: .02em;
}

nav.site { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
nav.site a {
  display: inline-flex; align-items: center;
  min-height: var(--tap); padding: 0 var(--sp-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--text-soft); text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
nav.site a:hover { background: var(--n-2); color: var(--text-strong); }
/* Текущий раздел: заливка чернилами. Не только цвет — ещё и вес, чтобы
   положение читалось при любом зрении. */
nav.site a[aria-current], nav.site a.active {
  background: var(--accent); color: var(--accent-fg);
  font-weight: var(--fw-semi);
}
.header-right { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }

/* Ноутбучные ширины: между полным экраном и телефоном была дыра. Замер
   (tools\redesign — снимок шапки на 1440/1100/900) показывал на 1100px две
   строки навигации и шапку в 109px вместо 66px: пункты не помещались рядом
   с логотипом и подписью под ним, а компактный режим включался только
   с 700px. Двухстрочная навигация на ноутбуке — это сломанная шапка,
   а не адаптация.

   Освобождаем место в том порядке, в каком элементы нужны: сначала уходит
   пояснение под названием (оно для первого знакомства, а не для навигации),
   потом поджимаются поля пунктов. Сами пункты остаются видимыми.

   Пороги взяты с запасом, а не впритык к замеру: на грани страницы
   расходились между собой из-за десятка пикселей в правой группе кнопок,
   и «починено» держалось бы до первого нового пункта меню. */
@media (max-width: 1400px) {
  .logo-sub { display: none; }
  nav.site a { padding-inline: var(--sp-2); }
}
@media (max-width: 1180px) {
  header.page-header, header.site, .sup-header { gap: var(--sp-3); }
  nav.site { gap: 0; }
  nav.site a { font-size: var(--fs-xs); padding-inline: var(--sp-1); }
}

/* Планшет: пункты в один ряд с логотипом уже не помещаются. Две строки тут
   неизбежны, но они должны быть задуманными, а не рваным переносом, при
   котором на вторую строку сползает один случайный пункт. Поэтому меню
   целиком уходит на свою строку во всю ширину и прокручивается вбок. */
@media (max-width: 950px) {
  header.page-header, header.site, .sup-header {
    flex-wrap: wrap;   /* иначе последняя кнопка уезжает за край и обрезается */
  }
  .logo { flex: 1 1 auto; min-width: 0; }
  .header-right { flex-shrink: 0; }
  nav.site {
    order: 3; width: 100%; flex-wrap: nowrap;
    overflow-x: auto; padding-bottom: var(--sp-1);
    scrollbar-width: none;
  }
  nav.site::-webkit-scrollbar { display: none; }
  nav.site a { flex: 0 0 auto; }
}

/* Узкий экран: в шапке остаётся только логотип и действия. Хлебные крошки
   на 390px не помещаются и начинают наезжать друг на друга — их место
   в теле страницы, а не в сдавленной шапке. */
@media (max-width: 700px) {
  header.page-header, header.site, .sup-header {
    gap: var(--sp-2);
    padding-inline: var(--sp-4);
  }
  header.page-header .crumbs, header.site .crumbs { display: none; }
  .logo-name { font-size: var(--fs-md); }
}

/* Узкий экран: поля карточек и врезок поджимаются. Иначе на 390px от меры
   строки остаётся 20 знаков — по три слова в строке, читать неудобно. */
@media (max-width: 560px) {
  .card { padding: var(--sp-4); }
  .definition, .highlight, .memo, .mistake, .callout {
    padding: var(--sp-3) var(--sp-4);
    gap: var(--sp-2);
  }
  .theory-col { padding-inline: var(--sp-3); }
}

/* ── КНОПКИ ────────────────────────────────────────────────────────────── */
/* Наведение меняет заливку и границу, а не подбрасывает элемент вверх.
   translateY(-2px) на кнопках, карточках и разделах разом — один жест на всё,
   от него ушли сознательно. */

.btn {
  --btn-h: 2.4rem;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: var(--btn-h); padding: 0 var(--sp-4);
  border: 1px solid transparent; border-radius: var(--radius-md);
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  text-decoration: none; cursor: pointer;
  /* Длинную надпись переносим, а не выпускаем за край экрана: на 390px
     кнопка «Записаться на бесплатное занятие» шире самого экрана. */
  max-width: 100%;
  white-space: normal;
  text-align: center;
  text-wrap: balance;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
/* Короткие кнопки в плотных рядах переносить не нужно */
.btn-sm, .tab-btn, .step-btn { white-space: nowrap; }
@media (max-width: 560px) {
  /* Главное действие на телефоне занимает всю ширину — так его не промахнуть */
  .btn-lg { width: 100%; }
}
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: default; }

/* Главное действие: чернила днём, мел ночью */
.btn-primary, .btn.primary, .btn-login, .topic-nav-all {
  background: var(--accent); color: var(--accent-fg);
  border-color: var(--accent);
}
.btn-primary:hover:not(:disabled), .btn.primary:hover:not(:disabled),
.btn-login:hover, .topic-nav-all:hover {
  background: var(--accent-hover); border-color: var(--accent-hover);
}

.btn-outline, .btn-ghost, .btn.secondary {
  background: var(--surface); color: var(--text-strong);
  border-color: var(--border-strong);
}
.btn-outline:hover:not(:disabled), .btn-ghost:hover, .btn.secondary:hover:not(:disabled) {
  background: var(--n-2); border-color: var(--accent);
}
/* Выбранное состояние переключателя — заливка, плюс вес шрифта */
.btn-outline.active, .btn-outline[aria-pressed="true"] {
  background: var(--accent); color: var(--accent-fg);
  border-color: var(--accent); font-weight: var(--fw-semi);
}

.btn-quiet {
  background: transparent; color: var(--text-soft); border-color: transparent;
}
.btn-quiet:hover:not(:disabled) { background: var(--n-2); color: var(--text-strong); }

/* Малая кнопка выглядит плотно, но зона нажатия всё равно не меньше 44×44.
   Расширяем её невидимым слоем, а не самой кнопкой: иначе в плотной шапке
   кнопки начали бы расталкивать друг друга. Промахи на телефоне —
   не мелочь, это правило C8. */
.btn-sm {
  --btn-h: 2rem;
  padding: 0 var(--sp-3);
  font-size: var(--fs-xs);
  position: relative;
}
.btn-sm::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: 50%; transform: translateY(-50%);
  height: var(--tap);
  min-width: var(--tap);
}
.btn-lg { --btn-h: 3rem; padding: 0 var(--sp-6); font-size: var(--fs-md); }

.theme-toggle, .theme-btn {
  width: var(--tap); height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text-soft); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.theme-toggle:hover, .theme-btn:hover { background: var(--n-2); color: var(--text-strong); }

/* ── КАРТОЧКА ──────────────────────────────────────────────────────────── */
/* Возвышение даёт граница. Тень — только у того, что действительно висит. */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
  padding: var(--sp-6);
  color: var(--text);
}
.card > * + * { margin-top: var(--sp-4); }
.card h2 { font-size: var(--fs-2xl); }
.card h3 { font-size: var(--fs-xl); }
.card-float { box-shadow: var(--shadow-float); }

/* Карточка-ссылка: наведение подсвечивает границу, элемент не прыгает */
a.card, .card-link {
  display: block; text-decoration: none; color: inherit;
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
a.card:hover, .card-link:hover { border-color: var(--accent); background: var(--n-2); }

.section-title {
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-soft);
}

/* ── ВРЕЗКИ: определение, пример, запомни, ошибка ──────────────────────────
   ГЛАВНОЕ ПРАВИЛО: у врезки ВСЕГДА есть знак, а не только цвет. При красно-
   зелёной слепоте «запомни» (янтарь) и «ошибка» (красный) неразличимы —
   различает их именно значок и слово в заголовке.

   Раскладка сознательно flex, но у .definition и соседей в старой разметке
   бывает два поколения содержимого: новое с .a-icon/.a-title/.a-body и старое
   простым текстом. Поэтому flex включается ТОЛЬКО когда внутри есть .a-icon —
   иначе inline-элементы вроде <strong> становились бы флекс-элементами
   и врезка разъезжалась по ширине. Этот случай уже ломал 206 страниц. */

.definition, .highlight, .memo, .mistake, .callout {
  display: block;
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid transparent;
  border-left-width: 3px;
  border-radius: var(--radius-md);
  line-height: var(--lh-md);
  color: var(--text);
}
.definition:has(.a-icon), .highlight:has(.a-icon),
.memo:has(.a-icon), .mistake:has(.a-icon), .callout:has(.a-icon) {
  display: flex; gap: var(--sp-3); align-items: flex-start;
}

.definition { background: var(--ok-soft);   border-color: var(--ok);   }
.highlight  { background: var(--info-soft); border-color: var(--info); }
.memo       { background: var(--warn-soft); border-color: var(--warn); }
.mistake    { background: var(--err-soft);  border-color: var(--err);  }

.definition .a-title { color: var(--ok-fg);   }
.highlight  .a-title { color: var(--info-fg); }
.memo       .a-title { color: var(--warn-fg); }
.mistake    .a-title { color: var(--err-fg);  }

.definition .a-icon { color: var(--ok);   }
.highlight  .a-icon { color: var(--info); }
.memo       .a-icon { color: var(--warn); }
.mistake    .a-icon { color: var(--err);  }

.a-icon {
  flex-shrink: 0;
  width: 1.25em; height: 1.25em;
  margin-top: .18em;
  font-size: var(--fs-md); line-height: 1;
}
.a-title {
  display: block;
  font-weight: var(--fw-semi);
  margin-bottom: var(--sp-1);
}
.a-body {
  font-size: var(--fs-md); line-height: var(--lh-md);
  /* Обязательно: без этого выключная формула внутри врезки растягивает её
     за край экрана. Флекс-элемент по умолчанию не сжимается уже содержимого,
     а .katex-display шириной в 500px как раз такое содержимое. */
  min-width: 0;
  flex: 1 1 auto;
}
.a-body > * + * { margin-top: var(--sp-2); }

/* ── БЛОК ПРЕДПОСЫЛОК ──────────────────────────────────────────────────── */

.prereq {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-line);
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  font-size: var(--fs-sm); line-height: var(--lh-sm);
}
.prereq-title {
  display: block; margin-bottom: var(--sp-1);
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-soft);
}
.prereq a { color: var(--text-strong); text-decoration-color: var(--accent); }
.prereq a + a::before { content: " · "; text-decoration: none; opacity: .5; }

/* ── ЗНАЧКИ СОСТОЯНИЯ ──────────────────────────────────────────────────── */
/* У значка всегда есть текст. Цветной кружок без подписи — не сообщение. */

.badge, .chip, .status-badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  background: var(--n-2); color: var(--text-soft);
  font-size: var(--fs-xs); font-weight: var(--fw-medium);
  white-space: nowrap;
}
.badge-ok   { background: var(--ok-soft);   border-color: var(--ok);   color: var(--ok-fg);   }
.badge-err  { background: var(--err-soft);  border-color: var(--err);  color: var(--err-fg);  }
.badge-warn { background: var(--warn-soft); border-color: var(--warn); color: var(--warn-fg); }
.badge-info { background: var(--info-soft); border-color: var(--info); color: var(--info-fg); }
.badge-free { background: var(--ok-soft); border-color: var(--ok); color: var(--ok-fg); }
.badge.soon { background: var(--warn-soft); border-color: var(--warn); color: var(--warn-fg); }

/* ── ПОЛОСА ПРОГРЕССА ──────────────────────────────────────────────────── */
/* Сплошная заливка, не градиент: градиент здесь ничего не кодировал. */

.progress-track {
  height: 6px; border-radius: var(--radius-pill);
  background: var(--n-3); overflow: hidden;
}
.progress-fill {
  height: 100%; border-radius: var(--radius-pill);
  background: var(--accent);
  transition: width var(--dur-base) var(--ease-out);
}
.progress-fill.is-ok { background: var(--ok); }

/* ── ТАБЛИЦА ───────────────────────────────────────────────────────────── */

.table { width: 100%; font-size: var(--fs-sm); }
.table th, .table td {
  padding: var(--sp-3) var(--sp-4);
  text-align: left; border-bottom: 1px solid var(--border);
}
.table th {
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-xs); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-soft);
}
.table tbody tr:hover { background: var(--n-2); }
.table td.num { font-variant-numeric: tabular-nums; text-align: right; }

/* ── ПОЛЯ ВВОДА ────────────────────────────────────────────────────────── */

.field {
  display: flex; flex-direction: column; gap: var(--sp-1);
}
.field > label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-soft); }
.input, input[type="text"], input[type="number"], textarea, select {
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font-size: var(--fs-md);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.input:hover, input[type="text"]:hover { border-color: var(--n-5); }
.input.is-err { border-color: var(--err); }
.input.is-ok  { border-color: var(--ok); }

/* Ползунок: цвет ручки из токена, дорожка нейтральная.
   Высота задана тач-целью: у голого range зона нажатия ~16px, и попасть
   в него пальцем почти нельзя. */
input[type="range"] {
  accent-color: var(--accent);
  min-height: var(--tap);
  flex: 1 1 120px;
}

/* ── РАСКЛАДКА СТРАНИЦЫ ТЕМЫ ───────────────────────────────────────────────
   Теория слева, интерактив справа. Правая половина липкая и ровно в высоту
   окна: прокрутки ВНУТРИ интерактива быть не должно — если панели не влезают,
   сокращается содержимое панелей, а не добавляется скролл.

   Высота считается от фактической высоты шапки (--hdr-real, её пишет скрипт),
   а не от объявленной: при другом кегле они не совпадают и блок вылезал вниз. */

.page-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
}
.theory-col {
  min-width: 0;
  padding: var(--sp-8) var(--sp-8) var(--sp-24);
}
.theory-col > * + * { margin-top: var(--sp-5); }

.interactive-col, .viz-col {
  position: sticky;
  top: var(--hdr-real, var(--hdr, 64px));
  height: calc(100vh - var(--hdr-real, var(--hdr, 64px)));
  min-width: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-4);
  overflow: hidden;
}

@media (max-width: 900px) {
  .page-split { grid-template-columns: minmax(0, 1fr); }
  .theory-col { padding: var(--sp-5) var(--sp-4) var(--sp-12); }
  .interactive-col, .viz-col {
    position: static; height: auto;
    min-height: 60vh; padding: var(--sp-3) var(--sp-4) var(--sp-8);
  }
}

/* ── КОРОБКА ИНТЕРАКТИВА ──────────────────────────────────────────────────
   Сцена занимает всю доступную высоту, панели стоят под ней и меряются своей
   высотой. Холст выведен из потока: иначе SVG держит собственную высоту
   и не даёт сцене ужаться. */

.viz-block {
  width: 100%;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
  user-select: none; -webkit-user-select: none;
}
.viz-block .stage { position: relative; min-height: 0; }
.viz-block .stage > svg, .viz-block .stage > canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.viz-block svg, .viz-block canvas { touch-action: none; margin-inline: auto; }
.viz-inner { padding: var(--sp-5) var(--sp-5) var(--sp-2); }

.viz-caption {
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--n-2);
  font-size: var(--fs-xs); line-height: var(--lh-xs);
  color: var(--text-soft); text-align: center;
}

/* Панель показаний — как на приборе: подпись капслоком, значение моношрифтом.
   tabular-nums не даёт цифрам дёргаться при перетаскивании. */
.readout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(84px, 100%), 1fr));
  border-top: 1px solid var(--border);
  background: var(--n-2);
}
.readout-cell {
  padding: var(--sp-2) var(--sp-3);
  border-right: 1px solid var(--border);
  text-align: center;
}
.readout-cell:last-child { border-right: none; }
.readout-k {
  display: block;
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-soft);
}
.readout-v {
  display: block;
  font-size: var(--fs-lg); color: var(--text-strong);
}
.readout-cell.is-total .readout-v { color: var(--accent); }

.formula-box {
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--n-2);
  text-align: center; min-height: 1.4em;
  font-size: var(--fs-md); color: var(--text);
}
.formula-box b { color: var(--text-strong); font-weight: var(--fw-semi); }

/* ── ПЕРЕКЛЮЧАТЕЛЬ ВКЛАДОК ────────────────────────────────────────────────
   Сегментированный переключатель: рамка одна на всю группу, внутри — кнопки.
   Так видно, что это выбор одного из нескольких, а не набор отдельных кнопок. */

.tab-row {
  display: flex; gap: 0;
  width: fit-content; max-width: 100%;
  padding: 3px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  background: var(--n-2);
  /* На телефоне три-четыре вкладки в строку не влезают, и последняя уезжает
     за край экрана — до неё физически нельзя дотянуться. Поэтому ряд
     прокручивается внутри себя. Полосу прокрутки прячем: на тач-экране она
     не нужна, а на десктопе ряд обычно влезает целиком. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.tab-row::-webkit-scrollbar { display: none; }
.tab-row > .tab-btn { flex-shrink: 0; }
.tab-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--tap);   /* тач-цель: без этого выходило 43px — мимо на 1px */
  padding: var(--sp-2) var(--sp-4);
  border: none; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-soft);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.tab-btn:hover { color: var(--text-strong); }
.tab-btn.active, .tab-btn[aria-selected="true"] {
  background: var(--surface); color: var(--text-strong);
  font-weight: var(--fw-semi);
  box-shadow: var(--shadow-raised);
}

/* ── ПОШАГОВЫЙ РАЗБОР ──────────────────────────────────────────────────── */

.step-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  min-height: 2.2rem; padding: 0 var(--sp-4);
  border: 1px solid var(--accent); border-radius: var(--radius-md);
  background: var(--accent); color: var(--accent-fg);
  font-size: var(--fs-sm); font-weight: var(--fw-semi); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.step-btn:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
.step-btn:disabled { opacity: .45; cursor: default; }

.proof-step {
  display: flex; gap: var(--sp-4); align-items: flex-start;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
  opacity: 0; transform: translateY(6px);
  transition: opacity var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}
.proof-step:last-child { border-bottom: none; }
.proof-step.step-visible { opacity: 1; transform: none; }
.proof-step .num {
  flex-shrink: 0;
  width: 1.7em; height: 1.7em;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--accent); color: var(--accent-fg);
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-sm);
}
.proof-step .txt { font-size: var(--fs-md); line-height: var(--lh-md); }

.slider-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5) 0;
}
.slider-row span.lbl { font-size: var(--fs-sm); color: var(--text-soft); }
.slider-row span.val {
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-sm); color: var(--text-strong);
  text-align: right; min-width: 3.5ch;
}

/* ── СВЯЗЬ ТЕКСТ ↔ ЧЕРТЁЖ ─────────────────────────────────────────────────
   Наведение на упоминание в тексте подсвечивает элемент на чертеже.
   Пунктир под словом показывает, что связь есть, до наведения. */

.hl {
  cursor: pointer;
  border-bottom: 1.5px dashed var(--accent-line);
  transition: background-color var(--dur-instant) var(--ease-out),
              border-color var(--dur-instant) var(--ease-out);
}
.hl:hover, .hl.is-active {
  background: var(--accent-soft);
  border-bottom-color: var(--accent);
}

/* ── НАВИГАЦИЯ ПО ТЕМАМ ────────────────────────────────────────────────── */

.topic-nav {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: stretch; gap: var(--sp-3);
  margin-top: var(--sp-12);
}
.topic-nav-side {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 0; max-width: 100%; width: fit-content;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}
.topic-nav-side:hover { border-color: var(--accent); background: var(--n-2); }
.topic-nav-side:empty { background: none; border: none; padding: 0; }
.topic-nav-prev { justify-self: start; text-align: left; }
.topic-nav-next { justify-self: end; text-align: right; }
.topic-nav-meta {
  font-family: var(--font-mono); font-weight: var(--fw-mono);
  font-size: var(--fs-xs); color: var(--text-soft); white-space: nowrap;
}
.topic-nav-title {
  display: block; max-width: 100%;
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  color: var(--text-strong);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topic-nav-all {
  justify-self: center; align-self: center;
  display: inline-flex; align-items: center;
  min-height: var(--tap); padding: 0 var(--sp-5);
  border-radius: var(--radius-md);
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  text-decoration: none; white-space: nowrap;
}

/* На узком экране три колонки навигации сжимаются до 37px, и от названия темы
   остаётся одна буква с многоточием. Ставим в столбец: лучше три полные строки,
   чем три обрубка. */
@media (max-width: 640px) {
  .topic-nav { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); }
  .topic-nav-side { width: 100%; }
  .topic-nav-prev, .topic-nav-next { justify-self: stretch; text-align: left; }
  .topic-nav-all { justify-self: stretch; justify-content: center; }
}

/* ── ХЛЕБНЫЕ КРОШКИ ───────────────────────────────────────────────────── */

.crumbs {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap; font-size: var(--fs-sm); color: var(--text-soft);
}
.crumbs a { color: var(--text-soft); text-decoration: none; }
.crumbs a:hover { color: var(--text-strong); text-decoration: underline; }
.crumbs .sep { color: var(--n-5); }
.crumbs .here { color: var(--text-strong); font-weight: var(--fw-medium); }

/* ── ФУТЕР ─────────────────────────────────────────────────────────────── */

footer.site {
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: var(--sp-3);
  padding: var(--sp-6) var(--page-pad);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--text-soft);
}
footer.site a { display: inline-flex; align-items: center; min-height: var(--tap); }

/* ── МАТЕМАТИКА (KaTeX) ────────────────────────────────────────────────────
   Кегль формулы НЕ увеличиваем глобально: раньше стояло 1.08em с nowrap,
   и на узком экране формула выпирала за край. Выключной формуле разрешено
   быть крупнее, но она умеет прокручиваться внутри себя. */

.katex { font-size: 1em; }
.katex-display {
  margin: var(--sp-4) 0;
  text-align: center;
  overflow-x: auto; overflow-y: hidden;
  overscroll-behavior-x: contain;
  padding-bottom: 2px;
}
.katex-display > .katex { font-size: 1.15em; }

/* Абзац, в котором только формула, центрируется вместе с ней */
p:has(> .katex-display:only-child),
p:has(> .katex:only-child) { text-align: center; }

/* Метки на чертежах — курсивная засечка, как в учебнике */
.svg-label, text.label {
  font-family: var(--font-math);
  font-style: italic;
}

/* ── ДВИЖЕНИЕ ──────────────────────────────────────────────────────────── */

.reveal {
  opacity: 0; transform: translateY(10px);
  animation: sup-reveal var(--dur-slow) var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}
@keyframes sup-reveal { to { opacity: 1; transform: none; } }

/* Обводка появляется прорисовкой — как будто чертят от руки */
@keyframes sup-draw { to { stroke-dashoffset: 0; } }
@keyframes sup-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sup-pop  { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }

.draw-in-stroke { animation: sup-draw var(--dur-slow) var(--ease-out) forwards; }
.draw-in-fade   { animation: sup-fade var(--dur-base) var(--ease-out) forwards; }
.draw-in-fill   {
  transform-box: fill-box; transform-origin: center;
  animation: sup-pop var(--dur-base) var(--ease-out) forwards;
}

/* Не «замедлить», а выключить: анимация появления обязана оставить элемент
   видимым, иначе при выключенном движении контент просто исчезнет. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal, .proof-step { opacity: 1; transform: none; animation: none; }
  .draw-in-stroke, .draw-in-fade, .draw-in-fill { animation: none; opacity: 1; }
}

/* ── ПЕЧАТЬ ────────────────────────────────────────────────────────────────
   Ученик распечатывает тему, чтобы решать ручкой. Фактура, интерактив
   и навигация на бумаге не нужны. */

@media print {
  body::before, .interactive-col, .viz-col, .topic-nav,
  header.page-header, header.site, footer.site, .theme-toggle { display: none !important; }
  .page-split { grid-template-columns: 1fr; }
  .card { border: 1px solid #999; box-shadow: none; break-inside: avoid; }
  .definition, .highlight, .memo, .mistake { break-inside: avoid; }
}
