/* Главная страница «Образование Пушкинский».
   Дизайн-токены и размеры взяты из ТЗ (FOR-S-1/CLAUDE_CODE_TZ.md, разделы 7–9),
   визуальный эталон — FOR-S-1/reference/selected-design.png. */

/* ─── Шрифт ────────────────────────────────────────────────────────────────
   Manrope лежит локально: страница не должна зависеть от доступности
   Google Fonts. unicode-range разделяет кириллицу и латиницу, поэтому
   на русской странице латинские файлы качаются только ради адресов почты. */

@font-face {
  font-family: Manrope;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/manrope-400-cyrillic.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: Manrope;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/manrope-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Manrope;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(fonts/manrope-700-cyrillic.woff2) format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: Manrope;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(fonts/manrope-700-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Пока Manrope грузится, текст рисуется системным шрифтом. Manrope на 3.6%
   шире Arial (замерено в браузере), поэтому абзацы занимали другое число
   строк, и после подмены весь контент прыгал: Lighthouse показывал CLS 0.2
   на медленной мобильной сети. size-adjust выравнивает ширину запасного
   шрифта под Manrope, и подмена перестаёт двигать вёрстку. */
@font-face {
  font-family: "Manrope Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 103.6%;
}

/* Вес 800 не подключаем: ТЗ допускает для H1 700–800, а каждый лишний вес —
   это ещё два файла (кириллица + латиница) в загрузке первого экрана. */

/* ─── Токены ─────────────────────────────────────────────────────────────── */

:root {
  /* Объявлено явно, а не оставлено на «light dark»: полосы прокрутки и
     переключатели панели доступности красит браузер, и они обязаны следовать
     за той схемой, которая реально показана. Тёмной эта строка становится
     только там, где тёмной стала и страница. */
  color-scheme: light;

  --color-bg: #f7fafc;
  --color-surface: #ffffff;
  --color-navy: #183153;
  --color-navy-hover: #102743;
  --color-cyan: #19a7ce;
  --color-cyan-hover: #1288aa;
  --color-cyan-soft: #ddf4fa;
  --color-blue-soft: #eaf3f8;
  --color-text: #183153;
  /* Не #52667a, как было. Каталог типа «государственный портал» просит
     усиленный порог 7:1, а прежний серый давал 5.20 на самом тёмном из фонов
     страницы (полоса приёма #ddf4fa) — это AA, но не AAA. Тон сохранён,
     убавлена только яркость: худший фон теперь 7.03. */
  --color-text-secondary: #425262;
  --color-border: #d5e3ec;
  --shadow-soft: 0 10px 30px rgba(24, 49, 83, 0.08);
  --shadow-hover: 0 14px 36px rgba(24, 49, 83, 0.12);

  /* Фирменный #19A7CE на светлом фоне даёт 2.8:1 — этого хватает декоративным
     иконкам, но не тексту. Для текста берём затемнённый вариант.
     Прежний #0e7490 давал 4.69 на полосе приёма: порог AA взят впритык,
     усиленный — нет. Этот держит 7.09 на худшем фоне. */
  --color-cyan-text: #0a576c;

  /* Цвета шапки и подвала — токенами, а не значениями внутри правил.
     Раньше здесь стояли жёсткие #fff и rgba(255,255,255,.96), и каждая новая
     цветовая схема требовала отдельного блока переопределений на компоненты.
     Теперь схема меняет пять строк, а вёрстка остаётся общей. */
  --color-header-bg: rgba(255, 255, 255, 0.96);
  --color-footer-bg: var(--color-navy);
  --color-footer-text: #ffffff;
  --color-footer-muted: #d5e3ec;
  --hero-gradient: linear-gradient(135deg, #f4f9fc 0%, var(--color-blue-soft) 55%, #e2eef6 100%);

  /* Типографическая шкала: шесть ступеней вместо девяти разрозненных размеров.
     Верхняя граница h1 — 60px, а не 72: колонка текста первого экрана шириной
     около 467px не вмещала «Пушкинский» при 72 пикселях, и слово переносилось. */
  --step-hero: clamp(2.5rem, 4.5vw, 3.75rem);
  --step-section: clamp(1.875rem, 3vw, 2.5rem);
  --step-card: 1.375rem;
  /* Ступень между секцией и плиткой: заголовок сервисной карточки. Раньше он
     был h2 и спорил с заголовком раздела, а на --step-card (22px) читался бы
     как подпись к плитке. Держим 28–34px: ниже карточка теряла вес — это
     главные заголовки на странице после h1, — а выше начинала спорить
     с заголовком раздела (30–40px), и иерархия снова пропадала. */
  --step-card-lg: clamp(1.625rem, 2.5vw, 2.125rem);
  --step-lead: 1.25rem;
  --step-body: 1.125rem;
  --step-small: 1rem;

  --container: 1360px;
  --gutter: 40px;
  --radius-hero: 24px;
  --radius-card: 16px;
  --radius-button: 10px;
  /* Раньше отступ переключался ступенями в двух медиазапросах: 96 → 80 → 52.
     Ступени попадали ровно в границы 900px и 600px, и на промежуточных ширинах
     ритм страницы прыгал. Формула проходит через те же крайние точки —
     52px при 600px ширины и 96px при 1440, — но между ними идёт плавно. */
  --section-gap: clamp(52px, 5.25vw + 20.5px, 96px);
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --speed: 170ms;
}

/* ─── База ───────────────────────────────────────────────────────────────── */

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

html {
  scroll-behavior: smooth;
  /* Якорь не должен уезжать под липкую шапку. Значение чуть больше её высоты
     (.header-inner min-height: 104px), иначе заголовок приземляется под шапку. */
  scroll-padding-top: 112px;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: Manrope, "Manrope Fallback", Inter, Arial, sans-serif;
  font-size: var(--step-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

h1,
h2,
h3 {
  color: var(--color-text);
  margin: 0;
  overflow-wrap: break-word;
  /* Русские заголовки длинные, и на части ширин последнее слово падало
     в строку одно. Браузер выравнивает строки по длине сам — вручную
     ни <br>, ни неразрывные пробелы не расставляем: они верны ровно для
     одной ширины экрана и одного кегля, а их здесь по три десятка.
     Свойство работает на этапе раскладки, поэтому CLS не задевает;
     старые браузеры его игнорируют и рисуют как прежде. */
  text-wrap: balance;
}

h1 {
  font-size: var(--step-hero);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

h2 {
  font-size: var(--step-section);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.01em;
}

h3 {
  font-size: var(--step-card);
  font-weight: 700;
  line-height: 1.25;
}

p {
  margin: 0;
  /* То же для абзацев, но мягче: balance пересобрал бы весь абзац ради
     ровных строк, pretty трогает только хвост — убирает висячее слово
     в последней строке. */
  text-wrap: pretty;
}

a {
  color: var(--color-navy);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  /* Раньше половина hover на странице срабатывала рывком, половина плавно —
     язык взаимодействия был несогласован. */
  transition: color var(--speed) var(--ease),
    text-decoration-thickness var(--speed) var(--ease);
}

a:hover {
  color: var(--color-cyan-hover);
}

/* border-radius здесь не задаётся намеренно. Раньше стояли жёсткие 4px, и они
   не наследовались, а НАВЯЗЫВАЛИ форму: круглые чипы и карточки со скруглением
   16 и 24 пикселя при фокусе меняли очертания. Современный outline сам повторяет
   собственный радиус элемента, и это ровно то, что нужно. */
:focus-visible {
  outline: 3px solid var(--color-cyan-hover);
  outline-offset: 3px;
}

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Первая цель табуляции: выпрыгивает из-под шапки только при фокусе. */
.skip-link {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 100;
  padding: 12px 20px;
  background: var(--color-navy);
  /* Не #fff: в тёмной контрастной теме --color-navy становится белым, и жёстко
     заданный белый текст давал белым по белому — ровно для тех, кто эту тему
     и включает. --color-bg инвертируется вместе с фоном. */
  color: var(--color-bg);
  border-radius: var(--radius-button);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--speed) var(--ease);
}

.skip-link:focus-visible {
  transform: translateY(0);
  color: var(--color-bg);
}

.section {
  padding: var(--section-gap) 0;
}

/* Ритм полос. Раньше hero, плитки, «Онлайн-сервисы» и «Как воспользоваться»
   лежали на одном фоне подряд, а ниже шли две полосы, различающиеся на три
   процента светлоты, — стык между ними читался как артефакт, а не как граница.
   Теперь фоны чередуются, и каждая граница между секциями видна.
   Порядок сверху вниз: bg → blue-soft → bg → cyan-soft → bg → подвал. */
.band {
  background: var(--color-blue-soft);
}

/* Надзаголовок раздела. Приём взят из первого экрана и стал общим: у каждого
   h2 появилась короткая строка-указатель, и разделы читаются как одна система,
   а не как набор непохожих блоков.
   Цвет — тёмный циан: #19a7ce давал бы 2.5:1, а здесь текст. Проверено на всех
   трёх фонах, где надзаголовок появляется: 5.11 на фоне страницы, 4.76 на
   полосе сервисов, 4.69 на полосе приёма. */
.eyebrow {
  margin-bottom: 12px;
  color: var(--color-cyan-text);
  font-size: var(--step-small);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* В первом экране надзаголовок отбит сильнее: под ним сразу крупный h1. */
.hero-text .eyebrow {
  margin-bottom: 24px;
}

/* Своя ступень шкалы: раньше лид отличался от основного текста только цветом,
   и после крупного h2 сразу шёл обычный кегль — ступени между ними не было. */
/* Мера строки задана в em, а не в ch. Единица ch — это ширина глифа «0»
   текущего шрифта, и до загрузки Manrope она берётся от запасного Arial:
   коробка лида выходила на 23px уже, текст переносился на лишнюю строку,
   а с приходом шрифта строка исчезала и вся страница подпрыгивала на 32px.
   Это и был весь CLS первого экрана. em привязан к кеглю, а не к шрифту,
   и коробка одинакова в обоих. Значения — прежние ширины в Manrope. */
.section-lead {
  margin-top: 20px;
  max-width: 37.8em;
  color: var(--color-text-secondary);
  font-size: var(--step-lead);
  /* Лид — две-три строки сразу под заголовком, и висячий хвост здесь виден
     не меньше, чем в самом заголовке. Отсюда balance, а не pretty от p. */
  text-wrap: balance;
}

/* ─── Кнопки ─────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 56px;
  padding: 14px 28px;
  border: 2px solid transparent;
  border-radius: var(--radius-button);
  font-size: var(--step-small);
  font-weight: 700;
  line-height: 1.3;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  /* box-shadow из списка убран: тень у кнопок нигде не задаётся, переход
     висел вхолостую. */
  transition: background-color var(--speed) var(--ease),
    border-color var(--speed) var(--ease), color var(--speed) var(--ease),
    transform var(--speed) var(--ease);
}

/* Нажатие обязано быть заметно: без :active кнопка на касание не отвечает
   ничем, и на медленной сети непонятно, засчитался ли тап. */
.btn:active {
  transform: translateY(1px);
}

.btn-primary {
  background: var(--color-navy);
  border-color: var(--color-navy);
  color: var(--color-bg);
}

/* Сдвиг на 3px, а не на 1: пиксель физически не различим, и отклика не было. */
@media (hover: hover) {
  .btn-primary:hover {
    background: var(--color-navy-hover);
    border-color: var(--color-navy-hover);
    /* Не #fff: в тёмной теме --color-navy-hover белый, и надпись пропадала. */
    color: var(--color-bg);
    transform: translateY(-3px);
  }

  /* Заливка --color-blue-soft в обеих контрастных темах равна фону, то есть
     hover там переставал существовать. Утолщение рамки видно всегда. */
  .btn-secondary:hover {
    background: var(--color-blue-soft);
    border-color: var(--color-navy-hover);
    color: var(--color-navy);
    transform: translateY(-3px);
    box-shadow: inset 0 0 0 1px var(--color-navy-hover);
  }
}

.btn-secondary {
  background: var(--color-surface);
  border-color: var(--color-navy);
  color: var(--color-navy);
}

/* ─── Шапка ──────────────────────────────────────────────────────────────── */

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--color-header-bg);
  border-bottom: 1px solid var(--color-border);
}

/* Полоса прочитанного. Растёт по прокрутке страницы, целиком на CSS.
   Масштабируется transform, а не width: ширина пересчитывала бы вёрстку
   на каждом кадре. Объявление анимации — ниже, в секции «Движение». */
.header::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 3px;
  pointer-events: none;
  background: var(--color-cyan-text);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* Тень появляется при прокрутке — иначе шапка «лежит» на контенте без границы.
   Анимируется прозрачность псевдоэлемента, а не box-shadow самой шапки:
   opacity composited, тень пришлось бы перерисовывать на каждом кадре. */
.header::after {
  content: "";
  position: absolute;
  inset: auto 0 -12px;
  height: 12px;
  pointer-events: none;
  background: linear-gradient(rgba(24, 49, 83, 0.09), rgba(24, 49, 83, 0));
  opacity: 0;
}

/* Шапка выше стандартных 80px: логотип вертикальный, с надписью над книгой,
   и при меньшей высоте надпись внутри картинки становится нечитаемой. */
.header-inner {
  display: flex;
  align-items: center;
  gap: 24px;
  min-height: 104px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--color-navy);
  text-decoration: none;
  flex: none;
}

.brand:hover {
  color: var(--color-navy);
}

/* Логотип выводится целиком, включая прозрачные поля исходника: пропорции
   не меняем и ничего не режем. Отрицательные поля не обрезают картинку —
   они лишь не дают пустым краям файла раздувать шапку, поэтому сам логотип
   можно показать крупнее и надпись внутри остаётся читаемой. */
.brand img {
  width: 210px;
  height: auto;
  margin: -11px 0 -14px;
  flex: none;
}

/* Меню примыкает к логотипу. Раньше здесь стоял margin-left: auto — он отжимал
   навигацию к правому краю, и между логотипом и «О сервисе» зияла пустота
   в половину шапки. Свободное место теперь собирается справа, одним куском. */
.nav {
  margin-left: 16px;
}

.nav-list {
  display: flex;
  align-items: center;
  gap: 36px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Промежуточный вес отсюда убран: подключены только 400 и 700, и браузер молча
   рисовал его как 400. Акцент даёт индикатор ниже, а не мнимый кегль. */
.nav-list a {
  position: relative;
  display: inline-block;
  padding: 8px 0;
  font-size: var(--step-small);
  color: var(--color-text);
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}

/* Подчёркивание растёт от центра. Тёмный циан, а не фирменный #19a7ce:
   у последнего на светлом фоне 2.5:1, для индикатора состояния этого мало. */
.nav-list a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--color-cyan-text);
  transform: scaleX(0);
  transition: transform var(--speed) var(--ease);
}

.nav-list a:hover {
  color: var(--color-cyan-hover);
}

/* Текущий раздел помечает a11y.js атрибутом aria-current — тем же, который
   объявляет диктор. Отдельного класса нет намеренно: два источника правды
   о «текущем» рано или поздно расходятся. Индикатор переиспользуется. */
.nav-list a:hover::after,
.nav-list a:focus-visible::after,
.nav-list a[aria-current]::after {
  transform: scaleX(1);
}

.nav-list a[aria-current] {
  color: var(--color-cyan-hover);
}

.a11y-toggle {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 10px 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-button);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
  flex: none;
  transition: border-color var(--speed) var(--ease),
    background-color var(--speed) var(--ease);
}

/* Заливка в контрастных темах совпадает с фоном, поэтому опираемся на рамку. */
.a11y-toggle:hover {
  border-color: var(--color-navy);
  background: var(--color-blue-soft);
  box-shadow: inset 0 0 0 1px var(--color-navy);
}

.a11y-toggle svg {
  color: var(--color-cyan-hover);
  flex: none;
}

.burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-button);
  background: var(--color-surface);
  color: var(--color-navy);
  cursor: pointer;
  flex: none;
}

.burger:hover {
  border-color: var(--color-navy);
}

/* Бургер превращается в крестик. Опираемся на aria-expanded, который a11y.js
   уже проставляет: отдельный класс завёл бы второй источник правды о том,
   открыто меню или нет. */
.burger line {
  transition: transform var(--speed) var(--ease),
    opacity var(--speed) var(--ease);
  transform-origin: center;
}

.burger[aria-expanded="true"] .burger-top {
  transform: translateY(6px) rotate(45deg);
}

.burger[aria-expanded="true"] .burger-mid {
  opacity: 0;
}

.burger[aria-expanded="true"] .burger-bottom {
  transform: translateY(-6px) rotate(-45deg);
}

/* ─── Первый экран ───────────────────────────────────────────────────────── */

.hero {
  padding: 24px 0 0;
}

.hero-inner {
  display: grid;
  grid-template-columns: 5fr 7fr;
  align-items: center;
  gap: 24px;
  min-height: 620px;
  padding: 68px;
  border-radius: var(--radius-hero);
  background: var(--hero-gradient);
}

.hero-text p.hero-description {
  max-width: 20.7em;
  margin: 28px 0 40px;
  color: var(--color-text-secondary);
  font-size: var(--step-lead);
  text-wrap: balance;
}

/* Три кнопки подряд читались как список равнозначных вариантов. Разложить
   вторичные в ряд не вышло: замер на живой странице дал «Подать заявление
   в детский сад» = 315px и «Записаться на приём» = 226px при колонке 467 —
   вместе они не помещаются ни при каком раскладе, а перенос на две строки
   выглядит хуже стопки.
   Поэтому группируем отбивкой: главное действие, воздух, пара дополнительных. */
.hero-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 430px;
}

.hero-actions .btn-primary {
  margin-bottom: 12px;
}

.hero-media {
  display: flex;
  justify-content: center;
}

/* Робот — главный персонаж первого экрана: показывается целиком (антенна,
   голова, руки, корпус), ширина задана в clamp по ТЗ. Единственный декор —
   очень мягкая голубая тень под ним.
   Размер держит обёртка, а не картинка: слоёв два, и оба обязаны получить
   одинаковую коробку. Тень тоже на обёртке — навешенная на слои, она дала бы
   вторую тень: рука отбросила бы собственную прямо на корпус. */
.hero-figure {
  position: relative;
  width: clamp(360px, 34vw, 520px);
  max-width: 100%;
  filter: drop-shadow(0 22px 28px rgba(24, 49, 83, 0.12));
}

/* picture по умолчанию строчный, и блочная картинка внутри него порождает
   анонимные боксы — лишний повод для вертикального люфта между слоями. */
.hero-figure picture {
  display: block;
}

.hero-figure img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
}

/* Верхний слой берёт ширину от обёртки, а высоту — из собственных пропорций.
   Холсты у файлов одинаковые, поэтому коробка получается ровно такой же, как
   у корпуса; растягивать её через inset не нужно, и незачем спорить с
   height: auto из правила выше. */
.hero-arm {
  position: absolute;
  top: 0;
  left: 0;
}

/* ─── Карточка: общий примитив ───────────────────────────────────────────── */

/* Один и тот же рецепт «белый фон + рамка + скругление» был выписан пять раз.
   Различия между блоками — только в радиусе и внутренних отступах, они ниже. */
.service,
.steps li,
.contact-card,
.priem-cta {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
}

.service,
.priem-cta {
  border-radius: var(--radius-hero);
  box-shadow: var(--shadow-soft);
}

/* ─── Строка возможностей ────────────────────────────────────────────────── */

/* Примыкает к первому экрану — это его продолжение, а не отдельный раздел.
   Снизу половина обычного отступа: дальше начинается цветная полоса,
   и полный отступ с обеих сторон границы дал бы провал. */
.features {
  padding: 36px 0 calc(var(--section-gap) / 2);
}

.features-strip {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px 40px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Иконка слева от текста, а не над ним: три вертикальные плитки занимали
   двести пикселей высоты на телефоне каждая, а несут по одной фразе. */
.features-strip li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

/* Кружок под иконкой убран вместе с плиткой: он держал значок на белой
   карточке, а в строке рядом с текстом значку хватает собственного цвета. */
.features-strip svg {
  flex: none;
  margin-top: 3px;
  color: var(--color-cyan-text);
}

.features-strip h3 {
  font-size: var(--step-body);
}

.features-strip p {
  margin-top: 2px;
  color: var(--color-text-secondary);
  font-size: var(--step-small);
}

/* ─── Сервисные блоки ────────────────────────────────────────────────────── */

/* Половина карточки под картинку и 48px внутренних отступов давали 700px
   высоты на сервис — на всю полосу 2168px, сорок процентов страницы. Текста
   в карточке три строки, столько места он не просит. Картинка ушла в узкую
   колонку по своему размеру, отступы сжаты. */
.service {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 40px;
  padding: 32px 36px;
  transition: transform var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
}

.service + .service {
  margin-top: 32px;
}

/* Карточки начинаются после заголовка раздела, а не сразу под шапкой секции. */
.service:first-of-type {
  margin-top: 48px;
}

/* Заголовок карточки был h2 и спорил с заголовком раздела: два одинаковых
   кегля подряд, из которых непонятно, какой главнее. */
.service-text h3 {
  font-size: var(--step-card-lg);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

/* Чередования сторон больше нет. Оно имело смысл при трёх карточках во всю
   ширину; на двух зигзаг читается не ритмом, а сбоем — картинка прыгает
   слева направо один раз и на этом кончается. Список ровнее. */
.service-media {
  display: flex;
  justify-content: center;
}

.service-media img {
  width: 100%;
  max-width: 220px;
  height: auto;
  object-fit: contain;
}

.service-text p {
  margin: 20px 0 32px;
  max-width: 28em;
  color: var(--color-text-secondary);
}

/* ─── Как воспользоваться + полезная информация ──────────────────────────── */

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 48px;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.steps li {
  position: relative;
  padding: 32px;
  counter-increment: step;
}

/* Номер — главный смысл блока, а раньше он был почти невидим: круг
   --color-cyan-soft на белой карточке давал 1.1:1 при норме 3:1 для графики.
   Тёмный циан на белом — 4.8:1, и белая цифра на нём тоже 4.8:1. */
.steps li::before {
  content: counter(step);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: 20px;
  border-radius: 999px;
  background: var(--color-cyan-text);
  color: var(--color-surface);
  font-size: var(--step-lead);
  font-weight: 700;
}

/* Соединительная линия между шагами: три одинаковые карточки сами по себе
   не читаются как последовательность. Только на десктопе — в колонку они
   и так идут сверху вниз. */
@media (min-width: 901px) {
  .steps li:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 54px;
    left: calc(100% + 1px);
    width: 24px;
    height: 2px;
    background: var(--color-border);
  }
}

/* Ссылка стала вторичной кнопкой: текстовой строкой в конце раздела она
   терялась, хотя это единственный выход на официальный сайт комитета.
   Раскладку и кегль задаёт .btn, здесь остаётся только отбивка. */
.info-link {
  margin-top: 40px;
}

.info-link svg {
  flex: none;
}

/* ─── Контакты ───────────────────────────────────────────────────────────── */

/* Фон страницы, а не blue-soft: выше стоит акцентная полоса приёма (cyan-soft),
   и две бледно-голубые подряд сливались в одно пятно. */
.contacts {
  background: var(--color-bg);
}

/* Две колонки, а не четыре: в узкой карточке адрес почты отдела переносится
   посреди слова и читается как ошибка. */
.contacts-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  margin-top: 48px;
}

.contact-card {
  display: flex;
  gap: 16px;
  padding: 28px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
}

/* Тёмный циан вместо фирменного #19a7ce: у последнего на белом 2.81:1, иконка
   выглядела выцветшей рядом с текстом. У --color-cyan-text — 5.36:1. */
.contact-card svg {
  color: var(--color-cyan-text);
  flex: none;
  margin-top: 4px;
}

.contact-card h3 {
  font-size: 1.0625rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

.contact-card p,
.contact-card a {
  margin-top: 8px;
  /* Именно anywhere, а не break-word: только он учитывается при расчёте
     min-content, иначе длинный адрес почты распирает колонку грида и
     на узком экране появляется горизонтальная прокрутка. */
  overflow-wrap: anywhere;
}

.contact-card a {
  display: inline-block;
  font-weight: 700;
}

/* Личный приём: собственная секция между «Полезной информацией» и «Контактами».
   Раньше блок был хвостом «Контактов» и упирался в подвал — читался как
   приписка к адресам, хотя это отдельный сервис.

   Устроен как «Контакты»: цветная полоса на всю ширину, белая карточка внутри.
   Полоса и отделяет его цветом от «Как воспользоваться сервисами», которые
   лежат на фоне страницы. */
.priem-section {
  background: var(--color-cyan-soft);
  /* Половина обычного отступа сверху. Два блока соседние по смыслу — сначала
     как работают сервисы, потом как прийти лично; полный отступ разрывал их
     на два несвязанных экрана, а цветная граница и так читается разделителем. */
  padding-top: calc(var(--section-gap) / 2);
}

#info {
  padding-bottom: calc(var(--section-gap) / 2);
}

/* Две равные колонки: слева призыв с кнопкой, справа список документов.
   Кнопка отдельным столбцом оставляла под собой пустоту во всю высоту
   списка — правая половина блока пустовала. */
.priem-cta {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  align-items: start;
  gap: 40px;
  padding: 40px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-hero);
}

/* Третья колонка по размеру картинки. Высоту блока она не задаёт: колонка
   с документами и так выше, поэтому иллюстрация встала в готовую пустоту
   и ничего не удлинила. */
.priem-media {
  display: flex;
  justify-content: center;
}

.priem-media img {
  width: 100%;
  max-width: 210px;
  height: auto;
  object-fit: contain;
}

/* Заголовок мельче обычного h2 секции: блок — призыв к действию, а не раздел,
   и полноразмерный кегль спорил бы с «Контактами» ниже. */
.priem-cta h2 {
  font-size: clamp(1.75rem, 2.2vw, 2.25rem);
}

.priem-cta p {
  margin-top: 12px;
  max-width: 28em;
  color: var(--color-text-secondary);
}

/* Кнопка не тянется на всю колонку: 700 пикселей сплошной заливки читались бы
   как полоса, а не как действие. */
.priem-cta .btn {
  margin-top: 28px;
  justify-self: start;
}

/* Список документов. Заголовок «Что взять с собой» — h3 после h2 блока,
   порядок уровней не рвётся. */
.priem-cta h3 {
  font-size: var(--step-card);
}

.priem-docs {
  margin: 12px 0 0;
  padding-left: 22px;
  color: var(--color-text-secondary);
}

.priem-docs li {
  margin-bottom: 6px;
}

.priem-docs li::marker {
  color: var(--color-cyan-text);
}


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

.footer {
  background: var(--color-footer-bg);
  color: var(--color-footer-text);
  padding: 64px 0 40px;
}

.footer h2 {
  color: var(--color-footer-text);
  font-size: 1.5rem;
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  justify-content: space-between;
  align-items: flex-start;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer a {
  color: var(--color-footer-text);
}

/* Раньше был перекрас в --color-cyan-soft: в светлой теме он равен #fff на белом
   подвале, в тёмной #000 на чёрном — ссылка пропадала в обеих. Подчёркивание
   видно при любой палитре, потому что берёт цвет самого текста. */
.footer a:hover {
  text-decoration-thickness: 3px;
}

.footer-note {
  margin-top: 48px;
  padding-top: 24px;
  /* currentColor с прозрачностью: линия сама подстраивается под цвет подвала
     в любой схеме, отдельного правила на каждую тему не нужно. */
  border-top: 1px solid color-mix(in srgb, var(--color-footer-text) 24%, transparent);
  color: var(--color-footer-muted);
  font-size: 1rem;
}

/* ─── Кнопка «Наверх» ────────────────────────────────────────────────────── */

/* Базовое состояние — видима. Прятать её по умолчанию в расчёте на анимацию
   нельзя: там, где таймлайны прокрутки не поддержаны, осталась бы невидимая
   ссылка в порядке обхода клавиатурой. Скрытие объявляется отдельно, в секции
   «Движение», и только внутри @supports. */
.to-top {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 40;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-navy);
  box-shadow: var(--shadow-soft);
  transition: border-color var(--speed) var(--ease),
    transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease);
}

@media (hover: hover) {
  .to-top:hover {
    border-color: var(--color-cyan-text);
    box-shadow: var(--shadow-hover);
    transform: translateY(-3px);
  }
}

.to-top:active {
  transform: translateY(1px);
}

/* ─── Панель «Версия для слабовидящих» ───────────────────────────────────── */

.a11y-dialog {
  width: min(520px, calc(100vw - 32px));
  padding: 28px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-hero);
  background: var(--color-surface);
  color: var(--color-text);
  /* Плавное появление вместо рывка. allow-discrete нужен для display и overlay:
     без него браузер переключает их мгновенно и переход не виден. Скрипт
     не трогаем — он как вызывал showModal(), так и вызывает. */
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--speed) var(--ease),
    transform var(--speed) var(--ease),
    overlay var(--speed) var(--ease) allow-discrete,
    display var(--speed) var(--ease) allow-discrete;
}

.a11y-dialog[open] {
  opacity: 1;
  transform: none;
}

/* Стартовое состояние для первого кадра после появления в top layer. */
@starting-style {
  .a11y-dialog[open] {
    opacity: 0;
    transform: translateY(8px);
  }
}

.a11y-dialog::backdrop {
  background: rgba(16, 39, 67, 0.55);
}

.a11y-dialog h2 {
  font-size: var(--step-card);
}

.a11y-group {
  margin: 24px 0 0;
  padding: 0;
  border: 0;
}

.a11y-group legend {
  padding: 0;
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text-secondary);
}

.a11y-options {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}

/* Радиокнопка скрыта, но остаётся фокусируемой: подсветку рисует подпись. */
.a11y-options input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.a11y-options label {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 10px 18px;
  border: 2px solid var(--color-border);
  border-radius: var(--radius-button);
  cursor: pointer;
  font-size: 1rem;
}

/* Не #fff: в тёмных схемах --color-navy сам становится светлым, и белая
   надпись на нём пропадала. --color-bg инвертируется вместе с заливкой,
   поэтому одно правило работает во всех четырёх схемах. */
.a11y-options input:checked + label {
  border-color: var(--color-navy);
  background: var(--color-navy);
  color: var(--color-bg);
}

.a11y-options input:focus-visible + label {
  outline: 3px solid var(--color-cyan-hover);
  outline-offset: 3px;
}

.a11y-check {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 24px;
  min-height: 48px;
  font-size: 1rem;
  cursor: pointer;
}

.a11y-check input {
  width: 24px;
  height: 24px;
  accent-color: var(--color-navy);
  flex: none;
}

.a11y-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
}

.a11y-actions .btn {
  flex: 1 1 180px;
  min-height: 48px;
}

/* ─── Системные схемы ────────────────────────────────────────────────────── */

/* Ниже — две схемы, которые страница берёт из настроек операционной системы,
   не спрашивая. Обе спрятаны за `:not([data-a11y-theme])`, и это не осторожность,
   а точное условие: атрибут data-a11y-theme СНИМАЕТСЯ, когда в панели выбрана
   «обычная» тема, — так делает и инлайн-скрипт в <head>, и a11y.js. Значит
   «атрибута нет» буквально означает «человек ничего не выбирал», а любой явный
   выбор в панели автоматически отменяет системный. Селекторы `:not([data-a11y-theme])`
   и `[data-a11y-theme]` взаимно исключают друг друга, поэтому за специфичность
   они не спорят и порядок в файле роли не играет.

   Почему это вообще понадобилось: тёмная тема на странице была ровно одна —
   ГОСТовская «версия для слабовидящих», чистый чёрный с белым и рамками в 2px.
   Для своей задачи она верна, но человеку, у которого в телефоне просто включён
   тёмный режим, она не предназначена: он получал вспышку белого во весь экран. */

/* Мягкая тёмная схема. Не чёрная: фирменный синий уводится в тень, а не
   заменяется. Пять уровней фона выстроены по светлоте снизу вверх —
   подвал → страница → полосы → градиент первого экрана → карточки, — иначе
   белые карточки, которые в светлой теме лежат поверх цветных полос, слились
   бы с ними. Все пары считаны, а не подобраны на глаз: худшая из текстовых —
   7.44 (вторичный текст на карточке) при пороге 7. */
@media (prefers-color-scheme: dark) {
  :root:not([data-a11y-theme]) {
    color-scheme: dark;

    --color-bg: #0d1826;
    --color-surface: #1e3454;
    --color-blue-soft: #132339;
    --color-cyan-soft: #0f2733;

    /* --color-navy здесь светлый, и это не опечатка. Токен работает сразу
       в двух ролях: цвет текста ссылок и заливка первичной кнопки, а надпись
       на ней — --color-bg. Пара инвертируется целиком, поэтому кнопка
       остаётся кнопкой, а не белым по белому. Тот же приём уже держит
       ГОСТовскую тёмную. */
    --color-navy: #e8eef5;
    --color-navy-hover: #ffffff;
    --color-text: #e8eef5;
    --color-text-secondary: #bac9da;

    /* На тёмном фоне затемнённый циан #0a576c нечитаем — акцент осветляется.
       11.45 на фоне страницы. */
    --color-cyan: #7fdcf5;
    --color-cyan-text: #7fdcf5;
    --color-cyan-hover: #a5e6f8;

    --color-border: #527ba8;

    /* Тень на тёмном фоне не читается синей — только чёрной и глубже. */
    --shadow-soft: 0 10px 30px rgba(0, 0, 0, 0.45);
    --shadow-hover: 0 14px 36px rgba(0, 0, 0, 0.55);

    --color-header-bg: rgba(13, 24, 38, 0.96);

    /* Подвал в светлой теме собран из --color-navy, а тот здесь стал светлым:
       без этой строки внизу тёмной страницы включалась бы лампа. */
    --color-footer-bg: #091320;
    --color-footer-text: #e8eef5;
    --color-footer-muted: #bac9da;

    --hero-gradient: linear-gradient(135deg, #101d31 0%, #152741 55%, #0f1c30 100%);
  }

  /* Знак книги тёмно-синий — на тёмном фоне пропадает. Тот же приём, что
     и в ГОСТовской тёмной схеме ниже. */
  :root:not([data-a11y-theme]) .brand img {
    filter: brightness(0) invert(1);
  }

  /* Флажок остаётся нативным: свой рисованный чекбокс ломается в режиме
     принудительных цветов Windows, а выигрыш чисто косметический. Правится
     только цвет отметки — иначе она берётся из --color-navy, который здесь
     стал почти белым, и «включено» читается блёкло. Голубой совпадает
     с акцентом схемы, галочку поверх него браузер рисует тёмной сам. */
  :root:not([data-a11y-theme]) .a11y-check input {
    accent-color: var(--color-cyan);
  }
}

/* Системная настройка «повышенный контраст». Своих значений не изобретаем:
   подключаем уже написанные наборы токенов ГОСТовских схем — они проверены
   и живут ниже в этом же файле. Человеку, который включил повышенный контраст
   в системе, больше не нужно искать панель доступности.

   Схема при этом сохраняется: светлая система получает чёрное на белом,
   тёмная — белое на чёрном. Одна светлая ветка на оба случая означала бы,
   что человек с тёмной системой и повышенным контрастом ловит вспышку белого
   во весь экран — ровно ту, ради которой выше написана тёмная схема. */
@media (prefers-contrast: more) {
  :root:not([data-a11y-theme]) {
    --color-bg: #ffffff;
    --color-surface: #ffffff;
    --color-blue-soft: #ffffff;
    --color-cyan-soft: #ffffff;
    --color-navy: #000000;
    --color-navy-hover: #000000;
    --color-text: #000000;
    --color-text-secondary: #000000;
    --color-cyan: #000000;
    --color-cyan-text: #000000;
    --color-cyan-hover: #000000;
    --color-border: #000000;
    --shadow-soft: none;
    --shadow-hover: none;
    --color-header-bg: #ffffff;
    --color-footer-bg: #ffffff;
    --color-footer-text: #000000;
    --color-footer-muted: #000000;
    --hero-gradient: none;
  }

  /* Заливки в этой схеме схлопываются в фон, границы блоков несут рамки —
     ровно как в контрастных темах панели. */
  :root:not([data-a11y-theme]) .hero-inner,
  :root:not([data-a11y-theme]) .service,
  :root:not([data-a11y-theme]) .steps li,
  :root:not([data-a11y-theme]) .contact-card,
  :root:not([data-a11y-theme]) .priem-cta {
    border: 2px solid var(--color-border);
  }

  :root:not([data-a11y-theme]) .btn-primary {
    background: var(--color-text);
    border-color: var(--color-text);
    color: var(--color-bg);
  }
}

/* Повышенный контраст при тёмной системе: те же токены, что у ГОСТовской
   тёмной схемы панели. Блок стоит ниже светлой ветки и перекрывает её —
   специфичность у них одинаковая, решает порядок. Компонентные правила
   (рамки 2px, инверсия кнопки) уже заданы выше и действуют в обеих ветках. */
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
  :root:not([data-a11y-theme]) {
    color-scheme: dark;
    --color-bg: #000000;
    --color-surface: #000000;
    --color-blue-soft: #000000;
    --color-cyan-soft: #000000;
    --color-navy: #ffffff;
    --color-navy-hover: #ffffff;
    --color-text: #ffffff;
    --color-text-secondary: #ffffff;
    --color-cyan: #4fd1f0;
    --color-cyan-text: #4fd1f0;
    --color-cyan-hover: #4fd1f0;
    --color-border: #ffffff;
    --color-header-bg: #000000;
    --color-footer-bg: #000000;
    --color-footer-text: #ffffff;
    --color-footer-muted: #ffffff;
  }

  /* Знак книги тёмно-синий: на чёрном пропадает, выводим в инверсии —
     тем же приёмом, что в мягкой тёмной схеме и в схеме панели. */
  :root:not([data-a11y-theme]) .brand img {
    filter: brightness(0) invert(1);
  }
}

/* ─── Режимы доступности ─────────────────────────────────────────────────── */

:root[data-a11y-size="large"] {
  font-size: 125%;
}

:root[data-a11y-size="huge"] {
  font-size: 150%;
}

/* В увеличенных режимах декоративные поля съедают место, нужное тексту. */
:root[data-a11y-size="large"],
:root[data-a11y-size="huge"] {
  --section-gap: 72px;
}

:root[data-a11y-theme="light"] {
  --color-bg: #ffffff;
  --color-surface: #ffffff;
  --color-blue-soft: #ffffff;
  --color-cyan-soft: #ffffff;
  --color-navy: #000000;
  --color-navy-hover: #000000;
  --color-text: #000000;
  --color-text-secondary: #000000;
  --color-cyan: #000000;
  --color-cyan-text: #000000;
  --color-cyan-hover: #000000;
  --color-border: #000000;
  --shadow-soft: none;
  --shadow-hover: none;
  --color-header-bg: #ffffff;
  --color-footer-bg: #ffffff;
  --color-footer-text: #000000;
  --color-footer-muted: #000000;
  --hero-gradient: none;
}

:root[data-a11y-theme="dark"] {
  color-scheme: dark;
  --color-bg: #000000;
  --color-surface: #000000;
  --color-blue-soft: #000000;
  --color-cyan-soft: #000000;
  --color-navy: #ffffff;
  --color-navy-hover: #ffffff;
  --color-text: #ffffff;
  --color-text-secondary: #ffffff;
  --color-cyan: #4fd1f0;
  --color-cyan-text: #4fd1f0;
  --color-cyan-hover: #4fd1f0;
  --color-border: #ffffff;
  --shadow-soft: none;
  --shadow-hover: none;
  --color-header-bg: #000000;
  --color-footer-bg: #000000;
  --color-footer-text: #ffffff;
  --color-footer-muted: #ffffff;
  --hero-gradient: none;
}


/* Заливки полос в контрастных схемах сами схлопываются в фон: они собраны
   из токенов, а те равны --color-bg. Градиент первого экрана держится тем же
   способом — --hero-gradient: none, иначе текст лёг бы на его середину.
   Границу между блоками в этих схемах несут рамки. */
:root[data-a11y-theme] .hero-inner,
:root[data-a11y-theme] .service,
:root[data-a11y-theme] .steps li,
:root[data-a11y-theme] .contact-card,
:root[data-a11y-theme] .priem-cta {
  border: 2px solid var(--color-border);
}

/* Шапка, подвал и чипы панели раньше требовали здесь отдельных правил на
   компоненты — теперь это строки токенов выше, и переопределять нечего. */
:root[data-a11y-theme] .btn-primary {
  background: var(--color-text);
  border-color: var(--color-text);
  color: var(--color-bg);
}

/* Знак книги тёмно-синий: на чёрном фоне он пропадает, поэтому в тёмной
   схеме выводим его в инверсии. */
:root[data-a11y-theme="dark"] .brand img {
  filter: brightness(0) invert(1);
}

:root[data-a11y-theme] .a11y-dialog::backdrop {
  background: rgba(0, 0, 0, 0.8);
}

/* Иллюстрации не несут информации — в режиме «без изображений» просто уходят. */
:root[data-a11y-images="off"] .hero-media,
:root[data-a11y-images="off"] .service-media {
  display: none;
}

:root[data-a11y-images="off"] .hero-inner,
:root[data-a11y-images="off"] .service {
  grid-template-columns: 1fr;
}

/* ─── Адаптив ────────────────────────────────────────────────────────────── */

@media (max-width: 1200px) {
  .hero-inner {
    padding: 48px;
    gap: 32px;
    /* Было 5fr 7fr. При 1000px это давало колонку текста в 330px, куда не
       помещались ни описание (34ch ≈ 340px), ни кнопки (430px), — а картинка
       рядом занимала 340px в колонке 462px и оставляла 122px пустоты. */
    grid-template-columns: 6fr 5fr;
  }

  /* Обе ширины были рассчитаны на широкую колонку и здесь только распирают её. */
  .hero-text p.hero-description,
  .hero-actions {
    max-width: none;
  }

  .hero-figure {
    width: clamp(260px, 30vw, 400px);
  }

  .service {
    gap: 40px;
    padding: 40px;
  }
}

/* Шапка ещё горизонтальная, но места в ней уже нет: на 1000px четыре пункта
   меню и кнопка «Версия для слабовидящих» с полной подписью требовали 1022px
   и выдавливали кнопку за правый край — появлялась горизонтальная прокрутка.
   Ужимаем промежутки, а не прячем подпись: она нужна именно тем, кто её ищет. */
@media (max-width: 1120px) {
  .header-inner {
    gap: 14px;
  }

  .nav {
    margin-left: 8px;
  }

  .nav-list {
    gap: 20px;
  }

  .a11y-toggle {
    padding: 10px 14px;
  }
}

/* Шапке с полной подписью нужно минимум 934px — замерено на живой странице.
   Ниже этого в кнопке остаётся только иконка: доступное имя даёт тот же span,
   спрятанный визуально, поэтому диктор по-прежнему читает «Версия для
   слабовидящих». Порог 960, а не 934: запас на другие шрифты подстановки. */
@media (max-width: 960px) {
  .a11y-toggle span {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* Порог 960 посчитан для обычного кегля, а «Версия для слабовидящих» шрифт
   увеличивает: 125% требуют шапке около 1170px, 150% — около 1400. Порог
   обязан расти вместе со шрифтом, иначе в самом нужном режиме страница
   выезжала вбок: на 1200px при максимальном кегле — на 85 пикселей.
   Проверено замером и на боевом: дефект застарелый, не от перестройки. */
@media (min-width: 961px) and (max-width: 1240px) {
  :root[data-a11y-size="large"] .a11y-toggle span {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (min-width: 961px) and (max-width: 1460px) {
  :root[data-a11y-size="huge"] .a11y-toggle span {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* Прежде здесь карточка ломалась в одну колонку: при картинке в половину
   ширины на текст оставалось около 350px, и заголовок «Помощник по вопросам
   дошкольного образования» разваливался на пять строк. Картинка теперь узкая,
   и две колонки живут до самого телефона — достаточно поджать иллюстрацию. */
@media (max-width: 1080px) {
  .service {
    gap: 32px;
  }

  .service-media img {
    max-width: 180px;
  }

  .priem-media img {
    max-width: 150px;
  }
}

@media (max-width: 900px) {
  :root {
    --gutter: 24px;
  }

  .header-inner {
    min-height: 84px;
    gap: 12px;
  }

  .brand img {
    width: 150px;
    margin: -8px 0 -10px;
  }

  .burger {
    display: inline-flex;
    order: 3;
  }

  .nav {
    order: 4;
    flex-basis: 100%;
    margin-left: 0;
  }

  /* Прячет меню только при работающем JS — иначе кнопка-гамбургер бесполезна,
     а навигация недоступна. Класс js ставится инлайном в <head>.

     Схлопнутая грид-строка вместо display: none. display анимировать нельзя,
     а высота здесь остаётся нулевой до первой отрисовки — ровно как раньше,
     поэтому CLS не появляется. Раскрытие происходит по действию пользователя,
     в метрику сдвигов оно не попадает. */
  .js .nav {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--speed) var(--ease);
  }

  .js .nav.is-open {
    grid-template-rows: 1fr;
  }

  .js .nav > ul {
    overflow: hidden;
    min-height: 0;
  }

  .header-inner {
    flex-wrap: wrap;
  }

  /* Без padding-bottom: схлопнутая грид-строка сжимает содержимое до нуля,
     но не отступы — border-box не даёт боксу стать ниже суммы своих полей,
     и закрытое меню держало в шапке лишние 12 пикселей. Воздух снизу дают
     собственные отступы последнего пункта. */
  .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .nav-list li:last-child a {
    padding-bottom: 22px;
  }

  .nav-list a {
    padding: 14px 0;
    border-top: 1px solid var(--color-border);
    font-size: 1.125rem;
  }

  .a11y-toggle {
    margin-left: auto;
  }

  /* Мобильная шапка ниже десктопной (84px против 104), а отступ якоря был
     один на все ширины — заголовок приземлялся на 28px ниже, чем нужно. */
  html {
    scroll-padding-top: 92px;
  }

  .hero-inner,
  .service,
  .features-strip,
  .steps,
  .contacts-grid,
  .priem-cta {
    grid-template-columns: 1fr;
  }

  /* В одну колонку список документов встаёт под кнопку — порядок чтения
     остаётся тем же, что и в разметке. */
  .priem-cta {
    gap: 32px;
  }

  .hero-inner {
    min-height: 0;
    padding: 40px 28px;
    gap: 40px;
  }

  .hero-text p.hero-description {
    max-width: none;
  }

  .hero-actions {
    max-width: none;
  }

  /* На узком экране clamp из desktop-правила шире вьюпорта — персонаж
     переходит на обычную резиновую ширину. */
  .hero-figure {
    width: 100%;
    max-width: 380px;
  }

  .service-media img {
    max-width: 160px;
  }

  /* Блок приёма здесь уже в одну колонку, картинка стоит по центру под
     текстом — ей можно вернуть размер. */
  .priem-media img {
    max-width: 180px;
  }

  .service {
    gap: 28px;
    padding: 28px;
  }
}

@media (max-width: 600px) {
  :root {
    --gutter: 16px;
  }

  /* 48px с двух сторон на узком экране съедают половину ширины под текст. */
  .priem-cta {
    padding: 28px 20px;
    border-radius: 18px;
  }

  h1 {
    font-size: clamp(2.125rem, 9vw, 3rem);
  }

  /* Нижняя граница clamp растёт вместе с корневым кеглем, и при 150% даёт
     51px. Слово «Образование» на таком кегле требует 328px, а колонка на
     узком телефоне — 288: страница выезжала вбок на 44 пикселя. Переносить
     заголовок посреди слова хуже, чем убавить кегль: 42px здесь всё равно
     заметно крупнее обычных 34. Дефект застарелый, воспроизводится и на
     боевом; режимов large он не касается — там запас есть. */
  :root[data-a11y-size="huge"] h1 {
    font-size: 1.75rem;
  }

  /* Нижняя граница поднята с 1.75rem: на 375px заголовок раздела упирался
     в неё и совпадал по кеглю с заголовком карточки — ступень между разделом
     и карточкой на телефоне исчезала. */
  h2 {
    font-size: clamp(1.875rem, 6.5vw, 2.25rem);
  }

  body {
    font-size: 1.0625rem;
  }

  .hero {
    padding-top: 16px;
  }

  .hero-inner {
    padding: 32px 20px;
    border-radius: 18px;
  }

  .hero-text p.hero-description {
    font-size: 1.125rem;
    margin: 20px 0 32px;
  }

  .btn {
    width: 100%;
    /* Иначе «Подать заявление в детский сад» ломается на две строки. */
    padding: 14px 16px;
  }

  .service,
  .steps li,
  .contact-card {
    padding: 24px 20px;
  }

  /* Здесь две колонки наконец кончаются: на телефоне под текст осталось бы
     около 170px, и заголовок сервиса рассыпался бы по одному слову в строку. */
  .service {
    grid-template-columns: 1fr;
  }

  /* Номер шага уходит влево, к тексту. Кружок над текстом — раскладка для
     трёх карточек в ряд; в колонке он добавлял к каждому шагу 64px высоты
     (сам кружок и отступ под ним) ради трёх строк текста. */
  .steps {
    gap: 16px;
    margin-top: 28px;
  }

  /* min-width: 0 обязателен. У элемента сетки автоматический минимум равен
     ширине его содержимого, а содержимое здесь — флексовая строка «кружок
     плюс текст», которую браузер не считает сжимаемой. На 320px шаг выходил
     316px при колонке 288 и давал горизонтальную прокрутку. */
  .steps li {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    min-width: 0;
    padding: 18px 16px;
  }

  .steps li::before {
    flex: none;
    width: 34px;
    height: 34px;
    margin-bottom: 0;
    font-size: var(--step-small);
  }

  .contact-card {
    padding: 18px 16px;
  }

  .hero-figure {
    max-width: 300px;
  }

  .service-media img,
  .priem-media img {
    max-width: 180px;
  }

  .footer {
    padding: 48px 0 32px;
  }
}

/* ─── Движение ───────────────────────────────────────────────────────────── */

/* Подъём карточки только там, где внутри есть кнопка. Плитки «возможностей»,
   шаги и контакты не кликабельны — подъём обещал бы им действие, которого нет.
   hover: hover обязателен: на тач-экране состояние залипает после тапа. */
@media (hover: hover) {
  .service:hover,
  .priem-cta:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-hover);
    /* В контрастных темах тени равны none, так что подъём обязан читаться
       и без них — за это отвечает рамка. */
    border-color: var(--color-cyan);
  }
}

.priem-cta {
  transition: transform var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
}

/* Появление блоков при прокрутке — на чистом CSS, без скриптов.

   Две обёртки, и обе обязательны.
   @supports: где таймлайны не поддержаны, правило не применяется вовсе, и блоки
   просто видны сразу. Спрятать контент за opacity: 0 в надежде на скрипт нельзя —
   при отказе страница осталась бы пустой.
   no-preference: при «уменьшить движение» анимация не объявляется в принципе.
   Полагаться на общий сброс ниже нельзя: он гасит длительность, но не трогает
   animation-delay, и блоки провисели бы невидимыми весь период задержки. */
/* Взмах руки. Углы не на глаз: до головы у поднятой ладони всего 21px
   исходника, поворот «внутрь» этот просвет съедает. Замер по контурам дал
   при +3° десять пикселей зазора, при +6° — касание, поэтому внутрь ходим
   на градус-два, а размах набираем наружу, где свободно.
   Ось — середина шва между рукой и корпусом; там же, где слои соприкасаются,
   смещение при повороте минимально, и стык не расходится. */
@keyframes hero-wave {
  0%,
  100% {
    rotate: 0deg;
  }
  12% {
    rotate: -13deg;
  }
  30% {
    rotate: 1deg;
  }
  48% {
    rotate: -12deg;
  }
  66% {
    rotate: 1deg;
  }
  84% {
    rotate: -8deg;
  }
}

@keyframes reveal-in {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes header-shadow {
  to {
    opacity: 1;
  }
}

@keyframes read-progress {
  to {
    transform: scaleX(1);
  }
}

/* visibility анимируется дискретно, но в @keyframes работает — и в отличие
   от одной только opacity убирает кнопку из порядка обхода, пока её не видно. */
@keyframes to-top-in {
  from {
    opacity: 0;
    visibility: hidden;
  }
  to {
    opacity: 1;
    visibility: visible;
  }
}

/* Робот здоровается: два взмаха и замирает. Бесконечное движение рядом с
   текстом нарушало бы WCAG 2.2.2 — там всё, что дольше пяти секунд, обязано
   иметь кнопку паузы. Здесь движение длится 3.2 секунды и кончается само,
   поэтому кнопка не нужна. Повторить взмах можно наведением: перезапуск
   делает a11y.js.
   Задержка даёт странице дорисоваться: анимация, начатая в момент появления
   картинки, на медленной машине съедает первые кадры. */
@media (prefers-reduced-motion: no-preference) {
  .hero-arm {
    transform-origin: 37.6% 54.9%;
    animation: hero-wave 1.6s ease-in-out 0.6s 2;
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Анимируются только opacity и transform: обе composited, вёрстка
       не пересчитывается, CLS остаётся нулевым. */
    /* Диапазон считается только по entry — фазе входа элемента в экран.
       С «cover» блок внизу страницы мог до конца диапазона не дойти: прокрутка
       упиралась в подвал, и карточка навсегда оставалась полупрозрачной.
       Полностью вошедший элемент даёт entry = 100%, то есть анимация всегда
       доигрывается до конца. */
    .reveal {
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }

    .header::after {
      animation: header-shadow linear both;
      animation-timeline: scroll();
      animation-range: 0 100px;
    }

    /* Полоса прочитанного: диапазон по умолчанию — вся прокрутка страницы,
       от нуля до конца, задавать range не нужно. */
    .header::before {
      animation: read-progress linear both;
      animation-timeline: scroll();
    }

    /* «Наверх» проявляется на втором экране: раньше кнопка спорила бы с
       первым экраном, где возвращаться ещё некуда. */
    .to-top {
      animation: to-top-in linear both;
      animation-timeline: scroll();
      animation-range: 400px 600px;
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
  }

  .btn:hover,
  .btn:active,
  .service:hover,
  .priem-cta:hover,
  .to-top:hover,
  .to-top:active {
    transform: none;
  }

  /* Полоса прогресса — это движение как таковое, при «уменьшить движение»
     её быть не должно вовсе. Кнопка «Наверх», наоборот, остаётся видимой
     постоянно: её появление отменено, а сама она полезна. */
  .header::before {
    display: none;
  }
}

/* ─── Печать ─────────────────────────────────────────────────────────────────
   Страницу печатают ради контактов и списка документов на приём. Всё, что
   нельзя нажать на бумаге, с листа уходит; экранные заливки — тоже, иначе
   принтер выводит светло-голубые плашки серым и текст на них теряется. */

@media print {
  .header,
  .to-top,
  .a11y-dialog,
  .skip-link,
  .hero-media,
  .service-media,
  .footer-nav,
  .info-link {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
  }

  .hero-inner,
  .band,
  .contacts,
  .priem-section,
  .footer {
    background: #fff;
    color: #000;
  }

  .footer h2,
  .footer a,
  .footer-note {
    color: #000;
  }

  .section {
    padding: 16pt 0;
  }

  .hero-inner,
  .service,
  .priem-cta {
    padding: 0;
    border: 0;
    box-shadow: none;
    min-height: 0;
  }

  /* Карточка, разрезанная границей страницы пополам, — самая частая претензия
     к печати с сайтов. */
  .features-strip li,
  .service,
  .steps li,
  .contact-card,
  .priem-cta {
    break-inside: avoid;
  }

  /* Адреса дописывать не нужно: почта и телефон в карточках и так выведены
     текстом, а не спрятаны под словом-ссылкой. */

  .reveal {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}
