/* Стили разбора. ПОРОЖДЁННЫЙ ФАЙЛ — не править руками.
   Источник: proto/build_viewer.py (CSS) + proto/bake_geom.py (шрифты).
   Пересобрать: python3 site/extract_css.py <путь>
   Каждый селектор заперт в #tx-answer: иначе шаблон сайта
   (#content p) перебивает межстрочный интервал разбора. */

@font-face{font-family:'Fira Sans';font-weight:400;font-style:normal;font-display:block;src:url('/templates/gdz/fonts/FiraSans-Regular.subset.woff2') format('woff2');}
@font-face{font-family:'Fira Sans';font-weight:500;font-style:normal;font-display:block;src:url('/templates/gdz/fonts/FiraSans-Medium.subset.woff2') format('woff2');}
@font-face{font-family:'Fira Sans';font-weight:600;font-style:normal;font-display:block;src:url('/templates/gdz/fonts/FiraSans-SemiBold.subset.woff2') format('woff2');}
@font-face{font-family:'Fira Sans';font-weight:700;font-style:normal;font-display:block;src:url('/templates/gdz/fonts/FiraSans-Bold.subset.woff2') format('woff2');}
@font-face{font-family:'Fira Sans';font-weight:400;font-style:italic;font-display:block;src:url('/templates/gdz/fonts/FiraSans-Italic.subset.woff2') format('woff2');}
@font-face{font-family:'Fira Sans';font-weight:500;font-style:italic;font-display:block;src:url('/templates/gdz/fonts/FiraSans-MediumItalic.subset.woff2') format('woff2');}



#tx-answer {
  --bg: #f7f6f3; --surface: #ffffff;
  --ink: #1d1d1f; --ink-2: #515158; --ink-3: #86868b;
  --line: rgba(0,0,0,0.06);
  /* Фаза 2 — палитра ролей (ТЗ_дополнение_синий-подсветка-устное §5,§7). */
  --insert: #d1452f;   /* роль A: вставленная/проверяемая буква/запятая (вес 500 — Ф3) */
  --sign-b: #9E6A2F;    /* роль B: разбираемый знак — бронза (реш. владельца; было графит #6b6157) */
  --oral: #8a8175;      /* устная инлайн-ремарка (серый курсив) */
  --honey: #f3d982;     /* точечная подсветка важного (применение — Ф6) */
  --warm-bg: #fff8ec; --warm-bd: #e6a337;
  --warm-line: #ecd9ad;   /* тонкая тёплая рамка карточек (вариант 1: без боковой черты) */
  /* Стиль карточек-шапок (часть и пояснения) — один источник, легко переключать. */
  --card-bg: #fdf4e1; --card-bd: none; --card-rad: 12px;
  --card-pad: 9px 16px; --card-ink: #4a4034;
  --shadow-1: 0 1px 2px rgba(0,0,0,0.04), 0 4px 24px -8px rgba(0,0,0,0.06);
}
#tx-answer * { box-sizing: border-box; }
#tx-answer {
  margin: 0; padding: 0; color: var(--ink);
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif;
  font-feature-settings: 'kern' 1, 'liga' 1;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
/* ==== Задание (сшито из корпуса) ==== */
#tx-answer .ex-task { margin: 0 0 10px; font-size: 13px; color: var(--ink-2); }
#tx-answer .ex-task > summary { cursor: pointer; font-weight: 600; color: var(--ink-3);
  font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
  list-style: none; user-select: none; }
#tx-answer .ex-task > summary::-webkit-details-marker { display: none; }
#tx-answer .ex-task > summary::before { content: "▸ "; color: var(--ink-3); }
#tx-answer .ex-task[open] > summary::before { content: "▾ "; }
#tx-answer .ex-task-body { margin: 6px 0 0; padding: 8px 12px; background: #f4f3ef;
  border-radius: 8px; line-height: 1.5; color: var(--ink-2); }

/* ==== Флаги аудита ответов ==== */
#tx-answer .ex-audit { margin: 0 0 12px; display: flex; flex-direction: column; gap: 6px; }
#tx-answer .aud-item { font-size: 12.5px; line-height: 1.45; padding: 7px 11px;
  border-radius: 8px; border-left: 3px solid #c9c9c9; background: #faf9f6; }
#tx-answer .aud-badge { font-weight: 700; font-size: 10.5px; letter-spacing: 0.03em;
  text-transform: uppercase; padding: 1px 6px; border-radius: 4px;
  margin-right: 4px; white-space: nowrap; }
#tx-answer .aud-prob { color: var(--ink); }
#tx-answer .aud-fixhint { color: var(--ink-2); }
#tx-answer .aud-crit { border-left-color: #c0392b; background: #fdecea; }
#tx-answer .aud-crit   .aud-badge { background: #c0392b; color: #fff; }
#tx-answer .aud-fix { border-left-color: #e67e22; background: #fef4e9; }
#tx-answer .aud-fix    .aud-badge { background: #e67e22; color: #fff; }
#tx-answer .aud-minor { border-left-color: #d4b106; background: #fdfae7; }
#tx-answer .aud-minor  .aud-badge { background: #d4b106; color: #fff; }
#tx-answer .aud-manual { border-left-color: #7f8c8d; background: #f2f4f4; }
#tx-answer .aud-manual .aud-badge { background: #7f8c8d; color: #fff; }
#tx-answer mark.audit-hl { background: #ffe08a; color: inherit; border-radius: 3px;
  padding: 0 2px; box-shadow: 0 0 0 1px #e6a33755; }

/* Исходный вопрос учебника (Повторение) — временный серый курсив под шапкой */
#tx-answer .kv-question { margin: 2px 0 6px; color: var(--ink-3); font-style: italic;
  font-size: 13px; line-height: 1.4; }

/* Заметка-подсказка к ответу (не ошибка) — дружелюбный инфо-callout */
#tx-answer .ex-note { margin: 14px 0 2px; display: flex; gap: 8px; align-items: flex-start;
  font-size: 13px; line-height: 1.45; color: #2f5568; background: #eef5fb;
  border: 1px solid #cfe2f0; border-radius: 8px; padding: 8px 12px; }
#tx-answer .ex-note-ic { flex: 0 0 auto; margin-top: 1px; display: block; }
/* Заметка на уровне ЧАСТИ: с красной строки (2em), не во всю ширину.
   flex-контейнер НЕ схлопывает margin → зазор = ровно margin-bottom.
   ВИЗУАЛЬНЫЙ стандарт «текст→шапка» = box-зазор 14px + полу-интерлиньяж текста 6px = 20px;
   у плашки края рамки без интерлиньяжа, поэтому margin-bottom = 20px (край плашки → шапка). */
#tx-answer .part-note { margin: 12px 2em 20px 2em; }
/* Плашка-подсказка ⓘ ПЕРЕД следующей шапкой — чуть больше воздуха снизу.
   У плашки есть свой фон и рамка, то есть жёсткий нижний край; на равном
   отступе он читается ближе к кремовой шапке, чем обычная строка текста
   (та же оптика, что у таблиц под шапкой). +3px хватает. Затрагивает 2 места
   (упр.26, 349); плашки в конце карточки не трогаем — им запас не нужен. */
#tx-answer .part:has(+ .part) .part-note { margin-bottom: 23px; }
/* Часть с таблицей: содержимое прижато влево, плашка равняется по нему. */
#tx-answer .part-note-flush { margin-left: 0; margin-right: 0; }
/* Подпись-источник под воспроизведённым чужим текстом (поле части `_source`).
   Тихая, некрупная, курсивом — чтобы не спорила с ответом, но была видна:
   это указание автора, обязательное при использовании чужого произведения. */
/* ★Цвет — ТЁПЛЫЙ серый той же гаммы, что --oral (#8a8175), но темнее ради AA:
   #746C62 даёт контраст 5.17 к белому (у --oral 3.83 — ниже порога 4.5), а
   указание автора несёт юридический смысл и не должно быть самой бледной
   строкой. ★НЕ курсив: связка «серый + курсив» уже занята под устную ремарку
   (см. ORAL_GRAY), иначе источник читался бы как «проговорить вслух».
   ★НЕ --ink-3 (#86868b): тот холодный и в тёплой палитре смотрится инородно —
   он служебный (панели/тултипы/буллеты), а это контент. */
/* ★Кегль — на ВНУТРЕННЕМ span, а не на блоке. `em` в margin считается от
   СОБСТВЕННОГО размера шрифта элемента: при font-size:0.88em отступ «2em»
   даёт всего 1.76em базового кегля, и подпись уезжает влево относительно
   красной строки абзацев (text-indent: 2em). Так отступ считается от базового. */
/* ★Зазор «текст → подпись» задаём ЯВНО. Иначе его определяет нижний отступ
   ПРЕДЫДУЩЕГО абзаца (соседние отступы схлопываются в больший), а он разный:
   стих 3px, проза 6px, разборы/обычный абзац 14px — ритм плавает от упражнения
   к упражнению (упр.161 против 354). Подпись принадлежит тексту НАД ней,
   поэтому сверху узко, снизу просторнее — она не должна «прилипать» к тому,
   что идёт следом. */
#tx-answer .text-para:has(+ .part-source) { margin-bottom: 4px; }
#tx-answer .part-source {
  margin: 4px 2em 14px 2em;
  color: #746C62;
}
#tx-answer .part-source > span { font-size: 0.88em; }
/* ==== Иллюстрации (серия рисунков, упр.126) ==== */
/* Системные отступы блока иллюстраций. У картинки НЕТ полу-интерлиньяжа (у текста
   над буквами ~6px пустоты), поэтому при равном margin картинка визуально липнет к
   шапке сильнее. Компенсируем: шапка→картинка 16px (= текстовые 8px box + ~6px
   полу-интерлиньяж + запас → визуально ≥ зазора «шапка→текст»). Низ 10px — там
   полу-интерлиньяж даёт следующий текст/подпись. */
#tx-answer .illus-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
  max-width: 520px; margin: 16px 0 10px; }
#tx-answer .illus-img { width: 100%; height: auto; display: block; border-radius: 6px;
  border: 1px solid var(--warm-line); cursor: zoom-in; background: #fff; }
#tx-answer .illus-img:focus-visible { outline: 2px solid var(--honey); outline-offset: 2px; }
/* Лайтбокс (тап-зум): клик по кадру → на весь экран, клик по фону/Esc → закрыть */
#tx-answer .illus-lb { position: fixed; inset: 0; z-index: 9999; display: none;
  align-items: center; justify-content: center; padding: 16px;
  background: rgba(0,0,0,.82); cursor: zoom-out; }
#tx-answer .illus-lb.open { display: flex; }
#tx-answer .illus-lb img { max-width: 100%; max-height: 100%; border-radius: 8px;
  box-shadow: 0 8px 40px rgba(0,0,0,.5); }

/* ===== Электронная презентация: нативные слайд-карточки (упр.123) ===== */
/* ★aspect-ratio 16/9 БЕЗ фикс-высоты и без overflow:hidden — карточка не
   меньше 16:9, но растёт под контент. В узкой колонке ответа (~380px) строгие
   16:9 = ~214px высоты, пункты бы обрезались. */
#tx-answer .slidedeck { display: flex; flex-direction: column; gap: 14px; margin: 12px 0 6px; }
#tx-answer .slide { position: relative; aspect-ratio: 16 / 9; background: #fffdf8;
  border: 1px solid var(--warm-line); border-radius: 10px; box-shadow: var(--shadow-1);
  padding: 24px 28px; display: flex; color: #2a2620; }
#tx-answer .slide-no { position: absolute; top: 12px; right: 16px; font-size: 12px;
  color: var(--ink-3); font-variant-numeric: tabular-nums; }
#tx-answer .slide-body { width: 100%; display: flex; flex-direction: column; min-width: 0; }
#tx-answer .slide-center { justify-content: center; align-items: center; text-align: center; }
#tx-answer .slide-h { font-size: 21px; font-weight: 700; color: #3a3228; margin: 0 0 12px;
  line-height: 1.2; }
/* Заголовок контентного/схемного слайда — с тёплой чертой снизу (как у слайдов). */
#tx-answer .slide-content .slide-h, #tx-answer .slide-figure .slide-h { padding-bottom: 8px;
  border-bottom: 2px solid var(--warm-bd); }
#tx-answer .slide-h-title { font-size: 29px; margin: 0; }
#tx-answer .slide-h-closing { font-size: 27px; margin: 0; }
#tx-answer .slide-accent { width: 54px; height: 4px; border-radius: 2px;
  background: var(--warm-bd); margin-bottom: 18px; }
#tx-answer .slide-sub { font-size: 16px; color: var(--ink-2); margin: 12px 0 0; }
#tx-answer .slide-intro { font-size: 15px; color: var(--ink-2); margin: 0 0 8px; line-height: 1.45; }
#tx-answer .slide-bul { margin: 4px 0 0; padding-left: 22px; }
#tx-answer .slide-bul li { font-size: 15.5px; line-height: 1.5; margin-bottom: 7px; color: #2a2620; }
#tx-answer .slide-bul li::marker { color: var(--warm-bd); }
#tx-answer .slide-bul li strong, #tx-answer .slide-intro strong { font-weight: 700; color: #3a3228; }
#tx-answer .slide-fig { flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 8px 0; min-height: 0; }
#tx-answer .slide-fig svg { max-width: 100%; max-height: 100%; height: auto; }
#tx-answer .slide-cap { font-size: 13px; color: var(--ink-3); text-align: center;
  margin: 8px 0 0; font-style: italic; line-height: 1.4; }

#tx-answer header {
  padding: 14px 22px; background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10;
}
#tx-answer header h1 { margin: 0 0 6px; font-size: 14px; font-weight: 600;
  letter-spacing: -0.005em; color: var(--ink); }
/* Навигация по 400+ номерам: свёрнута в одну строку, раскрывается по кнопке.
   Прежде это была полоса на 4 строки с ПРОКРУТКОЙ — на 13" она съедала экран,
   а на большом мониторе искать номер прокруткой внутри полосы неудобно.
   Теперь: свёрнуто — строка состояния «‹ Упражнение N ›»; раскрыто — сетка
   на всю ширину, все номера сразу и без внутреннего скролла. */
#tx-answer header .navbar { display: flex; align-items: center; gap: 8px; font-size: 12px; }
/* Ширина фиксирована, чтобы стрелки не прыгали при смене номера («4» → «236»),
   а текст внутри — ПО ЦЕНТРУ: иначе весь запас ширины копится справа и правая
   стрелка зрительно отодвинута от надписи, а левая стоит вплотную. */
#tx-answer header .nav-cur { color: var(--ink); font-weight: 600; min-width: 11em;
  text-align: center; }
#tx-answer header .nav-step {
  font-family: inherit; font-size: 15px; line-height: 1; width: 24px; height: 24px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--surface);
  color: var(--ink-2); cursor: pointer; padding: 0;
}
#tx-answer header .nav-step:hover { background: var(--warm-bg); }
#tx-answer header .nav-toggle {
  font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  padding: 4px 10px; border-radius: 4px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2); cursor: pointer; margin-left: 4px;
}
#tx-answer header .nav-toggle:hover { background: var(--warm-bg); }
#tx-answer header .nav-find {
  font-family: inherit; font-size: 12px; width: 4.5em; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--surface);
  color: var(--ink); margin-left: 4px;
}
#tx-answer header .nav-find:focus { outline: none; border-color: var(--warm-bd); }
/* Номера нет — короткая подсветка поля вместо всплывающего окна: на 400+
   упражнениях промах по номеру дело обычное, ради него не стоит прерывать работу. */
#tx-answer header .nav-find.miss { border-color: var(--insert); background: #fff2f0; }
#tx-answer header .nav-toggle.on { background: #ffe9a8; border-color: var(--warm-bd); color: #6a4400; }
#tx-answer header .nav { font-size: 12px; line-height: 1.9; color: var(--ink-2);
  letter-spacing: -0.003em; margin-top: 8px;
  /* Раскрытый список: высокий потолок вместо прокрутки, но не во весь экран —
     иначе шапка (sticky) закрывает ответ. Внутренний скролл — только страховка
     на совсем узком окне. */
  max-height: 46vh; overflow-y: auto; padding-right: 4px; }
#tx-answer header .nav a.nav-here { background: var(--warm-bg); font-weight: 700; }
#tx-answer header .nav::-webkit-scrollbar { height: 6px; width: 6px; }
#tx-answer header .nav::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
#tx-answer header .nav a { color: var(--ink); text-decoration: none; padding: 0 3px;
  border-radius: 3px; }
#tx-answer header .nav a:hover { background: var(--warm-bg); }

/* ============ QA-режим ============ */
#tx-answer .qa-toggle {
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; padding: 5px 10px; border-radius: 4px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-2); cursor: pointer; margin-left: 8px;
}
#tx-answer .qa-toggle.on { background: #ffe9a8; border-color: var(--warm-bd); color: #6a4400; }
#tx-answer .qa-toggle:hover { background: var(--warm-bg); }

/* В QA-режиме слова с морфемами кликабельны */
#tx-answer body.qa-mode .word { cursor: pointer; outline: 1px dashed transparent; }
#tx-answer body.qa-mode .word:hover { outline-color: var(--warm-bd); background: #fff8ec; }

/* Накопитель правок справа сверху */
#tx-answer .qa-panel {
  position: fixed; top: 76px; right: 14px; width: 360px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 8px; box-shadow: var(--shadow-1);
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif; font-size: 12px;
  z-index: 30; display: none;
}
#tx-answer body.qa-mode .qa-panel { display: block; }
#tx-answer .qa-panel-header {
  padding: 10px 12px; border-bottom: 1px solid var(--line);
  font-weight: 600; color: var(--ink); display: flex;
  justify-content: space-between; align-items: center;
}
#tx-answer .qa-panel-body { padding: 8px 12px; max-height: 30vh; overflow-y: auto; }
#tx-answer .qa-panel-empty { color: var(--ink-3); font-style: italic; }
#tx-answer .qa-entry {
  border-bottom: 1px solid var(--line); padding: 6px 0;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, 'Courier New', monospace; font-size: 11px;
  color: var(--ink-2); display: flex; justify-content: space-between;
}
#tx-answer .qa-entry button {
  border: 0; background: none; color: #c00; cursor: pointer;
  font-size: 14px; padding: 0 4px;
}
#tx-answer .qa-panel-actions {
  padding: 8px 12px; border-top: 1px solid var(--line);
  display: flex; gap: 6px;
}
#tx-answer .qa-panel-actions button {
  flex: 1; padding: 6px 8px; font-size: 11px; border-radius: 4px;
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink); cursor: pointer; font-family: inherit;
}
#tx-answer .qa-panel-actions button.primary {
  background: var(--ink); color: var(--surface); border-color: var(--ink);
}
#tx-answer .qa-panel-actions button:hover { background: var(--warm-bg); }

/* Модалка ввода правки */
#tx-answer .qa-modal-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.3);
  z-index: 40; display: none; align-items: center; justify-content: center;
}
#tx-answer .qa-modal-backdrop.open { display: flex; }
#tx-answer .qa-modal {
  background: var(--surface); border-radius: 10px; padding: 18px;
  width: 360px; box-shadow: 0 12px 40px rgba(0,0,0,0.2);
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif;
}
/* Заголовок — «ручка» для перетаскивания окна. */
#tx-answer .qa-modal h3 { margin: 0 0 12px; font-size: 14px; cursor: move;
  user-select: none; }
#tx-answer .qa-modal h3::before { content: '\2059 '; color: var(--ink-3); font-size: 12px; }
#tx-answer .qa-modal label { display: block; font-size: 11px; color: var(--ink-3);
  margin-top: 8px; margin-bottom: 2px; font-weight: 500; }
#tx-answer .qa-modal input, #tx-answer .qa-modal select {
  width: 100%; box-sizing: border-box; padding: 6px 8px;
  border: 1px solid var(--line); border-radius: 4px;
  font-family: inherit; font-size: 13px;
}
#tx-answer .qa-modal-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* Строка start/end/выделено — три колонки; превью пошире. */
#tx-answer .qa-range-3col { grid-template-columns: 1fr 1fr 1.4fr; }
#tx-answer #qa-selpreview { background: var(--bg); color: var(--ink-2); }
/* Кнопки переносятся на новую строку, если не влезают (их теперь 5). */
#tx-answer .qa-modal-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px;
  justify-content: flex-end; }
#tx-answer .qa-modal-actions button {
  flex: 1 1 auto; min-width: 88px; padding: 8px; border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--surface); cursor: pointer; font-family: inherit; font-size: 13px;
}
#tx-answer .qa-modal-actions button.primary {
  background: var(--ink); color: var(--surface); border-color: var(--ink);
}

#tx-answer .layout {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  height: calc(100vh - 78px);
}
#tx-answer .col { overflow-y: auto; padding: 24px; }
#tx-answer .col-left { background: var(--bg); border-right: 1px solid var(--line); }
#tx-answer .col-right { background: #ebebed; }
/* PDF viewer (исходник учебника) — занимает всю высоту правой колонки,
   за вычетом заголовка ".col-title" сверху. */
#tx-answer .pdf-frame {
  width: 100%;
  height: calc(100vh - 78px - 24px*2 - 14px - 18px);
  border: 0;
  background: #fff;
  box-shadow: var(--shadow-1);
  border-radius: 6px;
}
#tx-answer .col-title {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-3); margin-bottom: 14px; font-weight: 600;
}

#tx-answer .exercise {
  background: var(--surface); border-radius: 14px;   /* вариант 1: мягкие углы со всех сторон, без боковой черты */
  padding: 22px 26px; margin-bottom: 18px;
  box-shadow: var(--shadow-1); border: 1px solid var(--line);
  position: relative;            /* для absolute SVG-оверлея стрелок-связей */
}
/* SVG-оверлей со стрелками словосочетаний (связи формы B: главное→зависимое).
   pointer-events:none — клики проходят сквозь к тексту. */
#tx-answer .link-arrows {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  pointer-events: none; overflow: visible; z-index: 4;
}
/* Строка-участник стрелки словосочетания: вопрос-подпись рисуется НАД словом.
   Базовый зазор .text-para (14px снизу) вмещает подпись; этот floor гарантирует
   ≥14px и в редких тесных контекстах, НЕ превышая базовый (иначе разнобой, упр.57).
   Класс ставит JS initLinkArrows до отрисовки. */
#tx-answer .text-para.has-link-arrow { margin-top: 14px; }
/* Те же резервы места в ЯЧЕЙКЕ таблицы: margin у td не работает, поэтому
   верхний зазор даём padding'ом, а разведение строк — тем же line-height. */
/* ★специфичность: базовые `.data-table td` (0,2,1) перебивают простой `td.…`,
   поэтому классы пишем вместе с таблицей. */
#tx-answer .data-table td.has-link-arrow { padding-top: 20px; }
#tx-answer .data-table td.has-link-arrow-wrap { line-height: 2.85; }
/* Строка словосочетания не должна ломаться посередине: стрелка тогда уходит
   через край строки, а в ячейке для неё нет запаса. Переносим ПО СТРОКАМ <br>. */
#tx-answer .data-table td.has-link-arrow { white-space: nowrap; }
/* СОГЛАСОВАНИЕ КОЛОНОК в ряду, где одна ячейка разведена под стрелки.
   Замер источника (упр.142, кегль 18pt): обе колонки выровнены ПО ВЕРХУ, шаг строк
   слева 33pt, справа 38.4pt — правая просторнее ровно на место под стрелку,
   отношение 0.86. Поэтому соседние ячейки НЕ уравниваем со стрелочной (ряды бы
   разъехались зря) и НЕ оставляем компактными (колонки читаются как чужие друг
   другу), а держим то же отношение: 2.85 × 0.86 ≈ 2.45. */
#tx-answer .data-table tr.has-arrow-row td { vertical-align: top; }
#tx-answer .data-table tr.has-arrow-row td:not(.has-link-arrow) { line-height: 2.45; }
/* Многострочный абзац со стрелками: над КАЖДОЙ строкой нужен просвет под
   кронштейн (11px) + подпись вопроса (15px). Ставится из JS (см. has-link-arrow-wrap):
   в одну строку правило не нужно — там работает margin-top.
   ЗАМЕР (упр.137): при 2.3 подпись 2-й строки начиналась на 36.8px от верха абзаца,
   а слово 1-й строки с РАМКОЙ ОКОНЧАНИЯ тянется до 45.5px (у `.word` нижний
   отступ 9px под рамку) — наложение 8.7px. 2.85 ≈ 62.7px даёт +12px и ~3px просвета. */
#tx-answer .text-para.has-link-arrow-wrap { line-height: 2.85; }
/* Первая строка со стрелкой сразу под шапкой: подпись вопроса висит ~7.8px выше
   строки, и при обычном margin-top до шапки оставалось 4.2px — вопрос липнул к
   плашке. Разводим до ритма карточки: ЗАМЕР соседних отступов — заголовок→плашка
   18px, плашка→шапка 14px, шапка→обычный абзац 8px. Берём 18px видимого зазора:
   26px − 7.8px подписи ≈ 18px. */
/* Специфичность важна: ниже по листу идёт `.part-heading + .text-para.tpara-hasgfx`
   с 18px и той же специфичностью — она перебивала правило. Добавляем класс. */
/* ★ЗАМЕР ПЕРЕСЧИТАН (2026-08-05). Прежние 26px считались от подписи высотой
   7.8px — столько она давала, пока шрифт не догрузился. Реально подпись 15px, и
   видимого просвета до плашки оставалось 17.7px: вопрос липнул к шапке
   (замечание владельца по упр.105). Берём 32px — просвет ≈24px, вопрос стоит
   отдельной строкой, а не подписью под плашкой. */
#tx-answer .part-heading + .text-para.has-link-arrow, #tx-answer .part-heading + .text-para.tpara-hasgfx.has-link-arrow, #tx-answer .part-heading + .text-para.tpara-hasgfx.has-link-arrow-wrap { margin-top: 32px; }
/* Ф4 (ТЗ дизайнера): верхний уровень = номер-заголовок + тёплый hairline во всю
   ширину под ним. Без пилюли, без синего — одно правило на любую длину ярлыка.
   Отступы единые: номер→линия 12px, линия→контент 18px. */
/* flex-wrap: техническая meta-строка (только review-сборки) уходит на вторую
   строку, если не помещается рядом с заголовком. Без этого она отжимала
   название параграфа и «§74. Буквы З и С…» ломалось на четыре строки. */
#tx-answer .ex-header { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 18px; border-bottom: 1px solid #E2D8C4; }
#tx-answer .ex-num { font-size: 32px; font-weight: 700; color: #241F1A;
  letter-spacing: -0.01em; line-height: 1; }
/* Название параграфа рядом с номером («§74. Буквы З и С на конце приставок»):
   тот же цвет и вес, но кегль 0.66 от номера (≈21px) и обычный интерлиньяж —
   иначе длинное название перебивает номер и разъезжается при переносе. */
#tx-answer .ex-title { font-size: 0.66em; font-weight: 700; line-height: 1.25; }
/* Заголовок забирает свободную ширину, техническая meta ужимается: она
   `nowrap` и в узкой колонке отъедала место у названия параграфа —
   «§74. Буквы З и С…» ломалось на 4 строки. min-width:0 нужен, иначе
   flex-элемент не даёт себя сузить ниже содержимого. */
#tx-answer .ex-num { flex: 1 1 auto; min-width: 0; }
#tx-answer .ex-meta { font-size: 12px; font-weight: 400; color: #9A9186; margin-left: auto;
  flex: 0 1 auto; min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, 'Courier New', monospace; }
/* Тех-метка группы сборки (A/B/C/D) в правом углу шапки — только для вычитки.
   Зелёная = надёжный реюз из Пилота 1; янтарная = машинный кандидат (сверить по PDF).
   Пояснение группы — в нативном тултипе (title, наведение). */
#tx-answer .grp-chip { position: relative; flex: 0 0 auto; margin-left: 8px; cursor: help;
  user-select: none; outline: none;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 12px; font-weight: 700; padding: 2px 9px; border-radius: 6px;
  border: 1px solid transparent; }
#tx-answer .grp-chip.grp-verified { background: #e6f4ec; color: #2b7a54; border-color: #c4e4d2; }
#tx-answer .grp-chip.grp-candidate { background: #fbe9dd; color: #b1502c; border-color: #eecab4; }
/* Свой тултип (нативный title капризен): всплывает сразу при наведении/фокусе. */
#tx-answer .grp-tip { position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  width: 250px; white-space: normal; text-align: left;
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  font-size: 12px; font-weight: 400; line-height: 1.45; letter-spacing: 0;
  color: #fff; background: #2a2620; padding: 9px 11px; border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0,0,0,.22);
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity .12s ease, transform .12s ease; pointer-events: none; }
#tx-answer .grp-chip:hover .grp-tip, #tx-answer .grp-chip:focus .grp-tip {
  opacity: 1; visibility: visible; transform: translateY(0); }

#tx-answer .ex-body {
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif;
  font-size: 19px; line-height: 1.85; color: var(--ink);
  letter-spacing: -0.005em;
}
#tx-answer .part { margin-bottom: 18px; }   /* воздух между частями: подчёркнутый/декорированный
   контент не должен упираться в следующую шапку (упр.440) */
#tx-answer .part-heading {
  color: var(--card-ink); margin: 14px 0 8px; padding: var(--card-pad);
  line-height: 1.4;   /* НЕ наследуем 1.85 тела — иначе многострочная шапка разъезжается */
  background: var(--card-bg); border-radius: var(--card-rad);
  border: var(--card-bd);
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif;  /* как тело ответа */
  font-size: inherit;                  /* такой же как .ex-body */
}
/* Заголовок ТЕКСТА (название сочинения/рассказа): по центру, полужирный,
   без плашки — как настоящий заголовок над текстом. */
#tx-answer .part-title {
  color: var(--ink); margin: 14px 0 6px; text-align: center;
  font-weight: 700; text-indent: 0;
}
/* Текст под заголовком-названием: книжный компактный интервал между абзацами. */
#tx-answer .part-title + .text-para { margin-top: 2px; }
#tx-answer .text-para.tpara-textbody { margin-bottom: 4px; }
/* Авто-заголовок текста (первый жирный короткий абзац-название) — по центру. */
/* Центрованный заголовок текста — ритм как у tpara-rubric: 16px сверху,
   а снизу столько же, сколько идёт МЕЖДУ абзацами текста, который он
   открывает (проза = 6px). Заголовок ближе к своему содержимому, чем к
   тому, что над ним. Прежние 4px/10px давали обратное: сверху 6-8px
   (зазор определял сосед), снизу 10px. */
#tx-answer .text-para.tpara-title { text-align: center; text-indent: 0; margin: 16px 0 6px; }
/* Заголовок СРАЗУ под шапкой части: общее .part-heading + .text-para (8px)
   имеет ту же специфичность и стоит НИЖЕ в файле, поэтому перебивало бы
   правило выше. Специфичность 3 — выигрывает независимо от порядка. */
#tx-answer .part-heading + .text-para.tpara-title { margin-top: 16px; }
/* Главный заголовок сообщения — крупнее подзаголовков (упр.123). */
#tx-answer .text-para.tpara-maintitle { font-size: 1.25em; margin: 8px 0 12px; }
/* Рубрика-подзаголовок внутри ответа (жирная строка-категория с «:») —
   отступ сверху для разделения тематических групп. */
#tx-answer .text-para.tpara-rubric { margin-top: 16px; }
/* Заголовок сочинения/текста: болд и по центру (решение владельца 2026-07-28).
   Красную строку снимаем — иначе центровка считается от сдвинутого края. */
#tx-answer .text-para.tpara-anstitle { text-align: center; text-indent: 0; margin: 14px 0 8px; }
/* ★КРАСНАЯ СТРОКА — У КАЖДОГО абзаца ответа (правило оформления по предмету, решение
   владельца 2026-07-28). Метка-рубрика её НЕ отменяет: она красит первые слова, но
   абзац остаётся абзацем. Без отступа остаются только заголовки (они по центру) и
   строки с висячим отступом — нумерованные пункты и подпункты, где отступ несёт
   структуру. */
/* Ф6 Часть B: ВЕРХНЕУРОВНЕВАЯ метка-секция с «:» («Устный разбор:», «1 вариант:»,
   тематические «Головные уборы:») — кремовая плашка, как заголовки §10 и
   .part-heading. Слова-заголовки словарных статей («Жесто́кий», без «:») и
   подзаголовки слов («Фигурист») — НЕ карточки (у них нет .tpara-section /
   есть .tpara-word). Единообразные кремовые секции (ТЗ §8). */
/* Кремовая плашка ОТМЕНЕНА (решение владельца 2026-07-22): по факту базы её
   получали лишь 6 строк из 23 несущих .tpara-section, и не по смыслу, а по
   случайности — попала ли метка в окружение словарных статей (.tpara-word
   выводил её из-под этого правила). Норма — жирная строка, как «Земляные
   сооружения:» в 276. Класс сохранён: он смысловая метка и якорь для правил
   ритма ниже (в т.ч. защищает от сжатия .tpara-rubric.tpara-prose).
   Осталось только выравнивание отступа — как у прочих меток-рубрик. */
/* Единый ритм метки-секции = «Земляные сооружения:» (упр.276), эталон владельца:
   красная строка как у обычного абзаца, 16px сверху (отделяет группу) и 3px
   снизу (метка вплотную к своей колонке). Раньше значения зависели от того,
   какие классы случайно достались СОСЕДЯМ: метка над «1. …» получала 3px по
   :has(+ .tpara-lexstart), над «2. …» — 8px; метка после колонки слов теряла
   16px сверху. Селектор с ТРЕМЯ классами (rubric+section есть у всех 23 меток)
   — чтобы честно перебивать .tpara-prose/.tpara-word, а не полагаться на
   порядок в файле (на этом я уже обжигался: удаление правила НЕ включает
   более общее). */
#tx-answer .text-para.tpara-rubric.tpara-section {
  text-indent: 2em; margin-top: 16px; margin-bottom: 3px;
}
/* Первый ЗАГОЛОВОК после шапки НЕ поджимаем: он получает те же 16px от
   .tpara-rubric, что и все остальные заголовки ответа. Прежнее правило ставило
   ему 8px, из-за чего зазор НАД заголовком (8px) выходил меньше, чем ПОД ним
   (14px) — заголовок липнул к шапке и отрывался от своего содержимого
   (упр.400 «Фигурист»). Обычный текст после шапки по-прежнему 8px:
   его задаёт .part-heading + .text-para. */
#tx-answer .part-heading + .text-para.tpara-rubric { margin-top: 16px; }
/* Первый пункт «1. …» СРАЗУ ПОД СВОИМ заголовком — вплотную, в ритм списка
   (между «1.» и «2.» тоже 3px). tpara-lexstart даёт 14px, чтобы разделять
   идущие подряд РАЗНЫЕ статьи («3. …» одной ⟶ «1. …» следующей, упр.339) —
   но под собственным заголовком этот воздух отрывал пункт от слова, к
   которому он относится (упр.79 «Язык», 298 «Поле», 400 «Фигурист»).
   Специфичность 4 — перебивает tpara-lexstart независимо от порядка. */
#tx-answer .text-para.tpara-rubric + .text-para.tpara-lexstart { margin-top: 3px; }
/* …и НИЖНИЙ отступ самого заголовка: зазор = max(низ предыдущего, верх
   следующего). У заголовков без .tpara-word (упр.278 «Жесто́кий») остаётся
   дефолтный margin-bottom 14px от .text-para, и он перебивал бы 3px сверху. */
#tx-answer .text-para.tpara-rubric:has(+ .text-para.tpara-lexstart) { margin-bottom: 3px; }
/* Рубрика-подзаголовок ВНУТРИ связного текста/диалога («Диалог:», «Обращение:»):
   16px сверху и стандартный низ разносят реплики слишком сильно — поджимаем
   (глоссарные рубрики без tpara-prose сохраняют просторные 16px). */
/* :not(.tpara-section) — кремовую плашку-секцию НЕ ужимаем (иначе липнет к тексту
   сверху, упр.123 «Интересные факты…»); она держит воздух 16/8 из правила выше. */
#tx-answer .text-para.tpara-rubric.tpara-prose:not(.tpara-section) { margin-top: 3px; margin-bottom: 1px; }
/* Зазор ПЕРЕД рубрикой диалога диктует margin-bottom предыдущей реплики (6px),
   а не margin-top рубрики (схлопывание берёт больший) — поджимаем реплику,
   стоящую прямо перед рубрикой. */
#tx-answer .text-para.tpara-prose:has(+ .text-para.tpara-rubric.tpara-prose:not(.tpara-section)) { margin-bottom: 1px; }
/* Каждый параграф (w:p в docx) — отдельный <p>.
   Красная строка (для русского языка) + отступ между абзацами.
   text-align: left — критично. С justify браузер раздвигает inline-block .ch
   внутри слов по всей строке. */
#tx-answer .text-para {
  margin: 0 0 14px 0;
  text-indent: 2em;
  line-height: 1.55;
  text-align: left;
}
#tx-answer .text-para:last-child { margin-bottom: 0; }
/* Иерархия «секция → Правило:/Лишнее слово:» отступами (упр.446): секция-заголовок
   к левому краю + воздух сверху для разделения групп; подпункт — сдвиг блока вправо
   (виден как вложенный).
   ★КРАСНУЮ СТРОКУ СОХРАНЯЕМ У ОБОИХ (решение владельца 2026-07-28): предмет —
   русский язык, абзац без отступа первой строки читается как ошибка оформления.
   Вложенность несёт `padding-left` блока, а не отсутствие красной строки. */
/* Ритм: 16 между группами, 6 внутри группы, 3 после заголовка группы —
   три ступени, не больше (18 и 16 рядом читались как случайность). */
#tx-answer .text-para.tpara-secthead { margin-top: 16px; }
#tx-answer .text-para.tpara-secthead:first-child { margin-top: 0; }
#tx-answer .text-para.tpara-subrule { padding-left: 2em; margin: 3px 0 6px; }
/* ★ЭЛЕМЕНТ ПЕРЕЧНЯ — с маркером и висячим отступом. Структура списка была видна
   только по сдвигу, без маркеров читалась как обычные абзацы (замечание владельца
   2026-07-28). Красной строки у элемента списка нет — это не абзац прозы, у него
   висячий отступ: маркер стои́т в поле, текст выровнен по левому краю строки. */
/* Элемент списка: МАРКЕР стои́т на ступени вложенности, поле под маркер 1.1em,
   текст — сразу за полем. Одинаково для «•» и для своих маркеров («а)», «1)»),
   чтобы текст всех элементов начинался на одной вертикали. */
#tx-answer .text-para.tpara-bullet, #tx-answer .text-para.tpara-listitem {
  text-indent: 0; padding-left: 2.6em; position: relative;
}
/* Проза-содержимое пункта: та же колонка, что и маркеры списка (3em), без висячего
   отступа — ей нечего выносить в поле. */
/* Проза-содержимое пункта — обычный абзац, только сдвинутый в колонку пункта:
   КРАСНАЯ СТРОКА У НЕГО ЕСТЬ (правило владельца: либо везде, либо нигде). Без неё
   пункт с отступом и его содержимое без отступа читались как разная типографика. */
#tx-answer .text-para.tpara-inner { padding-left: 1.5em; margin-bottom: 6px; }
/* Часть-СПИСОК: красной строки нет ни у одного абзаца — уровень показывают колонки.
   Идёт ПОСЛЕ правил колонок, чтобы перебить базовый text-indent: 2em. */
#tx-answer .text-para.tpara-flat, #tx-answer .text-para.tpara-flat.tpara-rubric.tpara-section, #tx-answer .text-para.tpara-flat.tpara-secthead { text-indent: 0; }
/* Метка-подзаголовок ВНУТРИ прозаической группы («Свои примеры:», упр.276).
   Она подчинена заголовку группы, поэтому обязана быть и в его колонке
   (красная строка 2em, как у статей группы), и отделена СЛАБЕЕ него.
   ★Иерархия была перевёрнута: метка получала 16px сверху от .tpara-rubric
   .tpara-section, а заголовок новой группы — 12px от .tpara-numitem, то есть
   подчинённая строка отбивалась сильнее главной. Ритм читается снизу вверх:
   6px между статьями < 8px перед меткой < 12px перед новой группой. */
#tx-answer .text-para.tpara-flat.tpara-rubric.tpara-section.tpara-prose {
  text-indent: 2em; margin-top: 8px; margin-bottom: 3px;
}
/* Часть-список целиком (подача назначена человеком): красной строки нет ни у
   одного абзаца — ни у прозы, ни у метки-заголовка группы. Левый край один:
   тот же, что у номеров пунктов. Селектор с .flat-list бьёт правило выше,
   которое поднимает метку в колонку прозы (оно писалось для СМЕШАННОЙ части,
   упр.276 «Свои примеры:», где рядом с меткой действительно идёт проза).
   Второй селектор перечислен полностью не для красоты: у правила выше пять
   классов, и коротким `.part.flat-list > .text-para` его не перебить. */
#tx-answer .part.flat-list > .text-para { text-indent: 0; }
/* …и тот же ритм у ОБЕИХ меток группы: 16px сверху, 3px снизу. Без этого первая
   метка получала 8px от правила смешанной части, вторая — 16px от общего
   правила метки-секции, и одинаковые по смыслу строки стояли по-разному
   (упр.350: «По горизонтали:» и «По вертикали:»). */
#tx-answer .part.flat-list > .text-para.tpara-flat.tpara-rubric.tpara-section.tpara-prose {
  text-indent: 0; margin-top: 16px; margin-bottom: 3px;
}
/* Заголовок группы прижат к СВОЕЙ прозе, а не оторван от неё. Общее правило
   «обычный абзац после компактной строки — 14px» ставило заголовку группы
   зазор БОЛЬШЕ (14px), чем зазор перед самим заголовком (12px): заголовок
   липнул к предыдущей группе и отрывался от собственных статей. Гейт
   `:not(.tpara-inner)` — чтобы не задеть содержимое пунктов (упр.174 П2), у
   которого прижатие уже своё. */
#tx-answer .text-para.tpara-word.tpara-numitem + .text-para.tpara-prose:not(.tpara-inner) {
  margin-top: 3px;
}
/* Продолжение пункта прижато к своему пункту. Общее правило «обычный абзац
   после компактной строки — 14px» писалось для случая «стих кончился, дальше
   проза»; когда компактная строка — это САМ ПУНКТ («1. Оранжевый — цвет…»), его
   вторая статья получала те же 14px, что и граница между пунктами, и ритм
   выходил плоским: группировки нет, номера ни на что не опираются (упр.274,
   и ещё 68 упражнений в двух пилотах).
   ★Значение 10px — НЕ произвольное: ровно столько ставит `tightenExplains()`
   длинному продолжению пункта. Когда правило давало 6px, две однородные
   словарные статьи одного упражнения расходились: «Лиловый…» (53 знака) шёл на
   6px, «Сосна…» (102 знака) — на 10px, потому что JS-порог «длинного пояснения»
   равен 60 знакам. Длина строки — не структурный признак, ритм от неё зависеть
   не должен; сравняли значения, чтобы оба механизма давали одно и то же. */
#tx-answer .text-para.tpara-word.tpara-numlead + .text-para:not(.tpara-word):not(.tpara-rubric):not(.tpara-prose) {
  margin-top: 10px;
}
/* Простой список: весь пункт (и его содержимое) сдвинут на красную строку —
   номер встаёт туда, где у прозы начинается первое слово, висячий отступ
   внутри пункта сохраняется. Сложный список (.part без .simple-list) не
   трогаем: там левый край держат колонки вложенности. */
/* ★РИТМ ПРОСТОГО СПИСКА (замечание владельца 2026-07-29). Воздух 12px между
   пунктами придуман для СЛОЖНОГО списка, где пункт — это группа со своим
   содержимым (памятка 174). В плоском перечне однострочных пунктов (пословицы
   82, типы монологов 86) он разводит строки: шаг был 37px, стал 46px, и ряд
   рассыпается. В простом списке держим прежний компактный ритм 3px. */
#tx-answer .part.simple-list > .text-para.tpara-numitem, #tx-answer .part.simple-list > .text-para.tpara-numitem.tpara-lexstart { margin-top: 3px; }
/* ★Одинаковый зазор после КАЖДОЙ метки-группы. `tpara-lexstart` («новая серия
   нумерации») ставится там, где счёт начинается с единицы, — в упр.82 пословицы
   идут вразнобой (2,3,4,7 / 1,5,6), поэтому первый пункт второй группы получал
   6px, а первый пункт первой — 3px, и зазоры под метками отличались. Расстояние
   до метки задаёт САМА метка (16px сверху), пункту добавка не нужна. */
#tx-answer .part.simple-list > .part-heading + .text-para.tpara-lexstart { margin-top: 6px; }
#tx-answer .part.simple-list > .text-para.tpara-numitem, #tx-answer .part.simple-list > .text-para[class*="tpara-lvl"] { margin-left: 2em; }
/* Метка-рубрика внутри простого списка («1) Об устной речи и слушании:») —
   заголовок группы, а не вложенный пункт: она встаёт на ту же вертикаль, что
   номера пунктов под ней. Без этого её сносило на ступень вправо (упр.82:
   метка 101px против 44px у пунктов) и группа читалась как подпункт. */
#tx-answer .part.simple-list > .text-para.tpara-rubric { padding-left: 0; text-indent: 0; }
/* Содержимое пункта не тянет за собой базовые 14px снизу — иначе перед следующим
   пунктом получается 14 вместо ритмичных 12. */
#tx-answer .text-para.tpara-listitem, #tx-answer .text-para.tpara-bullet { margin-bottom: 6px; }
/* Нумерованный пункт верхнего уровня: воздух сверху, чтобы пункты не слипались с
   содержимым предыдущего (ритм: 12 между пунктами, 3–6 внутри пункта). */
/* Нумерованный пункт — ВИСЯЧИЙ ОТСТУП: номер «5.» стои́т в поле, а текст пункта
   начинается ровно там же, где потом пойдёт его содержимое. Иначе номер съедает
   часть строки, и колонка текста пункта не совпадает с колонкой содержимого
   (замечание владельца по упр. 174). */
#tx-answer .text-para.tpara-numitem { margin-top: 12px; padding-left: 1.5em; text-indent: 0; }
/* Содержимое пункта прижато к своему пункту (3px), иначе общее правило «после
   компактной строки — 14px» отрывает его и оно читается как отдельный блок. */
#tx-answer .text-para.tpara-numitem:first-child { margin-top: 0; }

/* Глубина списка: МАРКЕР уровня N встаёт ровно под ТЕКСТ уровня N−1 — так вложенный
   список читается как продолжение своего пункта, а не как отдельная колонка.
   Уровень 1: маркер 2em, текст 3.1em. Уровень 2: маркер 3.1em, текст 4.2em. И т. д. */
/* Компактные строки-пункты плана: сдвиг по уровню без превращения в список. */
#tx-answer .text-para.tpara-word.tpara-lvl1:not(.tpara-listitem) { padding-left: 1.5em; }
#tx-answer .text-para.tpara-word.tpara-lvl2:not(.tpara-listitem) { padding-left: 3em; }
/* Каждый следующий уровень — ещё одна такая же ступень (1.5em). */
#tx-answer .text-para.tpara-lvl2 { padding-left: 4.1em; }
#tx-answer .text-para.tpara-lvl2.tpara-bullet::before { left: 3em; }
#tx-answer .text-para.tpara-lvl2.tpara-inner { padding-left: 3em; }
#tx-answer .text-para.tpara-lvl3 { padding-left: 5.6em; }
#tx-answer .text-para.tpara-lvl3.tpara-bullet::before { left: 4.5em; }
#tx-answer .text-para.tpara-lvl3.tpara-inner { padding-left: 4.5em; }
/* Пункт со СВОИМ маркером («а) …», «1) …»): маркер выносим в то же поле, что и «•»,
   чтобы левый край списка был один. Висячий отступ даёт отрицательный text-indent. */
#tx-answer .text-para.tpara-listitem { text-indent: -1.1em; }   /* маркер на ступень содержимого */
#tx-answer .text-para.tpara-bullet::before {
  /* маркер служебный — графит, как метка-рубрики. Медовый тут конкурировал бы
     с медовыми орфограммами внутри самой строки («де́рево», «ко́сит»). */
  content: "•"; position: absolute; left: 1.5em; color: #6b6157; font-weight: 700;
}
/* Абзац-одиночное слово (колонка имён/слов): компактный интервал, но красная
   строка (2em) сохраняется — наследуется от .text-para. */
#tx-answer .text-para.tpara-word { margin-bottom: 3px; }
/* ★ЧАСТЬ-РАЗБОР — плотнее прозы (решение владельца 2026-07-28: «много воздуха»).
   Разбор читается как СПИСОК помет к одному слову, а не как текст: строки
   короткие, и интервал прозы (1.55) рвёт их на отдельные полосы. Замер упр.97
   при кегле 22px: было строка 34.1px + 12…14px между пунктами (шаг 46px),
   стало 29.7px + 6…8px (шаг ~36px). Подпункты «П. п.:/Н. п.:» идут вплотную к
   своему пункту — они его продолжение. Фонетический блок сюда не попадает: у
   него своя разметка (.ph-row). */
#tx-answer .part.razbor .text-para { line-height: 1.35; margin-bottom: 2px; }
#tx-answer .part.razbor .text-para + .text-para { margin-top: 6px; }
#tx-answer .part.razbor .text-para.tpara-numitem { margin-top: 8px; }
/* ★ГРАНИЦА МЕЖДУ РАЗБОРАМИ РАЗНЫХ СЛОВ под одной шапкой. Было 8px против 6px
   между пунктами — глаз такую разницу не берёт, и две статьи читались одним
   столбиком (упр.107: «…сорок — дополнение» липло к «Стройная — имя
   прилагательное»). Ступень должна быть явной: 16px = вдвое больше межпунктового
   зазора, как между пунктами списка. Первый пункт статьи своё исключение
   сохраняет (правило ниже, оно специфичнее). */
#tx-answer .part.razbor .text-para.tpara-lexstart { margin-top: 16px; }
/* …но ПЕРВЫЙ пункт разбора — не новая статья. В морфологическом разборе за
   строкой-заголовком («Уточним — глагол») идёт «1. (Что сделаем?) …», и класс
   tpara-lexstart («счёт начался с единицы») давал ему 8px там, где между
   остальными пунктами 6px: внутри одного разбора был лишний шов. Настоящая
   новая статья стоит ДАЛЬШЕ по части и свои 8px сохраняет. По базе Пилота 2:
   36 разборов с лишним швом против 2 законных статей (упр. 237, 267). */
#tx-answer .part.razbor > .part-heading + .text-para + .text-para.tpara-lexstart {
  margin-top: 6px;
}
/* …то же и для ВТОРОЙ статьи: её «1. …» стоит сразу за строкой-заголовком
   разбора, и оба абзаца помечены tpara-lexstart. Без этого первый пункт получал
   границу между статьями (16px) внутри своей же статьи. */
#tx-answer .part.razbor .text-para.tpara-lexstart + .text-para.tpara-lexstart {
  margin-top: 6px;
}
#tx-answer .part.razbor .text-para.tpara-lvl1 { margin-top: 0; }
/* Подпункты «П. п.: …» / «Н. п.: …» — продолжение своего пункта: 2px вместо 6px.
   Иерархия читается снизу вверх: 2px внутри пункта < 6px между пунктами <
   8px между разборами разных слов.
   ★Одного зазора мало: 2px против 6px глаз почти не различает, и разбор читался
   плоским столбиком (замечание владельца по упр.317). Добавляем СТУПЕНЬ 1.5em —
   ту же, что у вложенных пунктов в правилах вёрстки: теперь видно, что «П. п.»
   и «Н. п.» принадлежат пункту «2. Н. ф. — …», а не стоят с ним вровень.
   ★Ступень считается ОТ СТАРТА ПУНКТА, а не от края колонки: у пункта своя
   красная строка 2em, поэтому padding 1.5em ставил подпункт ЛЕВЕЕ пункта —
   иерархия переворачивалась.
   ★Ступень НЕ произвольная: подпункт продолжает пункт «2. Н. ф. — …», поэтому
   встаёт ровно под ЕГО ТЕКСТОМ. Замер упр.141 при кегле 22px: пункт стартует на
   44px (красная строка 2em), номер «2. » занимает 22px (1em), текст пункта — с
   66px. Значит padding-left = 3em. Прежние 3.5em ставили подпункт на 77px — на
   11px правее текста пункта, и колонка не сходилась (заметил владелец). */
#tx-answer .part.razbor .text-para.tpara-subpoint:not(.tpara-inner):not(.tpara-listitem) {
  margin-top: 2px; padding-left: 3em; text-indent: 0;
}
/* ★ПАРА «ПУНКТ + ПОЯСНЕНИЕ» В РАЗБОРЕ: раздвигаем ПУНКТ, а не поджимаем
   пояснение. Пояснение под пунктом получает 10px (правило ниже), и при зазоре
   между пунктами 6px пара разъезжалась сильнее, чем граница пар (упр.237, 268).
   Поджать пояснение до 3px нельзя физически: под пунктом идут ЧЕРТЫ членов
   предложения, они опускаются ниже бокса абзаца — по замеру при 6px просвета
   остаётся 3px, почти касание, ради этого 10px и выбраны. Поэтому пункт,
   за которым идёт пояснение, получает 14px: 14 > 10, пара снова читается парой.
   Разборы без пояснений (морфологический: пункты + подпункты) не затронуты. */
#tx-answer .part.razbor .text-para.tpara-word.tpara-numlead:has(
    + .text-para:not(.tpara-word):not(.tpara-subpoint):not(.tpara-rubric)) {
  margin-top: 14px;
}
#tx-answer .part.razbor .part-heading + .text-para { margin-top: 4px; }
/* Начало новой словарной статьи/разбора «1. …» — воздух сверху, чтобы разборы
   разных слов не сливались (упр.339). Первый после шапки — меньше. */
#tx-answer .text-para.tpara-lexstart { margin-top: 14px; }
#tx-answer .part-heading + .text-para.tpara-lexstart { margin-top: 6px; }
/* Начало новой строфы стиха — разделяющий отступ сверху (внутри строфы строки
   идут плотно по tpara-word, между строфами — этот зазор; упр.382). */
#tx-answer .text-para.tpara-stanza { margin-top: 16px; }
/* Связный текст/диалог (ряд прозаических абзацев): межабзацный отступ меньше
   стандартного 14px — история и реплики читаются как единый текст (упр.366). */
#tx-answer .text-para.tpara-prose { margin-bottom: 6px; }
/* Разбор по составу с ОСНОВОЙ: скобка основы опускается ниже строки —
   добавляем нижний отступ, чтобы следующая шапка не прижималась к слову. */
#tx-answer .text-para.tpara-stem { padding-bottom: 14px; }
/* ★Компенсация запечённой геометрии (2026-07-22). Правило выше писалось ДО
   перехода на baked-геометрию: тогда скобка основы уходила под строку и её
   нечем было учесть. Теперь `bake_geom` сам резервирует место под всё, что
   рисуется ниже строки (pad_bottom = графика + 3px «дыхания»), поэтому 14px
   абзаца складывались с ним и давали двойной зазор: под последней краской
   выходило ~18px против ~6px полу-интерлиньяжа у обычного текста — разбор
   «отваливался» от следующей шапки (упр.127 «Пыльного» → «Значение слова»).
   Убираем избыток ТОЛЬКО у разбора, стоящего последним в части, т.е. прямо
   перед следующей плашкой. ★Условие `:has(+ …)` обязательно: без него правило
   ловит и разбор, завершающий ВСЮ карточку (там 14px нужны — иначе низ
   карточки поджимается), и охват прыгает с 13 мест до 57.
   Внутри части 14px тоже оставляем — там они разделяют строки разбора.

   ★ЗНАЧЕНИЕ 7px, а не 0 (пересчёт 2026-07-23, владелец: «стало меньше чем
   нужно»). Считать надо от НИЖНЕЙ КРАСКИ до плашки, и у чипа нет того, что
   есть у обычной строки:
       обычный абзац:  9.7px хвоста строки (полу-интерлиньяж 3.85 + descender
                       5.83 при кегле 22 / line-height 1.55) + 18px margin ≈ 28px;
       чип-разбор:     запечённый бокс обрезан в 3px под скобкой основы
                       (`bake_geom.gap_below`) — хвоста строки НЕТ.
   Значит компенсировать надо не до нуля: 3 + 7 + 18 ≈ 28px = эталон.
   При 2px выходило 23px (на 5px тесно), при исходных 14px — 35px. */
#tx-answer .part:has(+ .part) .text-para.tpara-stem:last-child { padding-bottom: 7px; }
/* Тот же случай, но сосед — не следующая часть, а блок ПОЯСНЕНИЙ (упр.41
   «Морфемный разбор» → плашка «Орфограммы»): разбор стоит последней частью,
   `:has(+ .part)` не срабатывает и 14px остаются. Оптически ситуация та же —
   впереди кремовая плашка, отступ между ними схлопывается до 18px, значит
   и компенсация та же. Разбор, завершающий ВСЮ карточку (пояснений
   после него нет), по-прежнему держит 14px. Охват: 18 упражнений. */
#tx-answer .part:has(+ .explanations) .text-para.tpara-stem:last-child { padding-bottom: 7px; }
/* Нумерованная группа «N. …» — висячий отступ. Цифра остаётся на красной
   строке (2em), текст пункта выровнен под первым словом (2em + ширина «N. »).
   numstart: первая строка с цифрой висит влево; numcont: следующие предложения
   пункта начинаются от той же текстовой линии. */
/* Цифра в фиксированном гутере 1.4em (старт на красной строке 2em), текст
   пункта и продолжения — на 3.4em (точное выравнивание при любой ширине цифры). */
#tx-answer .text-para.tpara-numgrp { padding-left: 3.4em; text-indent: 0; margin-top: 4px; margin-bottom: 4px; }
#tx-answer .text-para.tpara-numcont { padding-left: 3.4em; text-indent: 0; margin-bottom: 4px; }
/* Абзац ПОСЛЕ нумерованного списка (вывод/примечание) — отделяем от списка,
   чтобы граница «список → вывод» совпадала с «вступление → список» (между
   пунктами при этом остаётся плотно). */
#tx-answer .text-para.tpara-numgrp + .text-para:not(.tpara-numgrp):not(.tpara-numcont), #tx-answer .text-para.tpara-numcont + .text-para:not(.tpara-numgrp):not(.tpara-numcont) {
  margin-top: 12px;
}
/* Нумерованный пункт С ГРАФИКОЙ (морфемы/чипы/звуко-чипы) — просторный интервал,
   чтобы дуги/скобки разбора не налезали на соседнюю строку (вместо тесных 4px). */
#tx-answer .text-para.tpara-numgrp.tpara-num-graphic, #tx-answer .text-para.tpara-numcont.tpara-num-graphic { margin-top: 12px; margin-bottom: 12px; }
#tx-answer .numgut { display: inline-block; width: 1.4em; margin-left: -1.4em; text-indent: 0; }
/* Пункт памятки: поле под номер шире и совпадает со ступенью вложенности (1.5em). */
#tx-answer .numgut.numgut-item { width: 1.5em; margin-left: -1.5em; }
/* Интонационные упражнения: висячий отступ нумерации сохраняем, но межстрочный
   интервал крупнее — над словами стрелки повышения/понижения, нужен воздух. */
#tx-answer .text-para.tpara-into { margin-top: 14px; margin-bottom: 14px; }
#tx-answer .text-para.tpara-numgrp.tpara-into { margin-top: 20px; margin-bottom: 14px; }
#tx-answer .text-para.tpara-numcont.tpara-into { margin-top: 14px; margin-bottom: 14px; }
/* Пункт маркированного списка: без красной строки, маркер в левом гутере. */
#tx-answer .list-item { text-indent: 0; margin-left: 1.5em; }   /* отступ списка ≈ красная строка */
/* Плотный интервал — только у ПРОСТЫХ пунктов (без морфем/чипов над словами): тот же
   интервал, что у компактного/нумерованного контента (tpara-word: margin 3px,
   line-height 1.55 наследуется) — чтобы список не отличался от соседних строк упр.
   (упр.248 — плотно; упр.364 — совпадает с нумерованным ответом выше). */
#tx-answer .list-item.list-tight { margin-bottom: 3px; }
/* Кроссворд: пустые клетки невидимы, буквы — в квадратиках, цифры — красные
   номера (по горизонтали/вертикали) без рамки. */
#tx-answer .xword { border-collapse: collapse; table-layout: fixed; margin: 12px 0;
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif; }
#tx-answer .xword td { width: 1.7em; height: 1.7em; padding: 0; text-align: center;
  vertical-align: middle; font-size: 15px; line-height: 1; }
#tx-answer .xword .xw-empty { border: none; background: transparent; }
#tx-answer .xword .xw-let { border: 1px solid #c2b393; text-transform: uppercase;
  position: relative; }   /* Ф5: убран синий — тёплая рамка клетки */
/* Номер в углу стартовой клетки (по горизонтали/вертикали) — красный. */
#tx-answer .xword .xw-n { position: absolute; top: 0; left: 1px; font-size: 9px;
  line-height: 1; font-weight: 700; color: #E33; }
/* Второй номер (в клетке начинаются и горизонталь, и вертикаль) — в
   противоположном углу, как в книге. */
#tx-answer .xword .xw-n2 { top: auto; left: auto; bottom: 0; right: 1px; }
#tx-answer .list-bullet { display: inline-block; color: var(--ink-2); }
/* Тире-маркер — служебный: светло-серый и с тонким штрихом (scaleY), чтобы не
   сливаться со смысловым тире. */
#tx-answer .list-bullet.list-dash { color: var(--ink-3); transform: scaleY(0.7);
  transform-origin: center; }
/* Звуковой чип НАД буквой — стиль как у подписи «нареч.» (упр.31):
   серая плашка #f0f0f3, тонкая обводка, текст #8e8e93. */
#tx-answer .lchip { position: relative; }
#tx-answer .lchip-tag {
  position: absolute; bottom: 1.5em; left: 50%; transform: translateX(-50%);
  width: max-content; text-align: center; text-indent: 0;
  font-size: 9.5px; font-weight: 400; font-style: normal; line-height: 1.25;
  color: #8e8e93; background: #f0f0f3;
  border: 1px solid rgba(0,0,0,0.06); border-radius: 3px;
  padding: 1px 4px; white-space: nowrap; pointer-events: none;
}
/* Фонетика: звук в скобках. Наведение подсвечивает все такие же звуки фразы. */
#tx-answer .snd { border-radius: 3px; cursor: pointer;
  transition: background-color .08s ease, box-shadow .08s ease; }
#tx-answer .snd-hl { background: rgba(0,0,0,0.10);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.10); }
/* «Буквы и звуки» парами (type=letters_sounds) — карточка разбора. */
#tx-answer .letters-sounds { margin: 12px 0 8px; max-width: 560px;
  background: var(--surface); border: 1px solid rgba(0,0,0,0.10);
  border-radius: 12px; padding: 14px 16px 12px; }
#tx-answer .ls-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; border-bottom: 1px solid rgba(0,0,0,0.08);
  padding-bottom: 9px; margin-bottom: 12px; }
#tx-answer .ls-word { font-weight: 600; font-size: 1.25em; color: var(--ink); }
#tx-answer .ls-count { font-size: 0.8em; color: var(--ink-2); white-space: nowrap; }
#tx-answer .ls-body { display: flex; align-items: stretch; gap: 10px; }
/* Подписи рядов слева — зеркалят вертикальную структуру колонки
   (буква 34 / коннектор 8 / звук 34), поэтому выравниваются по рядам. */
#tx-answer .ls-rowlabels { display: flex; flex-direction: column; align-items: flex-end;
  padding: 3px 0; }
#tx-answer .ls-rl { font-size: 0.62em; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--ink-3); line-height: 34px; }
#tx-answer .ls-rl-gap { height: 8px; }
#tx-answer .ls-grid { flex: 1; display: flex; gap: 4px; flex-wrap: nowrap; }
#tx-answer .ls-col { flex: 1; display: flex; flex-direction: column; align-items: center;
  padding: 3px 0; border-radius: 8px; cursor: default;
  transition: background .1s ease; }
#tx-answer .ls-col:hover { background: #f4efe6; }
#tx-answer .ls-col.ls-multi { flex: 1.4; background: var(--bg); }
#tx-answer .ls-letter { font-weight: 600; font-size: 1.15em; line-height: 34px; color: var(--ink); }
#tx-answer .ls-conn { width: 1px; height: 8px; background: rgba(0,0,0,0.18); }
#tx-answer .ls-sound { font-size: 1.0em; line-height: 34px; color: var(--ink-2); }
/* Скобки приглушены, чтобы ударение на гласной (◌́) было хорошо видно. */
#tx-answer .ls-br { color: var(--ink-3); font-weight: 400; margin: 0 1px; }
#tx-answer .ls-snd-val { padding: 0 0.5px; }
/* Фонетический текст со звуками в скобках: чуть разрядка, чтобы ударение в
   «[о́]» не зажималось скобкой. */
#tx-answer .phon-sp { letter-spacing: 0.05em; }
#tx-answer .ls-col.ls-changed .ls-letter, #tx-answer .ls-col.ls-changed .ls-sound { color: #C25E00; }
#tx-answer .ls-col.ls-changed .ls-sound { font-weight: 600; }
#tx-answer .ls-col.ls-changed .ls-conn { background: rgba(194,94,0,0.45); }
#tx-answer .ls-cap { margin-top: 12px; font-size: 0.7em; color: var(--ink-3); line-height: 1.3; }
#tx-answer .ls-cap-mark { color: #C25E00; }
#tx-answer .ls-col[data-note] { position: relative; }
#tx-answer .ls-col[data-note]:hover::after {
  content: attr(data-note); position: absolute; bottom: 100%; left: 50%;
  transform: translateX(-50%); margin-bottom: 5px; white-space: nowrap;
  background: #333; color: #fff; font-size: 11px; font-weight: 400;
  padding: 3px 7px; border-radius: 4px; pointer-events: none; z-index: 6; }
/* Отступ первого абзаца после плашки-шапки. По умолчанию ТЕСНО — заголовок
   прижат к своему содержимому (обычный текст: списки, прозаический ответ). */
#tx-answer .part-heading + .text-para { margin-top: 8px; }
/* Метка-подзаголовок (_secthead) сразу под шапкой: больше воздуха, чтобы заливка
   на слове не липла к кремовой плашке шапки (упр.440 «Простые предложения:»). */
#tx-answer .part-heading + .text-para.tpara-secthead { margin-top: 14px; }
/* Абзац, начинающийся с медовой заливки на ПЕРВОМ слове (упр.445 «Безыскусственный
   — искренний…»): фон заливки достаёт до верха строки и липнет к шапке. Тот же
   компенсирующий отступ, что у метки-подзаголовка, — зазор становится как у
   обычного текста (чернила которого стоят ниже верхнего просвета строки). */
#tx-answer .part-heading + .text-para.tpara-hlstart { margin-top: 14px; }
/* Если первый абзац несёт графику НАД буквами (морфемы/крестики/чипы/звуко-чипы)
   — даём просторные 18px, чтобы графика не липла к плашке (разборы). */
/* ★ЗАМЕР: место под графику НАД буквами уже запечено в самом слове — у .word
   padding-top 8px (и у уголка приставки, и у полного разбора). Правило писалось
   до запекания, поэтому 18px давали двойной запас: в одной записи часть с
   разбором отбивалась от шапки втрое сильнее соседней прозы (КВ стр.60, ч.3-4).
   6px + запечённые 8 = 14px до букв против 8px у прозы — разница уже не режет. */
#tx-answer .part-heading + .text-para.tpara-hasgfx { margin-top: 6px; }
/* ★В блоках «Повторение» (Контрольные вопросы) части — это связный текст правила,
   и абзацы идут плотно (6px, как проза). Абзац со словом-примером внутри
   («прочитать», «объехать») получал общий межабзацный шаг 14px, и одна часть
   выбивалась из ритма соседних. Ограничено карточкой Повторения, чтобы не
   трогать разборы в обычных упражнениях. */
#tx-answer section[id^="ex-kv-"] .text-para.tpara-hasgfx:not(.tpara-word) { margin-bottom: 6px; }
/* ★СЕРИЯ СТРОК С ГРАФИКОЙ — перечень, а не проза (замечание владельца по упр.35
   и его реюзу П1 407). Серийный компактинг сюда не достаёт: он требует, чтобы ВСЕ
   блоки абзаца были текстовыми, а здесь в строке сидят слова с дугами морфем
   (`morphology`), поэтому четыре предложения-ответа верстались базовыми 14px, как
   отдельные абзацы прозы. Ступень 6px: втрое меньше прозы, вдвое больше компактной
   серии (3px) — строкам с дугами нужен запас над строкой, поэтому не 3px.
   ★Гейт `:not(.tpara-word)` обязателен: без него правило РАЗДВИГАЛО бы уже
   компактные серии (упр.97, 102 идут по 3px) — то есть чинило одно и ломало другое.
   Стрелки-словосочетания защищены сами: у них `.has-link-arrow` с margin-top 14px,
   он перебивает это правило (упр.105 сохранил прежний зазор). */
#tx-answer .text-para.tpara-hasgfx:not(.tpara-word):has(+ .text-para.tpara-hasgfx) { margin-bottom: 6px; }
/* Поток текста с НЕСКОЛЬКИМИ чипами над словами (упр.339): увеличенный
   межстрочный интервал, чтобы чипы не жались к строке ниже. */
#tx-answer .text-para.tpara-chipflow { line-height: 1.9; }
/* Поток со ЗВУКО-чипами ([а],[ы]…): слово с чипом ~47px, поэтому нужен больший
   интервал, чем у label-чипов (chipflow 1.9=41.8px мало). 2.15 ≈ 47px — все
   строки становятся одной высоты (упр.172). */
#tx-answer .text-para.tpara-sndchipflow { line-height: 2.15; }
/* Абзац с овалами неизменяемых: +~3px к интервалу (база 1.55), чтобы капсулы
   соседних строк не задевали друг друга. */
#tx-answer .text-para.tpara-ovalflow { line-height: 1.69; }
/* Словообразовательное гнездо (упр.342): корень → скобка с производными. */
#tx-answer .wordtree { display: flex; align-items: center; gap: 10px; margin: 12px 0 12px 2em;
  font-size: inherit; line-height: 1.3; }
#tx-answer .wt-num { color: var(--ink); margin-right: 2px; }
#tx-answer .wt-root { font-weight: 500; }
#tx-answer .wt-arr { color: var(--ink-3); }
#tx-answer .wt-main { font-size: 1.1em; }
#tx-answer .wt-branches { display: flex; flex-direction: column; gap: 7px;
  border-left: 2px solid var(--ink-3); padding-left: 14px; }
#tx-answer .wt-branch { display: flex; align-items: center; flex-wrap: wrap; gap: 4px; }
#tx-answer .wt-sub { display: inline-flex; align-items: center; gap: 6px; margin-left: 4px; }
/* Куст однокоренных слов (упр.33): проверочное в рамке, стрелки к остальным.
   Зазор между рамкой и ветками (gap 54px) — это поле, по которому идут
   диагонали; уже — и стрелка вырождается в чёрточку. Ветки разведены по
   вертикали (gap 16px), иначе дуги корня соседних строк задевают линии. */
#tx-answer .wscheme { position: relative; display: flex; align-items: center; gap: 54px;
  margin: 14px 0 14px 2em; line-height: 1.3; }
#tx-answer .ws-svg { position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; overflow: visible; }
#tx-answer .ws-box { border: 1.6px solid var(--ink-2); border-radius: 4px;
  padding: 7px 14px; flex: 0 0 auto; }
#tx-answer .ws-branches { display: flex; flex-direction: column; gap: 16px; }
#tx-answer .ws-branch { display: flex; align-items: center; }
/* Морфемный разбор в потоке (упр.346, §58): марки и над, и под буквами —
   нужен бо́льший интервал, чтобы морфемы соседних строк не наезжали. line-height
   раздвигает строки разбора, НО добавляет «воздух» и под последней строкой —
   компенсируем уменьшенным margin-bottom, чтобы зазор до след. абзаца был обычным. */
#tx-answer .text-para.tpara-morphflow { line-height: 2.4; margin-bottom: 0px; }
/* …и сверху: leading 2.4 уже даёт воздух над первой строкой разбора, поэтому
   после шапки НЕ добавляем ещё 18px (правило tpara-hasgfx) — подтягиваем разбор
   к плашке (идёт ПОЗЖЕ правила hasgfx, потому перебивает его). */
#tx-answer .part-heading + .text-para.tpara-morphflow { margin-top: 4px; }
/* Разбор ТОЛЬКО по основе (подчёркивание снизу, дуг сверху нет, упр.357
   «Запишем текст»): хватает скромного интервала — 2.4 (как у полного разбора)
   был бы избыточен. Дуг сверху нет → после шапки тоже не нужен большой зазор. */
/* Разбор по основе в ПОТОКЕ: бьём 14px padding-bottom от .tpara-stem (место под
   основу уже даёт line-height) — иначе между предложениями большой зазор.
   Идёт ПОЗЖЕ .tpara-stem, потому перебивает (равная специфичность). */
#tx-answer .text-para.tpara-stemflow { line-height: 1.95; margin-bottom: 2px; padding-bottom: 0; }
/* Между предложениями основа-разбора — плотно (выше), но на ГРАНИЦАХ блока
   воздуха больше: после шапки (перед основой) и у последней основы (перед
   следующей шапкой), чтобы подчёркивание не липло к плашке. */
#tx-answer .part-heading + .text-para.tpara-stemflow { margin-top: 12px; }
#tx-answer .text-para.tpara-stemflow:last-child { padding-bottom: 8px; }
/* Обычный абзац ПЕРЕД основа-разбором (напр. «Неизменяемые: …» перед
   «Изменяемые: спросил|а, отпугива|ешь»): line-height 1.95 основа-абзаца сам
   добавляет воздух сверху, поэтому нижний отступ обычного абзаца поджимаем,
   иначе зазор между парными строками-ответами слишком большой (упр.358). */
#tx-answer .text-para:not(.tpara-stemflow):has(+ .text-para.tpara-stemflow) { margin-bottom: 4px; }
/* Обычный абзац СРАЗУ ПОСЛЕ компактного блока (стих/список из коротких строк
   tpara-word) — даём нормальный отступ сверху: проза после стихотворного блока
   читается как новый абзац, а не приклеена к последней строке (упр.345). */
/* Рубрику (короткая строка, попавшая в tpara-word) исключаем — после
   «Диалог:»/«Обращение:» проза не должна получать 14px сверху (упр.366). */
#tx-answer .text-para.tpara-word:not(.tpara-rubric) + .text-para:not(.tpara-word) { margin-top: 14px; }
/* ...но СОДЕРЖИМОЕ пункта прижато к своему пункту: 3px. Специфичность у этих правил
   одинаковая, поэтому решает порядок — наше должно идти ПОСЛЕ общего. */
#tx-answer .text-para.tpara-word:not(.tpara-rubric) + .text-para.tpara-listitem, #tx-answer .text-para.tpara-word:not(.tpara-rubric) + .text-para.tpara-bullet, #tx-answer .text-para.tpara-word:not(.tpara-rubric) + .text-para.tpara-inner { margin-top: 3px; }
/* …но метка-секция после колонки слов — не «проза после стиха»: ей нужны свои
   16px (упр.72 «Сложные предложения:», 276 «Земледелие и уборка урожая:»).
   Специфичность РАВНА правилу выше и правило стои́т НИЖЕ — выигрывает порядком.
   ★Через :not(.tpara-section) в правиле выше делать НЕЛЬЗЯ: это подняло бы его
   специфичность 5→6, и оно перебило бы «стих→стих 0» (упр.169) и «статья→
   описание 3px» (упр.298) — проверено дифом, ловил 4 регрессии. */
#tx-answer .text-para.tpara-word:not(.tpara-rubric) + .text-para.tpara-section { margin-top: 16px; }
/* Заголовок словарной статьи «N. Слово» (_secthead + tpara-word, упр.290): описание
   ПРИЖИМАЕТСЯ к своему слову (перебивает 14px-правило выше той же специфичностью),
   а воздух между статьями даёт tpara-secthead сверху заголовка. */
#tx-answer .text-para.tpara-word.tpara-secthead + .text-para:not(.tpara-word) { margin-top: 3px; }

/* Явный воздух ПЕРЕД абзацем (флаг данных `_air`). Межабзацный шаг задаёт
   margin-BOTTOM предыдущего абзаца (у .text-para margin-top всегда 0), поэтому
   строку внутри компактной серии эвристикой не отделить — нужен явный верхний
   отступ. 14px, а не 11: соседние margin схлопываются, max(3,14) = 14 = обычный
   межабзацный шаг. Ставится там, где строка однородна ПО ФОРМЕ, но открывает
   новую мысль (упр.275: ответ на второй вопрос задания). */
#tx-answer .text-para.tpara-air { margin-top: 14px; }

/* СТИХОТВОРНЫЕ СТРОКИ (флаг абзаца _verse) — ровный плотный шаг.
   Зачем флаг: эвристики классов срабатывают на стихе ВРАЗНОБОЙ. В упр.169
   «Леле[й'у] тр[а́][в]ы» попала под шаблон строки фонразбора «Слово […»
   (он для упр.210) → tpara-word, а «[в][а]лну…» начинается со скобки →
   tpara-prose. Итог: зазоры 14/6/6/3px внутри одного отрывка. Править сам
   шаблон рискованно (сломает упр.210), поэтому явный флаг перебивает их.
   Блок идёт ПОСЛЕ правил tpara-word/prose/lexstart — та же специфичность,
   выигрывает порядком. Ритм: шапка→стих 10, строка→строка 3, между
   отрывками 16, стих→пояснение 14. */
#tx-answer .text-para.tpara-verse { margin-top: 0; margin-bottom: 3px; }
#tx-answer .part-heading + .text-para.tpara-verse { margin-top: 10px; }
#tx-answer .text-para.tpara-verse.tpara-stanza { margin-top: 16px; }
#tx-answer .text-para.tpara-verse + .text-para:not(.tpara-verse) { margin-top: 14px; }
/* Симметрия вокруг цитаты-стиха внутри прозы: отступ ПЕРЕД цитатой равен
   отступу ПОСЛЕ неё (упр.169, цитата из «Бородина» внутри «О приёмах
   звукописи»). .part-heading — это div, а не .text-para, поэтому правило
   «шапка → стих 10px» выше не задевается. */
#tx-answer .text-para:not(.tpara-verse) + .text-para.tpara-verse { margin-top: 14px; }
/* Стих→стих вплотную. Нужна повышенная специфичность: строка, попавшая в
   tpara-prose, иначе ловится правилом «обычный абзац после компактного»
   (.tpara-word + :not(.tpara-word) = 14px, специфичность 0,5,0).
   :not(.tpara-stanza) сохраняет разделитель между отрывками. */
#tx-answer .text-para.tpara-verse + .text-para.tpara-verse:not(.tpara-stanza) { margin-top: 0; }
/* Стих с ГРАФИКОЙ (_verse_air, упр.394 Бунин): тот же ровный ритм, но шаг
   14px — строкам нужен запас под морфемный оверлей, при 3px он столкнётся
   с соседней строкой. ★ОБЯЗАТЕЛЬНО НИЖЕ правила «стих→стих 0»: специфичность
   у них одинаковая (0,5,0), решает порядок в файле. */
#tx-answer .text-para.tpara-verse-air + .text-para.tpara-verse-air:not(.tpara-stanza) { margin-top: 14px; }

/* .word/.overlays/.ch — ЗАПЕЧЁННАЯ модель (bake_geom.WORD_CSS):
   inline-block + per-word padding из запечённой геометрии; SVG-оверлей с
   абсолютными координатами; КЕРНИНГ ВЫКЛЮЧЕН (иначе буквы стянутся и знаки
   уедут вправо). Ноль рантайм-замеров. */

#tx-answer .word { display:inline-block; position:relative; line-height:1; white-space:nowrap;
  vertical-align:baseline; text-indent:0; letter-spacing:0;
  /* text-indent:0 — иначе inline-block наследует красную строку абзаца (2em).
     letter-spacing:0 — иначе наследуется межбуквенный трекинг тела. */
  font-kerning:none; font-feature-settings:"kern" 0,"liga" 0,"calt" 0; }
#tx-answer .overlays { position:absolute; left:0; top:0; pointer-events:none; }
#tx-answer .overlays svg { position:absolute; left:0; top:0; overflow:visible; }
/* .ch — inline-block с ФИКСИРОВАННОЙ шириной = advance из запекания. Это ПРИШПИЛИВАЕТ
   буквы к той же сетке, по которой нарисованы знаки → ноль дрейфа (кернинг,
   letter-spacing, субпиксельный рендер шрифта больше не сдвигают буквы от знаков).
   Ширину каждой .ch проставляет генератор (char_widths). */
#tx-answer .ch { display:inline-block; vertical-align:baseline; text-align:left;
  letter-spacing:0; font-kerning:none; font-feature-settings:"kern" 0,"liga" 0;
  overflow:visible; }


/* Подписи над словом рисуются в SVG через layoutWord — см. drawLabel.
   Стиль (plain/chip) переключается классом body.label-style-* и читается
   из JS. CSS-стилей для .word-label больше не нужно.

   ВАЖНО: слова с подписью (data-label) запрещаем переносить по пробелам
   внутри (например, «не выбежит»), иначе .word разорвётся на две строки
   и SVG-оверлей не сможет нарисовать chip над правильным местом. */
#tx-answer .word[data-label], #tx-answer .word[data-sound-chips] { white-space: nowrap; }

/* Подчёркивания (одинарное и двойное) рисуем единой механикой —
   линиями через градиент-фон. Так у обоих ГАРАНТИРОВАННО одинаковая
   высота верхней линии и толщина, а ширину можно сделать короче буквы,
   чтобы соседние подчёркивания не склеивались.
   Переменные:
     --ul-y      — высота верхней линии (от верха бокса)
     --ul-w      — толщина линии (2px = как было у одинарного)
     --ul-gap    — зазор в двойном = 0.75 * толщина = 1.5px
     --ul-inset  — на сколько px линия короче буквы с каждой стороны */
#tx-answer .sunder, #tx-answer .dunder, #tx-answer .wunder, #tx-answer .dashunder, #tx-answer .dotdashunder {
  /* +2px к --ul-y — все подчёркивания опущены ниже, чтобы не задевать
     хвостики букв (д, р, у, ц...). Padding снизу синхронно увеличен,
     чтобы линия не «обрезалась» границей строки. */
  --ul-y: calc(1.0em + 2px);
  --ul-w: 2px;
  --ul-gap: 1.5px;
  --ul-inset: 0.5px;
  /* Подчёркивание ВСЕГДА чёрное, даже если буква цветная (напр. красная
     в упр.20) — линия не должна наследовать color буквы. */
  --ul-color: var(--ink);
  background-repeat: no-repeat;
  padding-bottom: calc(0.22em + 2px);
}
#tx-answer .sunder {
  background-image: linear-gradient(var(--ul-color), var(--ul-color));
  background-size: calc(100% - var(--ul-inset) * 2) var(--ul-w);
  background-position: center var(--ul-y);
}
/* Черта под ЧАСТЬЮ слова = орфограмма → роль B (бронза, вес 700), как и разбираемая
   буква, помеченная болдом. Вид черты (одна/две) роли не меняет: он говорит, КАКАЯ
   орфограмма, а не как её подавать. Линия остаётся чёрной (--ul-color). */
#tx-answer .sunder.orth, #tx-answer .dunder.orth { color: var(--sign-b); font-weight: 700; }
#tx-answer .dunder {
  background-image:
    linear-gradient(var(--ul-color), var(--ul-color)),
    linear-gradient(var(--ul-color), var(--ul-color));
  background-size:
    calc(100% - var(--ul-inset) * 2) var(--ul-w),
    calc(100% - var(--ul-inset) * 2) var(--ul-w);
  /* верхняя — на той же высоте, что одинарное; нижняя ниже на
     (толщина + зазор) */
  background-position:
    center var(--ul-y),
    center calc(var(--ul-y) + var(--ul-w) + var(--ul-gap));
}

/* Волнистая линия — определение (какой?/чей?). Цвет --ink (#1d1d1f) —
   как у остальных подчёркиваний; ТОЛЬКО ВЕРХНИЕ АРКИ (нижняя половина
   синусоиды срезана). Период 12px, амплитуда 5px, толщина 1.6px. */
#tx-answer .wunder {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 5' preserveAspectRatio='none'><path d='M0 5 Q 3 0 6 5 Q 9 0 12 5' stroke='%231d1d1f' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: repeat-x;
  background-size: 12px 5px;
  background-position: center calc(var(--ul-y) - 1px);
}
/* Пунктир — дополнение (вопросы косвенных падежей). Фаза от ЛЕВОГО края (left),
   чтобы штрихи начинались ровно с начала слова. */
#tx-answer .dashunder {
  background-image: linear-gradient(to right,
    var(--ul-color) 0, var(--ul-color) 65%,
    transparent 65%, transparent 100%);
  background-repeat: repeat-x;
  background-size: 7px var(--ul-w);
  background-position: left var(--ul-y);
}
/* ВЛОЖЕННЫЕ узорные подчёркивания (слово разбито на под-спаны из-за цветной буквы,
   напр. «обез·ь·янами») НЕ рисуют свой фон повторно — иначе у каждого куска своя фаза
   пунктира и штрихи сгущаются на стыках. Рисует ТОЛЬКО внешний непрерывный span. */
#tx-answer .dashunder .dashunder, #tx-answer .dotdashunder .dotdashunder, #tx-answer .wunder .wunder { background-image: none; }
/* ★ЛИНИЯ РВАЛАСЬ НА СТЫКЕ ЦВЕТНЫХ КУСКОВ. Внутри одного подчёркивания движок
   делит текст на спаны по стилю («не» красное + « п» чёрное), и каждый рисует
   свой фон с боковым инсетом 0.5px — на границе оставалась щель в 1px (упр.120
   «не проникал», замер ×3: два отрезка 89 и 36 вместо одного). У ВЛОЖЕННЫХ
   кусков инсет убираем: линия внешнего диапазона идёт сплошной, а по краям
   отступ по-прежнему даёт контейнер. */
.sunder .sunder, .dunder .dunder,
.dashunder .dashunder, .dotdashunder .dotdashunder,
/* ★0px, а НЕ 0. Переменная подставляется в `calc(100% - var(--ul-inset) * 2)`
   как текст: из «0» без единицы получается `calc(100% - 0 * 2)` — вычитание
   безразмерного числа из процентов. Выражение невалидно, браузер отбрасывает
   ВЕСЬ background-size, тот падает в `auto`, и градиент заливает букву целиком:
   вместо черты под буквой — чёрный квадрат (упр.42, 446 и всюду, где линия
   разбита на цветные куски). */
#tx-answer .wunder .wunder { --ul-inset: 0px; }

/* ★ВЛОЖЕННЫЙ ЧЛЕН ВНУТРИ ЧЛЕНА. «пятой» — определение внутри обстоятельства
   «к пятой платформе»: линии разных типов рисуются на одной высоте и сливаются
   в кашу (упр.235 — волнистой под «пятой» просто не было видно). Вложенную
   опускаем на 5px под основную и даём строке воздух снизу. */
#tx-answer .dashunder .wunder, #tx-answer .dotdashunder .wunder, #tx-answer .sunder .wunder, #tx-answer .dunder .wunder, #tx-answer .dashunder .sunder, #tx-answer .dotdashunder .sunder, #tx-answer .dotdashunder .dashunder {
  --ul-y: calc(1.0em + 7px);
  padding-bottom: calc(0.22em + 7px);
}
/* Тире-точка — обстоятельство (где?/куда?/как?/зачем?). Узор: длинное тире,
   зазор, короткая точка, БОЛЬШОЙ зазор — иначе при мелких зазорах сливается
   в сплошную линию (≈50% «чернил»). Период 16px. */
#tx-answer .dotdashunder {
  background-image: linear-gradient(to right,
    var(--ul-color) 0, var(--ul-color) 42%,        /* тире (≈6.7px) */
    transparent 42%, transparent 56%,              /* зазор (≈2.2px) */
    var(--ul-color) 56%, var(--ul-color) 62%,      /* точка (≈1px) */
    transparent 62%, transparent 100%);            /* зазор (≈6px) */
  background-repeat: repeat-x;
  background-size: 16px var(--ul-w);
  /* ★ФАЗА ОТ ЛЕВОГО КРАЯ, а не от центра: при `center` каждый отрезок начинает
     узор со своей фазы, и на стыке двух обстоятельств («Трое суток» + «в
     посёлке») точка вставала рядом с точкой. От левого края узор всегда
     начинается с тире и читается как «тире-точка». */
  background-position: left var(--ul-y);
}
/* Кружок вокруг союза при однородных членах.
   Классика «символ в кружке»: фиксированный квадрат width=height,
   буква центрируется line-height (по вертикали) и text-align (по
   горизонтали). border-radius:50% → ровный круг. Без flex/calc — самый
   надёжный способ во всех движках. */
#tx-answer .circ {
  display: inline-block;
  margin: 0 0.02em;
  overflow: visible;
}
#tx-answer .circ text { font-family: inherit; fill: var(--ink); }
#tx-answer .circ ellipse { color: var(--ink); }
/* Овал-обводка неизменяемого слова (нет окончания). Рамка-стадион вокруг
   текста, не разрывает строку; горизонтальные поля чуть больше для «капсулы». */
#tx-answer .oval {
  /* inline-block держит базовую линию заодно с соседними словами (flex её сбивал).
     «Капсула»: прямые верх/низ + полукруглые торцы (стадион). */
  display: inline-block;
  border: 1.8px solid var(--ink);
  border-radius: 999px;
  /* ЕДИНАЯ посадка для ВСЕХ изданий — по замеру самих учебников (эллипс в PDF):
       Пилот 1, упр.352 (2023): центр эллипса − центр бокса слова = −1.16…+0.66 pt,
                                 среднее ≈ 0.0 pt при кегле 21 pt;
       Пилот 2, упр.247 (2019): +0.22…+1.12 pt, среднее ≈ +0.67 pt.
     Т.е. эллипс центрирован по БОКСУ СТРОКИ (не по «оптической массе» букв и не по
     cap-height), смещение вниз ≈0…0.03em. Берём среднее по обоим изданиям: 0.01em.
     Высота эллипса в PDF = 1.00…1.21em бокса слова → 1.16em + рамка.
     Прежние 0.05/0.24 давали 0.095em — втрое больше любого издания, овал «съезжал». */
  padding: 0.07em 0.3em 0.09em;
  margin: 0 0.06em;
  line-height: 1;
  /* inline-блок наследует красную строку (2em) от .text-para — сбрасываем. */
  text-indent: 0;
}
/* .oval-uc БОЛЬШЕ НЕ НУЖЕН: замер PDF показал, что заглавные («И», «В») обведены
   так же, по боксу строки, а не по cap-height (упр.352: «И» −1.16 pt, «и» −0.38 pt —
   систематической разницы по регистру нет). Класс оставлен как no-op для
   совместимости со старыми собранными viewer.html. */
#tx-answer .oval.oval-uc { }
/* Боксы схем предложений: слова автора (пустой) и прямая речь (штриховка). */
#tx-answer .sch-box {
  display: inline-block;
  width: 3.2em;
  height: 1.15em;
  border: 1.5px solid var(--ink);
  vertical-align: -0.2em;
  margin: 0 0.12em;
  box-sizing: border-box;
}
/* Однородный член схемы: кружок с чертой своего вида внутри. Размер — по
   строчной букве тела ответа, посадка на базовую линию как у .oval. */
/* ★Бокс КВАДРАТНЫЙ — иначе окружность в нём растягивается в эллипс
   (было 1.55em × 1.42em, круг выходил приплюснутым). */
#tx-answer .sch-o { display: inline-block; width: 1.5em; height: 1.5em;
  vertical-align: -0.36em; margin: 0 0.06em; color: var(--ink); }
#tx-answer .sch-o svg { width: 100%; height: 100%; display: block; overflow: visible; }
#tx-answer .sch-p {
  background-image: repeating-linear-gradient(-45deg,
    var(--ink-3) 0, var(--ink-3) 1px, transparent 1px, transparent 5px);
}
/* Знак препинания с устным пояснением (показ по наведению/клику). */
#tx-answer .ptip { position: relative; cursor: help; border-bottom: 2px dotted var(--ink-3); }  /* Ф2: снят синий */
/* Подсказка — РЕАЛЬНЫЙ элемент (JS измеряет и зажимает в границы упражнения,
   чтобы не вылезала за левый/правый край). Длинные переносятся на 2+ строки. */
#tx-answer .ptip-pop {
  position: absolute; bottom: 100%; left: 0; margin-bottom: 5px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--ink-3);  /* Ф2: снят синий */
  font-style: normal; font-weight: 400; font-size: 12px; line-height: 1.25;
  text-align: left; text-indent: 0;
  white-space: normal; width: max-content; max-width: min(260px, 72vw);
  padding: 2px 6px; border-radius: 5px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
  opacity: 0; pointer-events: none; transition: opacity .12s; z-index: 40;
}
#tx-answer .ptip:hover .ptip-pop, #tx-answer .ptip:focus .ptip-pop, #tx-answer .ptip.pin .ptip-pop { opacity: 1; }

/* ===== Пояснения к ответу (схема v1.1) ===== */
/* Контейнер пояснений — только внешний отступ. КОРОБКА теперь у КАЖДОЙ секции
   (см. .exp-section), а не одна общая на все (п.1). */
#tx-answer .explanations { margin: 16px 0 4px; }
#tx-answer .exp-group + .exp-group { margin-top: 10px; }
#tx-answer .exp-title { font-size: 14px; font-weight: 600; color: var(--ink);
  text-transform: none; letter-spacing: 0; margin-bottom: 8px; }
#tx-answer .exp-oral { font-weight: 600; font-size: 10px; color: #6a4400;
  background: #ffe9a8; border-radius: 3px; padding: 1px 5px;
  letter-spacing: 0.03em; text-transform: none; }
#tx-answer .exp-review { font-size: 10px; color: #c0392b; background: #fdecea;
  border-radius: 3px; padding: 1px 5px; }
/* ===== Единая подача объяснений: значки-сноски ●/○ ===== */
/* Форма = статус (залитый «по заданию» / контурный «устно»);
   цвет = вид (красный орфограмма / синий пунктуация). */
/* Значок-сноска пунктуации = инлайн-SVG (НАДЁЖНО круглый). Цвет=статус:
   письменно синий / устно серый. Размер в em → масштабируется со строкой. */
/* ★overflow: visible — иначе у кружка срезается правый край. Считаем:
   viewBox 24, центр 12, радиус 10.8, обводка 2 → внешний край на
   12 + 10.8 + 1 = 23.8, до границы остаётся 0.2 единицы. При
   отрисовке в 13.68px это 0.11px, а на экране двойной плотности —
   четверть пикселя. Своё поле svg по умолчанию обрезает (overflow
   у svg — hidden), и сглаженный край обводки уходит под нож: круг
   выглядит приплюснутым справа. Радиус не трогаем — рисунок задаёт
   генератор; снимаем обрезку. */
#tx-answer .exbadge { vertical-align: -0.16em; flex: none; cursor: pointer;
  overflow: visible; }
#tx-answer .exp-item .exbadge { margin-right: 5px; }
#tx-answer .exbadge-intext { width: 0.72em; height: 0.72em; vertical-align: 0.3em;
  margin: 0 1px 0 1px; }
#tx-answer .exbadge.exflash { border-radius: 999px; box-shadow: 0 0 0 3px rgba(230,163,55,0.5); }
/* Точка нерезолвленного orthogram-пункта (без привязки). */
#tx-answer .exmark { display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.1em; height: 1.1em; box-sizing: border-box; font-size: 12px;
  line-height: 1; vertical-align: middle; }
#tx-answer .exp-item .exmark { margin-right: 4px; flex: none; }
#tx-answer .exmark-na { border:none; background:none; color: var(--ink-3); cursor: default; }
/* Вид орфограммы (rule_type) — ВАРИАНТ C: приглушённый текст, НЕ плашка. */
/* Тип орфограммы СКРЫТ по умолчанию, раскрывается тапом «вид орфограмм». */
#tx-answer .exp-type { color: var(--ink-3); white-space: normal; display: none; }
#tx-answer .exp-section.show-types .exp-type { display: inline; }
/* Чип «вид орфограмм» — лёгкая ghost-кнопка с глазом (без рамки), компактная.
   Открытый глаз = «показать»; перечёркнутый + заливка = «скрыто/нажато». */
#tx-answer .exp-typetoggle { display: inline-flex; align-items: center; gap: 5px;
  background: none; border: none; border-radius: 6px; padding: 2px 7px;
  cursor: pointer; font: inherit; font-size: 11px; font-weight: 600;
  color: var(--ink-2); white-space: nowrap; }
#tx-answer .exp-typetoggle .ett-ic { display: inline-flex; align-items: center; font-size: 14px; }
#tx-answer .exp-typetoggle .eye-off { display: none; }
#tx-answer .exp-section.show-types .exp-typetoggle { background: #efe7d4; color: var(--ink); }
#tx-answer .exp-section.show-types .exp-typetoggle .eye-on { display: none; }
#tx-answer .exp-section.show-types .exp-typetoggle .eye-off { display: inline-flex; }
/* Глаз-кнопку показываем только в раскрытой секции (нечего раскрывать в свёрнутой). */
#tx-answer .exp-section-oral.collapsed .exp-typetoggle { display: none; }
#tx-answer .exp-list { list-style: none; margin: 0; padding: 0;
  font-size: 14px; line-height: 1.7; }
/* ★Перенос внутри пункта выключен. Флекс раскладывает по строкам ДО
   того, как начинает сжимать: у длинного правила своя ширина больше
   остатка строки, и оно целиком уезжало вниз, оставляя кружок с
   цифрой одного на строке. С nowrap правило сжимается в остаток и
   переносится внутри себя, а номер остаётся при первой строке.
   ★min-width: 0 обязателен: без него флекс-элемент не сжимается ниже
   своего содержимого и вместо переноса вылезет за карточку. */
#tx-answer .exp-item { display: flex; gap: 0; align-items: baseline; flex-wrap: nowrap;
  padding: 3px 4px; border-radius: 4px; cursor: pointer; }
#tx-answer .exp-item > * { min-width: 0; }

/* ★Исключение: пункты со словами в морфемной разметке. Там дуги и
   крыши рисуются НАД буквами отдельным слоем, ширину такого слова
   ужимать нельзя — разметка разъедется. Им перенос оставлен. */
#tx-answer .exp-item:has(.word.expl-marks) { flex-wrap: wrap; }

/* ★Кружок с цифрой выравнивается по СЕРЕДИНЕ первой строки, а не по
   её базовой линии. Почему было иначе: у пункта стоит
   align-items: baseline, а базовая линия у встроенного svg — его
   нижний край. Значит нижний край кружка садился ровно на базовую
   линию букв, и текст читался «подвешенным» к низу кружка. Объявленный
   у значка vertical-align при этом не работал вовсе: во флекс-контейнере
   он к элементам не применяется — правило было мёртвым.
   ★Смещение задано в em, чтобы держаться при смене кегля: половина
   разницы между строкой (1.7em) и значком (1.05em). */
#tx-answer .exp-item-punctogram { align-items: flex-start; }
#tx-answer .exp-item-punctogram > .exbadge { margin-top: 0.325em; }

/* Устно-пункт с морфемной разметкой: дуги/крыши рисуются НАД буквами — даём воздух
   сверху, чтобы разметка не касалась строки выше. */
#tx-answer .exp-item:has(.word.expl-marks) { padding-top: 0.35em; }
#tx-answer .exp-item.exflash { background: rgba(230,163,55,0.16); }
#tx-answer .exp-rule { flex: 1 1 auto; min-width: 0; }
#tx-answer .exp-sign { font-weight: 700; }
#tx-answer .exp-section[data-kind="punctogram"] .exp-sign { color: var(--sign-b); }  /* Ф2: разбираемый знак — графит (роль B) */
/* Тире-разделитель «слово — разбор» с воздухом по бокам (не клеить к словам). */
#tx-answer .exp-dash { margin: 0 0.4em; color: var(--ink-3); }
/* Фрагмент-вырезка — ВСЕГДА на отдельной строке СЛЕВА под правилом (не вправо). */
#tx-answer .exp-context { flex: 1 0 100%; font-size: 12px; color: var(--ink-3);
  margin: 1px 0 0 1.7em; text-align: left; }
#tx-answer .exp-item-orthogram .exp-context { margin-left: 0; }
/* В фрагменте сам знак/буква подсвечены ЦВЕТОМ ВИДА. */
#tx-answer .frag-punct { color: var(--sign-b); font-weight: 700; }  /* роль B — графит, вес 700 */
#tx-answer .frag-orf { color: var(--insert); font-weight: 500; }    /* роль A — красный вставки, вес 500 (Ф3) */
/* Орфограмма: красная буква в тексте ответа — тап-цель (без значка). */
#tx-answer .orf-tap, #tx-answer .punc-tap { cursor: pointer; }
/* Знак препинания под сноской красится ПО ТОЙ ЖЕ системе, что буква (реш.
   владельца 2026-07-28): роль A — знак вставлен учеником (в условии его нет),
   красный вес 500; роль B — знак стоял в условии, мы его объясняем, медовый
   вес 700. Правило и вес — те же переменные, что у .orf-red / .sunder.orth,
   чтобы подача не разъезжалась между буквами и знаками. */
#tx-answer .punc-tap.punc-a { color: var(--insert); font-weight: 500; }
#tx-answer .punc-tap.punc-b { color: var(--sign-b); font-weight: 700; }
#tx-answer .orf-tap.exflash, #tx-answer .punc-tap.exflash { background: #ffe9a8; box-shadow: 0 0 0 2px #ffe9a8; border-radius: 3px; }
/* Каждая секция — СВОЯ карточка (единый стиль карточки-шапки). */
#tx-answer .exp-section { background: var(--card-bg); border: var(--card-bd);
  border-radius: var(--card-rad); padding: var(--card-pad); line-height: 1.4; }
/* Inline-пояснение (пунктограмма под СВОЕЙ частью, упр.382): нейтральный СЕРЫЙ фон,
   чтобы не контрастировать с тёплыми шапками частей выше/ниже. */
#tx-answer .exp-section.exp-inline { background: #f0f0f2; margin-top: 10px; margin-bottom: 24px; }
/* Стихоподобная часть (строки с красной строкой 2em, упр.382 четверостишие) — сдвигаем
   серый блок на 2em, чтобы его левый край совпал с ТЕКСТОМ строк выше. Для прозы (текст
   с левого поля, упр.195) — без сдвига. */
#tx-answer .exp-section.exp-inline.exp-inline-indent { margin-left: 2em; }
/* Вариант 3 (комментарий к учебному тексту): блок стоит СРАЗУ ПОД своим
   предложением внутри части, а не в конце ответа. Прижимаем к нему сверху
   (10 → 4) и не отрываем от следующего абзаца памятки (24 → 14). Сдвиг 2em —
   тот же, что у Варианта 1: левый край совпадает с текстом абзаца (красная
   строка), блок читается как примечание к нему, а не как новый пункт. */
#tx-answer .exp-section.exp-inline.exp-inline-under {
  margin-left: 2em; margin-top: 4px; margin-bottom: 14px; }
/* В сером inline-блоке выделение строк (наведение/вспышка) — тоже СЕРОЕ (нейтральное),
   оттеняется от фона блока по тому же принципу, что тёплое в кремовых секциях. */
#tx-answer .exp-inline .exp-item.exflash { background: rgba(0,0,0,0.11); }
#tx-answer .exp-inline .exp-item:hover { background: rgba(0,0,0,0.07); }
/* Сворачиваемый inline-блок (Вариант 2, часть без шапки): title — тоглер. Раскрыт по
   умолчанию; клик сворачивает список (JS вешает .collapsed на .exp-section). */
#tx-answer .exp-section.exp-collapsible:not(.collapsed) .exp-tri { transform: rotate(90deg); }
#tx-answer .exp-section.exp-collapsible.collapsed .exp-list { display: none; }
#tx-answer .exp-section.exp-collapsible.collapsed .exp-hrow { margin-bottom: 0; }
#tx-answer .exp-section + .exp-section { margin-top: 16px; }   /* отступ между карточками ×2 */
#tx-answer .exp-section-oral { margin-top: 8px; }
/* Свёрнутая секция = только шапка, без лишнего низа. */
#tx-answer .exp-section-oral.collapsed .exp-hrow { margin-bottom: 0; }
/* Единый ряд шапки секции: слева заголовок-тап-цель, справа группа чипов
   (глаз + «устно»). Один размер/шрифт/высота для всех секций объяснений. */
/* ★Ряд переносится целиком, а не по кускам. Было: чипы «flex: none»,
   заголовок «flex: 1 1 auto; min-width: 0» — значит сжимался ТОЛЬКО
   левый блок, и сжимался за счёт счётчика, у которого не было запрета
   на перенос. Получалось «· 8 / слов» в две строки и заголовок не по
   центру ряда. Ломать заголовок вместо счётчика нельзя: «Орфограммы» —
   одно слово, оно рвётся посреди буквы. Поэтому при нехватке места
   вниз уходит вся группа чипов. */
#tx-answer .exp-hrow { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
/* margin-left: auto — чтобы на своей строке чипы тоже стояли справа */
#tx-answer .exp-chips { display: flex; align-items: center; gap: 6px; flex: none;
  margin-left: auto; }
#tx-answer .exp-toggle-title { min-width: 0; }
#tx-answer .exp-toggle { flex: 1 1 auto; min-width: 0; display: flex; align-items: center;
  gap: 7px; background: none; border: none; padding: 2px 0; cursor: pointer;
  font: inherit; font-size: 16px; font-weight: 600; color: var(--card-ink);
  line-height: 1.4; text-align: left; text-transform: none; letter-spacing: 0; }
#tx-answer .exp-hrow-task .exp-toggle-title { font-size: 16px; font-weight: 600; color: var(--card-ink); }
#tx-answer .exp-tri { transition: transform .12s; display: inline-block; flex: none; color: var(--ink-3);
  font-size: 17px; line-height: 1; vertical-align: -1px; }
#tx-answer .exp-section-oral:not(.collapsed) .exp-tri { transform: rotate(90deg); }
#tx-answer .exp-count { font-size: 13px; font-weight: 400; color: var(--ink-3);
  white-space: nowrap; flex: none; }
/* Пометка «устно»: жёлтая плашка (статус). */
#tx-answer .exp-oral-pill { font-size: 11px; font-weight: 600; color: #8a6d00;
  background: #ffe9a8; border-radius: 4px; padding: 2px 8px;
  text-transform: none; letter-spacing: 0; }
#tx-answer .exp-section-oral.collapsed .exp-list { display: none; }

/* ★На узком экране у глаз-кнопки прячется ПОДПИСЬ, а сама кнопка
   остаётся. Замеры на 375: ряду доступно 283, а заголовку, счётчику и
   чипам нужно 329 — не хватает 46. Подпись «вид орфограмм» стоит 101
   из этих 329; без неё нужно 244, и всё встаёт в одну строку с запасом
   в 39. Убирать саму кнопку нельзя: это единственный способ увидеть
   вид орфограммы, и на телефоне он нужнее, чем на десктопе.
   ★Подпись — голый текстовый узел, своего элемента у неё нет, а
   разметку правит генератор (его не трогаем). Поэтому гасим кеглем:
   у кнопки font-size: 0, у значка — свой. Для читалки текст остаётся
   на месте, нулевой кегль его не прячет.
   ★flex-wrap у ряда оставлен как страховка: если заголовок секции
   окажется длиннее «Орфограмм», чипы всё же уйдут вниз, а не сломают
   слово. */
@media (max-width: 560px) {
    #tx-answer .exp-typetoggle {
        font-size: 0;
        gap: 0;
        padding: 4px 6px;
    }
    #tx-answer .exp-typetoggle .ett-ic { font-size: 16px; }
}

#tx-answer .qlink-from-on { background: #eef4ff; border-radius: 3px; box-shadow: 0 0 0 2px #eef4ff; }
/* Надстрочные маркеры разбора (¹ фонетич., ² по составу, ³ морфологич., …)
   — меньше основного слова, как принято. */
#tx-answer sup { font-size: 0.62em; line-height: 0; }
/* ===== Звуко-буквенный (фонетический) разбор ===== */
#tx-answer .phonetic { margin: 10px 0 4px; margin-left: 2em;   /* как красная строка ответа */
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif;
  font-size: inherit; color: var(--ink); }       /* как тело ответа (22px) */
#tx-answer .ph-head { margin-bottom: 4px; }
#tx-answer .ph-word { font-weight: 700; }
#tx-answer .ph-tr { }                                       /* транскрипция inline после слова */
#tx-answer .ph-row { display: flex; align-items: center; gap: 6px; margin: 1px 0; line-height: 1.35; }
#tx-answer .ph-letters { min-width: 1.1em; text-align: center; font-weight: 600; }
#tx-answer .ph-dash { color: var(--ink); }
#tx-answer .ph-brace { color: var(--ink-2); line-height: 0.8; font-weight: 300;
  transform: scaleX(0.6); display: inline-block; }
/* Коннектор «буква ↔ звуки» вместо скобки: тонкие серые штрихи, тянется по
   высоте строки. Ширина как у небольшого тире, штрих не толстеет (non-scaling). */
#tx-answer .ph-conn { flex: 0 0 auto; width: 16px; }   /* высота задаётся inline по числу строк */
#tx-answer .ph-conn line { stroke: var(--ink); stroke-width: 1.4;
  vector-effect: non-scaling-stroke; stroke-linecap: round; }
#tx-answer .ph-sounds { color: var(--ink); }
#tx-answer .ph-nosound { color: var(--ink-3); font-style: italic; }
/* Горизонтальная черта, отделяющая итог «N букв, N звуков» от разбора. */
#tx-answer .ph-divider { border: none; border-top: 1.5px solid var(--ink); margin: 6px 0 4px;
  width: 9em; }
#tx-answer .ph-total { }
#tx-answer .ph-note { color: var(--ink-3); }                /* пометка «(…)» в одну строку с итогом */
#tx-answer .exp-item:hover { background: rgba(230,163,55,0.14); }
#tx-answer .exp-word { font-weight: 600; color: var(--ink); }
/* Буква-орфограмма в проверяемом слове — красная. */
#tx-answer .orf-red { color: var(--insert); font-weight: 500; }   /* роль A — вставленная/проверяемая буква, вес 500 (Ф3) */
#tx-answer .orf-b { color: var(--sign-b); font-weight: 700; }   /* роль B — объясняемая буква: слово дано целиком */
/* Буква-подсказка в проверочном слове — жирная + подчёркнутая. */
#tx-answer .orf-proof { font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
/* Буква-УПОМИНАНИЕ в тексте пояснения («безударная о»). Графит роли B — буква на
   месте, мы её объясняем, а не вставляем (красный = вставленная). Наклон печатной
   формы, а НЕ italic-глиф: настоящий курсив даёт рукописные т→«m», и→«u». */
#tx-answer .exp-letter { color: var(--sign-b); font-weight: 700;
  display: inline-block; transform: skewX(-10deg); text-indent: 0; }
#tx-answer .exp-dash { color: var(--ink-3); }
#tx-answer .exp-text { color: var(--ink-2); }
/* Чип-разбор + приклеенная к нему пунктуация (.,;… после .word) — единый
   неразрывный блок, чтобы знак не начинал строку (упр.377). Нет разрыва ТОЛЬКО
   между чипом и знаком; список чипов по-прежнему переносится между парами. */
#tx-answer .nb-tail { white-space: nowrap; }
/* Подсветка привязанного слова в ответе при наведении на пункт.
   .exp-highlight — динамический span вокруг диапазона (text-блок);
   .blk/.word.exp-highlight — целый блок (morphology = всё слово). */
#tx-answer .exp-highlight, #tx-answer .blk.exp-highlight, #tx-answer .word.exp-highlight {
  background: #ffe9a8; border-radius: 3px;
  box-shadow: 0 0 0 2px #ffe9a8; }

/* ===== Вспомогательный диалог (замена prompt) ===== */
#tx-answer .qa-aux-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.35);
  z-index: 60; display: none; align-items: center; justify-content: center; }
#tx-answer .qa-aux-backdrop.open { display: flex; }
#tx-answer .qa-aux {
  background: var(--surface); border-radius: 10px; padding: 18px;
  width: 420px; max-width: calc(100vw - 40px);
  box-shadow: 0 12px 40px rgba(0,0,0,0.25);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; }
#tx-answer .qa-aux h3 { margin: 0 0 12px; font-size: 14px; }
#tx-answer .qa-aux label { display: block; font-size: 11px; color: var(--ink-3);
  margin: 10px 0 2px; font-weight: 500; }
#tx-answer .qa-aux input, #tx-answer .qa-aux select {
  width: 100%; box-sizing: border-box; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: 5px;
  font-family: inherit; font-size: 14px; }
#tx-answer .qa-aux-hint { font-size: 11px; color: var(--ink-2); margin-top: 5px;
  background: var(--warm-bg); border-radius: 5px; padding: 6px 8px;
  line-height: 1.45; }

/* ===== Связи (links): вопрос-чип над глаголом (всегда видим) ===== */
/* Параграф со связью получает запас сверху под чип (класс ставит JS). */
#tx-answer .text-para.has-qlink { padding-top: 1.4em; }
#tx-answer .qlink-target.qlink-has {
  /* inline-block — стабильный прямоугольный контейнер для чипа: иначе у
     слова с вложенными span'ами (подчёркнутая буква) точка отсчёта left:50%
     плывёт, и чип съезжает при наведении/рефлоу.
     text-indent:0 — иначе inline-block наследует красную строку (2em) от
     .text-para и слово уезжает вправо внутри своего блока. */
  display: inline-block; position: relative; cursor: help;
  text-indent: 0;
  border-bottom: 1.5px dotted var(--warm-bd); }
#tx-answer .qlink-chip {
  position: absolute; left: 50%; bottom: 100%;
  transform: translateX(-50%) translateY(-3px);
  white-space: nowrap; font-size: 13px; font-style: normal;
  color: var(--ink-3); background: var(--surface);
  border: 1px solid var(--warm-bd); border-radius: 10px;
  padding: 0 10px; line-height: 1.6; box-shadow: var(--shadow-1);
  /* Сброс text-indent: чип наследует красную строку (2em) от .text-para —
     иначе текст вопроса уезжает вправо, слева образуется пустота. */
  text-indent: 0; text-align: center;
  z-index: 5; }
/* Тонкий «поводок» от чипа к слову. */
#tx-answer .qlink-chip::after {
  content: ''; position: absolute; left: 50%; top: 100%;
  width: 1px; height: 4px; background: var(--warm-bd);
  transform: translateX(-50%); }
#tx-answer .qlink-target.qlink-pin { background: #fff8ec; border-radius: 3px; }
#tx-answer .qlink-target.qlink-on .qlink-chip { color: var(--ink-2); }
#tx-answer .qlink-from.qlink-from-on { background: #eef4ff; border-radius: 3px;
  box-shadow: 0 0 0 2px #eef4ff; }

/* Таблица данных (упражнение с разбиением слов по столбикам и т.п.) */
/* Обёртка таблицы: горизонтальная прокрутка для широких таблиц. Отступ
   живёт на обёртке; снизу — padding (не схлопывается с шапкой разбора). */
#tx-answer .table-wrap { overflow-x: auto; margin: 14px 0 0; padding-bottom: 10px; }
/* ★Таблица СРАЗУ ПОД шапкой — оптическая поправка. Метрически 14px уже равны
   тексту (у текста 8px + полу-интерлиньяж 6px = те же 14 до краски), но верх
   таблицы — сплошная линия во всю ширину, идущая параллельно нижнему краю
   кремовой плашки. Две параллельные горизонтали на равном расстоянии читаются
   теснее, чем плашка и «рыхлая» строка текста, поэтому жёсткому краю нужен
   запас. Тот же приём уже применён к картинкам (16px, у них нет интерлиньяжа
   по той же причине) — таблицу из этого правила упустили. 14 таблиц. */
#tx-answer .part-heading + .table-wrap { margin-top: 16px; }
/* Ф5 (ТЗ §6): «лёгкая полная сетка» — тёплый hairline 1px по всем ячейкам
   (шапка #e6dcc4 / тело #ece3d0), кремовая шапка #fdf4e1, текст шапки #241f1a
   жирный. Без синей рамки, без жёлтой шапки, без скругления. Полная сетка —
   зеркалит тетрадь. Зебра по умолчанию off. */
#tx-answer .data-table {
  border-collapse: collapse;
  margin: 0;
  border: 1px solid #e6dcc4;
  font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Helvetica, Arial, sans-serif; font-size: 16px; color: var(--ink);
}
#tx-answer .data-table th, #tx-answer .data-table td {
  border: 1px solid #ece3d0;
  padding: 8px 14px;
  vertical-align: middle;
  text-align: left;
  font-weight: normal;
  line-height: 1.45;
}
#tx-answer .data-table th { font-weight: 700; text-align: center; color: #241f1a;
  border-color: #e6dcc4; }
/* Ячейки с данными — по ВЕРХУ. При середине столбики разной длины разъезжаются
   по высоте (упр.74: 3 существительных против 4 глаголов) и таблица перестаёт
   читаться как одна раскладка. Шапка остаётся по центру. */
#tx-answer .data-table td { vertical-align: top; }
/* Широкая таблица (≥5 колонок) — чуть мельче шрифт и плотнее ячейки. */
/* Ширины колонок заданы источником → раскладка фиксированная, иначе браузер всё
   равно растянет колонку под самое длинное неразрывное слово шапки. */
#tx-answer .data-table.fixedw { table-layout: fixed; width: 100%; }

#tx-answer .data-table.wide { font-size: 14px; }
#tx-answer .data-table.wide th, #tx-answer .data-table.wide td { padding: 6px 10px; line-height: 1.3; }

/* Горизонтальная черта перед «N букв, N звуков» — школьный паттерн.
   Сдвиг слева 2em, чтобы линия начиналась от той же буквы, что и слово
   разбираемое слово (учитываем text-indent у .text-para). */
#tx-answer .phonetic-divider {
  border: 0;
  border-top: 1.5px solid var(--ink);
  margin: 6px 0 10px 2em;
  width: calc(40% - 2em);
}

#tx-answer .page-row { margin-bottom: 14px; }
#tx-answer .page-label {
  font-size: 11px; color: var(--ink-3); margin-bottom: 5px;
  text-transform: uppercase; letter-spacing: 0.08em;
}
#tx-answer .page-row img {
  width: 100%; display: block; border-radius: 8px;
  background: #fff; box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
