/* ============ Общий слой компонентов Hodlometer ============
   Один исходник на оба движка: KURS (грузит напрямую) и тема /learn/ (получает копию
   через wp-theme/sync.mjs). Здесь всё, что видно на обоих сайтах и раньше было написано
   дважды: каркас, типографическая шкала, шапка, подвал, карточка, кнопка, чип, таблица,
   фокус, 404. Движок-специфичное живёт в app.css / public.css (KURS) и theme.css (WP);
   оба грузятся ПОСЛЕ этого файла и потому переопределяют его.

   Цвета, радиусы, тени, шрифты, кегли, отступы и высоты контролов — только токенами
   из :root в app.css. Магический px на font-size / padding / margin / gap / border-radius /
   высоте контрола — ошибка; хардкод цвета здесь сломает тёмную тему. */

/* ---------- Шкала на узких экранах ----------
   Переопределяем сами токены, а не каждое правило: одно место на оба движка.
   Брейкпоинты общие с остальной вёрсткой: 1000 / 860 / 640 / 430. */
@media (max-width: 860px) {
  :root {
    --fs-4xl: 52px; --fs-3xl: 38px; --fs-2xl: 30px; --fs-xl: 24px;
    --fs-h1: 32px; --fs-h1-hero: 34px; --fs-h2: 21px;
  }
}
@media (max-width: 640px) {
  :root {
    --fs-4xl: 44px; --fs-3xl: 32px; --fs-2xl: 26px; --fs-xl: 22px;
    --fs-h1: 30px; --fs-h1-hero: 29px; --fs-lg: 19px; --fs-prose: 16.5px;
    /* Ритм тоже токен: секции сжимаются с 56 до 32, сетка с 16 до 12, поля карточки с 20 до 16 */
    --space-section: var(--space-7);
    --space-page-top: var(--space-6);
    --gap-grid: var(--space-3);
    --pad-card: var(--space-4);
    --space-cta: var(--space-5);
  }
}
@media (max-width: 430px) {
  :root { --fs-h1-hero: 26px; }
}

/* ---------- База ---------- */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Якоря вели себя по-разному в двух движках: в /learn/ прокрутка была плавной, в KURS —
   мгновенной. Правило переезжает сюда, чтобы переход по «#mayer» из статьи в глоссарий
   ощущался одинаково. Отмена — в блоке prefers-reduced-motion внизу файла. */
html { scroll-behavior: smooth; }

/* min-height + flex — прижатый подвал: на короткой странице под ним оставалось до 541px фона */
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Ссылка внутри ПРИГЛУШЁННОГО текста подчёркивается всегда (WCAG 1.4.1 «Use of Color»).
   В обычном интерфейсном тексте ссылку отличает контраст с --ink, и цвета хватает; внутри
   .sub/.fine/.stat-sub соседний текст сам --muted, разница с --brand падает ниже 3:1, и цвет
   остаётся единственным признаком — Lighthouse ловил это на карточке ETH/BTC. Толщина и
   отступ — те же, что у ссылок лонгрида ниже, чтобы приём был один на весь сайт. */
.sub a, .fine a, .stat-sub a, .legend-note a, .al-note a {
  text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.sub a:hover, .fine a:hover, .stat-sub a:hover, .legend-note a:hover, .al-note a:hover {
  text-decoration-thickness: 2px;
}
/* …кроме подсказок глоссария: у них своя пунктирная линия, две подряд читаются как дефект */
.sub .term a, .fine .term a, .stat-sub .term a { text-decoration: underline dotted; }

img, video { max-width: 100%; height: auto; }
svg { max-width: 100%; }

/* Space Grotesk — только «вывеска»: лого и заголовки. Цифры и текст остаются на Inter */
h1, h2, h3, .logo-word, .section-title, .eyebrow, .hero-title, .card-title, .tool-title, .err-title {
  font-family: var(--font-display);
  letter-spacing: -.015em;
}
h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: -.025em; }
h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); }
h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); }

/* Заголовок не должен ронять одно слово в последнюю строку («now?» само по себе);
   в абзацах балансировка дорога — там достаточно запрета висячих строк. */
h1, h2, .lede, .hero-title, .card-title, .err-title { text-wrap: balance; }
p { text-wrap: pretty; }

::selection { background: var(--brand-bg); color: var(--brand-ink); }

/* ---------- Каркас ----------
   Две ширины на весь сайт: full — 1140 (содержимое .wrap за вычетом паддингов),
   prose — 720 (--measure-prose). Третьей быть не должно: от неё рваный правый край. */
.wrap { max-width: calc(var(--measure-full) + var(--space-8)); margin: 0 auto; padding: 0 var(--space-5); }
/* Расстояние «шапка → h1» задаётся здесь и только здесь — одинаково в обоих движках.
   Собственных верхних отступов у .page-head / .hero / .doc / .article-head быть не должно. */
main { display: block; flex: 1 0 auto; padding: var(--space-page-top) 0 var(--space-10); }
.prose-w { max-width: var(--measure-prose); }

/* ---------- Служебное ---------- */
/* top: -100px, а не translate: -50% -120%: при сдвиге на свою высоту тень оставалась
   видимой полоской по верхней кромке страницы */
.skip-link {
  position: absolute; top: -100px; left: 50%; translate: -50% 0;
  z-index: 100; background: var(--card); color: var(--ink);
  border: 1px solid var(--line); border-radius: 0 0 var(--radius-s) var(--radius-s);
  padding: var(--space-3) var(--space-5); font-weight: 600; box-shadow: var(--shadow);
}
.skip-link:focus { top: 0; text-decoration: none; }

/* Кольцо фокуса — брендовое во всём сайте, а не дефолтное браузерное.
   Контраст --focus к фону ≥3:1 в обеих темах (см. комментарий у токена). */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--radius-xs); }

/* Недоступное действие — единое правило на весь сайт. До D3a состояние не было
   определено нигде: отключённая кнопка выглядела обычной. */
[disabled], .is-disabled, .btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; pointer-events: none;
}

/* видно только скринридеру */
.vh, .screen-reader-text {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.nowrap { white-space: nowrap; }

/* ---------- Иконки (спрайт Lucide) ---------- */
.ic {
  width: 1.15em; height: 1.15em; flex: none;
  vertical-align: -0.18em;
  /* внешний <use> не наследует presentation-атрибуты спрайта — задаём обводку здесь */
  fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.ic-sm { width: 1em; height: 1em; }
.ic-lg { width: 1.4em; height: 1.4em; }
button .ic, .btn .ic, .nav a .ic { stroke-width: 2.2; }
.ic-hint { color: var(--muted); cursor: help; vertical-align: -0.15em; }
/* Кнопка-подсказка «?»: выглядит как иконка, но фокусируется и принимает тап.
   Зона нажатия --control-h-xs (24) — минимум для вспомогательного элемента внутри строки. */
.ic-hint-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-h-xs); height: var(--control-h-xs); padding: 0;
  border: 0; background: none; color: var(--muted); cursor: help;
  border-radius: var(--radius-pill); vertical-align: -0.35em;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.ic-hint-btn:hover { color: var(--ink); background: var(--neutral-bg); }
.ic-hint-btn .ic { vertical-align: 0; }

/* ---------- Надзаголовки ----------
   Подпись над h1 и метка секции — это НЕ уровень документа: всегда <p>, иначе в одном
   `h2` оказывались и 11.5-пиксельная метка, и 26-пиксельный заголовок раздела. */
.eyebrow, .section-title {
  margin: 0 0 var(--space-2);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .08em;
  line-height: 1.4; text-transform: uppercase;
}
.eyebrow { color: var(--brand); }
.eyebrow.dim { color: var(--muted); }
/* Надзаголовок инструмента и симулятора несёт крошку («TOOLS» вёл в никуда, хотя
   ld_breadcrumb() отдавал поисковику полную цепочку). Крошка по контракту B6: без
   подчёркивания в покое, подчёркивание по наведению, текущая страница не выводится. */
.eyebrow a { color: inherit; text-decoration: none; }
.eyebrow a:hover { text-decoration: underline; text-underline-offset: 2px; }
.section-title { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-block); color: var(--muted); }
.section-title .ic { color: var(--muted); }

.lede { font-size: var(--fs-prose); line-height: 1.55; color: var(--ink2); margin: 0 0 var(--space-6); }
.fine { font-size: var(--fs-sm); color: var(--muted); }
.fine a { color: var(--brand); }

/* ---------- Шапка ----------
   Высота фиксированная (62px + рамка = 63px): при min-height нав на узких экранах
   переносилась вторым рядом и высота шапки гуляла от страницы к странице.
   Ниже 860px нав уезжает в .mnav под бургер. */
.topbar {
  background: var(--card);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 40;
}
.topbar-in { display: flex; align-items: center; gap: var(--space-6); height: 62px; }

.logo { display: flex; align-items: center; gap: var(--space-2); color: var(--ink); }
.logo:hover { text-decoration: none; }
.logo img, .logo svg { display: block; }
/* Лок-ап: колонка вместо <br> — зазор между строками контролируется line-height,
   а суммарная высота текста (21+14px) оптически совпадает с иконкой 34px. */
.logo > span { display: flex; flex-direction: column; }
.logo-word { font-size: var(--fs-lg); font-weight: 700; letter-spacing: -.015em; line-height: 1.05; }
/* --ink2, а не --muted: мелкий кегль — берём более контрастную ступень */
.logo-sub { font-size: var(--fs-xs); color: var(--ink2); letter-spacing: .01em; line-height: 1.15; white-space: nowrap; }

.nav { display: flex; gap: var(--space-1); flex: 1; }
.nav a {
  display: inline-flex; align-items: center; gap: var(--space-2);
  height: var(--control-h-sm); padding: 0 var(--space-4); border-radius: var(--radius-pill);
  color: var(--ink2); font-weight: 600; font-size: var(--fs-base);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav a:hover { background: var(--neutral-bg); color: var(--ink); text-decoration: none; }
.nav a.active { background: var(--brand-bg); color: var(--brand-ink); }

.topbar-right { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; font-size: var(--fs-sm); color: var(--ink2); }

/* Кнопка-иконка (тема, бургер). Фон --card, а не transparent: кнопка встречается и вне
   шапки (плавающий переключатель темы на /login), там прозрачная сливалась бы с фоном. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--control-h-sm); height: var(--control-h-sm); flex: none;
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--card); color: var(--ink2); cursor: pointer; padding: 0;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.icon-btn:hover { border-color: var(--muted); color: var(--ink); background: var(--neutral-bg); }
.icon-btn:active { transform: translateY(1px); }
.icon-btn .ic { width: 1.05em; height: 1.05em; }
.burger { display: none; }

/* Мобильное меню — раскрывается бургером (data-nav-toggle в ui.js / theme.js).
   Раскрытие анимируется CSS-ом, без участия JS: тот только снимает атрибут hidden.
   Приём — grid-template-rows 0fr↔1fr (высота содержимого заранее не известна, а анимировать
   max-height «на глазок» значит либо обрезать длинное меню, либо тормозить короткое).
   display в списке transition с allow-discrete: без него уход в hidden = display:none
   выключал бы панель мгновенно и сворачивание не было бы видно. @starting-style задаёт
   точку, ИЗ которой едет открытие: только что показанный элемент иначе стартует уже в 1fr.
   Без JS панель остаётся с hidden — то есть свёрнутой, как и было. */
.mnav {
  border-top: 1px solid var(--line); background: var(--card);
  display: grid; grid-template-rows: 1fr;
  transition: grid-template-rows var(--dur) var(--ease),
              display var(--dur) var(--ease) allow-discrete;
}
.mnav[hidden] { display: none; grid-template-rows: 0fr; }
@starting-style { .mnav:not([hidden]) { grid-template-rows: 0fr; } }
/* min-height: 0 — без него grid-элемент не сжимается ниже min-content и 0fr ничего не даёт */
.mnav > .wrap { overflow: hidden; min-height: 0; }
.mnav .wrap { display: flex; flex-direction: column; padding-top: var(--space-2); padding-bottom: var(--space-3); }
.mnav a { padding: var(--space-3); border-radius: var(--radius-s); color: var(--ink2); font-weight: 600; }
.mnav a:hover { background: var(--neutral-bg); color: var(--ink); text-decoration: none; }
.mnav a.active { background: var(--brand-bg); color: var(--brand-ink); }

/* ---------- Подвал ----------
   Четыре колонки, фон прозрачный (страница просвечивает): плоский ряд ссылок на белой
   карточке читался как ещё одна секция контента. */
.site-foot {
  margin-top: var(--space-11); padding: var(--space-7) 0 var(--space-9);
  border-top: 1px solid var(--line);
  color: var(--ink2); font-size: var(--fs-sm); font-weight: 400; line-height: 1.5;
}
/* Колонки — грид с равным шагом: у flex + space-between интервалы гуляли 88/265/223px */
.site-foot-in { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 3fr); gap: var(--space-7) var(--space-8); }
.foot-brand .logo { margin-bottom: var(--space-2); }
.foot-brand p { margin: 0; max-width: 40ch; color: var(--ink2); }
.foot-nav { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-8); }
.foot-nav div { display: flex; flex-direction: column; gap: var(--space-2); }
.foot-nav .eyebrow { margin-bottom: var(--space-1); }
.foot-nav a { color: var(--ink2); }
.foot-nav a:hover { color: var(--brand); }
.foot-legal {
  grid-column: 1 / -1; margin: 0; padding-top: var(--space-5);
  border-top: 1px solid var(--line-soft); max-width: 90ch;
}
.foot-fine { grid-column: 1 / -1; margin: 0; font-size: var(--fs-xs); color: var(--muted); }

/* ---------- Карточка ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--pad-card);
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.card h2, .card h3, .card-title { font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: 700; margin: 0 0 var(--space-1); }
/* заголовки карточек дашборда несут иконку — она должна стоять в одной строке с текстом */
.card h2, .card h3 { display: flex; align-items: center; gap: var(--space-2); }
.card h2 .ic, .card h3 .ic { color: var(--muted); }
/* а эти двое — обычный текст, и в пустом состоянии он центрируется по карточке */
.card-title, .empty-state h2 { display: block; }
.card .sub { color: var(--muted); font-size: var(--fs-xs); }

/* Анатомия карточки статьи — одна на оба движка: обложка (если есть), заголовок,
   выжимка, мета внизу. Рубрика — чипом в мете, не отдельной строкой над заголовком. */
.post-card { display: flex; flex-direction: column; gap: var(--space-3); padding: 0; overflow: hidden; color: var(--ink); }
.post-card:hover { box-shadow: var(--shadow-hover); text-decoration: none; }
.card-thumb { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: var(--card-2); }
.card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* flex:1 + margin-top:auto — мета прижата к низу карточки, в ряду не пляшет */
.card-body { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--pad-card); flex: 1 0 auto; }
.card-title { margin: 0; }
.card-title a { color: var(--ink); }
.card-title a:hover { color: var(--brand); text-decoration: none; }
.card-excerpt { margin: 0; color: var(--ink2); font-size: var(--fs-base); flex: 1; }
.post-card .meta-row { margin-top: auto; }

/* Мета записи */
.meta-row {
  display: flex; align-items: center; gap: var(--space-2) var(--space-4); flex-wrap: wrap;
  font-size: var(--fs-sm); color: var(--ink2); font-variant-numeric: tabular-nums;
}
.meta-item { display: inline-flex; align-items: center; gap: var(--space-2); }
/* все пункты меты одного веса: выделенный «Updated» читался важнее даты публикации */
.meta-item.upd { color: var(--ink2); font-weight: inherit; }

/* ---------- Кнопки ----------
   Высота — одна из трёх токенных (40 / 32); вес 600, а не 700: на заливке бренда
   700 читался крикливо. Максимум одна primary в блоке. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--control-h); padding: 0 var(--space-4);
  background: var(--brand-solid); color: var(--on-solid);
  border: 1px solid transparent; border-radius: var(--radius-s);
  font: inherit; font-size: var(--fs-base); font-weight: 600;
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* text-decoration: none — глобальный a:hover иначе подчёркивает подпись кнопки-ссылки */
.btn:hover { background: var(--brand-hover); color: var(--on-solid); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn.secondary { background: var(--card); color: var(--ink); border-color: var(--line); }
.btn.secondary:hover { background: var(--neutral-bg); color: var(--ink); }
.btn.danger { background: var(--down); }
.btn.sm { height: var(--control-h-sm); padding: 0 var(--space-3); font-size: var(--fs-sm); }

/* ---------- Чип ----------
   Одна пилюля на все роли. Модификаторы: состояние (up/down/flat/warn), зона термометра
   (zone + z1…z5), рубрика (cat), тег (tag), статус инструмента (live/soon).
   Раньше это были четыре независимых класса с разной высотой, радиусом и кеглем.
   Чип обязан нести различие: если у всех элементов набора он одинаков — не выводится. */
.chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  min-height: var(--control-h-xs); padding: 0 var(--space-3); border-radius: var(--radius-pill);
  font-size: var(--fs-xs); font-weight: 600; line-height: var(--lh-xs);
  color: var(--ink2); background: var(--neutral-bg);
}
.chip.up { color: var(--up); background: var(--up-bg); }
.chip.down { color: var(--down); background: var(--down-bg); }
.chip.warn { color: var(--warn); background: var(--warn-bg); }
.chip.flat { color: var(--ink2); background: var(--neutral-bg); }
.chip.brand, .chip.cat, .chip.live { color: var(--brand-ink); background: var(--brand-bg); }
a.chip:hover { text-decoration: none; filter: brightness(.97); }
/* контурные: тег ведёт в архив, «coming soon» стоит на карточке без заливки —
   у обоих --neutral-bg совпал бы с фоном страницы и пилюля пропала бы */
.chip.tag, .chip.soon { background: none; border: 1px solid var(--line); color: var(--ink2); }
.chip.tag:hover { border-color: var(--muted); color: var(--ink); filter: none; }
/* зоны термометра: <span class="chip zone z4">Warm</span> */
.chip.zone::before { content: ""; width: 8px; height: 8px; border-radius: var(--radius-pill); background: currentColor; opacity: .85; flex: none; }
.chip.z1 { background: var(--therm-1-bg); color: var(--therm-1-ink); }
.chip.z2 { background: var(--therm-2-bg); color: var(--therm-2-ink); }
.chip.z3 { background: var(--therm-3-bg); color: var(--therm-3-ink); }
.chip.z4 { background: var(--therm-4-bg); color: var(--therm-4-ink); }
.chip.z5 { background: var(--therm-5-bg); color: var(--therm-5-ink); }

/* ---------- Таблицы ----------
   Шапка — одна линейка 1px --line (2px в тёмной теме давали яркую полосу),
   ячейки выровнены по верху, числовые колонки вправо.
   Таблицы и оси — одно из четырёх мест, где tabular-nums уместен. */
/* ячейки core-блока WP приходят с border: 1px по всем сторонам, thead/tfoot — ещё 3px currentColor */
.prose th, .prose td, .prose thead, .prose tfoot { border: 0; }
.tbl, .prose table {
  width: 100%; border-collapse: collapse;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.tbl th, .prose th {
  text-align: left; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); font-weight: 700; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.tbl td, .prose td { padding: var(--space-3); border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.tbl tr:last-child td, .prose tr:last-child td { border-bottom: 0; }
.tbl .num, .tbl th.num, .tbl .r, .prose .num { text-align: right; }
/* крайние колонки заподлицо с текстом — иначе таблица в колонке чтения съезжает вправо */
.tbl th:first-child, .tbl td:first-child, .prose th:first-child, .prose td:first-child { padding-left: 0; }
.tbl th:last-child, .tbl td:last-child, .prose th:last-child, .prose td:last-child { padding-right: 0; }
/* Строка «где мы сейчас» в таблице распределения: подложка + полужирный, без цвета.
   Цвет здесь уже занят зоной (контракт B3), а вторая цветовая кодировка в одной строке
   читается как ещё одна категория. Тот же приём, что у .hv-lead на /tools/halving. */
.tbl tr.is-now > td { background: var(--neutral-bg); font-weight: 600; }

.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------- Лонгрид ----------
   Колонка чтения 720px, 17px/1.7 — одинаково в статьях /learn/ и в документах KURS
   (/about, /methodology). Раньше KURS давал 15px/1.5 на 780px: ~95–100 знаков в строке. */
.prose, .doc {
  max-width: var(--measure-prose);
  font-size: var(--fs-prose); line-height: var(--lh-prose); color: var(--ink);
  /* h3 из общей шкалы (17px) совпал бы с текстом лонгрида — здесь ступень выше */
  --fs-h3: var(--fs-lg);
}
.prose h2, .doc h2 {
  font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: 700;
  margin: var(--space-8) 0 var(--space-4); scroll-margin-top: 84px;
}
.prose h3, .doc h3 {
  font-size: var(--fs-h3); line-height: 1.3; font-weight: 700;
  margin: var(--space-7) 0 var(--space-3); scroll-margin-top: 84px;
}
.prose h4, .doc h4 { font-size: var(--fs-h3); margin: var(--space-6) 0 var(--space-2); font-weight: 700; }
.prose p, .doc p { margin: 0 0 var(--space-5); }
.prose ul, .prose ol, .doc ul, .doc ol { margin: 0 0 var(--space-5); padding-left: var(--space-6); }
.prose li, .doc li { margin-bottom: var(--space-2); }
.prose li::marker, .doc li::marker { color: var(--muted); }
/* Инлайн-ссылки подчёркиваются: одного цвета мало — контраст ссылки к тексту
   3.2:1 в светлой и 2.27:1 в тёмной, то есть ниже порога «различимо без подчёркивания». */
.prose a, .doc a, main p a:not(.btn), main li a:not(.btn) {
  text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px;
}
.prose a:hover, .doc a:hover { text-decoration-thickness: 2px; }

/* ---------- Термин с подсказкой ----------
   Разметка приходит с сервера из хелпера term() (app/services/glossary.php):
   <span class="term"><a class="term-w" href="/glossary#key" …>Mayer Multiple</a>
   <span class="term-pop" role="tooltip" hidden>…</span></span>

   Без JS подсказка остаётся скрытой атрибутом hidden, а термин — обычной ссылкой на
   глоссарий; показывает её assets/js/term.js по наведению и по фокусу (Esc закрывает).
   Определение всё равно доходит до скринридера: ссылка ссылается на него aria-describedby,
   а такой текст читается даже у скрытого элемента.

   Селектор `.term > a.term-w`, а не `.term-w`: блок лонгрида выше задаёт сплошное подчёркивание
   селектором `main p a:not(.btn)` — три элемента и класс, — и одиночный класс его не перебивает.
   Два класса перевешивают, сколько бы элементов ни было во втором селекторе. */
.term { position: relative; }
.term > a.term-w {
  color: inherit;
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: help;
}
.term > a.term-w:hover, .term > a.term-w:focus-visible {
  color: var(--brand-ink);
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
}

/* pointer-events: none — курсор не должен «заходить» в подсказку: иначе уход мыши с
   термина на неё считался бы уходом со ссылки и она моргала бы. Ссылок внутри нет.

   Появление: 120 мс fade с подъёмом на 3px — мгновенные 320×154 под курсором читались
   как глюк отрисовки. Закрытие намеренно мгновенное: анимировать исчезновение подсказки
   значит задерживать следующую, а по строке текста мышь идёт быстрее любой анимации.
   Подъём через --term-y: translate по X уже занят подстройкой под край экрана (term.js). */
.term-pop {
  position: absolute; z-index: 60;
  top: calc(100% + var(--space-2)); left: 0;
  translate: var(--term-x, 0px) 0;
  animation: term-in var(--dur-fast) var(--ease);
  width: max-content; max-width: min(320px, calc(100vw - var(--space-7)));
  padding: var(--space-3);
  background: var(--card); color: var(--ink2);
  border: 1px solid var(--line); border-radius: var(--radius-s);
  box-shadow: var(--shadow-pop);
  font-family: var(--font); font-size: var(--fs-sm); line-height: 1.5;
  font-weight: 400; font-style: normal; letter-spacing: normal; text-align: left;
  text-transform: none; white-space: normal;
  pointer-events: none;
}
.term-pop.up { top: auto; bottom: calc(100% + var(--space-2)); animation-name: term-in-up; }
.term-pop b { display: block; margin-bottom: var(--space-1); color: var(--ink); font-weight: 700; }
.term-pop .term-go { display: block; margin-top: var(--space-2); color: var(--muted); font-size: var(--fs-xs); }
/* Подсказка, открытая вниз, выезжает снизу вверх; открытая вверх — сверху вниз:
   в обоих случаях она «выходит из-под» термина, а не наезжает на него. */
@keyframes term-in { from { opacity: 0; translate: var(--term-x, 0px) 3px; } }
@keyframes term-in-up { from { opacity: 0; translate: var(--term-x, 0px) -3px; } }
/* На тач-устройстве первый тап открывает подсказку (term.js гасит переход), и «Full entry
   in the glossary →» становится подсказкой, что делает второй тап. Ссылки внутри по-прежнему
   нет — тапается сам термин, поэтому pointer-events остаются выключенными. */
@media (hover: none) {
  .term-pop .term-go { color: var(--brand); font-weight: 600; }
}

/* ---------- Мостик в глоссарий ----------
   Компактная строка рядом с дисклеймером в статьях /learn/ и под лидом инструментов. */
.gloss-note {
  display: flex; gap: var(--space-3); align-items: flex-start;
  margin: var(--space-7) 0 0; padding: var(--space-3) var(--space-4);
  background: var(--card-2); color: var(--ink2);
  border: 1px solid var(--line-soft); border-radius: var(--radius-s);
  font-size: var(--fs-sm); line-height: 1.55;
  max-width: var(--measure-prose);
}
.gloss-note .ic { flex: none; margin-top: 2px; color: var(--muted); }
.gloss-note b { color: var(--ink); font-weight: 700; }
/* Ссылка здесь лежит в <div>, а не в <p>, и правило подчёркивания лонгрида её не ловило:
   в потоке текста она отличалась только цветом (Lighthouse link-in-text-block на статьях). */
.gloss-note a { text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }

/* ---------- Колонка чтения с боковиком ----------
   Переехало из темы /learn/: длинные документы KURS (/methodology 6218px, /about,
   /tools/mayer, /tools/halving) имели якорные h2, но не имели оглавления — внутри одного
   сайта получались два разных опыта чтения. Теперь раскладка одна на оба движка.
   Побочный и намеренный эффект: на этих страницах появляется правая колонка — та самая,
   куда по ROADMAP лягут будущие баннеры (правило «максимум 2 слота, без попапов»). */
.article-layout {
  display: grid;
  grid-template-columns: minmax(0, var(--measure-prose)) var(--side);
  gap: var(--space-9); align-items: start;
}
/* Та же причина, что у `.grid > *`: у grid-элемента min-width по умолчанию auto, то есть
   его min-content. Формула и широкая таблица внутри /methodology держали колонку в 475px
   при доступных 343 — и страница на 375px ехала вбок. Ноль возвращает право сжиматься,
   а прокрутку берут на себя .tbl-wrap / .doc .tbl. */
.article-layout > * { min-width: 0; }
/* оглавление едет со страницей; max-height — чтобы длинный список не уезжал за экран */
.article-side { position: sticky; top: 80px; max-height: calc(100vh - 100px); overflow-y: auto; overscroll-behavior: contain; }

.toc {
  border-left: 1px solid var(--line);
  padding: 2px 0 2px var(--space-4);
  font-size: var(--fs-sm);
}
.toc-title {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink2); margin-bottom: var(--space-2);
  list-style: none;   /* треугольник <summary> заменяем своим — он читается как маркер списка */
}
.toc-title::-webkit-details-marker { display: none; }
/* На широком экране оглавление всегда раскрыто, и summary — просто заголовок */
.toc-d[open] > .toc-title { cursor: default; }
.toc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
/* Подчёркивание снимается явно: в KURS оглавление стоит рядом с .doc, и его правило
   `.doc a { text-decoration: underline }` протекало бы в навигацию (аудит A53). */
.toc-list a { color: var(--ink2); text-decoration: none; transition: color var(--dur-fast) var(--ease); }
.toc-list a:hover { color: var(--brand); text-decoration: none; }
.toc-list .lvl-3 { padding-left: var(--space-4); font-size: var(--fs-sm); }
/* активный пункт: ставит theme.js (/learn/) или ui.js (KURS) по позиции скролла.
   Цветная планка слева — второе кодирование помимо веса: одним жирным пункт не находится. */
.toc-list li { position: relative; }
.toc-list a.is-current { color: var(--ink); font-weight: 700; }
.toc-list a.is-current::before {
  content: ""; position: absolute; left: calc(var(--space-4) * -1 - 1px); top: 0; bottom: 0;
  width: 1px; background: var(--brand); box-shadow: 0 0 0 1px var(--brand);
}

/* ---------- Поделиться статьёй ----------
   Три обычные ссылки и одна кнопка: ни одного SDK, ни одного внешнего запроса, ни одной
   куки. Кнопки соцсетей в их «родном» виде тянут скрипты и трекеры — здесь это просто
   intent-адреса, которые открывают форму публикации уже у самого пользователя. */
.share {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  margin: var(--space-7) 0 0; max-width: var(--measure-prose);
}
.share-lbl { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-right: var(--space-1); }
.share .btn { flex: none; }
.share .btn.sm { gap: var(--space-2); }

/* ---------- 404 ---------- */
.error-404 { text-align: center; padding: var(--space-10) var(--space-6); }
.err-code {
  font-family: var(--font-display); font-size: var(--fs-4xl); font-weight: 700; line-height: var(--lh-4xl);
  color: var(--brand-2); font-variant-numeric: tabular-nums;
}
.err-title { font-size: var(--fs-h2); line-height: var(--lh-h2); margin: var(--space-4) 0 var(--space-2); }
.err-sub { color: var(--ink2); margin: 0 auto var(--space-6); max-width: 460px; }
.err-links { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; margin-top: var(--space-5); }
/* Остальные выходы — компактной строкой, а не рядом равновесных кнопок: шесть primary
   рядом заставляют прочесть все шесть, вместо того чтобы предложить один очевидный. */
.err-more {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-1) var(--space-2);
  margin: var(--space-5) auto 0; max-width: 60ch; font-size: var(--fs-sm); color: var(--ink2);
}
/* --muted, а не --line: на 13px разделитель цветом линии даёт 1.31:1 — он не «тихий»,
   он невидимый. Остальные точки-разделители на сайте и так --muted. */
.err-more .dot { color: var(--muted); }

/* ---------- Пустое состояние ---------- */
.empty-state { text-align: center; padding: var(--space-9) var(--space-6); }
.empty-state h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); margin: 0 0 var(--space-2); }
.empty-state p { color: var(--ink2); margin: 0 auto var(--space-5); max-width: 460px; }

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

   Оставлено мгновенным намеренно: кольцо фокуса (задержка ломает ориентацию при табе),
   перерисовка графика при смене диапазона, смена активной сегментной кнопки (слайд пилюли
   обещал бы связность, которой в данных нет), значения цифр — никаких count-up. */

/* Появление данных на месте скелетона: только opacity, 200 мс. translateY здесь намеренно
   нет — сдвиг вернул бы ровно тот CLS, ради которого скелетоны и держат высоту. */
@keyframes data-in { from { opacity: 0; } }

/* Нажатие — transform в списке переходов: :active даёт translateY(1px) (контракт B5),
   и без перехода отпускание кнопки щёлкает. Длительности берутся из собственных
   шорткатов компонентов (все --dur-fast), здесь дописывается только сам список свойств. */
.btn, .icon-btn, .user-trigger { transition-property: background, color, border-color, box-shadow, transform; }

/* Переключение темы — кроссфейд 200 мс и только на время переключения.
   Класс вешает applyTheme() (ui.js / theme.js) и снимает через --dur, поэтому ПЕРВАЯ
   отрисовка страницы кроссфейда не получает: сервер уже отдал верную тему в <html>.
   `html.theme-switching *` = специфичность (0,1,1) и стоит последним в файле — этого
   хватает, чтобы перебить собственные transition компонентов без !important (запрет B8). */
html.theme-switching *,
html.theme-switching *::before,
html.theme-switching *::after {
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), fill var(--dur) var(--ease),
              stroke var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

/* ---------- Адаптив ---------- */
@media (max-width: 1000px) {
  /* Боковик уходит НАД текстом: оглавление в одну колонку под статьёй бесполезно */
  .article-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .article-side { position: static; order: -1; margin-bottom: var(--space-6); max-width: var(--measure-prose); max-height: none; overflow: visible; }
  .toc { border-left: 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: var(--space-4) 0; }
  .toc-list a.is-current::before { display: none; }
}
@media (max-width: 860px) {
  /* Свёрнутое оглавление: раскрытое оно съедало ~220px первого экрана и отодвигало h1
     за сгиб, а скролл-спай на телефоне всё равно бесполезен. Атрибут open снимает
     ui.js / theme.js по этому же брейкпоинту; без JS остаётся раскрытым — то есть
     ровно как было, деградация не ухудшается. */
  .toc-d > .toc-title { cursor: pointer; margin-bottom: 0; }
  .toc-d[open] > .toc-title { cursor: pointer; margin-bottom: var(--space-2); }
  .toc-d > .toc-title::after {
    content: ""; margin-left: auto; width: 8px; height: 8px;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    rotate: 45deg; translate: 0 -2px;
    transition: rotate var(--dur-fast) var(--ease);
  }
  .toc-d[open] > .toc-title::after { rotate: 225deg; translate: 0 2px; }
}
@media (max-width: 860px) {
  .nav { display: none; }
  .burger { display: inline-flex; }
  .topbar-in { gap: var(--space-3); }
  .site-foot-in { grid-template-columns: 1fr; gap: var(--space-6); }
}
@media (min-width: 861px) {
  .mnav { display: none; }
}
@media (max-width: 640px) {
  .wrap { padding: 0 var(--space-4); }
  main { padding-bottom: var(--space-8); }
  .logo-sub { display: none; }
  .logo img, .logo svg { width: 28px; height: 28px; }
  .logo-word { font-size: var(--fs-h3); }
  /* Бургер и переключатель темы — самые нажимаемые кнопки сайта, а на телефоне они были
     32×32 при рекомендованном минимуме 40. Растёт только зона нажатия, не иконка. */
  .icon-btn { width: var(--control-h); height: var(--control-h); }
  /* Три колонки подвала на 375px переносились по словам — на узком экране их две */
  .foot-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); }
  .site-foot { margin-top: var(--space-9); padding: var(--space-6) 0 var(--space-7); }
  .share { gap: var(--space-2); }
}
@media (max-width: 430px) {
  .topbar-in { gap: var(--space-2); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  html { scroll-behavior: auto; }
}
