/**
 * Стили статьи учебника: типографика текста/картинок + рамка виджетов + sticky-сайдбар.
 *
 * Подключить ПОСЛЕ design-tokens.css (использует его переменные --color-*, --radius-*,
 * --shadow-* — см. design_handoff_article_style/reference/colors_and_type.css /
 * static/css/design-tokens.css в самом проекте сайта).
 *
 * Заменяет собой Tailwind Typography (`prose prose-lg dark:prose-invert`), который в
 * article_detail.html ничего не делает — в сборке tailwind.input.css нет
 * @tailwindcss/typography, поэтому markdown-контент (text-блоки) рендерился голым HTML.
 */

/* ============================================================
   ТИПОГРАФИКА СТАТЬИ — .article-body
   Оборачивает { % for block in blocks % } — заменяет class="prose prose-lg dark:prose-invert"
   ============================================================ */

/* ============================================================
   КОЛОНКА СТАТЬИ — .article-column
   Ширина 80% доступного места (после сайдбара) с центрированием: на широких
   экранах статья перестаёт висеть у левого края. На мобильных — во всю ширину
   с обычными полями, иначе 80% дают слишком узкую колонку.
   ============================================================ */
.article-column {
  max-width: 80%;
  margin-left: auto;
  margin-right: auto;
}
@media (max-width: 767px) {
  .article-column { max-width: 100%; padding-left: 24px; padding-right: 24px; }
}

/* Шкала шрифта объявлена на колонке, а не на .article-body: так H1 статьи,
   H2 блоков, таблицы и подписи к картинкам масштабируются заодно с markdown-
   текстом. По умолчанию "large" (крупный), одобрено в дизайн-ревью. Меняйте
   переменные ниже (или переключайте класс .article-column--normal), а не
   переопределяйте font-size у конкретных тегов. */
.article-column {
  --fs-h1: 30px;
  --fs-h2: 24px;
  --fs-p: 18px;
  --fs-li: 18px;
  --fs-cap: 14px;
  --fs-table: 16px;
  --lh-p: 1.8; /* @kind font */
  --lh-li: 1.75; /* @kind font */
}

/* Компактный вариант (опционально) — навесить class="article-column article-column--normal" */
.article-column--normal {
  --fs-h1: 24px;
  --fs-h2: 20px;
  --fs-p: 16px;
  --fs-li: 16px;
  --fs-cap: 12px;
  --fs-table: 14px;
  --lh-p: 1.75; /* @kind font */
  --lh-li: 1.7; /* @kind font */
}

/* Заголовок статьи и заголовки блоков — та же шкала, что и текст внутри. */
.article-title {
  font-size: var(--fs-h1); font-weight: 700; line-height: 1.2;
  color: var(--color-text-heading);
}
.article-block-title {
  font-size: var(--fs-h2); font-weight: 700; margin: 0 0 14px;
  color: var(--color-text-heading);
}

.article-body h1 { font-size: var(--fs-h1); font-weight: 700; color: var(--color-text-heading); margin: 0 0 10px; }
.article-body h2 { font-size: var(--fs-h2); font-weight: 700; color: var(--color-text-heading); margin: 0 0 14px; }
.article-body p { font-size: var(--fs-p); line-height: var(--lh-p); color: var(--color-text-default); margin: 0 0 16px; }
.article-body p:last-child { margin-bottom: 0; }
/* list-style обязателен: Tailwind Preflight глушит маркеры у всех ul/ol
   правилом `ol, ul, menu { list-style: none }`, и без этой строки список
   выводится без точек. Вводный блок (.article-lead__text) рендерится тем же
   markdownify, поэтому списки в нём стилизуются здесь же — иначе «О чём этот
   урок» показывает пункты сплошным текстом. Карточки «Коротко» и «Что нас
   ждёт» намеренно не входят сюда: у них свои маркеры через li::before. */
:is(.article-body, .article-lead__text) :is(ul, ol) { margin: 0 0 16px; padding-left: 22px; }
:is(.article-body, .article-lead__text) ul { list-style: disc; }
:is(.article-body, .article-lead__text) ol { list-style: decimal; }
:is(.article-body, .article-lead__text) li::marker { color: var(--color-brand-600); }
:is(.article-body, .article-lead__text) li { font-size: var(--fs-li); line-height: var(--lh-li); color: var(--color-text-default); margin-bottom: 6px; }
:is(.article-body, .article-lead__text) li:last-child { margin-bottom: 0; }
.article-body strong { color: var(--color-text-heading); font-weight: 600; }

/* Ссылок в текстах уроков раньше не было, поэтому и стиля не было: Tailwind
   Preflight оставляет <a> цветом обычного текста, и ссылка не читалась как
   ссылка. Ссылки открываются в новой вкладке (target проставляется
   в markdownify), подчёркивание — со смещением, чтобы не резать кириллицу.
   Первый текстовый блок статьи рендерится как .article-lead__text, а не
   .article-body, поэтому селектор перечисляет оба — иначе ссылка в лид-абзаце
   остаётся чёрной, как это и случилось в разборе задания 2. */
:is(.article-body, .article-lead__text) a {
  color: var(--color-brand-600);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  transition: color .15s;
}
:is(.article-body, .article-lead__text) a:hover { color: var(--color-brand-700); }
html.dark :is(.article-body, .article-lead__text) a { color: #60a5fa; }
html.dark :is(.article-body, .article-lead__text) a:hover { color: var(--color-dark-accent); }

/* markdownify рендерит "> **Термин** — определение" как <blockquote>. Показываем как
   карточку-определение с лейблом, а не как обычную цитату. */
.article-body blockquote {
  background: var(--color-brand-50);
  border: 1px solid var(--color-brand-100);
  border-radius: var(--radius-md);
  padding: 16px 20px;
  margin: 0 0 18px;
  font-size: var(--fs-p);
  line-height: var(--lh-p);
  color: var(--color-text-default);
}
.article-body blockquote::before {
  content: "Определение";
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--color-brand-700);
  margin-bottom: 6px;
}
.article-body blockquote p { margin: 0; }

/* Таблицы бывают и в markdown-карточках («Коротко», вводка, «Что нас
   ждёт»), которые рисуются вне .article-body, — поэтому селекторы
   таблиц перечисляют все markdown-контейнеры сразу. */
/* border-collapse: separate — иначе скругление рамки не работает; двойных линий
   не будет, так как границы ячеек заданы только снизу и справа. */
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) table {
  width: 100%; margin: 0 0 18px; font-size: var(--fs-table);
  border-collapse: separate; border-spacing: 0;
  border: 1px solid var(--color-border-medium);
  border-radius: var(--radius-md); overflow: hidden;
}
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) th {
  text-align: left; padding: 10px 14px; font-weight: 600; color: var(--color-text-heading);
  background: var(--color-bg); border-bottom: 2px solid var(--color-border-medium);
  border-right: 1px solid var(--color-border-medium);
}
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) td {
  padding: 10px 14px; border-bottom: 1px solid var(--color-border-medium);
  border-right: 1px solid var(--color-border-medium);
  color: var(--color-text-default); vertical-align: top;
}
/* Первый столбец — «ключ» строки, поэтому выделен как заголовок. */
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) td:first-child { color: var(--color-text-heading); font-weight: 600; }
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) :is(th, td):last-child { border-right: none; }
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) tr:last-child td { border-bottom: none; }
/* Строка-ответ в таблице перебора: <mark> в любой её ячейке красит строку целиком.
   Markdown-таблица не даёт повесить класс на <tr>, а :has() в файле уже используется
   (см. pre:has(> code.language-figure)). Тон — тот же --color-brand-50, которым
   подсвечиваются угаданные строки виджетов: смысл один, и в тёмной теме он уже
   переопределён. Сам <mark> обесцвечиваем: браузерный жёлтый внутри залитой строки
   читается как вторая подсветка поверх первой. */
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) tr:has(mark) td { background: var(--color-brand-50); }
:is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) mark { background: none; color: inherit; }

.article-body figure { text-align: center; margin: 0 0 26px; }
/* Preflight Tailwind делает img блочным, поэтому text-align его не центрирует. */
.article-body img { margin-inline: auto; }
/* Иллюстрация показывается целиком: высоту задаёт сама картинка.
   Здесь стоял единый бокс 4:3 с object-fit: cover, и он срезал всё, что
   в эти пропорции не укладывалось – а срезал ровно то, ради чего картинка
   нарисована: таблица ASCII в уроке 7.2 (≈2.6:1) теряла верхнюю и нижнюю
   строки, лента цепочек в уроке 8.3 (≈2.4:1) – подписи cur/best слева
   и плашку ответа справа, снимок окна turtle в разборе задания 6 – верхнюю
   и нижнюю стороны прямоугольника. Каждый такой случай приходилось заводить
   исключением по имени файла, и список рос с каждой новой картинкой не 4:3
   (кадр журнала в разборе задания 3 – 3.3:1 – был бы четвёртым).
   Единообразие бокса того не стоит: обрезанная иллюстрация не «аккуратная»,
   она неверная. max-height – единственная страховка: очень высокий снимок
   (скриншот длинной страницы) иначе занял бы экран целиком. */
.article-body figure img {
  width: 800px; max-width: 100%;
  height: auto; max-height: 80vh; object-fit: contain;
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border-medium); box-shadow: var(--shadow-sm);
}

/* ============================================================
   ПОВТОРЯЮЩИЕСЯ БЛОКИ СТАТЬИ
   Три текстовых блока есть почти в каждом уроке, и шаблон узнаёт их
   по заголовку («Коротко», «Что нас ждёт в этом блоке») либо по позиции
   (первый блок — вводка). Содержимое приходит из markdownify, поэтому классы
   навешены на обёртки, а вложенные ul/li/p стилизуются потомками.
   ============================================================ */

/* ---- Вводка: первый текстовый блок урока (медальон-номер, вариант 3c) ---- */
.article-lead { background: var(--color-brand-50); border-radius: 16px; padding: 28px 30px; margin: 0 0 18px; }
.article-lead__head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.article-lead__medal {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: 12px;
  background: var(--color-brand-600); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 16px;
}
.article-lead__text { min-width: 0; }
.article-lead__text p {
  font-size: var(--fs-p); line-height: var(--lh-p);
  color: var(--color-text-default); margin: 0 0 12px;
}
.article-lead__text p:last-child { margin-bottom: 0; }
.article-lead__text strong { color: var(--color-text-heading); font-weight: 700; }

/* ---- «Коротко»: карточка-стикер с цветной шапкой (стиль 1b) ---- */
.article-summary-card {
  border: 1px solid var(--color-border-medium);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin: 0 0 18px;
}
.article-summary-card__head {
  background: var(--color-brand-600); padding: 12px 20px;
  display: flex; align-items: center; gap: 8px;
}
.article-summary-card__head span { font-size: 14px; font-weight: 700; color: #fff; }
.article-summary-card__body { padding: 18px 20px; background: var(--color-surface); }
.article-summary-card__body ul {
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 10px;
}
.article-summary-card__body li {
  font-size: var(--fs-li); line-height: var(--lh-li); color: var(--color-text-default);
  padding-left: 16px; position: relative; margin: 0;
}
.article-summary-card__body li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--color-brand-600);
}
.article-summary-card__body p { font-size: var(--fs-p); line-height: var(--lh-p); color: var(--color-text-default); margin: 0 0 10px; }
.article-summary-card__body p:last-child { margin-bottom: 0; }
.article-summary-card__body strong { color: var(--color-text-heading); font-weight: 600; }

/* ---- Разбор задания: закрыт до занятия, открывает учитель ----
   Родня .article-outlook-panel, но янтарная: янтарь во всём проекте означает
   «видно учителю» (панель ответа в тренажёре ЕГЭ), и разбор читается тем же
   цветом, что и ответ к задаче. Цвета заданы явно, а не токенами: токены
   статьи – это фирменный синий, а здесь нужен ровно чужой, предупреждающий
   оттенок. */
.article-solution {
  border: 1.5px solid #fde68a;
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin: 0 0 18px;
}
/* Шапка панели – это <summary>: клик по ней сворачивает разбор. Свою стрелку
   рисуем сами, потому что ::marker в Safari не поддаётся ни размеру, ни цвету. */
.article-solution__head {
  background: #fffbeb; padding: 14px 24px; cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.article-solution__head::-webkit-details-marker { display: none; }
.article-solution__head::after {
  content: "▾"; margin-left: auto; color: #b45309;
  transition: transform .15s;
}
.article-solution:not([open]) .article-solution__head::after { transform: rotate(-90deg); }
.article-solution__head span { font-size: 14px; font-weight: 700; color: #92400e; }
.article-solution__state { font-size: 12px; font-weight: 600; color: #b45309; }
.article-solution__actions { margin-top: 16px; }
.article-solution__toggle {
  font-size: 12px; font-weight: 600; cursor: pointer;
  padding: 6px 12px; border-radius: var(--radius-md);
  background: #f59e0b; color: #fff; border: none;
}
.article-solution__toggle:hover { background: #d97706; }
.article-solution__body { padding: 18px 24px; background: var(--color-surface); }
/* Заглушка ученику – та же рамка без содержимого: задание не выглядит
   брошенным без ответа, и разбор не идут искать на стороне. */
.article-solution--locked .article-solution__body {
  font-size: var(--fs-p); color: var(--color-text-muted);
}

/* ---- «Что нас ждёт в этом блоке»: панель с шапкой-вывеской (стиль 5a) ---- */
.article-outlook-panel {
  border: 1.5px solid var(--color-brand-100);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin: 0 0 18px;
}
.article-outlook-panel__head {
  background: var(--color-brand-50); padding: 14px 24px;
  display: flex; align-items: center; gap: 10px;
}
.article-outlook-panel__head span { font-size: 14px; font-weight: 700; color: var(--color-text-heading); }
.article-outlook-panel__body { padding: 18px 24px 20px; background: var(--color-surface); }
.article-outlook-panel__body p {
  font-size: var(--fs-p); line-height: var(--lh-p);
  color: var(--color-text-default); margin: 0 0 10px;
}
.article-outlook-panel__body p:last-child { margin-bottom: 0; }
.article-outlook-panel__body ul {
  margin: 0 0 12px; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 7px;
}
.article-outlook-panel__body li {
  font-size: var(--fs-li); line-height: var(--lh-li); color: var(--color-text-default);
  padding-left: 24px; position: relative; margin: 0;
}
/* Галочка псевдоэлементом: SVG-иконку из markdown-контента не вставить. */
.article-outlook-panel__body li::before {
  content: "✓"; position: absolute; left: 2px; top: 0;
  color: var(--color-brand-600); font-weight: 700;
}
.article-outlook-panel__body strong { color: var(--color-text-heading); font-weight: 600; }
.article-body figcaption {
  margin-top: 10px; font-size: var(--fs-cap); color: var(--color-text-muted); font-style: italic;
  max-width: 560px; margin-left: auto; margin-right: auto; line-height: 1.5;
}

/* ============================================================
   ТЁМНАЯ ТЕМА — переопределяем сами токены на контейнере статьи.
   base.html перекрашивает только Tailwind-классы (.text-gray-700 и т.п.), а вся
   типографика статьи написана на var(--color-*) — без этой карты текст остаётся
   тёмно-серым на тёмном фоне. Значения — из набора --color-dark-* дизайн-системы.
   Переменные наследуются, поэтому чинится всё поддерево разом: текст, таблицы,
   карточки-определения, подписи и виджеты.
   ============================================================ */
html.dark .article-column {
  --color-bg:            #0f172a;
  --color-surface:       #1e293b;
  --color-border:        #1e293b;
  --color-border-medium: #334155;
  --color-border-input:  #475569;

  --color-text-heading:  #f1f5f9;
  --color-text-default:  #cbd5e1;
  --color-text-body:     #94a3b8;
  --color-text-muted:    #94a3b8;
  --color-text-faint:    #64748b;

  /* Карточка-определение (blockquote) и подсветка угаданных строк виджета */
  --color-brand-50:  #172554;
  --color-brand-100: #1e3a8a;
  --color-purple-bg: #2e1065;
}
/* Янтарь панели разбора в тёмной теме: тот же смысл, приглушённый фон. */
html.dark .article-solution { border-color: #78350f; }
html.dark .article-solution__head { background: #451a03; }
html.dark .article-solution__head span { color: #fcd34d; }
html.dark .article-solution__state { color: #fbbf24; }

/* Шапка таблицы должна отличаться от фона страницы, а он в тёмной теме тоже --color-bg. */
html.dark :is(.article-body, .article-summary-card__body, .article-lead__text, .article-outlook-panel__body) th { background: #1e293b; }

/* ============================================================
   РАМКА ВИДЖЕТА — .textbook-widget
   Оборачивает { % elif block.block_type == 'widget' % } вместо голого div.
   Одинаковая для ЛЮБОГО виджета (top-answers, будущие форматы, даже тёмная
   «Своя игра» — своя палитра внутри не будет резко выбиваться из страницы).
   ============================================================ */

.textbook-widget {
  background: var(--color-surface);
  border: 1px solid var(--color-border-medium);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  margin-bottom: 22px;
}
.textbook-widget__header {
  display: flex; align-items: center; gap: 12px; padding: 14px 20px;
  border-bottom: 1px solid var(--color-border-medium); background: var(--color-purple-bg);
}
.textbook-widget__icon {
  width: 32px; height: 32px; border-radius: 8px; background: #fff; color: var(--color-purple);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.textbook-widget__title { font-size: 14px; font-weight: 600; color: var(--color-text-heading); }
.textbook-widget__subtitle { font-size: 12px; color: var(--color-text-muted); margin-top: 1px; }
.textbook-widget__counter { font-size: 12px; font-weight: 600; color: var(--color-purple); white-space: nowrap; margin-left: auto; }
.textbook-widget__body { padding: 24px 26px; }
/* Если виджет — целая мини-страница в iframe (напр. Своя игра), уберите padding у
   __body и добавьте border-radius на сам iframe вместо этого. */

/* ---- top-answers («100 к одному») — конкретные элементы виджета ---- */
.tw-topanswers__question { font-size: var(--fs-p, 16px); font-weight: 600; color: var(--color-text-heading); line-height: 1.5; margin: 0 0 18px; }
.tw-topanswers__rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.tw-topanswers__row {
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
  border: 1px solid var(--color-border-medium); border-radius: var(--radius-md);
  background: var(--color-bg); transition: background .25s ease, border-color .25s ease;
}
.tw-topanswers__row.is-revealed { background: var(--color-brand-50); border-color: var(--color-brand-100); }
.tw-topanswers__rank {
  width: 28px; height: 28px; border-radius: 999px; background: #e5e7eb; color: var(--color-text-muted);
  display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex-shrink: 0;
}
.tw-topanswers__row.is-revealed .tw-topanswers__rank { background: var(--color-brand-600); color: #fff; }
.tw-topanswers__label { flex: 1; font-size: 14px; color: var(--color-text-faint); }
.tw-topanswers__row.is-revealed .tw-topanswers__label { color: var(--color-text-heading); font-weight: 600; }
.tw-topanswers__percent {
  font-size: 12px; font-weight: 700; color: var(--color-brand-700); background: var(--color-brand-100);
  padding: 3px 10px; border-radius: 999px;
}
.tw-topanswers__controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tw-topanswers__input {
  flex: 1; min-width: 180px; padding: 10px 14px; font-size: 14px; border: 1px solid var(--color-border-input);
  border-radius: var(--radius-md); font-family: inherit; outline: none; background: var(--color-surface); color: var(--color-text-default);
}
.tw-topanswers__btn { padding: 10px 18px; border-radius: var(--radius-md); font-size: 14px; font-weight: 600; border: none; cursor: pointer; font-family: inherit; }
.tw-topanswers__btn--primary { background: var(--color-brand-600); color: #fff; }
.tw-topanswers__btn--secondary { background: #f3f4f6; color: var(--color-text-default); font-weight: 500; }
.tw-topanswers__meta { display: flex; align-items: center; gap: 14px; margin-top: 14px; min-height: 14px; }
.tw-topanswers__strikes { display: flex; gap: 5px; }
.tw-topanswers__strike { width: 9px; height: 9px; border-radius: 999px; background: #e5e7eb; display: inline-block; }
.tw-topanswers__strike.is-active { background: var(--color-error); }
.tw-topanswers__message { font-size: 12px; color: var(--color-error); font-weight: 500; }
.tw-topanswers__note { font-size: var(--fs-cap, 12px); color: var(--color-text-faint); line-height: 1.5; margin: 18px 0 0; }

/* ============================================================
   STICKY-САЙДБАР статьи (список уроков раздела слева)
   ============================================================ */

/* Колонка-обёртка (управляет шириной при сворачивании — .w-collapsed { width:0 }) */
.article-sidebar-col {
  flex-shrink: 0; overflow: hidden; transition: width .2s ease;
  position: sticky; top: 56px; /* высота navbar */
  align-self: flex-start;
  height: calc(100vh - 56px);
  z-index: 1;
}
.article-sidebar-col.w-collapsed { width: 0; }
.article-sidebar-col:not(.w-collapsed) { width: 260px; }
.article-sidebar-inner { width: 260px; height: 100%; overflow-y: auto; border-right: 1px solid var(--color-border-medium); padding: 20px 16px; box-sizing: border-box; }

/* Кнопка-«язычок» сворачивания сайдбара — тоже sticky, чтобы быть доступной при
   чтении вниз страницы. Лежит в области справа от сайдбара (не в колонке текста,
   та центрирована), поэтому left:0 — это ровно линия разделения. */
.article-sidebar-toggle-wrap { height: 0; overflow: visible; position: sticky; top: 90px; z-index: 4; }
.article-sidebar-toggle {
  position: relative; left: 0; top: 32px; width: 16px; height: 44px; border-radius: 0 8px 8px 0;
  border-left: none; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
  background: var(--color-surface); border: 1px solid var(--color-border-medium); box-shadow: 2px 0 6px rgba(0,0,0,.06);
}
.article-sidebar-toggle.is-collapsed { background: var(--color-brand-600); border: none; box-shadow: 2px 0 6px rgba(37,99,235,.35); }
.article-sidebar-toggle svg { color: #6b7280; transition: transform .15s ease; }
.article-sidebar-toggle.is-collapsed svg { color: #fff; transform: rotate(180deg); }

/* ============================================================
   БЛОКИ КОДА — .code-block (обёртку строит decorateCodeBlocks() в article_detail.html)
   Общая для block_type='code' и для ```-фенсов внутри markdown.
   ============================================================ */
.code-block {
  margin: 0 0 18px;
  border: 1px solid var(--color-border-medium);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.code-block__head {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 14px;
  background: #f3f4f6;
  border-bottom: 1px solid var(--color-border-medium);
}
.code-block__lang {
  font: 600 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .08em; text-transform: uppercase; color: #6b7280;
}
.code-block__copy {
  margin-left: auto; cursor: pointer;
  padding: 4px 10px; border-radius: 6px;
  border: 1px solid var(--color-border-medium);
  background: transparent; color: #6b7280;
  font-size: 12px; line-height: 1.2;
  transition: color .15s ease, background .15s ease;
}
.code-block__copy:hover { color: var(--color-brand-600); background: var(--color-brand-50); }
/* Цвет текста задан здесь, а не только темой highlight.js: если языка нет
   среди загруженных модулей, hljs помечает блок no-highlight и не вешает
   класс .hljs – тогда тёмные чернила статьи ложились на тёмный фон. */
.code-block pre { margin: 0; border-radius: 0; overflow-x: auto; background: #282c34; color: #abb2bf; }
.code-block pre code { font-size: 14px; line-height: 1.6; background: transparent; }

/* ============================================================
   РИСУНОК В ТЕКСТЕ СТАТЬИ — .ege-fig (числовая прямая, координатная плоскость)
   Картинку рисует seed-команда: SVG уезжает в data-URI внутрь <img>, а это
   отдельный документ — ни currentColor, ни переменные темы в него не доходят.
   Поэтому картинок две, светлая и тёмная, и лишнюю прячем здесь. Дешевле, чем
   держать один «нейтральный» набор цветов: подписи, читаемые на обоих фонах
   сразу, выходят блёклыми и там, и там.
   ============================================================ */
.ege-fig { margin: 0 0 18px; }
.ege-fig__img { display: block; max-width: 100%; height: auto; margin: 0 auto; }
.ege-fig__img--dark { display: none; }
html.dark .ege-fig__img--light { display: none; }
html.dark .ege-fig__img--dark { display: block; }
/* На телефоне колонка уже картинки, и вписанная в неё числовая прямая ужимается
   вдвое — подписи становятся нечитаемы. Поэтому там рисунок показывается в
   натуральную величину, а прокручивается вбок, как таблица. */
@media (max-width: 560px) {
  .ege-fig { overflow-x: auto; }
  .ege-fig__img { max-width: none; }
}

html.dark .code-block__head { background: #1e293b; }
html.dark .code-block__lang, html.dark .code-block__copy { color: #94a3b8; }
html.dark .code-block__copy:hover { color: #fff; background: #334155; }

/* Светлая тема листингов (кнопка в шапке блока, класс на <html>, выбор в
   localStorage). Нужна проектору: тёмный фон на стене сливается в пятно.
   Палитра – по мотивам GitHub Light, но все цвета тёмные и насыщенные:
   проектор выбеливает полутона, и серый/салатовый с задней парты пропадают.
   .hljs переопределён явно – atom-one-dark ставит на <code> свой #abb2bf,
   и без этого переменные и скобки оставались светло-серыми.
   Правила скоупнуты .code-block – виджеты учебника красят код своей тёмной
   подложкой и остаются как были. */
html.code-light .code-block pre,
html.code-light .code-block .hljs { background: #fff; color: #111827; }
html.code-light .code-block .hljs-comment,
html.code-light .code-block .hljs-quote { color: #4b5563; font-style: italic; }
html.code-light .code-block .hljs-doctag,
html.code-light .code-block .hljs-keyword,
html.code-light .code-block .hljs-formula,
html.code-light .code-block .hljs-literal { color: #b3122a; font-weight: 600; }
html.code-light .code-block .hljs-section,
html.code-light .code-block .hljs-name,
html.code-light .code-block .hljs-selector-tag,
html.code-light .code-block .hljs-deletion,
html.code-light .code-block .hljs-subst { color: #b3122a; }
html.code-light .code-block .hljs-string,
html.code-light .code-block .hljs-regexp,
html.code-light .code-block .hljs-addition,
html.code-light .code-block .hljs-attribute { color: #0a6b2e; }
html.code-light .code-block .hljs-number,
html.code-light .code-block .hljs-symbol,
html.code-light .code-block .hljs-bullet,
html.code-light .code-block .hljs-link { color: #0550ae; }
html.code-light .code-block .hljs-attr,
html.code-light .code-block .hljs-variable,
html.code-light .code-block .hljs-template-variable,
html.code-light .code-block .hljs-type,
html.code-light .code-block .hljs-params { color: #111827; }
html.code-light .code-block .hljs-meta,
html.code-light .code-block .hljs-title,
html.code-light .code-block .hljs-title.function_ { color: #6b21a8; }
html.code-light .code-block .hljs-built_in,
html.code-light .code-block .hljs-title.class_ { color: #9a3412; }
.code-block__theme { margin-left: 0; }

/* ============================================================
   РЕЖИМ ПРОЕКТОРА — .present-root:fullscreen
   Масштаб задаётся корневым font-size (см. present-mode.js), поэтому расти
   умеет только то, что измерено в rem. Шкала статьи объявлена в px – и на
   проекторе текст остался бы кегля 18.5px при любом масштабе. Переводим ровно
   те шесть переменных, ради которых шкала и была вынесена наверх файла: сами
   значения те же, просто поделены на 16px базового кегля. Больше в файле
   менять нечего – весь текст, заголовки, списки, таблицы и подписи ходят
   через них.
   ============================================================ */
.present-root:fullscreen .article-column {
  /* py-8 сверху – это строка заголовка, отданная пустоте: панель управления
     на проекторе уехала в левое поле и место над h1 больше ничем не занято. */
  padding-top: 0;
  --fs-h1: 1.875rem;
  --fs-h2: 1.5rem;
  --fs-p: 1.125rem;
  --fs-li: 1.125rem;
  --fs-cap: 0.875rem;
  --fs-table: 1rem;
}
/* Листинги мимо шкалы: у кода свой кегль, а на уроке информатики читать с
   задней парты нужно именно его. */
.present-root:fullscreen .code-block pre code { font-size: 0.875rem; }
.present-root:fullscreen .code-block__head { font-size: 0.75rem; }
/* ponytail: подписи внутри виджетов (.textbook-widget__*) остаются в px –
   там же лежит SVG-графика со своими координатами, и её масштабирование
   через zoom сломало бы замеры getBoundingClientRect. Если у доски окажется
   мелко – переводить в rem вместе с координатами конкретного виджета. */

/* ============================================================
   ЛЕНТА КЛЕТОК – .tape
   Разбор задания 13 объясняется лентой чисел, которую заполняют слева
   направо: в клетке – само число и сколько программ до него ведёт.
   Разметку собирает textbook/management/commands/seed_ege_theory_13.py.
   Геометрия целиком здесь: bleach пропускает div/span с class, но вычищает
   style, поэтому инлайновых размеров в разметке быть не может.
   Дуга прыжка команды B не отдельный элемент – её собирают сами клетки,
   каждая своим куском линии (--arc, --arc-from, --arc-to). Поэтому она не
   может разъехаться с числами: она из них и состоит.
   ============================================================ */
.tape {
  display: flex;
  margin: 22px 0 36px;
  /* Сверху – стрелки шага A с буквой над первой, снизу – дуга прыжка B
     и подпись под ней. Оба поля посчитаны по вертикальной раскладке,
     описанной в докстринге _tape(); двигать их надо вместе со смещениями
     ::after/::before ниже, иначе overflow-x обрежет стрелки. */
  padding-top: 40px;
  padding-bottom: 46px;
  font-size: var(--fs-table);
  overflow-x: auto;
}

/* Шаг A: стрелка от центра своей клетки до центра соседней. Ширина ровно
   в клетку – клетки равной ширины (flex: 1 1 0), поэтому расстояние между
   центрами соседних клеток и есть ширина клетки.
   Концы загнуты вниз, зеркально дуге прыжка B: стрелка обязана смотреть
   в клетку, а не мимо неё. */
.tape__a {
  position: absolute;
  left: 50%;
  width: 100%;
  top: -16px;
  border-top: 2px solid var(--color-brand-600);
  /* Клетки идут в потоке позже и закрашивают своим фоном всё, что предыдущая
     выпустила за свою границу. z-index поднимает стрелку над фонами: она
     рисуется поверх ленты, а не под соседней клеткой. Хватает одного –
     стрелка становится контекстом наложения для наконечника и буквы. */
  z-index: 1;
}
/* Хвостик вниз – только в конце, в клетку, куда стрелка ведёт. Начало рисуется
   лишь у первой стрелки: у остальных на этом месте уже стоит наконечник
   предыдущей, и два конца сливались в мешанину. Горизонтальные участки идут
   встык, поэтому линия остаётся непрерывной и без начал.
   Высота равна подъёму линии над лентой (top: -16px), иначе стрелка
   не достанет до клетки. */
.tape__a::after,
.tape__cell:first-child .tape__a::before {
  content: "";
  position: absolute;
  top: 0;
  border-left: 2px solid var(--color-brand-600);
}
/* Начало доходит до клетки (16px – весь подъём линии над лентой), конец
   обрывается на основании наконечника (11px): у вершины треугольник тоньше
   двух пикселей линии, и доведённая до острия линия торчала из него
   прямоугольным огрызком. */
.tape__cell:first-child .tape__a::before { left: -1px; height: 16px; }
.tape__a::after { right: -1px; height: 11px; }
/* Наконечник смотрит вниз, в клетку. Отдельным элементом, а не псевдо:
   псевдоэлементы стрелки заняты хвостиками. */
.tape__a-tip {
  position: absolute;
  right: -4px;
  top: 11px;                       /* основание – там, где обрывается линия */
  width: 0; height: 0;
  border: 4px solid transparent;   /* 8px в основании */
  border-bottom: 0;
  border-top: 7px solid var(--color-brand-600);   /* и 7px в высоту */
}
.tape__a-label {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 6px;
  color: var(--color-brand-600);
  font-size: var(--fs-cap);
  font-weight: 600;
}
.tape__cell {
  flex: 1 1 0;
  min-width: 3.4em;
  position: relative;
  padding: 8px 4px;
  text-align: center;
  background: var(--color-bg);
  border: 1px solid var(--color-border-medium);
  border-right: none;
}
.tape__cell:first-child { border-radius: var(--radius-md) 0 0 var(--radius-md); }
.tape__cell:last-child {
  border-right: 1px solid var(--color-border-medium);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.tape__n { display: block; font-weight: 600; color: var(--color-text-heading); }
.tape__g {
  display: block;
  font-size: var(--fs-cap);
  color: var(--color-brand-600);
  font-variant-numeric: tabular-nums;
}
/* Заливка – тот же --color-brand-50, что и у строки-ответа в таблицах:
   смысл один, и в тёмной теме он уже переопределён у .article-column. */
.tape__cell--start,
.tape__cell--arc-from,
.tape__cell--arc-to { background: var(--color-brand-50); }

.tape__cell--arc::after,
.tape__cell--arc-from::after,
.tape__cell--arc-to::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -16px;
  border-top: 2px solid var(--color-brand-600);
}
.tape__cell--arc-from::after { left: 50%; }
.tape__cell--arc-to::after { right: 50%; }
/* Вертикальные хвостики от клетки к дуге: без них линия висит сама по себе. */
.tape__cell--arc-from::before,
.tape__cell--arc-to::before {
  content: "";
  position: absolute;
  left: calc(50% - 1px);
  bottom: -16px;
  border-left: 2px solid var(--color-brand-600);
}
/* Начало прыжка доходит до клетки, конец обрывается на основании наконечника –
   по той же причине, что и у стрелки шага A. */
.tape__cell--arc-from::before { height: 16px; }
.tape__cell--arc-to::before { height: 11px; }
/* Наконечник дуги B: смотрит вверх, в клетку, куда прыжок приземляется.
   Отдельным элементом, а не псевдо: оба псевдоэлемента клетки-цели заняты
   линией дуги и хвостиком. */
.tape__tip {
  position: absolute;
  left: calc(50% - 4px);
  bottom: -5px;                    /* основание – там, где обрывается линия */
  width: 0; height: 0;
  border: 4px solid transparent;   /* 8px в основании */
  border-top: 0;
  border-bottom: 7px solid var(--color-brand-600);   /* и 7px в высоту */
}
/* Подпись сидит в средней клетке прыжка, поэтому оказывается по центру дуги
   без единой вычисленной координаты. Стоит под линией, а не на ней: сидя на
   линии, она разрывала дугу надвое и читалась как её часть. */
.tape__b {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: -38px;
  white-space: nowrap;
  color: var(--color-brand-600);
  font-size: var(--fs-cap);
  font-weight: 600;
}
