/* ARBI.RU — базовая типографика, каркас страницы, шапка и подвал.
   Характер «АРБИТРАЖ!»: плотные заголовки, много воздуха, тонкие линии, салатовый акцент
   только там, где есть действие или текущий выбор. */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--graphite-700);
  font-family: var(--font-ui);
  font-size: var(--step-16);
  line-height: var(--leading-text);
  font-feature-settings: "case" on, "cv11" on, "ss01" on;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Подвал прижат к низу окна: на коротких страницах он не поднимается в середину,
     а на длинных остаётся после содержимого. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main { flex: 1 0 auto; }

h1, h2, h3, h4 {
  color: var(--graphite-900);
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-heading);
  margin: 0 0 12px;
  line-height: var(--leading-normal);
}
h1 { font-size: var(--step-38); line-height: var(--leading-tight); letter-spacing: var(--tracking-display); }
h2 { font-size: var(--step-30); }

/* Межстрочный интервал для плотного шрифта заголовков.
   У Oswald выносные элементы упираются в границы строки: при межстрочном 1,05 верх
   первой строки срезается — проверено снимком docs/screens/01-home.png, «Сложный
   вопрос.» обрезано сверху. Даём заголовкам чуть больше воздуха: 1,15 вместо 1,05.
   Заголовки третьего и четвёртого уровня остаются на Inter — мелкий плотный шрифт
   читается хуже, и в макетах он стоит только в крупных надписях. */
h1, h2 { line-height: 1.15; }
/* Салатовая подложка под частью заголовка (в макете — «Понятное решение.»).
   Отступ по бокам нужен, иначе подсветка прилипает к буквам и слово читается хуже. */
.mark { padding: 0 0.12em; box-decoration-break: clone; -webkit-box-decoration-break: clone; }
h3 { font-size: var(--step-20); font-family: var(--font-ui); font-weight: 650; letter-spacing: -0.01em; }
h4 { font-size: var(--step-18); font-family: var(--font-ui); font-weight: 640; letter-spacing: 0; }

p { margin: 0 0 16px; }
p:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 16px; padding-left: 22px; }
li { margin-bottom: 6px; }
a { color: var(--graphite-900); text-decoration-color: var(--graphite-300); text-underline-offset: 3px; }
a:hover { color: var(--graphite-900); text-decoration-color: var(--lime-500); }

b, strong { font-weight: 650; color: var(--graphite-900); }

small { font-size: var(--step-13); }

:focus-visible {
  outline: 2px solid var(--graphite-900);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* Ссылка-действие: подчёркивание салатовым — фирменный приём макетов. */
.link-action {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--step-14); font-weight: 620; color: var(--graphite-900); text-decoration: none;
}
.link-action::after { content: "→"; transition: transform var(--t-fast); }
.link-action:hover::after { transform: translateX(3px); }

.muted { color: var(--graphite-500); }
.tnum { font-variant-numeric: tabular-nums; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  /*   Обводка фокуса у этой ссылки **уже вынесена наружу** общим правилом
   *   `:focus-visible` (`outline-offset: 2px`). Своего смещения не задаём:
   *   сперва я добавил `3px`, но проверка показала, что фокус виден и без него,
   *   а два разных смещения на площадке — лишняя разница без смысла. */
  position: absolute; left: 12px; top: -64px; z-index: 100;
  background: var(--graphite-900); color: #fff; padding: 12px 18px;
  border-radius: var(--radius-md); transition: top var(--t-fast);
}
.skip-link:focus { top: 12px; color: #fff; }

/* --- Разметка --- */

.container { width: 100%; max-width: var(--container); margin: 0 auto; padding: 0 16px; }
.container--wide { max-width: var(--container-wide); }
.container--read { max-width: var(--container-read); }

@media (min-width: 640px) { .container { padding: 0 24px; } }
@media (min-width: 960px) { .container { padding: 0 40px; } }

.section { padding: 44px 0; }
.section--tight { padding: 24px 0; }
.section--warm { background: var(--paper-warm); }
.section--sand { background: var(--paper-sand); }
.section--lime { background: var(--lime-050); }
.section--dark { background: var(--graphite-900); color: var(--graphite-200); }
.section--dark h1, .section--dark h2, .section--dark h3 { color: #fff; }

@media (min-width: 960px) { .section { padding: 72px 0; } }

.grid { display: grid; gap: 20px; }
.grid--2 { grid-template-columns: 1fr; }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: 1fr; }
.grid--5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 640px) { .grid--2, .grid--3, .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) {
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* Пять колонок с шестью плитками дают вторую строку из одной карточки — это выглядит
     случайным. Шесть плиток раскладываем по три в ряд. */
  .grid--5 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1240px) { .grid--5 { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

.stack { display: flex; flex-direction: column; gap: 12px; }
.row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.grow { flex: 1 1 auto; min-width: 0; }

/* --- Шапка: логотип-начертание, меню, поиск, действие --- */

.header {
  position: sticky; top: 0; z-index: 40;
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line-200);
}
.header__inner { display: flex; align-items: center; gap: 20px; min-height: 68px; }
.header__nav { display: none; gap: 2px; align-items: center; }
.header__actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }

/* Порог, с которого показываем полное меню.
   Не 1024: в шапке девять пунктов плюс логотип, кнопка входа и кнопка действия.
   На 1024 пикселях они не помещаются, и шапка обрезалась по правому краю — пропадали
   «Инструменты», «Войти» и кнопка «Описать задачу», а бургера не было, потому что он
   показывается только до 1023. Войти и создать заявку из шапки было нельзя.
   Проверено снимком docs/screens/01-home-1024.png.
   На 1180 пикселях места хватает с запасом: 1180 минус поля и логотип. */
@media (min-width: 1280px) { .header__nav { display: flex; } }

/* На телефоне: кнопка меню, логотип и одно действие. Длинная надпись кнопки
   уступает место короткой, иначе шапка вылезает за экран. */
.header__burger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: var(--radius-sm);
  border: 1px solid var(--line-300); background: var(--paper); color: var(--graphite-900); cursor: pointer;
}
.header__burger:hover { border-color: var(--graphite-900); }
.header__burger[aria-expanded="true"] { background: var(--lime-500); border-color: var(--lime-500); }
@media (min-width: 1280px) { .header__burger { display: none; } }

.header__mobile { border-top: 1px solid var(--line-200); background: var(--paper); padding: 16px 0 20px; }
.header__mobile[hidden] { display: none; }
@media (min-width: 1280px) { .header__mobile { display: none; } }
.header__mobile-link {
  display: block; padding: 12px 4px; font-size: var(--step-18); font-weight: 620;
  color: var(--graphite-900); text-decoration: none; border-bottom: 1px solid var(--line-200);
}
.header__mobile-link:last-child { border-bottom: 0; }

/* На телефоне длинная подпись кнопки уступает место короткой: две ссылки в разметке,
   показывается одна. Так текст остаётся настоящим, а не собранным псевдоэлементом.
   Селектор с .header нужен, чтобы перебить .btn из components.css: у него та же
   сила, но он подключён позже. */
.header .header__cta-short { display: none; }

@media (max-width: 767px) {
  .header .header__cta { display: none; }
  .header .header__cta-short { display: inline-flex; padding: 9px 14px; }
  .header .header__link { padding: 10px 8px; }
  .header__inner { gap: 10px; min-height: 60px; }
  .header .brand__text { display: none; }
  /* Знак остаётся один — и должен быть удобен для пальца.
     На телефоне надпись скрыта, в шапке остаётся только знак. Он же — ссылка на
     главную, а самая частая ссылка на сайте обязана быть не меньше 32 точек по
     высоте: при кегле 22 знак выходил 17 x 17, и в него не попасть.
     Проверено измерением: tools/mobile-check.mjs находил эту ссылку на каждой
     странице. */
  .header .brand { --brand-size: 34px; }
}

.header__link {
  position: relative;
  padding: 10px 12px; border-radius: var(--radius-sm);
  font-size: var(--step-14); color: var(--graphite-700); text-decoration: none; font-weight: 560;
  transition: background var(--t-fast), color var(--t-fast);
}
.header__link:hover { background: var(--paper-warm); color: var(--graphite-900); }

/* Полное меню: ужимаем отступы, чтобы шапка не обрезалась.
   Измерено на живой странице: контейнер шапки не шире 1240 пикселей, а девять
   пунктов при отступах по 12 пикселей и шрифте 14 занимают 927. Вместе с логотипом
   (153) и действиями (138) нужно 1298 — на 80 пикселей больше контейнера. Шапка
   обрезалась по правому краю, и «Войти» с «Описать задачу» пропадали: войти и
   оставить заявку из шапки было нельзя. Проверено снимком docs/screens/01-home-1024.png
   и измерением в tools/nav-check.mjs.

   Здесь отступы уменьшены до 6 пикселей, шрифт на ступень меньше: меню занимает
   759 пикселей, и шапка помещается на любой ширине, где показывается полное меню.
   Правило без верхней границы: контейнер шире 1240 не становится, поэтому обычные
   отступы не поместились бы и на 1920. */
.header .header__link { padding: 10px 6px; font-size: var(--step-13); }
.header__nav { gap: 0; }

/* Кнопка «Каталог» шире остальных пунктов: у неё нет стрелки мега-меню, зато слово
   длиннее. Под вошедшим в шапке прибавляется ссылка на кабинет и значок человека,
   и шапке перестаёт хватать 40 пикселей. Здесь отдаём их кнопке: у неё подпись
   одна, а место она занимает как два пункта. */
.header__link--catalog { padding-right: 2px; }
.header__link--catalog::after { display: none; }

/* У вошедшего в шапке на один пункт больше: ссылка на админку и значок человека.
   Измерено на живой странице под администратором: на 1180 пикселях шапка обрезалась
   на 36 пикселей, а у гостя помещалась. Порог показа полного меню поднимаем для всех:
   держать два разных порога — значит однажды поправить один и забыть второй. */
@media (max-width: 1279px) {
  .header__nav { display: none; }
  .header__burger { display: inline-flex; }
  .header__mobile { display: block; }
}

/* Теснота в шапке: ужимаем отступы между блоками, а не подписи.
   Измерено под администратором: после запрета переноса кнопка занимает свои 42
   пикселя вместо сжатых 56, и шапке не хватает 8 пикселей на любой ширине от 1280.
   Здесь освобождаем 12: отступ между блоками с 20 до 14. Подписи и размер шрифта
   не трогаем — читаемость важнее плотности. */
.header__inner { gap: 14px; }

/* Кнопка действия и логотип в шапке не сжимаются.
   Измерено на живой странице под администратором: кнопка «Описать задачу» занимала
   площадь высотой 56 пикселей вместо 42 — текст переносился на две строки. Причина:
   при нехватке места флекс-элемент сжимается, и подпись ломается. Шапка при этом
   не обрезается, поэтому прежняя проверка этого не видела.
   Теперь шапка либо помещается целиком, либо уходит в меню по кнопке. */
.header .brand, .header .header__actions, .header .header__cta, .header .header__cta-short {
  flex-shrink: 0;
}
.header .header__cta, .header .header__cta-short, .header .header__link { white-space: nowrap; }
.header__link--active { color: var(--graphite-900); font-weight: 650; }
.header__link--active::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: -1px;
  height: 3px; background: var(--lime-500); border-radius: 2px;
}

/* Логотип: узкое плотное начертание с восклицательным знаком и подписью домена.
   Размеры сняты с референса (tools/measure-logo.py, docs/reference/brand-identity.png):
   высота начертания — единица масштаба, подпись домена — 0,45 от неё, знак — той же
   высоты, что прописная буква, зазор между начертанием и подписью — 0,28.
   Всё в em от --brand-size: меняя одну переменную, логотип масштабируется целиком,
   а пропорции остаются как в референсе. */
.brand {
  --brand-size: 22px;
  --brand-stretch: 1.19;
  /* Ширина начертания в единицах кегля: отношение из референса — 1431 / 267, а
     высота прописной буквы примерно равна кеглю. По этой величине считается
     поправка к месту, которое начертание занимает в разметке. */
  --brand-name-width: 5.36;
  display: inline-flex; align-items: center; gap: 0.55em;
  /* Место под растянутое начертание.
     Растяжка по горизонтали не меняет ширину в разметке: без этой поправки соседний
     пункт меню налезал на логотип (видно на снимке docs/screens/01-home.png —
     «АРБИТРАЖ!» упиралось в «Каталог»). Та же поправка нужна, чтобы шапку не
     обрезало: проверка tools/nav-check.mjs мерит ширину блоков. */
  margin-right: calc(var(--brand-size) * var(--brand-name-width) * (var(--brand-stretch) - 1));
  font-size: var(--brand-size); line-height: 1;
  /* Логотип — самая частая ссылка на сайте, и в неё должно быть удобно попасть
     пальцем: не меньше 32 точек по каждой стороне. Размер знака меньше этого, а
     растягивать сам знак нельзя — он перестанет совпадать с макетом. Поэтому
     увеличиваем область нажатия, а не картинку. */
  min-height: 32px; min-width: 32px;
  text-decoration: none; color: var(--graphite-900);
}
.brand--lg { --brand-size: 34px; }
.brand--sm { --brand-size: 15px; }
.brand__mark { flex: none; display: block; color: inherit; }
.brand__text { display: flex; flex-direction: column; align-items: center; }
.brand__name {
  font-family: var(--font-display); font-weight: 700; font-size: 1em;
  /* Плотная посадка букв: в референсе слово собрано в один блок, без просветов. */
  letter-spacing: -0.035em; text-transform: uppercase; color: inherit;
  white-space: nowrap;
  /* Начертание шире, чем даёт шрифт.
     В референсе «АРБИТРАЖ!» имеет отношение ширины к высоте 5,36 (измерено
     tools/measure-logo.py). Oswald при плотной посадке даёт 4,51 — слово выглядит
     уже и «худее» оригинала, и именно на это указывал пользователь. Свободного
     узкого шрифта с такой шириной нет, поэтому растягиваем по горизонтали.
     Вместе с начертанием на столько же растягиваем подпись — в референсе они
     одной ширины, подпись занимает 97% слова. */
  display: inline-block;
  transform: scaleX(var(--brand-stretch));
  transform-origin: center;
}
.brand__tag {
  font-family: var(--font-display); font-weight: 500;
  /* Подпись домена — тот же шрифт уменьшенным кеглем: в референсе это не другой
     шрифт, а уменьшенное начертание. Отсюда 0,45 высоты и лёгкий разряд. */
  font-size: 0.45em; letter-spacing: 0.06em; text-transform: lowercase;
  /* Цвет подписи — тот же, что у начертания: в референсе «arbi.ru» чёрное, а не
     серое. Серый делал подпись бледнее и она читалась как подпись-примечание. */
  color: inherit; margin-top: -0.14em;
  display: inline-block;
  transform: scaleX(var(--brand-stretch));
  transform-origin: center;
}
.brand--dark .brand__name { color: #fff; }
.brand--dark .brand__tag { color: var(--graphite-300); }

/* --- Подвал --- */

.footer { background: var(--paper-warm); border-top: 1px solid var(--line-200); margin-top: 72px; padding: 48px 0 28px; flex-shrink: 0; }
.footer__note { font-size: var(--step-13); color: var(--graphite-500); margin: -8px 0 12px; max-width: 34ch; }
/* Заголовки колонок подвала — второго уровня, а не третьего.
   Они идут сразу после главного заголовка страницы, и третий уровень читался бы
   как перескок: программа чтения сообщает о структуре, которой на странице нет.
   Оформление при этом остаётся прежним — сам заголовок в подвале выглядит
   подписью колонки, а не крупным заголовком. */
.footer h2 { font-family: var(--font-ui); font-size: var(--step-13); text-transform: uppercase; letter-spacing: 0.08em; color: var(--graphite-500); margin-bottom: 14px; }

/* Мега-меню: у каждого пункта своя панель, но живёт она под шапкой одна.
   Панель закреплена за контейнером шапки, а не за пунктом меню: иначе она
   сжимается до ширины пункта и колонки ломаются.
   Между пунктом и панелью остаётся зазор; чтобы меню не исчезало при переводе
   курсора, у панели сверху есть невидимый «мост», а скрипт закрывает её
   с небольшой задержкой. */
.header__inner { position: relative; }

/* Пункт меню с панелью: текст, одна стрелка вниз и невидимая площадка,
   которая закрывает зазор до панели. Без площадки курсор при переходе вниз
   выходит за пределы пункта, и меню закрывается. */
.mega-trigger {
  display: inline-flex; align-items: center; gap: 5px;
  position: relative; padding: 10px 12px;
}
.mega-trigger::before {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 18px;
}
/* Стрелка «раскрывается» поворотом, поэтому она нарисована псевдоэлементом:
   так в разметке нет второй стрелки, а состояние видно по классу is-active. */
.mega-trigger .mega-caret {
  width: 7px; height: 7px; margin-left: 1px; flex: none;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-1px);
  transition: transform var(--t-fast);
}
.mega-trigger.is-active .mega-caret { transform: rotate(-135deg) translateY(-1px); }

.mega-panel {
  display: none;
  position: absolute; top: calc(100% + 1px); left: 16px; right: 16px; z-index: 45;
}
@media (min-width: 640px) { .mega-panel { left: 24px; right: 24px; } }
@media (min-width: 960px) { .mega-panel { left: 40px; right: 40px; } }
.mega-panel__inner {
  background: var(--paper); border: 1px solid var(--line-200); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3); padding: 22px;
  max-height: calc(100vh - 110px); overflow-y: auto;
}
/* Невидимый мост над панелью: курсор, идущий от пункта меню вниз, остаётся
   в области панели и меню не пропадает. */
.mega-panel::before {
  content: ""; position: absolute; left: 0; right: 0; top: -16px; height: 16px;
}
.mega-panel[data-open="true"] { display: block; }
.mega-panel__pane[hidden] { display: none; }

.mega-panel__grid { display: grid; gap: 28px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1100px) { .mega-panel__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .mega-panel__grid--5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .mega-panel__grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.mega-panel__col { min-width: 0; }
.mega-panel__title {
  font-size: var(--step-12); text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--graphite-500); margin: 0 0 10px; font-weight: 640;
  display: flex; align-items: center; gap: 6px;
}
.mega-panel__group { margin-bottom: 14px; }
.mega-panel__group:last-child { margin-bottom: 0; }
.mega-panel__group-title { font-size: var(--step-13); font-weight: 640; color: var(--graphite-900); margin: 0 0 4px; }
.mega-panel__links { list-style: none; padding: 0; margin: 0 0 12px; }
.mega-panel__links li { margin-bottom: 1px; }
.mega-panel__links a {
  display: block; padding: 5px 8px; border-radius: var(--radius-xs);
  font-size: var(--step-14); color: var(--graphite-700); text-decoration: none;
}
.mega-panel__links a:hover { background: var(--lime-050); color: var(--graphite-900); }
.mega-panel__links--sub a { font-size: var(--step-13); color: var(--graphite-500); }
.mega-panel__links--sub a:hover { color: var(--graphite-900); }
.mega-panel__count { color: var(--graphite-500); font-size: var(--step-12); margin-left: 4px; }
.mega-panel__note { font-size: var(--step-13); color: var(--graphite-500); margin: 0 0 10px; }
.mega-panel__foot {
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line-200);
  display: flex; gap: 20px; flex-wrap: wrap; align-items: center; font-size: var(--step-14);
}
.mega-panel__cta { background: var(--lime-050); border-radius: var(--radius-md); padding: 16px; }
.mega-panel__cta h4 { font-size: var(--step-16); margin: 0 0 6px; }
.mega-panel__cta p { font-size: var(--step-13); color: var(--graphite-500); margin: 0 0 12px; }
/* Карточка-пример в панели: специалист, дело или материал журнала. */
.mega-panel__card {
  display: block; border: 1px solid var(--line-200); border-radius: var(--radius-md);
  padding: 12px; text-decoration: none; color: var(--graphite-900); margin-bottom: 8px;
}
.mega-panel__card:hover { border-color: var(--graphite-900); }
.mega-panel__card-title { font-size: var(--step-14); font-weight: 620; }
.mega-panel__card-note { font-size: var(--step-12); color: var(--graphite-500); margin-top: 2px; }

/* Карточка-ссылка: вся карточка ведёт на страницу, но остаётся обычной ссылкой —
   так её видят и скринридеры, и поисковые роботы. */
.card--link { display: block; text-decoration: none; color: inherit; transition: border-color var(--t-fast), box-shadow var(--t-fast); }
.card--link:hover { border-color: var(--graphite-900); box-shadow: var(--shadow-2); }

/* Предпросмотр текста документа: моноширинный шрифт с сохранением переносов.
   Внутри показываем ровно то, что попадёт в файл, поэтому без подсветки и переносов. */
.doc-preview {
  font-family: var(--font-mono, ui-monospace, 'Cascadia Mono', Consolas, monospace);
  font-size: var(--step-13);
  line-height: 1.65;
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--paper-warm);
  border: 1px solid var(--line-200);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  margin: 0;
  max-height: 420px;
  overflow: auto;
  color: var(--graphite-800);
}
.doc-preview--full { max-height: 640px; background: var(--paper); }

/* --- Оглавление документа: слева, закреплено, чтобы не терять структуру текста. */
.doc { display: grid; gap: 32px; grid-template-columns: minmax(0, 1fr); align-items: start; }
.doc > * { min-width: 0; }
@media (min-width: 1024px) { .doc { grid-template-columns: 300px minmax(0, 1fr); } .doc__aside { position: sticky; top: 88px; } }
.doc__aside { display: flex; flex-direction: column; gap: 16px; }
.doc__toc ol { margin: 0; padding-left: 20px; font-size: var(--step-14); }
.doc__toc li { margin-bottom: 7px; }
.doc__toc a { color: var(--graphite-700); text-decoration: none; }
.doc__toc a:hover { color: var(--graphite-900); text-decoration: underline; text-decoration-color: var(--lime-500); }
.doc__links { list-style: none; padding: 0; margin: 0; font-size: var(--step-14); }
.doc__links li { margin-bottom: 6px; }
.doc__links a { color: var(--graphite-700); }
.doc__body { max-width: var(--container-read); }
.doc__body h1 { margin-bottom: 12px; }
.doc__section { margin-top: 32px; scroll-margin-top: 96px; }
.doc__section h2 { font-size: var(--step-24); margin-bottom: 12px; }
.doc__section p { margin-bottom: 12px; }
.doc__section ul { margin: 0 0 14px; padding-left: 22px; }
.doc__section li { margin-bottom: 7px; }
.doc__list-title { font-weight: 620; color: var(--graphite-900); margin-bottom: 8px; }
.footer__grid { display: grid; gap: 32px; grid-template-columns: 1fr; }
@media (min-width: 640px) { .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .footer__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Пять колонок: логотип с подписью и четыре раздела — как в макете.
   Было шесть: колонка «Платформа» не помещалась в свой ряд и уезжала вниз, из-за
   чего подвал выглядел неровным. Число колонок должно совпадать с числом блоков
   в базе (сейчас их четыре), иначе сетка оставляет пустое место. */
@media (min-width: 1240px) { .footer__grid { grid-template-columns: 1.4fr repeat(4, minmax(0, 1fr)); } }
.footer__list { list-style: none; padding: 0; margin: 0; font-size: var(--step-14); }
.footer__list li { margin-bottom: 9px; }
.footer__list a { color: var(--graphite-700); text-decoration: none; }
.footer__list a:hover { text-decoration: underline; text-decoration-color: var(--lime-500); }
.footer__bottom {
  margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--line-200);
  font-size: var(--step-13); color: var(--graphite-500); display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
}
/* Пометка о демонстрационных данных.
   Не серая и не мелкая: это не украшение подвала, а предупреждение о том, что имена,
   отзывы и номера реестров на сайте вымышлены. Читатель должен её заметить. */
.footer__demo {
  display: inline-flex; align-items: center; padding: 3px 10px;
  border-radius: var(--radius-pill); background: var(--lime-100); color: var(--graphite-900);
  font-weight: 600;
}

/* Пути в шапке кабинетов: сайдбар, содержимое, верхняя панель.
   На телефоне колонка сайдбара не резервируется — меню уходит наверх, иначе
   содержимое не помещается и появляется горизонтальная прокрутка. */
.app-shell { display: grid; grid-template-columns: minmax(0, 1fr); min-height: 100vh; }
@media (min-width: 1024px) { .app-shell { grid-template-columns: 264px minmax(0, 1fr); } }

.app-side {
  background: var(--paper); border-right: 1px solid var(--line-200); padding: 20px 16px;
  display: flex; flex-direction: column; gap: 6px;
}
/* На телефоне меню кабинета сворачивается.
   Раньше оно разворачивалось сеткой в шесть строк и занимало 365 точек из 844 —
   почти пол-экрана до первого заголовка. Работать с телефона так нельзя: юрист
   открывает кабинет, чтобы увидеть дела, а видит список разделов.
   Теперь на телефоне видна одна кнопка с названием текущего раздела, а список
   раскрывается по нажатию. На широком экране всё как было. */
.app-side__toggle { display: none; }
@media (max-width: 1023px) {
  .app-side {
    flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px;
    border-right: 0; border-bottom: 1px solid var(--line-200); padding: 10px 16px;
  }
  /* Логотип в кабинете на телефоне не нужен: он уже есть в шапке выше, и второй
     такой же выглядел как ошибка — видно на снимке docs/screens/14-cabinet-advocate-390.png. */
  .app-side > .brand { display: none; }
  .app-side__group { display: none; }
  .app-side__toggle {
    display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
    padding: 0 14px; border: 1px solid var(--line-300); border-radius: var(--radius-sm);
    background: var(--paper); color: var(--graphite-900); font: inherit;
    font-size: var(--step-14); font-weight: 600; cursor: pointer;
  }
  .app-side__toggle::after { content: "▾"; font-size: 0.8em; color: var(--graphite-500); }
  .app-side__toggle[aria-expanded="true"]::after { content: "▴"; }
  /* Ссылки меню скрыты, пока не раскрыты. Раскрытие читается из aria-expanded через
     общий предок: так кнопка может стоять где удобно, и разметку ссылок не нужно
     ни повторять, ни переставлять. Если скрипт не загрузился, меню не раскроется,
     но разделы остаются доступны по прямым адресам. */
  .app-side__foot { margin: 0; padding: 0; border: 0; flex-direction: row; flex-wrap: wrap; }
  /* Кнопка идёт первой строкой, хотя в разметке стоит последней: ссылки скрыты, и
     порядок задаётся здесь. */
  .app-side__toggle { order: -1; }
}
@media (min-width: 1024px) { .app-side { position: sticky; top: 0; height: 100vh; overflow-y: auto; } }
.app-side__group { margin: 14px 0 6px; font-size: var(--step-12); text-transform: uppercase; letter-spacing: 0.08em; color: var(--graphite-500); }
.app-side__link {
  display: flex; align-items: center; gap: 12px; padding: 11px 12px; border-radius: var(--radius-sm);
  color: var(--graphite-700); text-decoration: none; font-size: var(--step-14); font-weight: 560;
}
.app-side__link:hover { background: var(--paper-warm); color: var(--graphite-900); }
.app-side__link--active { background: var(--lime-500); color: var(--graphite-900); font-weight: 660; }

/* Свёрнутое меню кабинета на телефоне.
   Правила стоят здесь, а не выше, намеренно: у них та же сила, что у общего
   «.app-side__link { display: flex }» выше, и при равной силе побеждает то, что
   написано позже. В первом варианте эти строки стояли до общего правила — и
   display: none молча проигрывал: меню не сворачивалось, хотя стиль выглядел
   написанным. Проверено измерением: ссылка оставалась display: flex. */
@media (max-width: 1023px) {
  .app-side__link { display: none; }
  .app-side:has(.app-side__toggle[aria-expanded="true"]) .app-side__link { display: flex; }
  .app-side:has(.app-side__toggle[aria-expanded="true"]) .app-side__foot { flex-basis: 100%; }
}
.app-side__link svg { color: currentColor; opacity: 0.85; }
.app-side__count { margin-left: auto; font-size: var(--step-12); background: var(--graphite-900); color: var(--lime-500); border-radius: var(--radius-pill); padding: 1px 7px; font-weight: 640; }
.app-side__foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line-200); display: flex; flex-direction: column; gap: 4px; }

.app-top {
  display: flex; align-items: center; gap: 16px; padding: 14px 24px;
  border-bottom: 1px solid var(--line-200); background: var(--paper);
}
/* Поиск в верхней панели не растягивается на всю ширину: иначе он выглядит
   как пустое поле и оттесняет действия. */
.app-top__search { flex: 0 1 420px; min-width: 200px; }
.app-main { padding: 24px; background: var(--paper-warm); min-height: 100vh; }
@media (min-width: 1024px) { .app-main { padding: 32px 40px; } }

.app-user { display: flex; align-items: center; gap: 10px; }
.app-user__name { font-size: var(--step-14); font-weight: 620; color: var(--graphite-900); line-height: 1.1; }
.app-user__role { font-size: var(--step-12); color: var(--graphite-500); }

/* ============================================================ Строка объявлений

   Салатовая полоса над шапкой: самая заметная строка сайта. В макете она есть на
   всех публичных страницах, поэтому живёт в каркасе, а не на главной.

   Объявления площадки и оплаченная реклама стоят в одной строке — по кругу, по
   четыре секунды. Реклама помечена словом «реклама» и номером маркировки: этого
   требует закон о рекламе, и проверка следит, чтобы маркировка не пропала. */

.promo-strip {
  background: var(--lime-500);
  color: var(--graphite-900);
  font-size: var(--step-13);
}
.promo-strip__inner {
  display: flex; align-items: center; justify-content: center;
  gap: 16px; min-height: 34px;
}
/* Высоту держим постоянной: без этого страница прыгает при смене объявления. */
.promo-strip__viewport { position: relative; min-height: 20px; flex: 1 1 auto; min-width: 0; }
.promo-strip__item {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  color: var(--graphite-900); text-decoration: none;
  opacity: 0; visibility: hidden; transition: opacity var(--t-medium), visibility var(--t-medium);
}
.promo-strip__item.is-active { position: relative; opacity: 1; visibility: visible; }
.promo-strip__text {
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
}
.promo-strip__item:hover .promo-strip__text { text-decoration-thickness: 2px; }
/* Пометка рекламы: не украшение, а требование закона. Поэтому она не мельче 11px
   и не серым по салатовому — контраст проверяется автоматически. */
.promo-strip__label {
  flex: 0 0 auto; padding: 1px 6px; border-radius: var(--radius-pill);
  background: rgba(19, 23, 14, 0.14); font-size: var(--step-12); font-weight: 620;
  text-transform: lowercase;
}
.promo-strip__erid { flex: 0 0 auto; font-size: var(--step-12); opacity: 0.75; }
.promo-strip__dots { display: flex; gap: 5px; flex: 0 0 auto; }
.promo-strip__dot {
  width: 7px; height: 7px; padding: 0; border: 0; border-radius: 50%;
  background: rgba(19, 23, 14, 0.25); cursor: pointer;
}
.promo-strip__dot.is-active { background: var(--graphite-900); }
/*   Точка объявления под клавиатурой.
 *
 *   Своего правила ей **не нужно**: общее `:focus-visible` уже даёт тёмную
 *   обводку и смещение два пикселя, а этого хватает — точка семь пикселей,
 *   обводка ложится на светлую полосу и видна.
 *
 *   Я сначала добавил отдельное правило со смещением три. Проверка показала,
 *   что фокус виден и без него; правило убрано, чтобы на площадке не было
 *   двух разных смещений обводки без причины. */
/* На телефоне объявление в одну строку не помещается: переносим, но не больше
   двух строк — иначе полоса съедает пол-экрана. */
@media (max-width: 640px) {
  .promo-strip__inner { min-height: 30px; }
  .promo-strip__item { position: static; }
  .promo-strip__viewport { display: grid; }
  .promo-strip__item { grid-area: 1 / 1; }
  .promo-strip__text {
    white-space: normal; display: -webkit-box; -webkit-line-clamp: 2;
    -webkit-box-orient: vertical; text-align: center; text-decoration: none;
  }
  .promo-strip__dots { display: none; }
}

/* ============================================================ Герой главной

   Разметка снята с макета: слева заголовок, описание и строка поиска, справа
   фотография специалиста с подписью на ней. Фотография занимает правую половину,
   подпись лежит в её правом нижнем углу — так подпись относится к лицу, а не
   висит отдельной карточкой. */

.hero__inner {
  display: grid; gap: 40px; align-items: center;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 960px) { .hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); } }
.hero__text { min-width: 0; }
.hero__lead { font-size: var(--step-18); max-width: 46ch; }

/* Ширина строки поиска ограничена: на широком экране она не растягивается на всю
   колонку — подсказка в одно короткое предложение, и поле во всю ширину выглядит
   пустым. Ограничение стоит здесь, а не на ::placeholder: перенос подсказки — это
   поведение интерфейса, а не оформление текста. */
.hero__search { max-width: 620px; }

/* Строка поиска: значок, поле и вложение — в одной обёртке, кнопка снаружи.
   На узком экране переносится только кнопка, значок остаётся слева от поля. */
.hero__field {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  background: var(--paper); border: 1px solid var(--line-300);
  border-radius: var(--radius-md); padding: 6px 6px 6px 12px;
}
/*   Строка поиска героя под фокусом.
 *
 *   Обводку у самого поля снимаем ниже намеренно: рамку рисует **вся строка**,
 *   и вторая рамка вокруг поля выглядела бы двойной.
 *
 *   Смена цвета рамки со светлого на тёмный — это контраст 15:1, признак
 *   сильный и достаточный. Кольцо я сперва добавил, но проверка показала,
 *   что фокус виден и без него: лишнее кольцо на площадке только добавляет
 *   разницу между похожими элементами. */
.hero__field:focus-within { border-color: var(--graphite-900); }
.hero__line { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; min-width: 0; }
/* Значок поиска не сжимается и стоит в потоке.
   В общей строке поиска (.search) значок лежит поверх поля абсолютно — там он
   нарисован внутри рамки. В строке героя он стоит рядом с полем, поэтому
   абсолютное положение из components.css нужно снять: иначе значок «выпадал» из
   строки и оказывался под полем — измерено на телефоне (значок на 40 пикселей ниже
   поля при ширине строки 340). */
.hero__field .search__icon {
  position: static; transform: none;
  flex: 0 0 auto; color: var(--graphite-500);
}
.hero__input {
  /* Ширина auto, а не 100%: при width:100% гибкая основа поля равна всей строке,
     и значок поиска выталкивался на вторую строку — измерено на телефоне
     (ширина поля 272 при строке 340, значок ниже поля). Растягивает поле flex-grow. */
  flex: 1 1 auto; min-width: 0; width: auto; border: 0; background: transparent;
  font: inherit; font-size: var(--step-14); color: var(--graphite-900);
  /* Длинную подсказку обрезаем многоточием.
     Проверено снимком: подсказка не помещалась и обрезалась на середине слова —
     выглядело как сломанное поле. Текст укорочен, обрезка задана явно. */
  padding: 10px 4px;
  text-overflow: ellipsis;
}
/*   Обводку у самого поля снимаем: рамку и кольцо рисует строка
 *   (`.hero__field:focus-within` выше). Вторая рамка вокруг поля выглядела бы
 *   двойной. */
.hero__input:focus { outline: none; }
.hero__input::placeholder { color: var(--graphite-500); }
/* Вложение и голос: отключены, пока не подключены. Приглушены и не ловят нажатие,
   но подсказку показывают — так видно, что кнопка есть и появится позже. */
.hero__attach {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--graphite-500); cursor: not-allowed;
}
.hero__attach[aria-disabled="true"] { opacity: 0.55; }
.hero__submit { flex: 0 0 auto; }
@media (max-width: 640px) {
  /* На телефоне в одну строку помещаются значок, поле и вложение; кнопка уходит под
     них на всю ширину. Обёртка .hero__line держит первую тройку вместе — без неё
     значок поиска уезжал на вторую строку (снимок docs/screens/01-home-390.png). */
  .hero__field { padding: 8px; }
  /* Кнопки вложения на телефоне мельче: 36 пикселей рядом с полем оставляли полю
     около 90 пикселей, и подсказка обрезалась на середине слова. */
  .hero__attach { width: 30px; height: 30px; }
  .hero__submit { flex: 1 0 100%; margin-top: 8px; }
}
.hero__alt { margin: 14px 0 0; }

/* Фотография специалиста. Пропорция задана заранее: без неё страница прыгает,
   когда картинка догружается, — а герой виден первым. */
.hero__media { position: relative; min-width: 0; }
.hero__photo {
  display: block; width: 100%; height: auto; aspect-ratio: 6 / 5;
  object-fit: cover; object-position: center 22%;
  border-radius: var(--radius-lg); background: var(--paper-warm);
}
.hero__portrait {
  display: grid; place-items: center; min-height: 300px;
  background: var(--lime-050); border-radius: var(--radius-lg);
}
.hero__empty {
  padding: 40px 24px; text-align: center;
  border: 1px dashed var(--line-300); border-radius: var(--radius-lg);
}
.hero__card {
  position: absolute; right: 16px; bottom: 16px; max-width: min(320px, calc(100% - 32px));
  background: var(--paper); border: 1px solid var(--line-200);
  border-radius: var(--radius-md); padding: 12px 16px; box-shadow: var(--shadow-2);
}
.hero__card-name { font-weight: 660; color: var(--graphite-900); }
.hero__card-role { font-size: var(--step-13); color: var(--graphite-700); }
.hero__card-note { font-size: var(--step-13); color: var(--graphite-500); }
@media (max-width: 640px) {
  .hero__card { position: static; margin-top: 12px; max-width: none; box-shadow: none; }
}

/* Текст для программ чтения: не занимает место на экране, но его слышно. */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
