/* Собран скриптом .claude/telezhka/trim-css.php из style-full.css.
   Руками не править: правки затрутся при следующей сборке.
   Исходник — стили elli.npoelm.ru. */


/* ===== 2. ТОКЕНЫ ===== */
:root {
  --brand:            #009541;
  --brand-light:      #10AC50;   /* наведение на зелёную кнопку без волны */

  /* Цвета бейджей каталога: подобраны к фирменному зелёному, каждый отвечает
     за свой смысл — гарантия, субсидия, «скоро». */
  --badge-blue:       #1B6FA8;
  --badge-amber:      #9A5C00;   /* затемнён: белая надпись «Субсидия
                                    до 60%» на прежнем #B26A00 давала 4,24:1 —
                                    ниже нормы AA. Стало 5,38:1 */
  --badge-slate:      #4A5459;
  --brand-press:      #007A35;   /* плашки с белым текстом: 5,48:1 при норме 4,5 */
  --brand-deep:       #006A2E;   /* наведение и нажатие на такой плашке */
  --brand-dim:        #0C6B36;   /* ссылки и мелкий текст на белом: чистый
                                    --brand на белом не добирает контраста */
  --on-brand:         #FFFFFF;

  --ink:              #0A0D0E;
  --ink-strong:       #161B1D;
  --body:             #3A4246;
  --muted:            #5B666B;   /* подписи и оговорки: прежний #6C777C давал
                                    4,24:1 на --surface — ниже нормы AA, и на
                                    телефоне текст читался как выключенный.
                                    Стало 5,44:1 */
  --faint:            #98A2A7;

  --report-ptzem:     #FBE3CF;   /* метка проекта ptzem в отчёте о работах — оранжевый из логотипа Технопарка, осветлённый */
  --canvas:           #FFFFFF;
  --surface:          #F4F6F6;
  --surface-2:        #E9EDEE;
  --surface-3:        #DCE2E3;   /* шапка таблицы: темнее строк-подзаголовков */
  --hairline:         #E1E6E7;
  --find-mark:        #FFE27A;   /* подсветка найденного на странице после перехода из поиска */
  --hairline-strong:  #C9D1D3;

  --dark:             #0A0D0E;
  --dark-2:           #12181A;
  --dark-3:           #1B2225;
  --header-bg:        #1B1B1B;
  --on-dark:          #FFFFFF;
  --on-dark-2:        rgba(255,255,255,.72);
  --on-dark-3:        rgba(255,255,255,.46);
  --hairline-dark:    rgba(255,255,255,.12);

  --quiz-bg:          #333333;
  --quiz-line:        #555555;

  --danger:           #C0392B;
  --warning:          #9A5C00;

  --font:             'Montserrat', Arial, -apple-system, 'Segoe UI', sans-serif;

  --fs-display:       3.75rem;     /* 60px — H1 первого экрана */
  --fs-h2:            2.0625rem;   /* 33px */
  --fs-h3:            1.5rem;      /* 24px */
  --fs-h4:            1.1875rem;   /* 19px */
  --fs-stat:          2.75rem;     /* 44px — цифра показателя */
  --fs-lead:          1.1875rem;   /* 19px */
  --fs-base:          1rem;        /* 16px — минимум для инпутов, иначе iOS зумит */
  --fs-sm:            0.9375rem;   /* 15px */
  --fs-caption:       0.8125rem;   /* 13px */
  --fs-label:         0.75rem;     /* 12px — прописными, вразрядку */

  --lh-display:       1.04;
  --lh-tight:         1.15;
  --lh-snug:          1.35;
  --lh-base:          1.65;

  --ls-display:      -0.03em;
  --ls-h2:           -0.025em;
  --ls-h3:           -0.015em;
  --ls-label:         0.12em;

  --sp-1:  4px;   --sp-2:  8px;   --sp-3:  12px;  --sp-4:  16px;
  --sp-5:  24px;  --sp-6:  32px;  --sp-7:  48px;  --sp-8:  64px;
  --sp-9:  96px;  --sp-10: 128px;

  --radius:           2px;
  --radius-md:        4px;
  /* Скругления: острые углы кнопок
     читались недружелюбно. Инженерный характер держат волосяные линии и
     типографика, а не прямые углы у всего подряд. */
  --radius-btn:       8px;
  --radius-lg:        12px;
  --radius-full:      999px;

  --shadow-menu:      0 16px 40px -20px rgba(10,13,14,.45);

  --wrap:             1408px;
  --wrap-medium:      1180px;   /* прайс и дорожная карта: широкая таблица неудобна во всю ширину */
  --wrap-narrow:      960px;
  --gutter:           24px;
  --header-h:         76px;

  /* Правый нижний угол: кнопка чата и кнопка «наверх» стоят друг над другом и
     обязаны совпадать по вертикальной оси. Размеры кругов разные, поэтому у
     верхней кнопки отступ считается от этих переменных, а не пишется числом.
     */
  --dock-right:       20px;
  --dock-chat:        56px;
  --dock-top:         44px;
  --dock-lift:        0px;    /* подъём кнопок над плашкой cookie, считается ниже */
}

/* ===== 2.1. ШРИФТЫ =====
   Объявления не было вовсе: файлы лежали в assets/fonts, стояла строка
   preload, но @font-face никто не написал — страница рисовалась системным
   шрифтом, а браузер ругался «preloaded but not used».
   Подмножества разделены по unicode-range: латиница не тянется ради
   кириллического текста и наоборот. */
@font-face {
  font-family: 'Montserrat';
  src: url('/elli-t/assets/fonts/montserrat-cyrillic.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/elli-t/assets/fonts/montserrat-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ===== 3. СБРОС И БАЗА ===== */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--body);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

[hidden] { display: none !important; }
button, input, select, textarea { font: inherit; color: inherit; }

table, .stats, .spec, .tech { font-variant-numeric: tabular-nums; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Место под полосу прокрутки резервируется всегда: иначе при открытии модального
   окна страница теряет полосу и дёргается вправо.
   Только справа: при both-edges слева оставалось пустое поле, и на тёмных
   секциях оно читалось как светлая вертикальная полоса. */
html { scrollbar-gutter: auto; }
@media (hover: hover) and (pointer: fine) { html { scrollbar-gutter: stable; } }
body.is-menu-open, body.is-modal-open { overflow: hidden; }

/* ===== 4. ТИПОГРАФИКА ===== */
h1, h2, h3, h4 {
  margin: 0 0 var(--sp-4);
  color: var(--ink);
  font-weight: 700;
  line-height: var(--lh-tight);
  text-wrap: balance;              /* переносы задаёт браузер, а не <br> вручную */
}
h1 { font-size: var(--fs-display); line-height: var(--lh-display); letter-spacing: var(--ls-display); }
h2 { font-size: var(--fs-h2);      line-height: 1.1;               letter-spacing: var(--ls-h2); }
h3 { font-size: var(--fs-h3);      line-height: 1.25;              letter-spacing: var(--ls-h3); }
h4 { font-size: var(--fs-h4);      line-height: var(--lh-snug);    font-weight: 600; }

/* Длинное слово не должно распирать страницу: «Машиностроение» в заголовке
   карточки документа, цепочка подчёркиваний в юридическом тексте, адрес почты.
   Без этого страница получала горизонтальную прокрутку на телефоне. */
h1, h2, h3, h4, p, li, dd, dt, td, th, figcaption, .lead { overflow-wrap: break-word; }

/* Ручной перенос действует только на широком экране. Переносы в офферах и
   подзаголовках расставлены по смыслу под десктоп; на телефоне строка и так
   короткая, и каждый <br> ломает её второй раз — в первом экране получалось
   «Станция приносит от 53 000 ₽ в / месяц,» с висящей запятой. */
br.br-wide { display: inline; }
@media (max-width: 640px) { br.br-wide { display: none; } }

p { margin: 0 0 var(--sp-4); }
p:last-child { margin-bottom: 0; }

h2 + p, h3 + p, h4 + p { margin-top: calc(var(--sp-2) * -1); }

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

/* Ширину текста внутри блока не ограничиваем: длину строки задаёт сам текст через <br> в JSON, а не отсечка
   по знакам. Взамен обязательна проверка переносов глазами — см. §7 в
   .claude/CLAUDE.md. */
.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--ink-strong);
}
/* Подзаголовок блока внутри текста: тот же кегль, но плотнее — иначе на длинной
   странице он читается как обычный абзац. */

/* Подзаголовок с цифрами рынка: числа зелёным, чтобы масштаб читался с одного
   взгляда. Выделение приходит из JSON тегом <b>. */
.lead--figures b { color: var(--brand-dim); font-weight: 700; }

/* Примечание под блоком: 15px, а не 13. Мелким кеглем набирают то, что можно
   не читать, а в примечаниях у нас условия, оговорки и цены — их читают.
   13px остаётся подписям: поля форм, шапка, подвал. */
.note    { font-size: var(--fs-sm); color: var(--muted); }
.prose p { max-width: none; }

.eyebrow {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  margin: 0 0 var(--sp-5);
  font-family: var(--font);
  font-size: var(--fs-label);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--brand-dim);
}



@media (max-width: 1024px) {
  :root { --fs-display: 3rem; --fs-h2: 1.875rem; --fs-stat: 2.25rem; }
}
@media (max-width: 640px) {
  :root {
    /* H1 тянется за шириной экрана, а не стоит на 36px. На 360px самое длинное
       слово («электромобилей» в заголовке про субсидию) занимало 319px из 328 и
       упиралось в край; здесь оно получает 33px кегля и запас. Верх clamp —
       прежние 36px: на 420px и шире размер не меняется. */
    --fs-display: clamp(1.75rem, 1.89rem + 0.89vw, 2.25rem);
    --fs-h2: 1.5625rem; --fs-h3: 1.3125rem;
    --fs-lead: 1.0625rem;  --fs-stat: 2rem;  --gutter: 16px;
    /* Мелкий текст на телефоне: 13px в оговорках и хлебных крошках заказчик
       читал с трудом. На большом экране 13px остаются. */
    --fs-caption: 0.875rem;
  }
  /* Перенос по слогам (lang="ru" стоит на <html>) — на узкой колонке это
     единственный способ получить ровный край без дыр. Разрыв по буквам
     (overflow-wrap выше) остаётся страховкой на случай, если словарь не
     справился: он рвёт слово посреди корня и выглядит хуже переноса. */
  h1, h2, h3, h4, p, li, dd, dt, figcaption { hyphens: auto; }
}

/* ===== 5. СЕТКА И СЕКЦИИ ===== */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--medium { max-width: var(--wrap-medium); }
/* Контейнер под текст с содержанием сбоку: колонка текста остаётся прежней, а свободные поля по краям отдаются виджету содержания. */

.wrap--narrow { max-width: var(--wrap-narrow); }

.section { padding-block: var(--sp-8); }
.section--tight { padding-block: var(--sp-7); }
.section--surface { background: var(--surface); }


/* Светлая секция с чертёжной абстракцией: тонкая сетка и мягкое пятно в углу.
   Заменила чёрный фон в кейсах — строго, но легко. */





/* Приглушённый зелёный сделан для белого фона (6,62:1); на тёмном он даёт
   2,95:1 и читается хуже чистого --brand (4,99:1). Поэтому в тёмных частях
   сайта акценты возвращаются к фирменному цвету. */
.section--dark .eyebrow, .hero .eyebrow, .footer .eyebrow, .quiz .eyebrow, .lead-band .eyebrow,
.section--dark b, .hero b, .footer b, .lead-band b { color: var(--brand); }


.section__head { margin-bottom: var(--sp-8); text-align: center; }
/* Таблица сразу за шапкой секции: полный отступ шапки плюс собственный отступ
   таблицы давали провал в целый экран. */

.section__head h2 { max-width: none; }
.section__head .lead { margin-inline: auto; }

/* Везде minmax(0, 1fr), а не 1fr: колонка «1fr» не может стать уже своего
   содержимого, и один широкий элемент (таблица, длинное слово без переноса)
   растягивает всю сетку за край экрана. */
.grid { display: grid; gap: var(--sp-6); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }


@media (max-width: 1024px) {
  .grid--4, .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
  .section { padding-block: var(--sp-7); }
  .section--tight { padding-block: var(--sp-7); }
  .section__head { margin-bottom: var(--sp-6); }
}

/* ===== 6. КНОПКИ И ССЫЛКИ ===== */
.btn {
  position: relative; isolation: isolate; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 48px;                    /* тап-таргет не меньше 44px */
  padding-inline: var(--sp-5);
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font-size: var(--fs-sm); font-weight: 600; line-height: 1;
  cursor: pointer; text-decoration: none;
  transition: background-color .15s, color .15s, border-color .15s;
}
.btn:hover { text-decoration: none; }

.btn::before {
  content: ''; position: absolute; z-index: -1;
  left: 50%; top: 50%; width: 220%; aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: currentColor;
  opacity: 0; transform: scale(0);
  transition: transform .45s cubic-bezier(.22,.61,.36,1), opacity .35s ease-out;
}
.btn:hover::before { transform: scale(1); opacity: .16; }
.btn:active::before { transition-duration: .1s; opacity: .22; }

.btn--primary::before { background: #fff; }

@media (prefers-reduced-motion: reduce) {
  .btn::before { display: none; }
  .btn--sheen::after { display: none; }
}

.btn--primary { background: var(--brand-press); color: var(--on-brand); }
.btn--primary:hover  { background: var(--brand-deep); }
.btn--primary:active { background: var(--brand-deep); }

.btn--outline { background: transparent; color: var(--ink); border-color: var(--hairline-strong); }
.btn--outline:hover { border-color: var(--brand); color: var(--brand-dim); }

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

   Наведение зелёные кнопки не обрабатывают вовсе:
   hover смешивался с волной и мешал ей читаться. */
.btn--primary::after {
  content: ''; position: absolute; z-index: -1;
  top: 0; left: -100%;
  width: 200%; height: 350%;
  background: rgba(255,255,255,.8);
  border-radius: 100%;
  transform: scale(0);
  animation: btn-ripple 6s linear infinite;
}
@keyframes btn-ripple {
  20%  { opacity: 0; transform: scale(2.5); }
  100% { opacity: 0; transform: scale(2.5); }
}

.btn--primary {
  padding: 17px 33px;
  font-size: 14px; font-weight: 600;
  border-radius: 4px; gap: 8px;
}
.btn--primary::before { display: none; }
.btn--primary:hover,
.btn--primary:active { background: var(--brand-deep); }
.btn--primary:hover svg { transform: none; }

/* Зелёная кнопка без волны. Волна — привилегия целевых
   кнопок блоков; на служебных («Заказать звонок», «Подробнее» в карточке)
   постоянное движение превращается в шум. Здесь работает обычный hover:
   фон светлеет. */
.btn--primary.btn--calm::after { content: none; }
.btn--primary.btn--calm:hover,
.btn--primary.btn--calm:focus-visible { background: var(--brand-light); }
.btn--primary.btn--calm:active { background: var(--brand-deep); }

.btn svg { transition: transform .2s ease-out; }
.btn--sheen:hover svg { transform: translateX(3px); }

.btn--ghost { background: none; }

/* Светлые кнопки не бликуют и не зеленеют при наведении:
   темнеет только обводка, фон и цвет текста остаются на месте. */
.btn--outline::before, .btn--ghost::before, .btn--on-dark::before { content: none; }
.btn--outline:hover, .btn--outline:focus-visible {
  background: transparent; border-color: var(--ink); color: var(--ink);
}

.btn--on-dark { background: transparent; color: var(--on-dark); border-color: var(--hairline-dark); }
.btn--on-dark:hover { border-color: var(--on-dark); }

.btn--lg { min-height: 56px; padding-inline: var(--sp-6); font-size: var(--fs-base); }







/* ===== 7. ФОРМЫ ===== */
.field { display: block; margin-bottom: var(--sp-4); }
.field__label {
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-caption); font-weight: 600; color: var(--ink-strong);
}

.input, .textarea, .select {
  width: 100%;
  /* min-width: 0 обязателен именно для <select>: его собственная минимальная
     ширина равна самому длинному пункту списка («Мощность: по убыванию» в
     фильтре каталога), и width: 100% её не перебивает. На экране 320px из-за
     этого распирало панель фильтра и появлялась горизонтальная прокрутка. */
  min-width: 0;
  min-height: 48px;
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-base);          /* не меньше 16px — иначе iOS зумит */
  color: var(--ink);
  background: var(--canvas);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-btn);
  transition: border-color .15s, box-shadow .15s;
}
.input:focus, .textarea:focus, .select:focus {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);   /* рамка «в 2px» без сдвига раскладки */
  outline: none;
}
.textarea { min-height: 120px; resize: vertical; }

.field--invalid .input,
.field--invalid .textarea { border-color: var(--danger); }
.field__error { display: none; margin-top: var(--sp-2); font-size: var(--fs-caption); color: var(--danger); }
.field--invalid .field__error { display: block; }

.consent { display: flex; gap: var(--sp-3); align-items: flex-start; font-size: var(--fs-caption); color: var(--muted); }
.consent input { width: 20px; height: 20px; margin-top: 2px; flex: none; accent-color: var(--brand); }
/* Ссылка на юридические документы внутри согласия: подчёркнута всегда. Без подчёркивания она сливается с текстом, и человек не понимает, что документы можно открыть. */
.consent a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.consent a:hover { color: var(--brand-dim); }

/* Объяснение, зачем нужен телефон: одна строка снимает бо́льшую часть
   беспокойства. Цвета — по
   контексту, как у согласия ниже по файлу. */
.form-why {
  margin: calc(var(--sp-2) * -1) 0 var(--sp-2);
  font-size: var(--fs-caption); color: var(--muted);
}
.quiz .form-why,
.lead-band__form .form-why,
.section--dark .form-why { color: var(--on-dark-3); }
/* Порядок как в разметке: поля, пояснение, согласие и под ними кнопка —
   флажок стоит над кнопкой. */
.lead-band__form .form-why { grid-column: 1 / -1; }

.trap {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}

/* ===== 8. ФИРМЕННЫЕ ЭЛЕМЕНТЫ ===== */

.mark {
  display: inline-grid; gap: 3px;
  width: 22px; flex: none;
}
.mark i { display: block; height: 4px; background: var(--brand); }
.mark i:last-child { background: var(--brand-dim); }


.icon { display: block; flex: none; color: var(--brand); }
.icon--card, .icon--step { color: var(--brand); }









/* ===== 9. ШАПКА ===== */
.header { background: var(--header-bg); color: var(--on-dark); }








/* ===== Выбор города ===== */
.city { display: inline-flex; align-items: center; gap: 6px; }







.header__main .wrap { display: flex; align-items: center; gap: var(--sp-6); min-height: var(--header-h); }

/* Логотипу разрешено сжиматься (flex: 0 1 auto вместо none). При flex: none
   содержимое шапки на экране 360px (логотип 151 + телефон 140 + бургер 48 при
   колонке 328) не помещалось, страница становилась 379px шириной и получала
   горизонтальную прокрутку: справа на телефоне видна белая полоса, чёрная шапка
   обрывается раньше края экрана, а заголовок уходит под эту полосу.
   */
.logo { display: flex; align-items: center; gap: var(--sp-3); flex: 0 1 auto; min-width: 0; }
.logo__img { height: 34px; width: auto; max-width: 100%; }
/* Дескриптор отделён от картинки: внутри logo.png он был нарисован
   и на телефоне выходил около 7px. Текстом им можно управлять — и он читается. */
.logo__text {
  font-family: var(--font); font-size: var(--fs-caption); font-weight: 600;
  line-height: 1.2; letter-spacing: .01em; color: var(--on-dark-2);
  white-space: nowrap;
}

/* Меню занимает всю свободную ширину между логотипом и контактами, пункты
   распределены равномерно: раньше они жались
   влево, а справа оставалась пустая полоса. */
.nav { flex: 1; }
.nav__list {
  display: flex; justify-content: space-between; gap: var(--sp-3);
  width: 100%; list-style: none; margin: 0; padding: 0;
}
.nav__item { position: relative; }
.nav__link {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding-block: calc((var(--header-h) - 20px) / 2);
  font-size: var(--fs-base); font-weight: 500; line-height: 20px;
  color: var(--on-dark); white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.nav__link:hover { color: var(--on-dark); text-decoration: none; border-bottom-color: var(--brand); }
.nav__item.is-active > .nav__link { border-bottom-color: var(--brand); }





/* Группа внутри выпадающего меню: заголовок-ссылка и список под ним. Так в
   каталоге вместо шести «Зарядные станции …» стоит одно название группы, а
   пункты называются коротко — «60 кВт», «Уличные». */


/* Без нижнего поля: с ним разрыв между последним пунктом группы и следующим
   пунктом меню был вдвое больше, чем между соседними строками списка. */






/* Второе выпадающее меню у пункта «О компании»: города и статьи
   раскрываются сбоку при наведении. «О компании» — крайний пункт строки меню,
   поэтому второе меню открывается влево: вправо оно уходило за край окна.
   Оба пункта стоят в конце списка — второе меню растёт вверх от своего пункта,
   иначе список статей уходил ниже края окна. */




/* Мостик до второго меню: без него курсор проваливается в зазор, и меню закрывается. */




.header__contacts { display: flex; align-items: center; gap: var(--sp-5); flex: none; }
/* Телефон со стрелкой: наведение (или фокус с клавиатуры) раскрывает окно со
   вторым номером и почтой. Оба значения — из конфига. */
.header__tel { position: relative; display: flex; flex-direction: column; line-height: 1.25; }





/* Мостик до окна: без него курсор «проваливается» в зазор и окно закрывается. */







/* Окно «Контакты» в шапке по подразделениям: канцелярия, снабжение, персонал, ниже — отдел зарядных станций. */









.header__phone {
  /* слово «Контакты» в шапке: кегль и жирность как у пунктов меню (.nav__link) */
  font-size: var(--fs-base); font-weight: 500; line-height: 20px; color: var(--on-dark);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.header__phone:hover { color: var(--brand); text-decoration: none; }


.burger {
  display: none; width: 48px; height: 48px; margin-right: calc(var(--sp-3) * -1);
  border: 0; background: none; color: var(--on-dark); cursor: pointer;
}

@media (max-width: 1460px) {
  .nav__list { gap: var(--sp-2); }
  .nav__link, .header__phone { font-size: var(--fs-sm); }
  .header__main .wrap { gap: var(--sp-5); }
  .header__contacts { gap: var(--sp-4); }
}

@media (max-width: 1200px) {
  .nav__list { gap: var(--sp-2); }
  .nav__link, .header__phone { font-size: var(--fs-sm); }
  
}

@media (max-width: 1200px) {
  /* Служебная строка: «Контакты» остаются рядом с выбором города — это главная
     навигационная ссылка, а в бургере её видно только после раскрытия меню.
     Остальное (документы, гарантия) уезжает в бургер. */
  
  
  /* Ссылка навигационная, а не служебная: набираем её тем же цветом, что название города. */
  
  
  .burger { display: inline-flex; align-items: center; justify-content: center; }
  .header__contacts { margin-left: auto; }

  .nav {
    position: fixed; inset: 0 0 0 auto; z-index: 60;
    width: min(380px, 88vw);
    padding: var(--sp-6) var(--sp-5) var(--sp-8);
    background: var(--dark-2);
    border-left: 1px solid var(--hairline-dark);
    overflow-y: auto;
    transform: translateX(100%);
    transition: transform .2s ease-out;
    visibility: hidden;
  }
  .nav.is-open { transform: none; visibility: visible; }
  .nav__list { flex-direction: column; gap: 0; }
  .nav__item { border-bottom: 1px solid var(--hairline-dark); }
  .nav__link { display: flex; width: 100%; padding-block: var(--sp-4); font-size: var(--fs-base); border-bottom: 0; }
  

  /* visibility: inherit, а не visible. С visible подменю
     оставалось «видимым» для браузера даже при закрытом меню, а меню лежит
     за правым краем экрана — отсюда горизонтальная прокрутка всей страницы
     на телефоне. */
  
  /* Подпункты набраны тем же цветом, что и лид на тёмном: при --on-dark-3 (46% белого) они читались как выключенные. */
  

  /* В бургере второго выпадающего меню нет: «Поставки в города» и «Статьи»
     ведут на свои хабы, список там же. */
  
  
}

@media (max-width: 640px) {
  .header__contacts .btn { display: none; }
  .header__main .wrap { gap: var(--sp-2); min-height: 64px; }
  .header__contacts { gap: var(--sp-3); }
  /* Номер остаётся в главной строке, рядом со знаком. Место под всё сразу — знак, дескриптор,
     номер и кнопку меню — набирается кеглем: дескриптор 11px, знак 24px.
     Внутри картинки logo.png та же надпись выходила около 7px. */
  .header__phone { font-size: var(--fs-caption); }
  .logo__img { height: 24px; }
  .logo { gap: var(--sp-2); }
  /* Дескриптор и номер 13px: 11px нарушали правило
     проекта «любой видимый текст не мельче 13px» и всплывали в каждой проверке.
     Раньше кегль был занижен ради того, чтобы знак, дескриптор, номер и кнопка
     меню помещались в 360px — поэтому после подъёма обязательно проверять
     прокрутку на 320/360/414. */
  /* Кегль штатный (13px): 11px нарушали правило «видимый текст не мельче 13px»
     и всплывали в каждой проверке. Ступени вниз — в медиазапросах 400 и 340px. */
  /* Дескриптор на телефоне 11px: при 13px он забирал ширину у номера, и тот
     обрезался на последних цифрах. Номер важнее подписи — кегль номера прежний. */
  .logo__text { font-size: 0.6875rem; line-height: 1.15; letter-spacing: 0; }

  /* Стрелка и окно со вторым номером на телефоне убраны: окно открывается
     наведением и :focus-within, а на тач-экране ни того, ни другого нет —
     стрелка обещала действие, которого не происходит, и занимала 15px ширины,
     которых шапке не хватало. Второй номер и почта остаются на /contacts —
     ссылка на неё стоит в верхней строке шапки. */
  
}

/* ===== 10. ПЕРВЫЙ ЭКРАН ===== */
.hero {
  position: relative; overflow: hidden;
  background: var(--dark); color: var(--on-dark-2);
  padding-block: var(--sp-9) var(--sp-10);
}
.hero__inner {
  position: relative; z-index: 1;
  display: grid;
  grid-template-columns: 56fr 44fr;   /* пропорция из ТЗ: текст важнее картинки */
  gap: var(--sp-8);
  align-items: center;
}

.hero--cover {
  display: flex; flex-direction: column; justify-content: center;
  min-height: calc(100dvh - var(--header-h) - 40px);
  padding-block: var(--sp-7) calc(var(--sp-6) + 84px);   /* снизу — место под полосу */
  text-align: center;
}
.hero--cover .hero__inner { grid-template-columns: minmax(0, 100%); gap: 0; justify-items: center; }
.hero--cover .hero__text { max-width: none; width: 100%; }

.hero--cover .eyebrow { justify-content: center; }
.hero--cover h1 { max-width: 18ch; margin-inline: auto; margin-bottom: var(--sp-4); }

.hero--cover .hero__actions { justify-content: center; margin-block: 30px; }





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


/* Условия сделки строкой под кнопками: на внутренней странице текст выровнен по
   левому краю, поэтому пункты идут по содержимому, а не растягиваются на всю ширину. */


/* На узком экране три колонки по содержимому не помещаются и уезжают за край. */

/* 26ch, а не 20: длинный заголовок услуги на 20ch ломается на четыре строки и вытягивает первый экран. */

/* Подзаголовок первого экрана внутренней страницы держим в одну строку. */




/* Крошки на фотографии: тёмно-серый по кадру не читается.
   ⚠️ Селектор через `.hero`: базовые правила `.crumbs a` объявлены ниже по файлу
   и при равной специфичности перебивают одиночный класс. */
.hero .crumbs { color: var(--on-dark-3); }
.hero .crumbs a { color: var(--on-dark-3); }
.hero .crumbs a:hover { color: var(--on-dark); }
.hero .crumbs .crumbs__current { color: var(--on-dark-2); }
.hero .crumbs .crumbs__sep { color: var(--on-dark-3); }

/* Выделенные цифры в лиде на фотографии: --brand-dim рассчитан на белый фон и
   по тёмному кадру почти не читается, здесь нужен основной фирменный. */
.hero .lead--figures b { color: var(--brand); }

/* Лид первого экрана внутренней страницы: кадр там светлее ролика главной, и
   даже основной фирменный на асфальте пропадает — выделяем белым и весом. */


/* Вторая кнопка стоит на фотографии: тёмная надпись по кадру не читается. */
.hero .btn--outline { color: var(--on-dark); }
.hero .btn--outline:hover { color: var(--on-dark); border-color: var(--on-dark); }

/* Кадр внутренней страницы светлее ролика на главной, поэтому левый край
   затемняется плотнее — иначе белый текст на асфальте теряется. */


/* Подзаголовок первого экрана внутренней страницы: H2 под H1, набирается
   заметно мельче обычного H2 — на кадре он второй строкой оффера, а не
   заголовком секции. */

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


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





.hero--left { text-align: left; }
.hero--left .hero__inner { justify-items: stretch; }
.hero--left .eyebrow { justify-content: flex-start; }
.hero--cover.hero--left h1 {
  max-width: none; margin-inline: 0;
  font-size: clamp(1.75rem, 3.85vw, 3.6rem);
  text-wrap: nowrap;
}
.hero--left .hero__actions { justify-content: flex-start; }

/* Кнопки первого экрана вернулись к общему большому размеру: площадь сокращена не геометрией, а текстом — подписи стали
   короче. Вторая кнопка тише первой: обычное начертание и стрелка вместо
   жирного шрифта. */
.btn--quiet { font-weight: 500; }
/* Вторая кнопка первого экрана стоит на фотографии, и обводка в 24% белого на
   ней почти не читалась. */
.hero .btn--outline { border-color: rgba(255,255,255,.55); }
.hero .btn--outline:hover { border-color: var(--on-dark); }
/* Та же плотность обводки у кнопки на тёмном: на первом экране главной она стояла на 12% белого и терялась на видеофоне. */
.hero .btn--on-dark { border-color: rgba(255,255,255,.55); }
.hero .btn--on-dark:hover { border-color: var(--on-dark); }

/* Ширину не ограничиваем: переносы расставлены в разметке через <br>, по
   смыслу фразы. Контейнер, режущий строку там, где кончилось место, рвал
   «55 000 ₽/мес» и «2,5 года» в неудобных местах. */
/* Воздух между строками первого экрана — 30px.
   Значения проставлены в «родных» правилах ниже по файлу: отдельный блок
   здесь перебивался ими по порядку следования, и отступ не применялся. */
.hero__offer {
  max-width: none;
  margin-block: 30px 80px;
  font-size: clamp(1.125rem, 1.9vw, 1.625rem);
  font-weight: 600; line-height: 1.45;
  color: var(--on-dark);
}
/* Цифры дохода и срока — зелёным, без добавочного веса:
   вся строка уже полужирная. Оттенок светлее фирменного: --brand на подвижном
   тёмном кадре теряется. */
.hero__offer b { color: var(--brand-light); font-weight: inherit; }

/* Оффер и награды одной строкой. Снимки уравновешивают
   правую половину кадра, поэтому прижаты к правому краю текстовой колонки.
   Выравнивание по верху, отступы у ряда одинаковые сверху и снизу — верх
   снимков должен совпадать с верхней линией текста. */
.hero__offer-row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-7); flex-wrap: wrap;
  margin-block: 30px;
}
/* Отрицательный отступ гасит полуинтерлиньяж первой строки: без него буквы
   начинаются ниже верхнего края снимка, хотя блоки выровнены. */
.hero__offer-row .hero__offer { margin-block: -0.22em 0; }

/* Снимки дипломов разной пропорции, и ряд выглядел рваным. Каждый кадр вписан в клетку одного размера на белом фоне —
   ряд ровный, при этом ничего не обрезается. Общую подложку под группой
   пробовали и убрали: лишняя рамка на первом экране. */
/* Награды прижаты к правому краю: слева от них стоит оффер, и свободное место
   должно оставаться между блоками, а не у края экрана. */
.hero__awards {
  display: flex; align-items: flex-start; justify-content: flex-end; gap: var(--sp-3);
  margin: 0; padding: 0; list-style: none;
}
.hero__awards li { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); width: 140px; }
.hero__award {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 116px; height: 92px; padding: 4px; overflow: hidden;
  background: #fff;
  border: 1px solid var(--hairline-dark); border-radius: var(--radius-md);
  cursor: zoom-in;                    /* курсор-лупа вместо приподнимания */
  transition: border-color .15s;
}
.hero__award img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.hero__award:hover { border-color: var(--brand); }
/* Лупа поверх кадра: подсказывает, что снимок открывается крупнее. */
.hero__award-zoom {
  position: absolute; right: 6px; bottom: 6px;
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  color: #fff; background: rgba(10,13,14,.7); border-radius: var(--radius);
}
.hero__award-title {
  font-size: 0.8125rem; line-height: 1.25; text-align: center;
  hyphens: auto;                      /* «электрозаправки» в подпись 96px иначе не переносится */
  color: var(--on-dark); text-shadow: 0 1px 10px rgba(10,13,14,.8);
}

/* Первый экран на телефоне: строка над заголовком идёт
   двумя строками вплотную и отделена от него мало; разделитель между частями на
   узком экране только мешает — части и так стоят на разных строках. Подсказки у
   преимуществ выключены: раскрывать их пальцем неудобно, а строка остаётся
   ссылкой на свой раздел. */
@media (max-width: 640px) {
  .eyebrow { line-height: 1.45; margin-bottom: var(--sp-7); }
  .eyebrow__sep { display: none; }
  /* Обводка второй кнопки вдвое заметнее: 12% белого на фотографии терялись. */
  /* Обводка второй кнопки первого экрана: 28% белого на видеофоне почти не видно — держим ту же плотность, что у внутренних страниц. */
  .hero .btn--on-dark { border-color: rgba(255,255,255,.55); }
  .hero__fact-arrow, .hero__fact-toggle, .hero__hint { display: none; }
}

@media (max-width: 900px) {
  /* На телефоне ряд разворачивается в колонку, и отступ над текстом должен
     равняться отступу под ним — иначе строка о доходе висит посреди пустоты.
     */
  .hero__offer-row { gap: var(--sp-6); margin-block: var(--sp-6); }
  .hero__awards { gap: var(--sp-3); }
  .hero__awards li { width: 96px; }
  .hero__award { width: 96px; height: 76px; }
}

/* Подсказка к преимуществу первого экрана. Открывается наведением, фокусом с
   клавиатуры и классом is-open (нажатие на телефоне). Позиционируется над
   строкой: под ней у первого экрана уже нет места. */
.hero__fact-line { display: inline-flex; align-items: center; gap: var(--sp-2); }
.hero__fact-text { color: inherit; text-decoration: none; }
a.hero__fact-text:hover { text-decoration: underline; text-underline-offset: 3px; }
/* Стрелка-переключатель подсказки: своя кнопка, потому что текст рядом — ссылка. */
.hero__fact-toggle {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  background: none; border: 0; cursor: pointer; color: inherit;
}
.hero__fact-arrow { flex: none; color: var(--brand-light); transition: transform .15s; }
[data-fact] { position: relative; }
[data-fact]:hover .hero__fact-arrow,
[data-fact].is-open .hero__fact-arrow { transform: rotate(180deg); }
.hero__hint {
  position: absolute; bottom: calc(100% + 10px); left: 50%; transform: translate(-50%, 4px);
  z-index: 5; width: max-content; max-width: 320px;
  padding: var(--sp-4);
  font-size: var(--fs-caption); font-weight: 500; line-height: 1.45; text-align: left;
  color: var(--on-dark-2); background: var(--dark-3);
  border: 1px solid var(--hairline-dark); border-radius: var(--radius-md);
  box-shadow: var(--shadow-menu);
  opacity: 0; visibility: hidden;
  transition: opacity .15s, transform .15s, visibility .15s;
  text-shadow: none;
}
.hero__hint b { color: var(--brand-light); font-weight: 700; }
[data-fact]:hover .hero__hint,
[data-fact]:focus-within .hero__hint,
[data-fact].is-open .hero__hint {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
@media (max-width: 900px) {
  .hero__hint { left: 0; transform: translate(0, 4px); max-width: min(320px, 100%); }
  [data-fact]:hover .hero__hint,
  [data-fact]:focus-within .hero__hint,
  [data-fact].is-open .hero__hint { transform: translate(0, 0); }
}

/* Три преимущества — карточками с прозрачной подложкой и скруглённой рамкой
: без рамок строка читалась как случайная
   подпись под кнопками. Содержимое по центру, кегль и иконка крупнее. */
.hero__facts {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5);
  margin: var(--sp-8) 0 0; padding: 0; list-style: none;
}
/* Поля сверху и снизу больше боковых — блок получается ближе к квадрату.
   Переносы в тексте расставлены руками
   в products.json, поэтому строка рвётся по смыслу. */
/* Без рамки и подложки: держатся зелёной
   иконкой, весом шрифта и тенью — кадр под ними остаётся открытым. */
.hero__facts li {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4);
  font-size: var(--fs-base); font-weight: 600; line-height: 1.35;
  color: var(--on-dark); text-align: center;
  text-shadow: 0 1px 12px rgba(10,13,14,.75);
}
.icon--fact { color: var(--brand); flex: none; }

@media (max-width: 900px) {
  .hero__facts { grid-template-columns: 1fr; gap: var(--sp-3); }
  .hero__facts li { flex-direction: row; justify-content: flex-start; text-align: left; }
  .hero--cover.hero--left h1 { text-wrap: balance; }
}

.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 48% 62%; }

.hero__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 55%;
  opacity: 0; transition: opacity .8s ease-out;
  pointer-events: none;
}
.hero__video.is-ready { opacity: 1; }

/* Ровная серая вуаль вместо двух
   градиентов — под ней видно, что происходит на видео.

   Поверх неё — мягкая тень слева, только под текстовой колонкой. Без неё
   надзаголовок (зелёный, мелкий, вразрядку) на светлых кадрах ролика
   пропадает: у него контраст ниже, чем у белого заголовка. Правый край,
   ради которого фон и осветляли, остаётся чистым. */
.hero__veil {
  position: absolute; inset: 0;
  background-color: rgb(49, 49, 49);
  opacity: .7;
}
.hero__veil::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(10,13,14,.5) 0%, rgba(10,13,14,.28) 45%, transparent 75%);
}

/* Надзаголовок первого экрана белый, а не зелёный: мелкий текст вразрядку
   зелёным по осветлённому кадру не читается, а затемнять фон сильнее нельзя —
   ради видимости ролика вуаль и осветляли. Зелёным остаётся только маркер. */
.hero .eyebrow { color: var(--brand); text-shadow: 0 1px 10px rgba(10,13,14,.6); }






/* Строка доверия на первом экране внутренней страницы: тот же приём, что на
   главной, но плашка уже — она стоит под кнопками, а не во всю ширину кадра. */

/* Кегль основной, а не подписной: это факты о заводе,
   которые читают, а не сноска. 13px тут читалось как «можно не читать». */





.hero h1 { margin-bottom: 80px; color: var(--on-dark); max-width: 12em; }

.hero__actions { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-block: 30px; }











@media (max-width: 1024px) {
  .hero { padding-block: var(--sp-8) var(--sp-9); }
  .hero__inner { gap: var(--sp-6); }
  .hero h1 { max-width: none; }
}

@media (max-width: 900px) {
  .hero__inner { grid-template-columns: 1fr; gap: var(--sp-5); }
  .hero__text { display: contents; }
  .hero__text > .eyebrow       { order: 1; }
  .hero__text > h1             { order: 2; }
  
  .hero__text > .hero__actions { order: 4; margin-block: var(--sp-5) 0; }
  
  
  .hero__actions .btn { width: 100%; }

  .hero--cover { min-height: auto; padding-block: var(--sp-8) var(--sp-9); }
  /* На телефоне поле над надзаголовком было 64px: до кнопки «Каталог и цены»
     первый экран не дотягивал. Сжато до 24px сверху и 48px снизу — обе кнопки
     помещаются в окно 700px. */
  @media (max-width: 640px) {
    .hero--cover { padding-block: var(--sp-5) var(--sp-7); }
    .hero--cover .hero__awards { margin-top: var(--sp-3); }
    /* Три диплома равными долями во всю ширину и по центру:
       фиксированная ширина карточки оставляла ряд прижатым влево. */
    .hero--cover .hero__awards {
      display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: var(--sp-3); width: 100%; justify-items: center;
    }
    .hero--cover .hero__awards li { width: 100%; }
    .hero--cover .hero__award { width: 100%; height: 64px; }
    .hero--cover .hero__text > .hero__actions { margin-block: 0; }
    /* Шаг между блоками первого экрана 16px вместо 24: на телефоне четыре
       промежутка по 24px забирали 96px — ровно те, из-за которых вторая
       кнопка уходила за границу экрана. */
    .hero--cover .hero__inner { gap: var(--sp-4); }
    .hero--cover .hero__offer-row { gap: var(--sp-4); margin-block: var(--sp-4); }
  }
  /* Кадр держим на станции и светлой стене: при 68% по вертикали в окно попадал
     тёмный асфальт, и первый экран выглядел чёрным прямоугольником. */
  .hero--cover .hero__bg img { object-position: 50% 70%; }
  /* Затемнение плотное только под текстом, ниже фотография открывается.
     ⚠️ opacity базового правила здесь снимается: вместе с ним градиент давал
     0,92 × 0,7 сверху и почти чёрный экран. */
  .hero--cover .hero__veil {
    opacity: 1;
    background:
      linear-gradient(180deg, rgba(10,13,14,.84) 0%, rgba(10,13,14,.66) 40%, rgba(10,13,14,.26) 66%, rgba(10,13,14,.44) 100%);
  }

  .hero--cover .hero__text { display: block; }
  .hero--cover .hero__actions { flex-direction: column; align-items: stretch; gap: var(--sp-3); }
  
  /* На десктопе под заголовком 80px воздуха, на телефоне это половина экрана:
     строка о доходе должна отстоять от заголовка ровно настолько же, насколько
     от наград под ней. */
  .hero h1 { margin-bottom: var(--sp-6); }
}

/* ===== 11. ПОЛОСА ХАРАКТЕРИСТИК ===== */













/* ===== 12. КАРТОЧКИ ===== */
.card {
  position: relative;
  padding-top: var(--sp-6);
  border-top: 1px solid var(--hairline);
  background: none;
}
/* Иконка обтекается текстом: она встроена в левый верхний угол карточки, а не
   отодвигает заголовок и абзац вправо колонкой. */
.card__head {
  float: left;
  margin: 0 var(--sp-4) var(--sp-2) 0;
  color: var(--brand);
}

/* Короткая карточка с иконкой по центру: текста мало, и обтекание не нужно —
   иконка стоит над заголовком, всё выровнено по центру. */




/* Заголовок держит высоту двух строк: иначе в ряду из трёх карточек абзацы
   стартуют на разной высоте — у короткого заголовка текст поднимается, и ряд
   читается неровно. */
/* Верхнее поле снимаем: общее правило h3 отодвигало заголовок вниз, и обтекающая
   иконка оказывалась выше первой строки — она висела над заголовком отдельно. */
.card__title {
  font-size: var(--fs-h3); line-height: 1.25; letter-spacing: var(--ls-h3);
  margin-top: 0; margin-bottom: var(--sp-3);
  min-height: calc(2 * 1.25em);
}
.card p { font-size: var(--fs-sm); color: var(--body); }
/* Схема в карточке (две архитектуры зарядного хаба): рисунок идёт над
   заголовком и тянется на всю ширину карточки. Фон светлый — SVG нарисован
   на белом, на тёмной секции такие карточки не используются. */

.card::after { content: ''; display: block; clear: both; }




/* Рассказ о производстве идёт продолжением блока про завод, без своего
   заголовка: отделяем его воздухом и шириной строки, а не линией. */


/* ===== 13. ПОКАЗАТЕЛИ ===== */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); }
.stats__item {
  padding: 0 var(--sp-5);
  border-left: 1px solid var(--hairline);
}
.stats__item:first-child { padding-left: 0; border-left: 0; }
.stats__value {
  display: block; margin-bottom: var(--sp-3);
  font-size: var(--fs-stat); font-weight: 700; line-height: 1;
  letter-spacing: var(--ls-display); color: var(--brand);
}
/* Единица измерения набирается 0.6 от цифры: на телефоне это 17px, то есть уже
   не крупный текст, и фирменный зелёный даёт 3,91:1. Для мелкого зелёного в
   проекте есть --brand-dim (6,62:1) — цифра рядом остаётся на --brand. */
.stats__value small { font-size: .6em; font-weight: 700; color: var(--brand-dim); }
.stats__label { font-size: var(--fs-caption); color: var(--muted); }

/* Цифры завода — одной рамкой на весь ряд:
   четыре отдельные плитки распадались, а вместе читаются как показатели
   одного предприятия. Кегль цифры крупнее, подпись — 15px и темнее. */

          /* цифра и подпись по центру ячейки */
/* Цифра не переносится и подстраивается под ширину ячейки: «165 000 м²» на узком контейнере рвалось на две строки, и
   единица измерения повисала под числом. Заодно боковые поля ячеек уже —
   ряду из четырёх показателей нужна ширина, а не воздух по краям. */




/* Показатели полосой под первым экраном. Без рамки:
   блок и так отделён от тёмного экрана сменой фона, а вторая рамка внутри
   белой полосы превратила бы её в карточку. Держат волосяные линии между
   колонками и воздух сверху-снизу. */
.section--figures { padding-block: var(--sp-7); }
.stats--band { text-align: center; }
.stats--band .stats__item { padding-inline: var(--sp-4); }
.stats--band .stats__value { font-size: clamp(1.75rem, 2.4vw, 2.75rem); white-space: nowrap; }
.stats--band .stats__label { font-size: 0.9375rem; color: var(--body); line-height: 1.35; }
@media (max-width: 900px) {
  .section--figures { padding-block: var(--sp-6); }
  .stats--band { gap: var(--sp-5) 0; }
}

/* Две кнопки в ряд по центру: целевая и второстепенная. */



@media (max-width: 900px) {
  /* minmax(0, …): у показателей значение набрано white-space: nowrap, и колонка
     «1fr» раздувалась до его ширины — сетка вылезала за экран на узких телефонах. */
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-6) 0; }
  .stats__item:nth-child(odd) { padding-left: 0; border-left: 0; }
}

/* Ниже 560px показатели идут столбиком. Значение набрано без переноса,
   и такие подписи, как «ПП РФ №719» или «60–240 кВт», в половину
   ширины телефона не помещаются: ячейка получалась 108px против нужных 175,
   ряд вылезал за экран и вся страница получала горизонтальную прокрутку.
   Одна колонка сохраняет и цельность цифры, и ширину под неё. */
@media (max-width: 560px) {
  .stats { grid-template-columns: minmax(0, 1fr); gap: var(--sp-5) 0; }
  .stats__item { padding-left: 0; border-left: 0; }
}

/* ===== 14. ПОДВАЛ ===== */
.footer {
  background: var(--dark); color: var(--on-dark-2);
  padding-block: var(--sp-9) var(--sp-6);
  font-size: var(--fs-sm);
}
/* На телефоне подвал набирается основным кеглем: 15px в списке ссылок и в
   строке под логотипом читались мелко. */
@media (max-width: 640px) {
  .footer { font-size: var(--fs-base); }
  
}
.footer a { color: var(--on-dark-2); }
.footer a:hover { color: var(--on-dark); text-decoration: none; }
.footer h4 {
  margin-bottom: var(--sp-5);
  font-family: var(--font); font-size: var(--fs-label); font-weight: 700;
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--brand);
}
/* Шесть ячеек: блок бренда, каталог, услуги с инвестором, решения, «Компания» и
   разъёмы. Колонки равной ширины,
   шире только блок бренда: списки в них разной длины, но выравнивать их по
   самому длинному незачем — читается сверху вниз. */
.footer__cols { display: grid; grid-template-columns: 1.5fr repeat(5, minmax(0, 1fr)); gap: var(--sp-6); }
@media (max-width: 1280px) { .footer__cols { grid-template-columns: 1.4fr repeat(3, minmax(0, 1fr)); } }
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
/* Вторая группа в той же ячейке («Инвестору» под «Решениями»). */

/* Широкая колонка: ссылки в два столбца. Grid здесь не годится — columns
   раскладывает список по высоте сам, не деля пункты пополам вручную. */


/* Блок совместимости переехал в первый столбец, под адрес:
   так подвал стал компактнее. Отдельная линия ему там не нужна — хватает отступа,
   а кегль совпадает с соседними абзацами колонки. */

/* Текст о совместимости — var(--fs-caption), мельче абзацев колонки. */









/* Логотип с дескриптором — ссылка на главную. Цвет и
   кегль те же, что у соседних абзацев: ссылка не должна выглядеть кнопкой. */



/* Подписи подразделений в подвале. */




/* Кнопка «наверх»: белый кружок со стрелкой, всплывает после второго экрана
   (механика, цвета наши). */
/* Кнопка вызова чата — своя вёрстка, а не картинка: текст можно
   менять по времени, а на любом экране она остаётся чёткой. Круг с иконкой
   сообщения плюс плашка с надписью — компоновка привычна по Битрикс24.
   Появляется через две секунды после загрузки, как всплывает сам виджет;
   по нажатию иконка сменяется кружком ожидания и main.js подключает Jivo. */

/* Метка режима диагностики чата (?debug=chat): видно, что режим включился и
   события пишутся в лог. Обычному посетителю не показывается никогда. */
.diag-badge {
  position: fixed; left: var(--sp-3); bottom: var(--sp-3); z-index: 60;
  max-width: 320px; margin: 0; padding: var(--sp-2) var(--sp-3);
  background: var(--dark); color: var(--on-dark);
  font-size: var(--fs-caption); line-height: 1.4;
  border-left: 3px solid var(--brand);
}





/* Надпись остаётся и на телефоне: это призыв к действию, ради него кнопку и
   переверстали. На узких экранах она просто компактнее. */
@media (max-width: 480px) {
  
  
  :root { --dock-chat: 52px; }
}




/* «Стучится в экран»: круг и иконка чуть увеличиваются и возвращаются, а на
   месте увеличенного круга остаётся белый контур и плавно гаснет. */



@keyframes chat-knock {
  0%, 82%, 100% { transform: scale(1); }
  88%           { transform: scale(1.1); }
  94%           { transform: scale(1); }
}
@keyframes chat-ring {
  0%, 82% { transform: scale(1);    opacity: 0; }
  88%     { transform: scale(1.1);  opacity: .9; }
  100%    { transform: scale(1.35); opacity: 0; }
}


/* Кружок ожидания: показывается, пока грузится виджет. */




@keyframes chat-spin { to { transform: rotate(360deg); } }




@media (max-width: 640px) { :root { --dock-top: 40px; }  }
/* Кнопка «наверх» встаёт НАД кнопкой чата: обе живут в правом нижнем углу и
   накладывались друг на друга — белый круг поверх зелёного. Через :has(): нет чата на странице — кнопка остаётся внизу. */



/* Знаки группы: логотипы в ряд, пояснение — рядом мелким текстом.
   Отступы уменьшены в полтора раза: между колонками
   ссылок, знаком завода и копирайтом было слишком много воздуха. */



/* Знак завода приглушён: в родных цветах он ярче
   логотипа Elli и перетягивал внимание на себя. Прозрачность .65,
   обесцвечивания нет: с ним знак становился совсем серым. */


/* Знак концерна на странице о компании: там он довод для тендерного отдела,
   поэтому крупнее подвального и в полную силу цвета. */





/* Оговорка об оферте: та же подпись, что у нижней строки подвала, но отдельным абзацем над ней. */



.footer__bottom {
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--hairline-dark);
  display: flex; justify-content: space-between; gap: var(--sp-5); flex-wrap: wrap;
  font-family: var(--font); font-size: var(--fs-caption); color: var(--on-dark-2);
}
.footer__bottom a { color: var(--on-dark-2); }
/* Ссылки подвала — самостоятельные цели нажатия, а не слова в строке: без
   вертикального поля палец попадает в них с трудом (высота строки 19px). */
/* Поле у ссылки — это её тап-таргет: на телефоне оставляем прежним, на десктопе
   строки идут плотнее. */
.footer__list a, .footer__bottom a { display: inline-block; padding-block: 6px; }
@media (min-width: 901px) { .footer__list a { padding-block: 2px; } }

@media (max-width: 900px) {
  .footer__cols { grid-template-columns: 1fr 1fr; }
  .footer__list { gap: var(--sp-2); }
  
}
@media (max-width: 560px) { .footer__cols { grid-template-columns: 1fr; gap: var(--sp-7); } }

/* ===== 15. ПРИЗЫВ К ДЕЙСТВИЮ ===== */










.section__cta { margin-top: var(--sp-8); text-align: center; }
/* Под кнопкой нужен воздух: следующий блок, вставший к ней вплотную, читается
   как её продолжение, и призыв теряется. Последний
   элемент секции не трогаем — там отступ даёт сама секция. */
.section__cta:not(:last-child) { margin-bottom: var(--sp-7); }
/* Кнопки под строкой предложения: между ними воздуха меньше, чем между
   кнопками и предыдущим блоком, — призыв и кнопка должны читаться связкой. */


/* Строка предложения под лидом: то же, что делает компания, но набранное так,
   чтобы взгляд её поймал по дороге к кнопке. Крупнее основного текста, по
   центру, ключевое — акцентом. */



@media (max-width: 640px) {
  
  .section__cta .btn { width: 100%; }
}

/* ===== 16. КВИЗ ===== */
/* Ширина карточки — 1180px: типов объекта двенадцать, и в ширину 961px они укладывались
   тремя рядами, из-за чего первый шаг перестал помещаться в экран ноутбука.
   Шире плюс мельче плитки — шаг снова виден целиком, а карточка по-прежнему
   читается как одна форма. */
.quiz {
  position: relative;
  overflow: hidden;
  max-width: 1180px;
  margin-inline: auto;
  padding: var(--sp-7) var(--sp-7) var(--sp-6);
  background: var(--quiz-bg);
  color: var(--on-dark);
  border-radius: var(--radius-lg);
}
.quiz.is-live ~ .quiz__skip,
#quiz .section__head { max-width: 1180px; margin-inline: auto; }
/* Заголовок в одну строку: две строки над карточкой
   съедали высоту, которой не хватало самому шагу. */
/* Кегль как у остальных H2: уменьшенный выбивался из
   ряда заголовков. В одну строку он помещается — карточка квиза 1180px. */
#quiz .section__head h2 { text-wrap: nowrap; }

/* Одиночный кейс на городской странице: в сетке из трёх колонок он прижимался
   к левому краю и половина ряда пустовала. */

/* ===== Скрытые контакты =====================================================
   Хвост номера и имя почтового ящика приглушены, пока человек не потянулся к
   контакту: так считаются уникальные просмотры прямых контактов.
   Приглушение включает класс на <html>, который ставит main.js, — без скриптов
   контакты видны полностью. Текст остаётся в разметке: ссылка `tel:` рабочая,
   поисковик и микроразметка видят номер целиком. */

/* Хвост растворяется слева направо: маска, а не размытие.
   Начало номера читается полностью, последние знаки тают — понятно, что контакт
   есть, но переписать его нельзя. */


/* ===== Знаки мессенджеров =====
   Приём взят из проекта cncplus: фирменный цвет задаётся родителю, знак рисуется
   currentColor, при наведении гаснет прозрачностью. */
:root { --telegram: #26A5E4; --vk: #0077FF; }

/* Знак ВКонтакте набирается своим фирменным синим, знак Rutube двухцветный —
   его цвета заданы внутри самого SVG и от currentColor не зависят. */









/* В шапке и подвале ссылки перекрашены своими правилами — знак мессенджера держит фирменный цвет сильнее них. */




/* Короткий заголовок, который text-wrap: balance зря делит пополам: места в колонке
   хватает на одну строку, а браузер всё равно переносит. */


/* Под заголовком воздуха чуть больше, чем над ним:
   поле секции сверху — 64px, здесь 72px, иначе заголовок «прилипал» к
   карточке квиза. */
#quiz .section__head { margin-bottom: calc(var(--sp-8) + var(--sp-2)); }
@media (max-width: 820px) { #quiz .section__head h2 { text-wrap: balance; } }

.quiz__bar {
  position: absolute; top: 0; left: 0; right: 0;
  height: 8px; background: rgba(0,149,65,.22);
}
.quiz__bar-fill { display: block; height: 100%; width: 20%; background: var(--brand); transition: width .25s ease-out; }

.quiz__step { margin: 0 0 var(--sp-7); padding: 0; border: 0; }
.quiz__step:last-of-type { margin-bottom: 0; }
.quiz.is-live .quiz__step { display: none; }
.quiz.is-live .quiz__step.is-current { display: block; }

.quiz__legend {
  padding: 0; margin-bottom: var(--sp-5);
  font-size: var(--fs-h3); font-weight: 700; letter-spacing: var(--ls-h3);
  color: var(--on-dark);
}
.quiz__sub { margin-top: calc(var(--sp-4) * -1); margin-bottom: var(--sp-5); color: var(--on-dark-2); }   /* подсказка к вопросу — рабочий текст, контраст как у основного */

.quiz__options { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-3); }
.quiz__options--pills { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

.tile { position: relative; display: block; cursor: pointer; }
.tile input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.tile__body {
  display: flex; align-items: center; gap: var(--sp-3); min-height: 56px;   /* тап-таргет */
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm); line-height: 1.35; color: var(--on-dark);
  background: transparent;
  border: 1px solid var(--quiz-line);
  border-radius: var(--radius-md);
  transition: border-color .15s, background-color .15s;
}
.tile__body::before {
  content: ''; flex: none;
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--on-dark-3);
  transition: border-color .15s, box-shadow .15s;
}
.tile__text { display: block; }
.tile:hover .tile__body { border-color: var(--brand); }
.tile input:checked + .tile__body {
  border-color: var(--brand);
}
.tile input:checked + .tile__body::before {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 4px var(--brand);
}
.tile input:focus-visible + .tile__body { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Шесть плиток в ряд: двенадцать типов объекта ложатся в два
   ряда вместо трёх. Кадр в плитке узнаётся и в таком размере — это выбор
   «моё/не моё», а не рассматривание фотографии. */
.quiz__options--media { grid-template-columns: repeat(6, 1fr); gap: var(--sp-2); }
.tile--media .tile__body {
  display: block; min-height: 0; padding: 0; gap: 0;
  overflow: hidden;
}
.tile--media .tile__body::before { display: none; }
.tile__img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;

  transition: filter .15s;
}
/* Высоту ряда выравнивает сама сетка: плитка тянется на всю ячейку, поэтому
   двухстрочная подпись («Участок ещё выбираем») поднимает соседей, а не
   оставляет под ними пустое поле. Прежний min-height в две строки на телефоне
   давал заметную пустоту под каждой короткой подписью. */
.quiz__options--media .tile-slot,
.quiz__options--media .tile,
.tile--media .tile__body { height: 100%; }

/* Обёртка варианта: ячейкой сетки стала она, поэтому высоту
   тянет тоже она, а плитка занимает всю ячейку — ряд остаётся ровным.
   В строчных видах (пилюли) обёртка прозрачна для раскладки.
   Ссылки «Подробнее» в плитках нет: в квизе перелинковки нет. */
.tile-slot { display: flex; flex-direction: column; min-width: 0; }
.tile-slot .tile { flex: 1; }
.quiz__options--pills .tile-slot { display: contents; }
/* Подпись плитки без своего кегля и без жирности:
   так она не давит на кадр и читается спокойнее. */
.tile__caption {
  display: block; padding: var(--sp-2) var(--sp-3);
  line-height: 1.3;
}
.tile--media:hover .tile__img,
.tile--media input:checked + .tile__body .tile__img { filter: none; }

@media (max-width: 1100px) { .quiz__options--media { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 820px)  { .quiz__options--media { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .quiz__options--media { grid-template-columns: repeat(2, 1fr); } }

.tile--pill .tile__body {
  min-height: 44px; gap: 0;
  padding: var(--sp-2) var(--sp-5);
  border-radius: var(--radius-full);
}
.tile--pill .tile__body::before { display: none; }

/* Квиз: у плиток с фотографией — толстая рамка вместо
   зелёной подложки; пилюля при выборе заливается целиком; в списке «что
   передать нам» остаётся только обводка; сам список идёт в две колонки. */
.tile--media input:checked + .tile__body { border-width: 3px; border-color: var(--brand); }
.tile--media input:checked + .tile__body .tile__caption { color: var(--on-dark); }

.tile--pill input:checked + .tile__body {
  background: var(--brand-press);
  border-color: var(--brand-press);
  color: var(--on-brand);
}



/* Карта стандартов в начале статьи о разъёмах: тип тока × регион, ячейка ведёт
   в свой раздел. Заменила обложку-фотографию — по ней читатель сразу находит
   свой случай. */

/* Сетка, шапка и рамки берутся у базового класса .table — он и задаёт полную
   сетку всем таблицам сайта (§3.17). Здесь только то, чего в нём нет:
   выравнивание по центру, колонка типа тока и ячейка-ссылка со знаком. */


/* Колонка типа тока узкая намеренно: на телефоне таблица и так уезжает в
   прокрутку, и широкая подпись съедала бы место у самих разъёмов. */













/* Один столбец задаётся явно: без него сетка раскладывает длинные варианты в три колонки по ширине карточки. */
.quiz__options--one { grid-template-columns: 1fr; }

/* Незаполненное поле ввода в шаге квиза обводится так же, как блок вариантов: у страны и города своей рамки не было. */
.quiz__question .field.is-invalid .input { border-color: var(--danger); border-width: 2px; }






.quiz__fields { gap: 0 var(--sp-5); margin-bottom: var(--sp-4); }
/* Три поля в строку: имя, телефон, почта. */
.quiz__fields--three { display: grid; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 700px) { .quiz__fields--three { grid-template-columns: 1fr; } }
.quiz__req { margin: calc(var(--sp-2) * -1) 0 var(--sp-4); color: var(--on-dark-3); }
.quiz .field__label { color: var(--on-dark-2); }
.quiz .input {
  background: rgba(0,0,0,.20); border-color: var(--quiz-line); color: var(--on-dark);
}
.quiz .input::placeholder { color: var(--on-dark-3); }
.quiz .consent { color: var(--on-dark-3); }
/* В тёмной карточке квиза ссылка на документы набирается светлее текста: при одинаковом цвете её не отличить от подписи. */
.quiz .consent a { color: var(--on-dark); }
.quiz .consent a:hover { color: var(--brand); }



.quiz__question + .quiz__question { margin-top: var(--sp-7); }
/* Поле ввода после блока вариантов: без отступа они слипаются (квиз локации). */
.quiz__question + .field { display: block; margin-top: var(--sp-7); }

/* Карта в квизе по локации (страница «Бизнес на зарядных станциях»).
   Высота задана жёстко: контейнер карты без размеров Яндекс не рисует
   вовсе, а процент от высоты внутри fieldset ни во что не разрешается. */



/* Вопрос с несколькими полями ввода:
   страна короче, город — остальное место. */







/* Карточка квиза тёмная, а базовый .btn--outline красит текст в --ink: на этом
   фоне надписи кнопок пропадали. Правило то же, что у первого экрана. */
.quiz .btn--outline { color: var(--on-dark); border-color: rgba(255,255,255,.55); }
.quiz .btn--outline:hover,
.quiz .btn--outline:focus-visible { color: var(--on-dark); border-color: var(--on-dark); }





.quiz__question.is-invalid .quiz__options {
  padding: var(--sp-3);
  margin: calc(var(--sp-3) * -1);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md);
}
.quiz__error { margin: var(--sp-2) 0 0; font-size: var(--fs-caption); color: var(--danger); }






.quiz__legend--final { font-size: var(--fs-h2); letter-spacing: var(--ls-h2); }
/* Кегль на пункт больше и просторнее интерлиньяж: в исходном виде текст
   финального шага читался слипшимся. */
.quiz__lead {
  margin: calc(var(--sp-3) * -1) 0 var(--sp-6);
  font-size: 1.0625rem; line-height: 1.65; color: var(--on-dark-2);
}

/* Кнопка шага крупнее по площади, кегль тот же. */
.quiz__nav .btn--primary { padding: 21px 42px; }
/* Незаполненное поле финального шага обводится так же, как непройденный вопрос
   выше: рамка цвета ошибки вокруг всего поля, а не только подпись. Для согласия рамка рисуется вокруг самого флажка — обводить
   строку с текстом целиком было бы шумно. */
.quiz .field.is-invalid .input { border-color: var(--danger); border-width: 2px; }
.quiz .consent.is-invalid input { outline: 2px solid var(--danger); outline-offset: 2px; }
.quiz .field.is-invalid::after,
.quiz .consent.is-invalid::after {
  content: 'Обязательное поле';
  display: block; margin-top: var(--sp-2);
  font-size: var(--fs-caption); color: var(--danger);
}

/* Флажок согласия на тёмной карточке: белый квадрат бил по глазам сильнее
   самого текста.
   Грабля: без appearance: none браузер рисует флажок по-своему и
   ни background, ни border не применяются — квадрат так и оставался белым.
   Поэтому вид собирается сам: серая заливка, а галочка появляется фоновым SVG
   при checked. */
/* Заливка светлее фона карточки: тёмный квадрат на
   тёмном терялся, и флажок было не видно. */
.quiz .consent input,
.lead-band__form .consent input {
  appearance: none; -webkit-appearance: none;
  margin-top: 1px;
  background: rgba(255,255,255,.16);
  border: 1px solid rgba(255,255,255,.34); border-radius: 3px;
}
.quiz .consent input:checked,
.lead-band__form .consent input:checked {
  background-color: var(--brand); border-color: var(--brand);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'><path d='M3 8.5l3.5 3.5L13 5'/></svg>");
  background-repeat: no-repeat; background-position: center; background-size: 14px;
}

.quiz__nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); margin-top: var(--sp-7);
}
.quiz__nav-buttons { display: flex; gap: var(--sp-3); }
.quiz__counter {
  margin: 0;
  font-family: var(--font); font-size: var(--fs-label);
  /* Не --brand: на сером фоне карточки квиза он даёт 3,23:1. Служебной подписи
     цвет-акцент не нужен, белый читается уверенно. */
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--on-dark-2);
}
/* Кнопка «Назад» шире и полностью статична: ни волны,
   ни зелёной обводки, ни подсветки фона — она не должна спорить с «Далее». */
.quiz__back {
  width: 64px; padding: 0;
  background: none; border: 1px solid var(--quiz-line); color: var(--on-dark-2);
}
.quiz__back::before, .quiz__back::after { content: none; }
.quiz__back:hover, .quiz__back:focus-visible {
  background: none; border-color: var(--quiz-line); color: var(--on-dark-2);
}





@media (max-width: 640px) {
  .quiz { padding: var(--sp-5) var(--sp-4); }
  .quiz__options { grid-template-columns: 1fr; }
  .quiz__options--media { grid-template-columns: repeat(2, 1fr); }
  .quiz__nav .btn { flex: 1; }
}

/* ===== 17. КАТАЛОГ: КАРТОЧКИ СТАНЦИЙ И ПЛИТКИ ===== */
.products { align-items: stretch; }
/* Вторая сетка карточек на странице (сопутствующее оборудование после станций)
   прилипала к первой: между ними в разметке лежит только микроразметка, и
   соседний селектор через `+` её не перешагивает — поэтому `~`. */
.products ~ .products { margin-top: var(--sp-6); }
/* Карточки в листинге тянутся по высоте ряда, и кадр фото — как flex-элемент
   колонки — при этом терял свои 1:1 и сжимался. На главной этого не видно:
   там сетка без `.products`. Фиксируем кадр, чтобы обе страницы совпадали. */
.products .product__media { flex: 0 0 auto; }

/* Карточка обведена бледной рамкой со скруглением:
   без неё товары в ряду сливались в одну ленту. */
.product {
  display: flex; flex-direction: column;
  padding: var(--sp-5);
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
  background: var(--canvas);
}
.product__media {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; margin-bottom: var(--sp-5);
  background: transparent;
  overflow: hidden;
}
/* Кадр карточки квадратный, а фото приходят разной пропорции: у станций
   вертикальные, у аксессуаров и генераций — горизонтальные. Ограничиваем обе
   стороны, иначе горизонтальный снимок растягивается по высоте и обрезается
   боками об `overflow: hidden` родителя. */
.product__media img {
  max-width: 100%; max-height: 100%;
  width: auto; height: auto;
  object-fit: contain;
}




/* Бейджи карточки: набор и цвет задаются в products.json, здесь только тона.
   Кладутся стопкой в углу фото либо
   строкой под названием — место тоже приходит из JSON. */


/* Бейджи заливные и заметные: прозрачная «Гарантия до
   7 лет» на фото не читалась вовсе, а это сильное преимущество. Радиус мелкий —
   плашка, а не пилюля; цвета сочетаются с фирменным зелёным. */






/* Разъёмы — векторными логотипами от маркетинга. Type 2 использует тот же знак,
   что GB/T AC: разъём той же формы, отличается только протокол обмена данными.


   Значок 68px — вдвое крупнее прежнего и одинаковый у всех: мелкие логотипы
   разного размера в карточке не читались. */
.connectors {
  display: flex; flex-wrap: wrap; justify-content: space-around; gap: var(--sp-4);
  width: 100%; margin: 0 0 var(--sp-4); padding: 0; list-style: none;
}

   /* натуральный размер файлов 52×47: растягивать растр вверх нельзя — мылит */

/* Разделы каталога тегами: прозрачная пилюля с серой обводкой. */






.product__title { font-size: var(--fs-h4); margin-bottom: var(--sp-4); }

/* Нижней линии у характеристик и верхней у строки покупки нет: между ними оставалась пустая полоса, зажатая двумя правилами. */




/* Цена и кнопка в одной строке: цена слева, действие справа. */

/* Две кнопки в карточке: «Подробнее» прозрачной и «Запросить» — на узкой карточке встают в столбик. */
.product__actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.product__actions .btn { white-space: nowrap; }
.product__price { margin: 0; }
.product__price-label { font-size: var(--fs-caption); color: var(--muted); }
.product__price b { font-size: var(--fs-h4); color: var(--ink); letter-spacing: var(--ls-h3); }


.product__actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
.product__actions .btn { flex: 1 1 auto; }

/* Тезисы с галочкой — пояснение к блоку вместо абзаца. */
.points {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3) var(--sp-6);
  margin: 0 0 var(--sp-7); padding: 0; list-style: none;
}
.points--column { grid-template-columns: 1fr; margin-bottom: 0; }
@media (max-width: 720px) { .points { grid-template-columns: 1fr; } }
.points li { display: flex; gap: var(--sp-3); align-items: flex-start; font-size: var(--fs-sm); }

.points b { color: var(--brand-dim); font-weight: 700; }
/* Текст сразу за списком тезисов: без отступа абзац читается как продолжение последнего пункта. */
.prose .points + p { margin-top: var(--sp-5); }















/* ===== Преимущества =====
   Карточка держится не рамкой, а иконкой в зелёном круге: ряд читается как
   набор доводов, а не как таблица. */









/* Фотография вместо шестой карточки: заполняет ячейку целиком, без полей. */



/* ===== Решения под тип объекта =====
   Фотография слева, текст справа — карточка читается одной строкой взгляда.
   Кадр фиксированной ширины: снимки разного размера, но ряд должен быть ровным. */







/* Тип объекта, под который страницы ещё нет: та же плитка, но без отклика на
   наведение — иначе она обещает переход, которого не будет. */





/* На телефоне кадр уходит наверх во всю ширину: узкая колонка текста рядом с
   картинкой рвёт заголовок на четыре строки. */


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





/* Лента статей: карточка растягивается на всю высоту слайда, кнопка внизу. */







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















/* ===== 18. ТАБЛИЦЫ ===== */


/* Указатели прокрутки над и под таблицей — их ставит main.js у таблиц, которые
   шире экрана. Нативная полоса на телефоне видна только во время движения. */
.table-scroll__bar {
  position: relative; height: 6px; border-radius: 3px;
  background: var(--surface-2);
}


.table-scroll__thumb {
  position: absolute; inset-block: 0; left: 0;
  border-radius: 3px; background: var(--brand);
}
/* Нативную полосу прячем: положение показывают наши указатели, а вместе с ней
   под таблицей получалось две полосы подряд.
   Прокрутка колесом, пальцем и клавишами при этом работает как обычно. */


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

   Две грабли, из-за которых линий может снова не стать (уже ловились на прайсе):
   1) `tr:last-child { border-bottom: 0 }` специфичнее одного класса и срезает
      нижнюю границу — здесь такого правила нет намеренно;
   2) `border-collapse: collapse` вместе с `overflow: hidden` и скруглением
      прячет крайние линии под радиусом: радиус — только у обёртки. */
.table {
  width: 100%; border-collapse: collapse;
  font-size: var(--fs-sm);
  border: 1px solid var(--faint);
}
.table th, .table td {
  padding: var(--sp-1) var(--sp-4);
  text-align: left; vertical-align: top;
  border: 1px solid var(--faint);
}
.table thead th {
  font-family: var(--font); font-size: var(--fs-label); font-weight: 700;
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--ink-strong);
  text-align: center;
  background: var(--surface-3);
  border-bottom-color: var(--hairline-strong);
  white-space: nowrap;
}
.table tbody th { font-weight: 600; color: var(--ink-strong); }
.table td { color: var(--body); }



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






/* Варианты комплектации площадки: снимок, заголовок, короткое описание и
   признаки списком. Три карточки в ряд, на планшете две, на телефоне одна. */













/* Список нормативных документов: иконка, название и реквизиты. Файлы сводов
   правил у себя не размещаем, поэтому это не ссылки на скачивание, а карточки
   с выходными данными — по ним документ находится в государственном реестре. */



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





/* Колонка с миниатюрой площадки: снимок делает таблицу читаемой сканированием,
   а не сплошным текстом. На телефоне колонка скрывается — там дорог каждый
   пиксель ширины, а фотография не несёт данных. */
/* Длинный заголовок колонки в узкой таблице переносится по словам: с nowrap
   он забирает ширину у соседей, и подпись строки рвётся по слогам. */







/* На телефоне колонки не сжимаются до вертикальной строчки: ячейка переносится
   по словам, а всё, что не влезло, уезжает в горизонтальную прокрутку обёртки.
   Без этого браузер делит ширину экрана между всеми колонками поровну и в
   узких столбцах остаётся по одной букве в строке. */
@media (max-width: 640px) {
  .table { font-size: 0.8125rem; }
  .table th, .table td { padding: var(--sp-3); word-break: normal; }
  /* Пояснение под значением переносится по словам и не растягивает колонку. */
  .table .note { display: block; max-width: 17rem; white-space: normal; }

  /* Подпись строки занимала треть экрана, хотя текст в ней спокойно переносится:
     сужаем её и отдаём место цифрам. */
  .table thead th:first-child,
  .table tbody th[scope="row"] { max-width: 8.5rem; }

  /* Заголовки колонок переносятся по словам: с nowrap длинное название
     распирало узкую колонку и налезало на соседнюю. */
  .table thead th { white-space: normal; }

  /* Колонка с коротким значением (число, срок): ширину задаём в colgroup таблицы. */
  

  /* Подпись строки закреплена у левого края: при прокрутке вбок иначе не видно,
     к какой строке относятся цифры. Фон обязателен — сквозь прозрачную ячейку
     просвечивают проезжающие колонки. Правая граница нарисована тенью:
     при border-collapse обычная граница за закреплённой ячейкой не едет. */
  .table { --table-bg: var(--canvas); }
  .section--surface .table,
  .section--grid .table { --table-bg: var(--surface); }
  .table thead th:first-child,
  .table tbody th[scope="row"],
  .table tbody td.table__cell--sub {
    position: sticky; left: 0; z-index: 1;
    background: var(--table-bg);
    box-shadow: 1px 0 0 var(--faint);
  }
  /* Строка-статья сметы едет вместе со своим фоном, иначе закреплённая ячейка теряет заливку. */
  
  
  /* Шапка прайса залита серым, у остальных таблиц она на фоне секции —
     закреплённая ячейка повторяет фон своей шапки, иначе над первой колонкой
     повисает серый прямоугольник. */
  .table { --table-head-bg: var(--table-bg); }
  .price { --table-head-bg: var(--surface-3); }
  .table thead th:first-child { z-index: 2; background: var(--table-head-bg); }
}

/* ===== Прайс =====
   Таблица «позиция — стоимость» в цветах сайта: тёмная шапка, чередование строк, выделенные позиции с оборудованием.
   Стоимость выровнена вправо и набрана плотнее — колонка читается столбиком. */
/* Полная сетка вместо одних горизонтальных линий, шапка серая, названия
   колонок по центру и жирным, строки плотнее. Линии
   тонкие и светлые — таблица должна оставаться воздушной. */
/* Линии сетки видимые, а не волосяные: на --hairline
   вертикальный разделитель колонок практически не читался, и таблица выглядела
   как два независимых столбца текста.
   Две грабли, из-за которых линий не было видно даже после этого:
   1) `.table tr:last-child th/td { border-bottom: 0 }` специфичнее одного
      класса и срезал нижнюю границу таблицы — здесь она возвращается;
   2) `border-collapse: collapse` вместе с `overflow: hidden` и скруглением
      прячет крайние линии под радиусом — поэтому радиус снят с самой таблицы
      и оставлен только у обёртки. */
.price { border: 1px solid var(--faint); border-collapse: collapse; }
.price th, .price td { padding: var(--sp-2) var(--sp-4); border: 1px solid var(--faint); }
.price tr:last-child th, .price tr:last-child td { border-bottom: 1px solid var(--faint); }
.price th:first-child, .price td:first-child { padding-left: var(--sp-4); }
.price thead th {
  background: var(--surface-3); color: var(--ink-strong);
  text-align: center; font-weight: 700;
  border-bottom: 1px solid var(--hairline-strong);
}
.price tbody th { font-weight: 500; color: var(--body); }




/* На телефоне двухколоночный прайс должен помещаться в экран целиком: иначе
   цена уезжает за край и её не видно, пока не проскроллишь таблицу вбок.
   ⚠️ Ровно для двух колонок, поэтому и отдельный класс: раньше правило стояло
   на всех .price, и таблица окупаемости из шести колонок (/biznes-na-ezs)
   отдавала 62% первой колонке, остальные пять делили остаток по 7% и текст
   рвался по буквам в вертикальную строчку.
   Многоколоночные таблицы вместо сжатия уезжают в прокрутку — см. раздел 18. */
@media (max-width: 640px) {
  .price { font-size: 0.8125rem; }
  .price th, .price td { padding: var(--sp-2) var(--sp-3); }

  
  
  /* 12px, а не 10: шапка прайса на телефоне читалась хуже всего текста вокруг.
     Помещается за счёт word-break ниже. */
  
  
  
}

/* Строка-подзаголовок делит прайс по темам: оборудование, проект, монтаж. */



/* Пояснения под таблицей: три колонки со списками. */




/* Список с зелёной галочкой: галочка рисуется псевдоэлементом, чтобы в тексте
   не было символов, зависящих от кодировки файла. */









/* ===== 19. ЭТАПЫ, ЛЕСТНИЦА, ВРЕЗКА ===== */









/* ===== Субсидия: изображение с обтеканием и шаги кружками =====
   Блок на светлом фоне, кадр стоит
   справа и обтекается текстом, шаги — цифры в кружках, между ними пунктир. */






.ladder {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-6) var(--sp-6);
  margin: var(--sp-8) 0 var(--sp-6); padding: 0; list-style: none;
}
@media (max-width: 900px) { .ladder { grid-template-columns: 1fr; gap: var(--sp-5); } }
.ladder__item { position: relative; display: flex; gap: var(--sp-4); align-items: flex-start; }
/* Пунктир к следующему шагу: у последних в ряду его нет. */
.ladder__item:not(:nth-child(3n)):not(:last-child)::after {
  content: ''; position: absolute; top: 21px; right: calc(var(--sp-6) / -1);
  width: var(--sp-6); border-top: 2px dashed var(--hairline-strong);
}
@media (max-width: 900px) { .ladder__item::after { display: none; } }
.ladder__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; flex: none;
  border-radius: 50%; background: var(--brand-press); color: var(--on-brand);
  font-size: var(--fs-h4); font-weight: 700; line-height: 1;
}
.ladder__body { display: block; }
.ladder__title {
  display: block; margin-bottom: var(--sp-2);
  font-size: var(--fs-h4); font-weight: 700; color: var(--ink-strong);
}
.ladder__text { display: block; font-size: var(--fs-sm); color: var(--body); }

/* Кадр разъёма в статье: гнездо на машине и коннектор в руке одним снимком.
   Люди путают гнездо и штекер — в кадре видно и то, и другое. */




/* Крупные карточки типов объектов: уменьшенный кадр первого экрана страницы
   и название поверх него. Ссылка — только если
   страница есть; иначе карточка без перехода. */











/* Карточка направления без кнопки: у .post нижний отступ даёт абзац с кнопкой,
   без неё текст прилипал к рамке. */


/* Производственные переделы: квадратные снимки из каталога завода с подписью. */







/* Главные тезисы блока в рамке: цифра и одна фраза под ней.
   Человек читает заголовки и выделенное, а не абзацы — поэтому то, ради чего
   написан блок, выносится сюда, а подробности остаются текстом ниже. */








/* Выноска: важная мысль, которую нельзя пропустить при беглом чтении.
   Кегль основной — мелким такое не набирают. */










.icon--check { color: var(--brand); flex: none; margin-top: 2px; }






/* ===== Дорожная карта =====
   Построчный маршрут: слева крупный номер шага,
   справа название и подробности. Пунктир идёт сверху вниз и связывает шаги
   в один путь — сплошная линия читалась бы как граница таблицы. */



/* Пунктир к следующему шагу — от кружка вниз. */

/* Номер шага — в кружке с зелёной линией и прозрачной серединой.
   */








/* ===== 20. КАЛЬКУЛЯТОР ===== */



/* Внутри калькулятора зелёного нет: фирменный цвет
   закреплён за кнопками, а на регуляторах и переключателях он спорил с ними.
   Зелёной остаётся только итоговая цифра окупаемости. */










/* Кегль суммы считается от ширины самой колонки: в узкой паре «за станцию / за
   присоединение» знак рубля отрывался от числа и уезжал на вторую строку. */



.range { width: 100%; height: 32px; background: none; -webkit-appearance: none; appearance: none; }
.range::-webkit-slider-runnable-track { height: 2px; background: var(--hairline-strong); }
.range::-moz-range-track { height: 2px; background: var(--hairline-strong); }
.range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 20px; height: 20px; margin-top: -9px;
  background: var(--muted); border: 0; border-radius: var(--radius);
  cursor: pointer;
}
.range::-moz-range-thumb {
  width: 20px; height: 20px; background: var(--muted);
  border: 0; border-radius: var(--radius); cursor: pointer;
}

.switch { display: flex; }
.switch__opt { position: relative; flex: 1; }
.switch__opt input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.switch__opt span {
  display: flex; align-items: center; justify-content: center;
  min-height: 48px; padding-inline: var(--sp-4);
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-strong);
  background: var(--canvas); border: 1px solid var(--hairline-strong);
  transition: background-color .15s, color .15s, border-color .15s;
}
.switch__opt + .switch__opt span { border-left: 0; }
.switch__opt input:checked + span { background: var(--muted); border-color: var(--muted); color: #fff; }
.switch__opt input:focus-visible + span { outline: 2px solid var(--ink-strong); outline-offset: 2px; }







/* ===== 21. КЕЙСЫ =====
   Лента карточек с нативной прокруткой: стрелки только помогают, без JS блок
   остаётся рабочим — палец и колесо листают его сами. */







/* Ширина карточки задаётся жёстко: minmax(…, 1fr) в прокручиваемой ленте
   позволяет колонкам сжаться под контейнер, и вместо слайдера получается
   десять узких полосок в один экран. */





/* На телефоне карточка занимает всю ширину: край соседнего слайда съедал
   заметную часть и без того узкого экрана. Что лента
   прокручивается, показывают стрелки над ней. */















/* Страница документов: скан слева, пояснение справа — документ должен читаться
   и как картинка, и как строка списка. */






/* На телефоне миниатюра забирала 120px из 296 и тексту оставалось 160 —
   «производственному» не помещалось в строку целиком. */



/* min-width: 0 у текстовой части карточки: без него flex-элемент не становится
   уже своего самого длинного слова, и название вроде «ТехноЭкспо. Металлургия.
   Машиностроение» выносило карточку за край экрана. */




/* Награды на городских страницах: три карточки в ряд равными долями, снимок
   крупный и сверху, под ним заголовок и пояснение. */






/* ===== Форма захвата в конце страницы =====
   Фотография под затемнением: фон должен поддержать блок, но не спорить с
   текстом и полями. Затемнение сплошное, а не градиент, —
   иначе на светлых кадрах поля теряются. */
.lead-band {
  position: relative; overflow: hidden;
  padding-block: var(--sp-8);
  background: var(--dark) var(--lead-band-image) center / cover no-repeat;
  color: var(--on-dark);
}
.lead-band::before {
  content: ''; position: absolute; inset: 0;
  background: rgba(17, 20, 21, .82);
}
/* Свой кадр для узких экранов: иначе телефон грузит и мобильное фото первого
   экрана, и десктопное фото этого блока. */
@media (max-width: 900px) {
  .lead-band[style*="--lead-band-image-mobile"] {
    background-image: var(--lead-band-image-mobile);
  }
}
.lead-band__inner {
  position: relative;
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8);
  align-items: center;
}
/* Тонкая линия отделяет блок от подвала: два тёмных
   блока подряд сливались в один. Цвет непрозрачный: полупрозрачная белая
   линия смешивалась с фотографией под ней и получалась разноцветной. */
.lead-band { border-bottom: 1px solid #3A4246; }
@media (max-width: 900px) { .lead-band__inner { grid-template-columns: 1fr; gap: var(--sp-6); } }

.lead-band h2 { color: var(--on-dark); margin-bottom: var(--sp-4); }
.lead-band__sub { margin: 0; font-size: var(--fs-lead); line-height: 1.55; color: var(--on-dark-2); }
/* Полоса захвата всегда лежит на тёмном фото: здесь читается чистый --brand
   (4,99:1), а --brand-dim дал бы 2,95:1. */
.lead-band__sub b { color: var(--brand); font-weight: 700; }

.lead-band__form { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-3); align-items: start; }
@media (max-width: 640px) { .lead-band__form { grid-template-columns: 1fr; } }
.lead-band__form--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) { .lead-band__form--three { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .lead-band__form--three { grid-template-columns: 1fr; } }

/* Второй вид блока: заголовок и тезисы по
   центру, форма во всю ширину под ними. Здесь блок не сопровождает страницу, а
   сам является предложением, поэтому две колонки ему тесны. */


/* Кегль, разрядка и интерлиньяж — значения заказчика. Заголовок
   ложится ровно в две строки по ручному переносу. */




.lead-band__form .field { margin: 0; }
/* Поля прозрачные, с тонкой белой рамкой: заливка
   спорила с фотографией под блоком. */
.lead-band__form .input {
  width: 100%; min-height: 56px;
  background: transparent;
  border: 0.5px solid #fff; border-radius: 3px;
  color: var(--on-dark);
}
.lead-band__form .input::placeholder { color: var(--on-dark-3); }
.lead-band__form .btn { grid-column: 1; width: 100%; }
@media (max-width: 900px) { .lead-band__form--three .btn { grid-column: 1 / -1; } }
/* Согласие занимает всю ширину формы и остаётся читаемым на тёмном фоне. */
.lead-band__form .consent { grid-column: 1 / -1; color: var(--on-dark-3); }
.lead-band__form .consent a { color: var(--on-dark-2); text-decoration: underline; }

/* Хлебные крошки: путь до страницы, текущая — без ссылки. */
.crumbs {
  margin-bottom: var(--sp-5);
  font-size: var(--fs-caption); color: var(--muted);
}
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--brand-dim); }
.crumbs__sep { margin: 0 var(--sp-2); color: var(--faint); }
.crumbs__current { color: var(--ink-strong); }

/* Страница кейса: карточка фактов, разделы и показатели объекта. */





/* Отзывы водителей на странице объекта. Кегль основной: это то,
   ради чего блок и нужен, а не подпись под ним. Звёзды — текстом, не иконкой:
   их видно и в выдаче, и в нейроответе. */




/* Тёмная охра, а не жёлтый: жёлтый #f5a623 на светлой карточке даёт 1,87:1 при
   норме 4,5 для текста. Звёзды — символы, а не иконка, и норма к ним та же. */







/* Цифры и ключевые факты в тексте страницы — фирменным зелёным: взгляд цепляется за факт, а не за сплошной
   абзац. Выделение приходит из JSON тегом <b>. */
/* Не --brand: чистый #009541 на белом даёт 3,91:1, а выделенные факты набраны
   кеглем основного текста. --brand-dim — 6,62:1 при том же фирменном тоне. */
.case-section b, .prose b, .event__text b, .roadmap__text b { color: var(--brand-dim); font-weight: 700; }









/* Событие на странице выставок: заголовок, дата и место, текст, галерея. */







/* Галерея страниц (выставки, кейсы): та же механика просмотрщика, что была
   у блока кейсов на главной, но плитка крупнее — на странице есть место. */

/* Четыре снимка: по два в ряд. В сетке из трёх колонок четвёртый повисал в
   пустой строке, а в узкой колонке страницы кадры по 230px не читаются. */

/* На странице решения снимки объекта идут одним рядом: четыре кадра — четыре
   колонки, миниатюры мельче, но вторая строка ради одного снимка не заводится.
   Ниже 900px работает общее правило «по два в ряд». */








/* Та же галерея лентой: снимки идут одним рядом и
   листаются, как кейсы на главной. Кадры берут вид от .gallery, раскладку —
   от слайдера. */














/* ===== Просмотрщик фотографий ===== */
.zoom {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-4); padding: var(--sp-6) var(--sp-5);
  background: rgba(10,13,14,.975);
}
.zoom__close {
  position: absolute; top: var(--sp-4); right: var(--sp-4);
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border: 0; background: none; color: var(--on-dark-2); cursor: pointer;
}
.zoom__close:hover { color: var(--on-dark); }
.zoom__stage {
  display: flex; align-items: center; gap: var(--sp-4);
  width: 100%; min-height: 0; flex: 1;
}
/* min-width: 0 обязателен: без него флекс-элемент не сжимается уже своего
   содержимого, и на телефоне снимок уезжал за правый край вместе со стрелками.
   */
.zoom__img {
  flex: 1 1 auto; min-width: 0;
  max-width: 100%; max-height: 100%;
  margin-inline: auto; object-fit: contain;
}
.zoom__nav {
  flex: none; width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--hairline-dark); border-radius: 50%;
  background: none; color: var(--on-dark-2); cursor: pointer;
}
.zoom__nav:hover { color: var(--on-dark); border-color: var(--on-dark-3); }
.zoom__caption { margin: 0; max-width: 70ch; text-align: center; font-size: var(--fs-sm); color: var(--on-dark-2); }
.zoom__thumbs { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.zoom__thumbs button {
  width: 76px; height: 57px; padding: 0; cursor: pointer;
  border: 1px solid transparent; background: none; opacity: .5;
  transition: opacity .2s, border-color .2s;
}
.zoom__thumbs button:hover { opacity: .85; }
.zoom__thumbs button.is-active { opacity: 1; border-color: var(--brand); }
.zoom__thumbs img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* На телефоне стрелки ложатся поверх кадра, а не отбирают у него ширину:
   иначе на 390px от снимка остаётся полоска. */
@media (max-width: 640px) {
  .zoom { padding: var(--sp-7) var(--sp-3) var(--sp-4); gap: var(--sp-3); }
  .zoom__stage { position: relative; }
  .zoom__nav {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
    width: 40px; height: 40px;
    background: rgba(10,13,14,.55); color: var(--on-dark);
  }
  .zoom__nav--prev { left: 0; }
  .zoom__nav--next { right: 0; }
  .zoom__close { top: var(--sp-2); right: var(--sp-2); width: 40px; height: 40px; }
  .zoom__caption { font-size: var(--fs-caption); }
  .zoom__thumbs button { width: 56px; height: 42px; }
}









/* ===== 22. ПЛИТКИ ССЫЛОК, ДОКУМЕНТЫ, СТАТЬИ ===== */
/* Страница «не найдено»: крупный номер ошибки и одна кнопка. Плитки разделов с
   неё убраны — их текст попадал в замер сквозных слов. */
.error404 { text-align: center; }
.error404__code {
  margin: 0; font-size: clamp(96px, 22vw, 200px); line-height: 1;
  font-weight: 700; letter-spacing: -.04em; color: var(--ink-strong); opacity: .12;
}
.error404__note { margin: 0 0 var(--sp-6); font-size: var(--fs-h4); color: var(--muted); }










/* Карточка статьи: кадр, заголовок, короткий анонс и кнопка внизу карточки —
   ряд выравнивается по кнопкам независимо от длины анонса. */

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








   /* серо-белые тайлы */

/* Список городов идёт под картой: плашка поверх неё закрывала точки. */







/* ===== Поиск по сайту =====
   Страница результатов и строка запроса над ней. Оформление намеренно
   спокойное: это служебная страница, а не посадочная. */











/* Тип страницы справа от названия: «Раздел», «Статья», «Товар» — по нему видно,
   куда ведёт ссылка, до перехода. */





/* Страница, открытая из результатов поиска (?search=…): найденные слова на жёлтом фоне. */
mark.find-mark { background: var(--find-mark); color: inherit; border-radius: 2px; box-shadow: 0 0 0 2px var(--find-mark); }

/* Лупа в служебной строке шапки: там она есть на любой ширине, а главная строка
   на телефоне уже занята знаком, номером и кнопкой меню. */



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





/* Крестик очистки у type=search в Chrome спорил с лупой справа. */





/* Подсказки под полем на странице результатов: ширина поля, без отступов шапки. */



.search-bar__kind { margin-left: auto; flex: none; font-size: var(--fs-caption); color: var(--muted); }
/* «Все результаты» прилипает к низу окна подсказок, когда список длиннее экрана;
   над ссылкой — осветление, под ним прокручиваются подсказки. */
.search-bar__all { position: sticky; bottom: calc(-1 * var(--sp-2)); z-index: 1; background: var(--canvas); }


.search-bar__all a { color: var(--brand-dim); font-weight: 600; }
.search-bar__empty { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm); color: var(--body); }

@media (max-width: 560px) {
  
  .search-bar__kind { margin-left: 0; }
  
  
  
  
}

/* Теги-ссылки по разделам о заводе: навигация по теме прямо под
   заголовком. Стоят в начале страницы, поэтому набраны спокойно — акцент
   остаётся на самом тексте. */



/* Текущая страница — «нажатый» тег: тёмная заливка, без ссылки и без реакции на наведение. */


/* Нет ключа карт или узкий экран — от блока остаётся список городов. */



/* Флажок города на карте: база флагштока — точка на карте. */

.geo-pin__flag {
  flex: none; color: var(--brand);
  filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 2px 3px rgba(0,0,0,.35));
}
.geo-pin--hub .geo-pin__flag { color: var(--brand-press); }
/* Объект со своей страницей: круглое фото вместо флажка, клик открывает карточку. */

.geo-pin__photo {
  flex: none; width: 48px; height: 48px; border-radius: 50%; object-fit: cover;
  border: 3px solid var(--brand); background: #fff;
  box-shadow: 0 2px 6px rgba(10,13,14,.35);
  transition: transform .15s ease;
}



.geo-pin__photo, .geo-cluster__photo { max-width: none; }
.geo-cluster.geo-cluster--photo {
  position: relative; width: 56px; height: 56px; padding: 0; background: #fff;
  border: 3px solid var(--brand); overflow: visible;
}
.geo-cluster__photo { width: 50px; height: 50px; border-radius: 50%; object-fit: cover; display: block; }
.geo-cluster__count {
  position: absolute; top: -6px; right: -8px;
  min-width: 22px; height: 22px; padding: 0 5px; border-radius: 11px;
  background: var(--brand-press); color: #fff; border: 2px solid #fff;
  font-size: 12px; font-weight: 700; line-height: 18px; text-align: center;
}
.geo-pin__label {
  font-size: 12.5px; font-weight: 700; color: var(--ink);
  background: rgba(255,255,255,.92);
  padding: 2px 7px; border-radius: 5px;
  box-shadow: 0 1px 4px rgba(10,13,14,.22);
}
.geo-cluster {
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--brand-press); color: #fff; border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(10,13,14,.3);
  font-weight: 700; font-size: 13px;
  transform: translate(-50%, -50%);
}

   /* воздух над блоком статей */









/* Селектор с двумя классами намеренно: кнопка лежит в последнем абзаце
   карточки, а базовое `p:last-child { margin-bottom: 0 }` специфичнее одного
   класса — из-за него кнопка прижималась к нижней границе карточки.
   */





/* ===== 23. АККОРДЕОН ===== */
/* Вопросы стоят карточками на своей подложке: на сером фоне секции белая
   плашка отделяет вопрос от вопроса лучше, чем линия. */
/* minmax(0, 1fr) обязателен: у грид-элемента min-width по умолчанию auto, и
   карточка вопроса не сжимается уже таблицы внутри ответа — на телефоне из-за
   этого прокручивалась вся страница. */
.accordion { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
.accordion__item {
  min-width: 0;
  background: var(--canvas);
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
  padding: 0 var(--sp-6);
}
.accordion__item.is-open { border-color: var(--brand); }
.accordion__head {
  position: relative;
  margin: 0; padding: var(--sp-5) var(--sp-8) var(--sp-5) 0;
  font-size: var(--fs-h4); font-weight: 600; color: var(--ink);
  cursor: pointer; list-style: none;
}
.accordion__head::after {
  content: ''; position: absolute; top: 50%; right: var(--sp-3);
  width: 10px; height: 10px; margin-top: -8px;
  border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand);
  transform: rotate(45deg); transition: transform .15s;
}
.accordion__item.is-open .accordion__head::after { transform: rotate(-135deg); margin-top: -3px; }
.accordion__body {
  overflow: hidden; max-height: 0;
  transition: max-height .2s ease-out;
}
.accordion__item.is-open .accordion__body { max-height: 140em; }

/* Ответ занимает всю ширину блока: ограничение по знакам здесь снято намеренно
   — вместо узкой колонки текст структурируется
   абзацами, списками и таблицами. */
.answer { padding-bottom: var(--sp-5); font-size: var(--fs-sm); }
.answer > * + * { margin-top: var(--sp-5); }
.answer p { margin: 0; }




/* ===== 24. ДВЕ КОЛОНКИ И КОНТАКТЫ ===== */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8); align-items: start; }

.split__aside .prose p { color: inherit; }

















.form__done {
  padding: var(--sp-6); border-left: 2px solid var(--brand);
  background: rgba(255,255,255,.04);
}
.section:not(.section--dark) .form__done, .modal .form__done { background: var(--surface); }



@media (max-width: 900px) {
  .split, .split--form { grid-template-columns: 1fr; gap: var(--sp-7); }
  
}

/* ===== 25. МОДАЛЬНОЕ ОКНО ===== */
.modal {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  padding: var(--gutter);
  background: rgba(10,13,14,.72);
  overflow-y: auto;
}
.modal__window {
  position: relative;
  width: 100%; max-width: 520px;
  padding: var(--sp-7);
  background: var(--canvas);
  border-radius: var(--radius);
  box-shadow: var(--shadow-menu);
}
.modal__close {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 0; background: none; color: var(--muted); cursor: pointer;
}
.modal__close:hover { color: var(--ink); }
.modal__title { font-size: var(--fs-h3); margin-bottom: var(--sp-2); padding-right: var(--sp-7); }

.modal.is-short .field--optional { display: none; }

.field__req { color: var(--danger); }
.modal__req { margin-top: var(--sp-3); text-align: center; }








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








.modal__submit { width: 100%; margin-top: var(--sp-5); }

/* ===== Окно выбора города ===== */
/* Светлая тема окна выбора города: тёмное
   окно поверх тёмного первого экрана сливалось с фоном. Оформление то же, что
   у окна заказа звонка. */
















.city-group { break-inside: avoid; }
.city-group__letter {
  display: block; margin-bottom: var(--sp-2);
  font-family: var(--font); font-size: var(--fs-label);
  letter-spacing: var(--ls-label); color: var(--brand-dim);
}
.city-group__items { list-style: none; margin: 0; padding: 0; }
.city-item {
  display: block; width: 100%; padding: 3px 0;
  background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; font-size: var(--fs-sm); color: var(--body);
}
.city-item:hover { color: var(--brand-dim); }
.city-item.is-active { color: var(--ink-strong); font-weight: 600; }








.modal .form { margin-top: var(--sp-5); }
.modal__submit { width: 100%; margin-top: var(--sp-5); }

@media (max-width: 640px) {
  .modal { align-items: flex-start; padding: 0; }
  .modal__window { max-width: none; min-height: 100%; padding: var(--sp-6) var(--sp-4); border-radius: 0; }
}

/* ===== 25.0. КНОПКА ВО ВРЕМЯ ОТПРАВКИ ===== */
/* Кружок перед надписью: между нажатием и ответом сервера проходит около двух
   секунд, и без индикатора человек жмёт «Отправить» второй раз. Спиннер —
   отдельный элемент, его вставляет main.js: оба псевдоэлемента кнопки уже
   заняты волной и подсветкой наведения. */
.btn.is-loading { cursor: progress; }
.btn.is-loading::after { animation: none; }        /* волна не спорит со спиннером */

.btn__spinner {
  flex: 0 0 auto;
  width: 16px; height: 16px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--radius-full);
  animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .btn__spinner { animation-duration: 1.8s; }
}

/* ===== 25.1. РЕЖИМ РАБОТЫ ===== */
/* Точка «сейчас работаем»: зелёная в рабочее время, серая вне его. Состояние
   считает сервер (work_status), скрипт к этому отношения не имеет. */














/* Неделя горизонтальной таблицей: дни в шапке, часы одной строкой под ними.
   Семь колонок держатся в 480px, поэтому на телефоне
   таблица прокручивается внутри .table-scroll, а на любом настольном экране
   помещается целиком.

   Колонка сегодняшнего дня подсвечивается: зелёная, пока идёт рабочее время,
   серая, если день выходной или рабочее время уже кончилось. Состояние
   считает сервер (work_status + work_week), скрипт к этому отношения не имеет. */










/* Фон секции здесь серый, поэтому «серая» колонка берёт тон на ступень темнее
   строк — иначе выделения не видно. */


/* На телефоне те же семь колонок помещаются целиком: часы переносятся на две
   строки по разделителю, отступы сжимаются. Прокручивать неделю пальцем,
   чтобы увидеть пятницу, — плохая замена одному взгляду. */


/* ===== 26. УТИЛИТЫ ===== */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}





.scrim {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(10,13,14,.6);
  opacity: 0; visibility: hidden; transition: opacity .2s, visibility .2s;
}
body.is-menu-open .scrim { opacity: 1; visibility: visible; }

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


/* Страница тендеров: три кадра оборудования и контакты списком. */











/* ===== 27. КАТАЛОГ: ФИЛЬТРЫ, ЛИСТИНГ, КАРТОЧКА ТОВАРА =====
   Разделы каталога сгруппированы по смыслу (тип, мощность, разъём) — так же,
   как фильтры у лидеров ниши power-on.su и punkt-e.ru: плоский список из
   двенадцати ссылок читается хуже. */













/* Первая колонка сравнения — подпись строки, а не значение: она уже и тише. */

/* Названия позиций в шапке переносятся: в одну строку три названия не помещаются и таблица уезжает за край. */


/* Карточка товара: слева кадр, справа цена и действие. */
/* minmax(0, …) обязателен: в правой колонке лежит таблица комплектаций шириной
   544px в своём .table-scroll. Колонка «1fr» не уже содержимого, поэтому
   прокручивалась не таблица, а вся страница — на телефоне карточка DC 150
   уезжала вправо на 200px. */
.product-page { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--sp-8); align-items: start; }
@media (max-width: 860px) { .product-page { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); } }
.product-page__media {
  position: relative;
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
  overflow: hidden; background: var(--canvas);
}
.product-page__media img { width: 100%; height: auto; display: block; }
.product-page__media a { display: block; cursor: zoom-in; }

/* Дополнительные снимки под основным: клик открывает общий просмотрщик. */





/* Позиция без снимка: заглушка держит пропорцию колонки, иначе рамка схлопывается в полоску. */


.product-page__info h1 { margin-bottom: var(--sp-4); }
.product-page__buy {
  display: flex; align-items: center; gap: var(--sp-5); flex-wrap: wrap;
  margin: var(--sp-6) 0;
  padding: var(--sp-5) var(--sp-6);
  border: 1px solid var(--hairline-strong); border-radius: var(--radius-lg);
}
.product-page__price { margin: 0; font-size: var(--fs-h3); }
.product-page__price b { color: var(--ink-strong); }
.product-page__price .product__price-label { display: block; font-size: var(--fs-caption); color: var(--muted); }

.product-page__text { margin-top: var(--sp-7); }
.product-page__text p + p { margin-top: var(--sp-4); }
.product-page__title { margin: var(--sp-8) 0 var(--sp-5); font-size: var(--fs-h3); }


/* Строка с моделью в окне заявки: показывается только для кнопок каталога. */
.modal__product {
  margin: 0 0 var(--sp-4); padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm); color: var(--body);
  background: var(--surface); border-radius: var(--radius);
}
.modal__product b { color: var(--ink-strong); }

/* Калькулятор возмещения на странице субсидии: та же сетка, что у калькулятора
   окупаемости, но проще — четыре поля и одна цифра-ответ. */
/* Городской калькулятор: та же механика и те же data-атрибуты, другой макет —
   результат идёт первым и во всю ширину, поля собраны под ним в три колонки.
   На городской странице человек сначала смотрит на цифру, а уже потом
   подкручивает параметры под свою площадку. */














/* Поля, которым нужна вся ширина строки: переключатель мощности и подписи под формой. */






/* ---------------------------------------------------------------------------
   Каталог: фильтр слева, товары справа
   ---------------------------------------------------------------------------
   Компоновка каталогов топа (punkt-e.ru, power-on.su — сканы в выгрузке ГАР):
   человек сразу видит и товары, и по чему их отбирать. Фильтр — обычная форма
   GET, без скриптов; JS нужен ровно для одного — схлопнуть панель на телефоне.
   --------------------------------------------------------------------------- */
.catalog-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: var(--sp-6);
  align-items: start;
}
.catalog-layout__bar {
  display: flex; align-items: baseline; justify-content: space-between;
  /* Перенос обязателен: счётчик «30 из 30 позиций» набран white-space: nowrap,
     и на узком экране строка «заголовок + счётчик» не помещалась — страница
     получала горизонтальную прокрутку. С переносом счётчик уходит под заголовок. */
  flex-wrap: wrap;
  gap: var(--sp-4); margin-bottom: var(--sp-5);
}

.catalog-layout__count { color: var(--muted); font-size: var(--fs-caption); white-space: nowrap; }

/* Панель фильтра */
.cat-filter-wrap { border: 1px solid var(--hairline); border-radius: var(--radius-lg); background: var(--canvas); }
.cat-filter-wrap__toggle {
  display: none;                      /* на десктопе панель всегда раскрыта */
  padding: var(--sp-4) var(--sp-5);
  font-weight: 700; cursor: pointer;
}
.cat-filter-wrap__toggle::-webkit-details-marker { display: none; }
.cat-filter { padding: var(--sp-5); }
.cat-filter__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-4);
}
.cat-filter__title { font-weight: 700; }
.cat-filter__reset { font-size: var(--fs-caption); }
.cat-filter__group { border: 0; padding: 0; margin: 0 0 var(--sp-5); }
.cat-filter__group legend {
  padding: 0; margin-bottom: var(--sp-3);
  font-size: var(--fs-caption); font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted);
}
.cat-filter__opt {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 6px 0; cursor: pointer;
}
.cat-filter__opt span { flex: 1 1 auto; }
/* Число позиций в срезе — подсказка, а не значение: приглушаем. */
.cat-filter__opt b { color: var(--muted); font-weight: 400; font-size: var(--fs-caption); }
.cat-filter__opt input { accent-color: var(--brand); width: 16px; height: 16px; }


@media (max-width: 1024px) {
  .catalog-layout { grid-template-columns: 240px minmax(0, 1fr); }
}
@media (max-width: 900px) {
  /* minmax(0, 1fr), а не 1fr: колонка «1fr» не уже своего содержимого, а внутри
     лежит панель фильтра с <select>. На экране 320px она распирала раскладку до
     347px и вся страница получала горизонтальную прокрутку. */
  .catalog-layout { grid-template-columns: minmax(0, 1fr); }
  .cat-filter-wrap__toggle { display: block; }   /* появляется кнопка-раскрытие */
}

/* ===========================================================================
   Уведомление о cookie
   Полоса внизу экрана до первого «Принять» (blocks.php → cookie_bar,
   показ и запоминание — main.js). Тёмная, как подвал: это служебное сообщение,
   а не часть контента, и оно не должно спорить с блоками страницы.
   =========================================================================== */
/* Уведомление о cookie — небольшая карточка в углу, а не полоса во всю ширину
: прежняя занимала треть экрана телефона и закрывала
   кнопки первого экрана. Показывается не сразу — main.js выводит её после
   прокрутки на два экрана: до этого человек ещё не начал пользоваться сайтом.
   Угол левый: правый занят кнопкой чата. */








/* На телефоне карточка занимает почти всю ширину, и круг чата ложится на её
   текст и кнопку «Принять». Пока плашка видна, кнопки чата и «наверх» встают
   над ней: высоту карточки главному элементу проставляет main.js. */


/* ===========================================================================
   Юридические документы (/law/*)
   Длинный текст с нумерованными пунктами. Читается редко, но должен читаться
   без усилий: узкая колонка, спокойные интервалы, заметные подзаголовки.
   =========================================================================== */




   /* пояснения в скобках */

/* Плашка «документ не готов»: видна только пока не заполнены реквизиты. */


/* Список документов в разделе «Юридическая информация» */






/* ===========================================================================
   Расширенный калькулятор окупаемости
   Четыре колонки в один ряд на широком мониторе: параметры оборудования,
   параметры эксплуатации, результат и накопленная прибыль по годам. Ниже
   1280px колонки встают попарно, на телефоне — друг под другом.
   =========================================================================== */
/* Колонки калькулятора одной высоты: разная длина подписей делала карточки
   разного роста, и ряд читался неровно. */


/* Колонка результата: тёмная плашка с диагональной штриховкой вместо плоской заливки: плоский чёрный
   читался мрачно. Линии 6% белого, шаг 6px: под текстом
   не видны, на фоне дают фактуру. */















/* Подсказка по наведению и с клавиатуры: у иконки есть tabindex, поэтому
   :focus-within открывает её без мыши. */
.hint {
  position: relative; display: inline-grid; place-items: center;
  width: 1.125rem; height: 1.125rem; margin-left: .25rem; vertical-align: middle;
  border: 1px solid var(--hairline-strong); border-radius: 50%;
  font-size: .6875rem; color: var(--muted); cursor: help;
}
.hint__text {
  position: absolute; bottom: calc(100% + .5rem); left: 50%; transform: translateX(-50%);
  width: 16rem; padding: .625rem .75rem; z-index: 5;
  background: var(--dark-2); color: var(--on-dark); font-size: var(--fs-caption);
  line-height: 1.45; text-align: left; border-radius: 2px; box-shadow: var(--shadow-menu);
  opacity: 0; visibility: hidden; transition: opacity .15s;
}
.hint:hover .hint__text, .hint:focus-within .hint__text { opacity: 1; visibility: visible; }
@media (max-width: 560px) {
  /* у края экрана всплывающая подсказка уезжала за границу */
  .hint__text { left: auto; right: 0; transform: none; width: min(16rem, 70vw); }
}

/* ---- Накопленная прибыль: полосы влево-вправо от оси ---------------------- */







/* Позицию подписи задаёт скрипт: она встаёт за концом полосы, иначе
   перекрывается ею и не читается. */








/* Содержание страницы: якорная навигация по длинному документу.
   Две колонки на широком экране, одна на мобильном — восемь пунктов в столбик
   съедали бы целый экран до первого блока текста. */









/* Содержание виджетом сбоку: на широком экране оно уходит в узкую
   колонку рядом с текстом и едет вместе с прокруткой — второй экран начинается
   сразу с содержательного блока. Ниже 1000px возвращается обычным блоком над
   текстом: колонка в 280px и текст на телефоне рядом не помещаются. */
/* До 1000px обёртка ничего не делает: обычный блок ужимается по экрану сам,
   а сетка на узком экране вытягивала страницу вбок на 7px. */

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


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


/* Смежные услуги: сетка ссылок-карточек внизу страницы услуги. */







/* Изображение с обтеканием справа — переиспользуемый вариант того, что было
   сделано для блока субсидии на главной. Нужен на каждой длинной
   странице под ГАР: сплошной текст без картинок снижает вовлечённость, а
   отдельного компонента под это не было. */





/* Видео объекта в теле страницы: постер до нажатия, подпись под кадром. */




/* Нумерованный список порядка действий — когда шаги важны последовательностью,
   но карточки «дорожной карты» избыточны. */




/* ===========================================================================
   КАРТОЧКА ТОВАРА: СУБСИДИЯ, ДОСТАВКА, ДОКУМЕНТАЦИЯ, ОТЗЫВЫ
   Каждый блок — своя секция с якорем, поэтому первый заголовок в секции
   не должен добавлять верхний отступ поверх отступа самой секции.
   =========================================================================== */




/* Пояснение в рамке: длинная оговорка про подтверждение документами читается
   хуже, если идёт тем же потоком, что и абзацы выше. */



/* Перелинковка списком: ссылки на смежные страницы под блоком. */



/* Логотипы транспортных компаний. Приведены к одной высоте: файлы заказчика
   разного кегля, и без ограничения строка выглядит рваной. */
.carriers {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-5) var(--sp-6);
  margin: var(--sp-4) 0 0; padding: 0; list-style: none;
}
.carriers__item { display: flex; align-items: center; }
.carriers__item img {
  width: auto; height: 28px; max-width: 150px; object-fit: contain;
  filter: grayscale(1); opacity: .75;
}
.carriers__item img:hover { filter: none; opacity: 1; }

/* Файлы к скачиванию. */










/* Обложки документов в ряд: первая страница файла как миниатюра. Пропорции у
   листов разные (презентация 16:9, документы A4), поэтому высота кадра задана,
   а снимок вписывается целиком. */










/* Отзывы. Пустого рейтинга «0.0» здесь нет намеренно: пока отзывов нет, блок
   показывает приглашение, а не ноль. */












@media (max-width: 700px) {
  
  
  .carriers { gap: var(--sp-4) var(--sp-5); }
}

/* Список после абзацев в колонке «Оплата»: без отступа первый пункт прилипает
   к последней строке текста. */



/* Баннер услуги в колонке фильтра каталога.
   Держится на светлой подложке и зелёной кнопке — тёмная плашка в узкой
   колонке спорила бы с шапкой. */











/* ===========================================================================
   БЛОГ: ХАБ И СТАТЬЯ
   Классы статьи названы article__*, а не post__*: post — это карточка статьи
   в ленте на главной, у неё свои размеры заголовка и отступы.
   =========================================================================== */




























/* Вертикальный снимок во всю ширину колонки вырастает на полтора экрана — держим его уже. */






/* Обложка статьи: кадры проекта бывают вертикальными (съёмка станции в рост),
   и без ограничения пропорций такая обложка занимает три экрана. */


/* Список сразу после абзацев: без отступа первый пункт прилипает к последней
   строке текста. Правило общее — раньше оно стояло только для колонок карточки. */
.prose + .points { margin-top: var(--sp-5); }

/* Фото в карточке каталога резалось сверху и снизу.
   Кадр был флексом с aspect-ratio, а картинка внутри — flex-элементом: при
   вертикальном снимке она не сжималась до квадрата и уезжала под overflow.
   Теперь кадр — обычный блок фиксированной высоты, а вписыванием занимается
   сама картинка через object-fit. */
.product__media { display: block; height: 280px; aspect-ratio: auto; }
.product__media img { width: 100%; height: 100%; object-fit: contain; }

/* Вкладки карточки товара. Имитация табов интернет-магазина:
   содержимое остаётся на странице целиком, вкладка — якорь на свой блок.
   Так и человеку понятнее, и текст полностью виден поисковику. */
.tabs {
  display: flex; flex-wrap: wrap; gap: var(--sp-1);
  margin: var(--sp-7) 0 0;
  border-bottom: 1px solid var(--hairline);
}
.tabs__item {
  padding: var(--sp-3) var(--sp-5);
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--muted); text-decoration: none; white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tabs__item:hover { color: var(--body); }
.tabs__item.is-active { color: var(--ink); border-bottom-color: var(--brand); }

@media (max-width: 860px) {
  /* Лентой с прокруткой: восемь вкладок в столбик занимают целый экран. */
  .tabs { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs__item { padding: var(--sp-3) var(--sp-4); }
}

/* Файл документации: иконка с подписью PDF. Подчёркивание при
   наведении — только на названии, хотя кликабельна вся карточка. */






/* «Читайте также» — ссылки на смежные страницы с миниатюрой.
   Заменил простой список: у ссылки без картинки нет якоря для глаза, и такие
   блоки читатель пролистывает. */
/* Разделы каталога: те же карточки, что «Читайте также», но плотнее — их двенадцать. */














/* ===========================================================================
   ТИПОГРАФИКА ТЕКСТОВЫХ БЛОКОВ
   Строка во весь экран читается плохо, но и обрезать её справа нельзя — рядом
   с текстом появляется пустое поле. Поэтому колонка текста ограничена шириной
   узкого контейнера и стоит по центру блока, а таблицы, изображения и листинги
   остаются во всю ширину секции.
   Карточка товара — исключение: там текст идёт в узкой колонке рядом с фото.
   =========================================================================== */
/* Колонка ограничивается целиком, а не по абзацам: тогда заголовки, текст,
   таблицы и картинки идут по одному левому краю. */
.prose,
.article__body {
  max-width: var(--wrap-narrow);
  margin-inline: auto;
  /* Нижнее поле: под текстом обычно идут карточки, таблица или галерея, и без
     него вводный абзац читается как подпись к ним. */
  margin-bottom: var(--sp-6);
}

/* Сетки карточек, колонка рядом с фото товара и карточка выставки живут во всю ширину секции. */
.prose.catalog__text,
.prose.product-page__text,
.prose.event__text {
  max-width: none;
}

/* Раздел каталога с развёрнутым текстом: колонка ограничена, как в статье. */


/* Таблица не обтекает картинку с обтеканием: в узкой колонке её столбцы схлопываются. */


.product-page__text p,
.table-scroll,
.article__table,
.post__table,
.prose .table-scroll,
.prose figure {
  max-width: none;
}

/* Заголовок внутри текстового блока: без верхнего отступа он прилипает к
   предыдущему абзацу — так было на разделах каталога. */
.catalog__text h2,
.catalog__text h3,
.prose h2,
.prose h3,
.article__body h2,
.article__body h3 {
  margin-top: var(--sp-8);
}
.catalog__text h3,
.prose h3,
.article__body h3 { margin-top: var(--sp-6); }

.catalog__text > :first-child,
.prose > :first-child,
.article__body > :first-child { margin-top: 0; }

/* Заголовок карточки живёт не в текстовом потоке: правило выше отодвигало его
   вниз, и обтекающая иконка вставала отдельной строкой над заголовком. */
.catalog__text .card__title,
.prose .card__title,
.article__body .card__title { margin-top: 0; }

/* Текст после блока с цифрами: рамка стоит вплотную к следующему абзацу. */


/* Квиз ужат по ширине: 1180px растягивали плитки в ленту. */
.quiz { max-width: 993px; }

/* Заголовок таблицы сравнения стоит сразу после текста раздела и прилипал к
   последнему абзацу. */


/* Контакты: тот же список фактов, но в две колонки и с обычным начертанием у длинных значений */


/* Форма обращения на странице контактов: три поля в ряд, сообщение во всю ширину. */





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


/* Карточки подразделений завода: строка контакта — иконка и ссылка в одну
   линию, высота строки сбита под размер иконки, чтобы телефоны шли ровным
   столбцом. Заголовок карточки здесь короткий, и резерв в две строки не нужен. */









/* Контакты по подразделениям: компактные рамки; отдел зарядных станций выделен брендовой рамкой, общие контакты завода — отдельной. */









/* Заливки: три отдела — серым, отдел зарядных станций — зелёным с белым текстом; общие контакты завода — без заливки. */





/* Текст кнопки отдела персонала — обычной жирности: в окне шапки, на странице контактов и в подвале. */

/* Окно «Контакты» в шапке: те же заливки блоков. */





/* Подвал: отдел зарядных станций — зелёным блоком, остальные контакты — серым; совместимость на всю ширину под колонками. */







/* Таблица сравнения токов идёт по ширине текстового блока и отделена от него отступом. */


/* Пара снимков с обтеканием: миниатюры открываются общим просмотрщиком. */



/* Две комплектации станции: цены не должны переноситься по цифрам. */


/* Таблица стоит в колонке рядом с фотографией: 752px в 623px не помещались, и
   правый столбец уезжал за край. Ширину задаём долями,
   заголовки переносим по словам — суммы при этом остаются в одну строку. */
/* Доли колонок — только на широком экране. На телефоне таблица по-прежнему
   уезжает в горизонтальную прокрутку обёртки: при фиксированных долях сумма
   «2 200 000 ₽» не помещалась в свои 83px. */



/* Документы позиции на первом экране карточки: выписка из реестра и декларация. */







/* ===== 30. ВОЗДУХ МЕЖДУ СОСЕДНИМИ БЛОКАМИ =====================================
   Текст или заголовок, идущий сразу за сеткой карточек, лентой, списком шагов
   или рамкой с цифрами, прилипал к ним вплотную: у самих блоков нижнего поля
   нет, а верхнее у абзаца съедалось правилом «первый элемент без отступа».
   Заказчик ловил это на боевом сайте по одной странице за раз,
   поэтому правило общее, а не точечное. Проверяется скриптом: он обходит карту
   сайта и ищет соседей с разрывом меньше 16px. */
.grid + .prose,
.grid + .note,
.grid + h2,
.grid + h3,
.grid + .section__head,
.products + .prose,
.products + .note,
.roadmap + .prose,
.roadmap + .article__body,
.roadmap + .note,
.roadmap + h2,
.carriers + .note,
.related-grid + .note,
.gallery + h2,
.list-check + h2,
.prose + .section__head,
.prose + .checklist,
.prose + .roadmap,
.prose.legal + .note,
.stats + .prose,
.stats + .note,
.benefits + .prose,
.benefits + .note,
.table-scroll + .prose { margin-top: var(--sp-7); }

/* Текст сразу под таблицей: у таблицы нижнего поля нет, и абзац вставал
   вплотную к последней линии — читалось как продолжение ячейки.
   Правило общее, а не для конкретной страницы.

   ⚠️ Отступ задан самой обёртке, а не соседу через `+`: под таблицей
   main.js печатает указатель прокрутки `.table-scroll__bar--bottom`, и
   селектор `.table-scroll + p` не срабатывает — соседей разделяет он. */


/* Служебная строка шапки на очень узких экранах: «Санкт-Петербург» вместе с «Контактами» и
   значком Telegram не помещался в 320px и распирал страницу. У строки стоит
   nowrap, поэтому названию города нужен запасной план — обрезка эллипсисом (правило §3.14.4). */
@media (max-width: 400px) {
  
  .city { min-width: 0; flex: 0 1 auto; }
  
  /* Осознанное отклонение от правила «видимый текст не мельче 13px»: в главной строке шапки знак, дескриптор, номер и
     кнопка меню при 13px не помещаются — номер налезает на дескриптор
     (проверено замером: правый край дескриптора 203px при начале контактов на
     190px). На 401px и шире кегль штатный. */
  .header__phone { font-size: var(--fs-caption); }   /* вместо номера теперь слово «Контакты»: занимает вдвое меньше места, штатные 13px помещаются */
  /* Дескриптор ступенью мельче номера: на 360px номер обрезался
     даже при равных 11px — подпись уступает ширину номеру. */
  .logo__text { font-size: 0.625rem; }
}

/* Совсем узкие экраны: дескриптор накладывался на номер даже при 11px (замер на
   320px: край надписи 185px, контакты с 150px). Надпись уступает место номеру —
   знак Elli на месте, а «Электрозарядные станции» есть в первом экране. */
@media (max-width: 340px) {
  .logo__text { display: none; }
}

/* Карточки доводов на светлом фоне: главное в абзаце выделено фирменным
   зелёным. */


/* Крупные значки разъёмов в статье: векторные, поэтому
   увеличение не мылит; насыщенный чёрный вместо серого растра. */





/* Миниатюра-значок (SVG разъёма) в «Читайте также»: вписываем целиком, а не
   обрезаем по кадру — растровые значки 52px растягивались и мылились. */


/* Зарядный хаб на странице дилеров: блок в рамке на ту же ширину и
   сетку, что три карточки объектов ниже — текст в первой колонке, два кадра
   объекта во второй и третьей. */









/* Заголовок страниц темы «НПО «Электромашина»: на 60px длинные названия с юрлицом
   рвались на две-три строки. 40px остаётся крупнее H2 (33px); на телефоне действует общая
   ступень --fs-display, она и так меньше. */


/* Варианты поставок: крупные карточки с фото,
   три в ряд на широком экране. Цифры выделены тем же зелёным, что в тексте страниц. */
/* Флекс, а не сетка: неполный последний ряд встаёт по центру, а не прижимается влево. */








/* Опорный факт карточки прижат к низу: у карточек разной длины текста он стоит на одной линии. */




/* Четыре шага в ряд: у поставки для сети шагов четыре, и в сетке на три последний повисал отдельной строкой. */




/* ===== Служебный раздел /service =====
   Внутренние отчёты для заказчика: закрыты паролем, оформление рабочее. */












/* Оформленные блоки внутри текстовой колонки раздела каталога. Правило «.prose h3 — отступ сверху» отодвигало название шага
   от номера в кружке, а абзац после шагов и цифр прилипал к ним. */




/* Шаги сразу после вводного абзаца (блок агентского договора на /dileram) прилипали к нему. */



/* ===== Отчёт о работах (/report) ===== */

















/* Страница товарного знака: снимок записи реестра слева, сведения справа */





/* Калькулятор лизинга (/lizing): ползунки слева, расчёт справа */






/* Кнопки с готовой ценой стоят на тёмной секции: базовый .btn--outline тёмного цвета на ней не виден */













