/* Дополнения сайта к дизайн-системе (версия — src/sajt/ds.json). Только переменные системы: своих цветов здесь нет — смена
   темы это новая версия tokens.css, страницы при этом не переделываются. */

/* Ловушка для ботов в форме: человек её не видит и не доходит */
.sajt-trap { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }

/* Ошибка отправки заявки: слово под полем, не цвет один */
.sajt-form-error { margin: 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm); background: var(--signal-crit-veil); color: var(--ink); font-size: 14px; line-height: 21px; }
.sajt-form-error[hidden] { display: none; }
/* Страницы ответа заявки без скрипта (src/sajt/otvet.ts): кнопки под ответом. Класс свой: .halo-hero__actions система прячет на телефоне, а там кнопки нужны */
.sajt-otvet__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }

/* Строка согласия в форме. Фраза у галочки — просто подпись: нажатие на неё ставит галочку и со страницы не уводит. «Текст согласия»
   и политика — две отдельные ссылки рядом (в новой вкладке). Вид ссылок остаётся классом системы halo-consent-row__policy, здесь только
   их расположение: в ряд под подписью, с отступом под текстом подписи, при нехватке места — в две строки; поля вокруг — чтобы цель
   нажатия на телефоне была не тоньше 28 px. */
.sajt-consent-links { display: flex; flex-wrap: wrap; column-gap: var(--space-5); margin-left: 32px; }
.sajt-consent-links .halo-consent-row__policy { margin-left: 0; padding-block: var(--space-1); }

/* Кнопка-ссылка, у которой пока нет адреса (профиль на Яндекс Услугах): подпись видна, нажать нельзя */
.sajt-nolink { cursor: default; opacity: .7; }

/* Нумерованный список документов (согласие на обработку данных) */
.sajt-ol { list-style: none; counter-reset: sajt-ol; display: grid; gap: var(--space-3); margin: 0; padding: 0; }
.sajt-ol > li { counter-increment: sajt-ol; font-size: 17px; line-height: 28px; color: var(--ink-soft); max-width: 68ch; }
.sajt-ol > li::before { content: counter(sajt-ol) ". "; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.sajt-ol strong { font-weight: 400; color: var(--ink); }
.halo-article__body strong { font-weight: 400; color: var(--ink); }

/* Документы: первый раздел без заголовка занимает всю ширину */
.sajt-legal > .halo-article__body:only-child { grid-column: 1 / -1; }

/* Углы экрана. От 1400 px спидометр прокрутки и карточка cookie дизайн-системы стоят в одном правом нижнем углу (оба —
   right/bottom: space-5) и лежат друг на друге. Систему не правим: пока карточка показана, спидометр встаёт левее неё
   (ширина карточки 360 px + зазор), как только её закрыли — возвращается в угол. Кнопку жучка эта пара не задевает: она слева. */
@media (min-width: 1400px) {
  .halo-cookie:not([hidden]) ~ .halo-speedo--dock { translate: calc(-1 * (360px + var(--space-4))) 0; }
}
@media (min-width: 1400px) and (prefers-reduced-motion: no-preference) {
  .halo-speedo--dock { transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-glide) var(--ease-expo), translate var(--dur-base) var(--ease-out); }
}
/* Сдвиг спидометра — свойством translate, а не right (02.11, 09:17: «тряска» при прокрутке): плашка cookie появляется после 80 px прокрутки, и спидометр уезжал влево на 376 px,
   анимируя right — свойство вёрстки: каждый кадр пересчёт раскладки, браузер считает его сдвигами вёрстки (layout-shift) посреди прокрутки. translate — на компоновщике, вёрстка не
   двигается, вид тот же (то же расстояние и время). Число км/ч в центре спидометра меняется с прокруткой (1, 2, 3 знака), и его коробка то расширялась, то сужалась — тоже сдвиг вёрстки
   на каждом переходе разряда: коробка держит три знака (самое большое число — 260), цифры у системы табличные, текст по центру. */
.halo-speedo--dock .halo-speedo__num { min-inline-size: 3ch; text-align: center; }

/* Главная: строка адреса, маршрута и часов лежит на фото героя (на компьютере — на светлой части кузова, на телефоне — на нижней
   кромке кадра) и читалась хуже нормы: контраст в худшем месте 1,8:1 (норма 4,5:1). Под строкой — глубокое стекло системы: текст
   поверх фото ставится только на halo-glass--deep (README дизайн-системы, «Изображения»). Систему не правим — свойства те же,
   что у стекла, значения — её переменные. */
.halo-hero--home .halo-hero__meta { width: fit-content; max-width: 100%; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: var(--glass-deep); -webkit-backdrop-filter: blur(var(--blur-glass)); backdrop-filter: blur(var(--blur-glass)); box-shadow: inset 0 0 0 1px var(--glass-edge); }

/* ── Телефон ─────────────────────────────────────────────────────────────────────────────────────────────────────────
   Три места, где дизайн-система на узком экране ломает страницу или прячет слова (находки независимой проверки 27.10). */

/* 1. Срок работы в строке прайса. Система прячет колонку «Срок» от 600 px и уже (display: none) — на телефоне пропадали сроки всех
   46 строк, хотя слова на телефоне не прячут (README системы: «ничего не прячем, только сворачиваем и перестраиваем»). Срок встаёт второй строкой
   под названием, цена — справа. */
@media (max-width: 600px) {
  .halo-prices:not(.halo-prices--two) tbody tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-3); border-bottom: 1px solid var(--line); }
  .halo-prices:not(.halo-prices--two) tbody th, .halo-prices:not(.halo-prices--two) tbody td { border-bottom: 0; }
  .halo-prices:not(.halo-prices--two) tbody th { grid-column: 1; grid-row: 1; padding-bottom: 0; }
  .halo-prices:not(.halo-prices--two) .halo-prices__time { display: block; grid-column: 1; grid-row: 2; width: auto; text-align: left !important; padding: 0 0 var(--space-3) !important; font-size: 13px; line-height: 18px; white-space: normal; }
  .halo-prices:not(.halo-prices--two) .halo-prices__price { grid-column: 2; grid-row: 1 / span 2; align-self: center; width: auto; padding-block: var(--space-3); white-space: nowrap; }
}

/* 2. Подпись кнопки длиннее экрана («Записаться на диагностику», «Открыть профиль на Яндекс Исполнителях»): кнопка системы не переносит
   текст (white-space: nowrap) и на 320–360 px выталкивает страницу вбок. Узкий экран — кнопка переносит подпись и не шире окна. */
@media (max-width: 420px) {
  .halo-hero__actions > .halo-btn, .halo-cta__actions > .halo-btn, .halo-cta__links > .halo-btn, .halo-msg > .halo-btn { max-width: 100%; height: auto; min-height: var(--h); padding-block: var(--space-2); padding-inline: var(--space-5); white-space: normal; text-align: center; }
  .halo-hero__actions > .halo-msg, .halo-cta__actions > .halo-msg { max-width: 100%; }
}
/* крупный номер в блоке связи (32 px, неразрывный) шире 240 px внутренней ширины панели на 320 px; карточка рейтинга на «Отзывах» с датчиком 260 px — шире окна */
@media (max-width: 380px) {
  .halo-cta__phones a { font-size: clamp(22px, 8vw, 32px); }
  .halo-trust--solo .halo-speedo { --size: min(260px, calc(100vw - 96px)) !important; }
}
/* нижняя панель: на 320 px номер, «Написать» и «Маршрут» не помещались в три колонки (правая уходила за край на 5 px) */
@media (max-width: 340px) {
  .halo-bar { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 1fr); gap: 4px; padding-inline: 6px; }
  .halo-bar__btn { padding-inline: 2px; }
  .halo-bar__btn--call { gap: 4px; font-size: 13px; }
  .halo-bar__btn--call .halo-icon { display: none; }
}

/* 3. Меню «Написать мастеру» в теле страницы (шапка, герой, блок «Как записаться») на телефоне: система открывает его под кнопкой, и оно
   уезжало влево за край (−26 px на 390) и под нижнюю панель с плашкой cookie — касание «Заявка на сайте» попадало в «Настроить». Узкий
   экран — листом над нижней панелью, как меню самой панели; положение по высоте скрипт сайта выставляет при открытии (sajt.js). */
@media (max-width: 900px) {
  .halo-msg:not(.halo-bar__msg) .halo-msg__menu { position: fixed; left: 8px; right: 8px; top: auto; bottom: calc(var(--bar-h) + 12px); width: auto; }
  /* колонка блока связи на телефоне — просто 1fr (минимум = самое широкое содержимое): на 320 px она растягивалась до 283 px при 240 внутренней
     ширины панели и выталкивала страницу вбок на 3 px; minmax(0, 1fr) даёт ей сжиматься, а длинному содержимому — переноситься */
  .halo-cta { grid-template-columns: minmax(0, 1fr); }
  /* backdrop-filter делает предка опорным для position: fixed — лист в блоке «Как записаться» привязался бы к панели, а не к окну */
  .halo-cta.halo-glass { -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* 4. Номер телефона в тексте страницы (контакты, политика) в файлах штаба написан с обычными пробелами — на узком экране он рвался
   посреди номера на две строки; слова не трогаем, запрещаем перенос внутри ссылки */
a.halo-tnum[href^="tel:"] { white-space: nowrap; }

/* Правки по замечаниям владельца 28.10 — устройство каждого правила в SAJT.md, «Правки по замечаниям владельца». Своих цветов нет. */

/* Свечение не двоится (10:06): система делает --mx/--my наследуемыми, и блик формы внутри стекла рисовался от координат стекла — свои значения каждому */
.halo-glass, .halo-alcantara, .halo-btn, [data-halo-sheen] { --mx: 30%; --my: -10%; }

/* Плашка первого экрана по ширине содержимого (09:53) */
.halo-hero--home .halo-hero__meta { justify-self: start; }

/* Метка «Работаем до 19:00» (09:28): значок «дышит» у открытого, у закрытого стоит. Так же «дышит» значок у каждой плашки системы — «Берём только BMW и MINI» на
   страницах работ (14:16: «все такие плашки должны унаследовать анимацию с главного экрана»); стоит он только у закрытой метки режима работы. Движение
   в системе гасится само при prefers-reduced-motion (её общее правило «Меньше движения»). */
@keyframes sajt-breathe { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
.halo-only::before { animation: sajt-breathe 2.4s var(--ease-breathe) infinite; }
.halo-only.sajt-work.is-closed::before { animation: none; opacity: .45; box-shadow: none; }

/* Телефон на компьютере (09:29, 09:51): где есть мышь — кнопка «Записаться на сервис» вместо «Позвонить», у номеров подчёркивание и значок «копировать» справа,
   дубль кнопки к форме спрятан. Вид задан условием, а не классом от скрипта: страница не перестраивается после загрузки. */
.sajt-call-book { display: none; }
@media (hover: hover) and (pointer: fine) {
  a[href^="tel:"]:not([data-sajt-call]) { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); }
  a[href^="tel:"]:not([data-sajt-call]):hover { text-decoration-color: currentColor; }
  a[href^="tel:"]:not([data-sajt-call])::after {
    content: ""; display: inline-block; flex: none; width: .72em; height: .72em; margin-left: .4em; vertical-align: -.04em; background: currentColor; opacity: .6;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='14' height='14' x='8' y='8' rx='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='14' height='14' x='8' y='8' rx='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/svg%3E") center / contain no-repeat;
  }
  a[href^="tel:"]:not([data-sajt-call]):hover::after { opacity: 1; }
  /* в шапке значок копирования — последний элемент самой ссылки (строка flex: расстояние до номера 6 px при зазоре системы space-2; селектор длиннее общего
     правила значка выше, иначе оно оставило бы ему .4em), а не наложенный
     на зазор: так он занимает своё место и ни на какой ширине не заходит под «Написать мастеру» (14:14, «наезд элементов»). Ширину шапки он прибавляет
     (порог бургера — ниже, @container halo-header). */
  .halo-header a.halo-header__phone[href^="tel:"]::after { margin: 0 0 0 calc(6px - var(--space-2)); }
  .halo-cta__phones a::after { width: .5em; height: .5em; margin-left: .3em; vertical-align: .08em; }
  .halo-bar__btn--call { text-decoration: none !important; }
  .halo-bar__btn--call::after { display: none !important; }
  .sajt-call-tel { display: none; }
  .sajt-call-book { display: inline-flex; }
  .halo-hero__actions > .sajt-call-book ~ a[href="#zayavka"], .halo-cta__actions > .sajt-call-book ~ a[href="#zayavka"], .halo-hero__actions > .sajt-call-book ~ a[href="#napisat"] { display: none; }
}

/* Шапка в окне 961–1120 px (ноутбук, браузер на пол-экрана; находка рецензента 28.10): меню, номер и «Написать мастеру» вместе требуют 1082 px, а со значком
   копирования, который стоит в строке у номера (замечание 14:14), — 1107 px; бургер система включает только ниже 960 — шапка выходила за окно, и страница
   прокручивалась вбок. Бургер включается раньше, при ширине шапки до 1120 px (запас 13 px на шрифт и полосу прокрутки; до 30.10 было 1100): те же две строки,
   что у системы на 960 px. Систему не правим; порог системе предложен пачкой дизайнеру. С 31.10 порог — 70em, а не 1120px: размер шрифта шапки 16 px, и при обычном тексте это те же 1120 px,
   а когда текст крупнее (увеличение «только текста» на компьютере: Safari, Firefox) шрифт шапки растёт и порог вместе с ним — меню уходит в бургер раньше, а не выходит за край окна (находка независимого
   рецензента 31.10: при ×1,15 на 1200 px шапка уезжала на 56 px, пока пункты не имели права переноситься). То же у двух правил ниже. */
@container halo-header (max-width: 70em) {
  .halo-nav { display: none; }
  .halo-header__burger { display: inline-flex; }
}

/* Пункты меню шапки — в одну строку на любой ширине, где меню развёрнуто (находка рецензента 30.10, № 19: «Примеры работ» уходила на две строки на 1130–1165 px; было и до кнопки
   «Заказать звонок»). Знак, меню, номер и «Заказать звонок» вместе требуют 1159 px, а порог бургера — 1120: в промежутке пункты сжимались по ширине, и двусловный переносился.
   Теперь пункт не переносится никогда, а в этом промежутке (1121–1180 px) отступы поуже — зазор между знаком, меню и номером 32 → 20 px, поле у пункта 12 → 8 px (подчёркивание —
   по тексту, а не шире него): шапке нужно 1095 px, запас у порога 25 px на шрифт и полосу прокрутки. Выше 1180 px всё как было. Границы — в em (70,01em = 1121 px, 73,75em = 1180 px при 16 px). */
.halo-nav__link { white-space: nowrap; }
@container halo-header (min-width: 70.01em) and (max-width: 73.75em) {
  .halo-header__inner { gap: var(--space-5); }
  .halo-nav__link { padding-inline: var(--space-2); }
  .halo-nav__link::after { left: var(--space-2); right: var(--space-2); }
}

/* Тост после копирования и подсказка у номера («Скопировать номер», 14:20) — одна плашка стекла системы; обе рядом с номером, не под курсором, касаний не ловят */
.sajt-toast, .sajt-tip {
  position: fixed; left: 0; top: 0; z-index: var(--z-modal); display: flex; align-items: center; gap: var(--space-2); max-width: min(360px, calc(100vw - 16px));
  padding: 8px 14px 8px 10px; border-radius: var(--radius-sm); font-size: 13px; line-height: 18px; font-weight: 450; color: var(--ink); pointer-events: none;
  background: linear-gradient(180deg, var(--glass-top), transparent 70%), var(--glass-deep);
  -webkit-backdrop-filter: blur(var(--blur-glass)); backdrop-filter: blur(var(--blur-glass));
  box-shadow: inset 0 0 0 1px var(--glass-edge), var(--shadow-float);
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-expo), visibility 0s linear var(--dur-base);
}
.sajt-toast.is-on, .sajt-tip.is-on { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.sajt-tip { white-space: nowrap; }
.sajt-tip svg { flex: none; width: 15px; height: 15px; color: var(--ice); }
.sajt-toast.is-fail::before { display: none; }
.sajt-toast::before { content: ""; flex: none; width: 16px; height: 16px; background: var(--signal-ok); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat; }

/* Плавная прокрутка (Lenis, 09:54): правила из его lenis.css */
html.lenis, html.lenis body { height: auto; }
.lenis [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* Тряска прокрутки, второй заход (02.11, 14:40: «как будто 10 фпс», «больше всего в Услугах, Общих услугах, Мотоциклах», «застревание … от подвала»). Замер — настоящее окно Chrome на LG 4K
   (1920×963, плотность 2), загрузка GPU из ioreg («Device Utilization»): прокрутка главной съедала 65–82 % видеокарты, запаса не было — чужая нагрузка на GPU или нагрев машины (у владельца
   Mac без вентилятора) роняли кадры до 30 и ниже. Две причины, обе стекло системы (backdrop-filter): живое — на экране до 16 плашек, каждая размывает фон позади себя на каждом кадре прокрутки
   (16–18 пунктов из 66); и бегущее — точка 6×6 px «дышит» внутри стекла блока «Как записаться», пока она на экране, размытие всего блока пересчитывается 60 раз в секунду (70 % GPU у страницы,
   которая просто стоит на этом месте), а «дрейф» атмосферы секции «О сервисе» двигает слой 1905×546 px (40 %). Систему не правим — переопределения сайта, устройство и числа в SAJT.md.
   Живое стекло плашек (шапка, «хиро», карточки, кнопки, спидометр) стоит всегда, на ходу и в покое одинаково: 02.11 его снимали на время движения страницы, а 03.11 по слову владельца («мигание матового
   стекла убираем, пусть будет как раньше — слишком грубое решение») это снято, от движения страницы не зависит ни один стиль сайта. Остались две правки ниже — они одинаковы и в покое, и на ходу. */
/* 1. Блок «Как записаться» лежит на плоском фоне: размывать позади него нечего (кадры до/после — средняя разница 0,3 из 255), а точка внутри «дышит» всегда */
.halo-cta.halo-glass { -webkit-backdrop-filter: none; backdrop-filter: none; }
/* 2. Атмосфера не плывёт: сдвиг ±1,5 % за 30 с глазом не виден, а слой двигался на каждом кадре, пока секция на экране (на паузу не годится: слой остаётся, цена та же; сброс при
   остановке прокрутки дёргал бы свет) */
.halo-atmos::before { animation: none; }

/* Рейтинг (09:49, 09:50): «Обновлено …» мельче прежней даты и блок на 6 px выше — строка не цепляется за цифры шкалы «0» и «5» */
.sajt-upd { font-variant-numeric: tabular-nums; }
.halo-speedo__meta .sajt-upd { font-size: 11px; letter-spacing: 0; white-space: nowrap; }
.halo-speedo[data-halo-speedo="rating"] .halo-speedo__read { margin-top: 4%; }

/* Адрес в скобках не рвётся (плашка карты, подвал) */
.sajt-nowrap { white-space: nowrap; }

/* ── Видео «Сервис изнутри» на главной (решение штаба № 39; разметка — src/sajt/video.ts, поведение — sajt.js, video()) ─────────────────────────────────────────────────────
   Размер блока задаёт система (.halo-video: aspect-ratio 16 / 9) — до загрузки файла ничего не сдвигается. Постер лежит под роликом; ролик выплывает поверх, когда пошёл кадр (is-playing).
   Затемнение постера под кнопкой («Смотреть видео») — как в системе, но только пока кнопка на виду (is-still): пока ролик идёт или ждёт, постер — как есть. */
.sajt-video > img, .sajt-video__el { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.sajt-video > img { filter: none; }
.sajt-video.is-still > img { filter: brightness(.7) saturate(.85); }
.sajt-video__el { opacity: 0; transition: opacity .35s ease; background: transparent; }
.sajt-video.is-playing .sajt-video__el { opacity: 1; }
.halo-video__play[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .sajt-video__el { transition: none; } }

/* ── Замечания владельца 28.10 вечером и 30.10 (задание 2026-10-30-sajt-zamechaniya-30-10-verstka-foto-podval) ───────────────────────────────────────── */

/* Фото «приподнимаются» под курсором (28.10, 20:49: «Фото должны реагировать на наведение "приподнятием" — это про все страницы»): каждое фото страницы — кадр первого
   экрана работы, галереи, «Контактов», «О сервисе». Исключены: фон первого экрана главной (под текстом и кнопками — он не карточка), фото внутри ссылки-карточки (у карточки
   услуги приподнимается вся карточка, система: a.halo-service:hover) и с 02.11 кадр здания в блоке записи (.sajt-cta-photo; 09:14: «Фото внизу сделать статичным»: кадр
   неподвижен ни под курсором, ни при прокрутке, когда он уходит из-под неподвижного указателя). Только где есть мышь, и без движения при prefers-reduced-motion. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  figure.halo-photo:not(.halo-service__art):not(.sajt-cta-photo):not(a *) { transition: transform var(--dur-glide) var(--ease-out), box-shadow var(--dur-glide) var(--ease-out); }
  figure.halo-photo:not(.halo-service__art):not(.sajt-cta-photo):not(a *):hover { transform: translateY(-6px); box-shadow: var(--edge-light), var(--shadow-deep), 0 0 28px -6px var(--ice-glow); }
}

/* Окно «Настройки cookie» (30.10, 10:09: «При нажатии на настройки куки почему то перекидывать на хиро экран»): .halo-glass системы задаёт position: relative и перебивает
   position: fixed, которое браузер даёт модальному окну, — окно вставало в поток страницы, а фокус на нём прокручивал страницу к началу. Окно возвращается в фиксированное
   положение (оно по центру окна браузера, страница не двигается); ссылку-якорь, которая его открывает, гасит скрипт сайта (sajt.js, toggles). Система не правится — пачка дизайнеру. */
dialog.halo-dialog { position: fixed; }

/* Карта «Контактов» (30.10, 10:27: «Нужна карта )»): статичная картинка со своего адреса (src/sajt/mapa.ts) — точка сервиса в её центре, поэтому булавка на 50 %/50 %
   при любой обрезке по центру; линии-заглушка системы (::before) под картинкой не нужны; подпись OpenStreetMap — правый верхний угол. В одну колонку (до 900 px) у карты нет
   соседа, по которому тянуться, — своя высота. */
.sajt-map { min-height: 340px; background: var(--night-300); }
.sajt-map::before { display: none; }
.sajt-map__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.sajt-map .halo-map__pin { left: 50%; top: 50%; }
.sajt-map__attr { z-index: 2; color: var(--ink-soft); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); text-shadow: 0 0 8px var(--night-000); }
.sajt-map__attr:hover { color: var(--ink); text-decoration-color: currentColor; }
.sajt-map__addr { font-weight: 400; font-size: 17px; }
.sajt-map__route { justify-self: start; }
@media (max-width: 900px) { .sajt-map { min-height: 380px; } }

/* Плитки цен и кнопки под ними — одна сетка (30.10, 09:51 и 09:56: «первая кнопка в длину верхней плашки с ценой, вторая пара это не повторяет», «очень плохая
   композиция … зависит от текста на кнопке»). Столько колонок, сколько плиток (--n ставит страница: 2 или 3); кнопки стоят в колонках плиток и тянутся на ширину колонки,
   поэтому длина подписи ширину не меняет: подпись длиннее колонки переносится. На компьютере кнопок две: при трёх плитках «Записаться …» встаёт под первыми двумя (две колонки),
   «Написать мастеру» — под третьей; при двух плитках — по одной под каждой. На планшете три кнопки (звонок, «Написать», «Записаться»): под тремя плитками — по одной, под двумя —
   третья на всю ширину. Узкая колонка текста (меньше трёх плиток по 185 px — столько нужно цене «от 15 200 ₽») — две колонки: третья плитка встаёт вторым рядом, как у системы (auto-fit). Телефон (до 600 px): кнопки спрятаны системой, плитки — её двумя колонками. */
.halo-hero--split .halo-hero__copy { container: sajt-copy / inline-size; }
@media (min-width: 601px) {
  .halo-hero--split .halo-facts--work, .halo-hero--split .halo-hero__actions { display: grid; grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); gap: var(--space-3); align-items: stretch; }
  .halo-hero--split .halo-hero__actions > * { min-width: 0; }
  .halo-hero--split .halo-hero__actions > .halo-btn, .halo-hero--split .halo-hero__actions > .halo-msg, .halo-hero--split .halo-hero__actions > .halo-msg > .halo-btn { width: 100%; }
  .halo-hero--split .halo-hero__actions > .halo-btn, .halo-hero--split .halo-hero__actions > .halo-msg > .halo-btn { height: auto; min-height: var(--h); padding-block: var(--space-2); padding-inline: var(--space-3); white-space: normal; text-align: center; text-wrap: balance; }
  .halo-hero--split .halo-hero__actions > .halo-msg { display: flex; }
  .halo-hero--split .halo-hero__actions.sajt-n3 > .sajt-call-book { grid-column: span 2; }
  .halo-hero--split .halo-hero__actions.sajt-n2 > a[href="#zayavka"]:last-child, .halo-hero--split .halo-hero__actions.sajt-n2 > a[href="#napisat"]:last-child { grid-column: 1 / -1; }
}
@container sajt-copy (max-width: 578px) {
  .halo-hero--split .halo-facts--work.sajt-n3, .halo-hero--split .halo-hero__actions.sajt-n3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .halo-hero--split .halo-hero__actions.sajt-n3 > .sajt-call-book { grid-column: span 1; }
}

/* Кейс: фото колонкой справа от рассказа (30.10, 10:52: «Сюда бы фото BMW X3 E83») остаётся на виду, пока читают рассказ; в одну колонку (до 900 px) идёт после рассказа */
@media (min-width: 901px) { .sajt-case-side { position: sticky; top: calc(var(--header-h, 72px) + var(--space-6)); } }

/* Подвал (30.10): названия мессенджеров — ссылки (10:20 28.10 «Нет ссылок на мессенджеры»), «Разработчик:» со значком Telegram — неброско, строкой подвала */
.halo-footer__col p.sajt-msg-row a { display: inline; line-height: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); }
.halo-footer__col p.sajt-msg-row a:hover { color: var(--ink); text-decoration-color: currentColor; }
.halo-footer__legal a.sajt-dev { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--ink-muted); }
.halo-footer__legal a.sajt-dev:hover { color: var(--ink-soft); }
.sajt-dev .halo-icon { width: 14px; height: 14px; }

/* Блок записи без пустоты (30.10, 10:51: «слева номер и кнопки, под ними пусто, справа высокая форма»): левая колонка тянется на высоту формы, и кадр здания сервиса (то, куда
   приедет человек) занимает остаток — его высота сама равна разности высот, поэтому колонки уравновешены на любой ширине окна и при любой высоте формы. Форму не трогаем.
   В одну колонку (до 900 px) кадр спрятан: колонок нет, а страница и так длинная. */
.halo-cta { align-items: stretch; }
.halo-cta > .halo-form-panel { align-self: start; }
/* «Позвоните или напишите» (03.11, формы выключены до уведомления в Роскомнадзор — src/sajt/shell.ts, contactPanel): та же карточка, что и форма записи (halo-form-panel), на её месте — номер
   крупно, три мессенджера кнопками в ряд, часы работы. Своих цветов нет — переменные системы; кнопки переносятся по ширине карточки (при крупном тексте — столбиком), номер не рвётся. */
.sajt-write { display: grid; gap: var(--space-4); align-content: start; }
.sajt-write > * { margin: 0; min-width: 0; }
.sajt-write .halo-cta__phones { margin: 0; }
.sajt-write .halo-cta__phones a { font-size: clamp(18px, 6.2vw, 32px); }   /* на 320–390 px весь номер в одну строку (при 8vw он рвался по группам после «997-») */
/* Кнопки «Записаться …» ведут к #napisat; у «Контактов», политики и согласия это секция с тесными полями, и без отступа карточка уезжала под шапку (форма держала отступ сама, .halo-form-panel) */
.halo-section--tight[id="napisat"] { scroll-margin-top: var(--sajt-header-h, var(--header-h, 72px)); }
.sajt-write__lead, .sajt-write__hours { color: var(--ink-muted); }
.sajt-write__msgs { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.sajt-write__msgs > .halo-btn { flex: 1 1 8.5em; min-width: 0; max-width: 100%; justify-content: center; }
.halo-cta__main { display: flex; flex-direction: column; align-content: normal; }
.sajt-cta-photo { flex: 1 1 auto; min-height: 150px; }
.sajt-cta-photo img { position: absolute; inset: 0; }
@media (max-width: 900px) { .sajt-cta-photo { display: none; } }

/* ── Дневные замечания владельца 28.10 (задание 2026-10-30-ispravleniya-zamechaniya-28-10-dnyom) ───────────────────────────────────────────────── */

/* «Цены»: плитки групп стоят по рядам (14:06: «левые и правые плитки пляшут друг относительно друга»). Система кладёт их колонками (columns: 2) — у левой
   и у правой своя высота, верхние края расходились. Сетка в две колонки и столько рядов, сколько нужно (--price-rows ставит страница: групп пополам с округлением
   вверх): плитки одного ряда — на одной верхней линии и одной высоты; слева и справа те же группы в том же порядке, что были в колонках (сначала левая колонка
   сверху вниз, потом правая). До 1080 px система и сама ставит одну колонку. */
.halo-price-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: repeat(var(--price-rows, 5), auto); grid-auto-flow: column; gap: var(--space-6); columns: auto; align-items: stretch; }
.halo-price-cols > * { margin-bottom: 0; break-inside: auto; }
@media (max-width: 1080px) { .halo-price-cols { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-auto-flow: row; } }

/* Срок работы — отдельная заметная метка со знаком «≈» (14:23, 14:26: «само по себе время шум — и не выделяется никак»; «значок равно-примерно + 1ч/45м/2ч/2ч30м»).
   Слова — из текста штаба; вид — чип системы halo-chip--info (лёд на ледяной вуали), здесь только цифры одной ширины. */
.sajt-term { font-variant-numeric: tabular-nums; }
/* в плитке: ниже названия (у системы название — order 2, примечание — 3) */
.halo-facts .sajt-term { order: 4; justify-self: start; margin-top: var(--space-1); }
/* в таблице: колонка «Срок» системы (120 px с отступом справа 32) тесна для метки с «на ось» */
.halo-prices .halo-prices__time { width: 148px; padding-right: var(--space-6) !important; }

/* Плитки со сроком светятся под курсором, как стеклянные плитки сайта (14:24): ту же точку ведёт скрипт системы (data-halo-sheen), блик — тот же, что у .halo-glass */
.halo-facts--work > div { position: relative; isolation: isolate; transition: --mx var(--dur-glide) var(--ease-out), --my var(--dur-glide) var(--ease-out); }
.halo-facts--work > div::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; border-radius: inherit;
  background: radial-gradient(520px circle at var(--mx) var(--my), var(--glass-sheen), transparent 62%);
}

/* ── Отзывы с Карт (задание 2026-10-30-sajt-otzyvy-s-kart; слово владельца 30.10: «на каждой карточке должна быть дата и источник») ───────────────────────────────── */

/* Строка над списком на «Отзывах»: «Отзывы с Яндекс Карт · обновлены 30.10.2026, 14:05 (МСК)» — статичная, из сервера */
.sajt-otzyvy__upd { margin: 0 0 var(--space-5); font-size: 13px; line-height: 20px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }

/* Подпись отзыва «имя · дата · оценка · Яндекс Карты». Точка — в тексте разметки, здесь она рисуется и прячется: ряд сдвинут влево на поле под точку (16 px), у каждого пункта
   поле слева, а figcaption срезает всё, что вышло за левый край. Точка первого пункта каждой строки уходит за край — при переносе на узком экране «·» не повисает ни в конце
   строки, ни в начале. Ссылку и звёзды поле не трогает: оно у обёртки пункта, поэтому рамка фокуса охватывает только саму ссылку. Карточки одного ряда выровнены по низу:
   подпись у нижнего края, пустое место — между текстом и подписью (у системы текст и подпись стоят вплотную, а у короткого отзыва рядом с длинным пустота оставалась под подписью). */
.sajt-review { align-content: space-between; }
.sajt-review__foot { display: block; overflow: hidden; line-height: 20px; padding-bottom: 4px; margin-bottom: -4px; }
.sajt-review__row { display: flex; flex-wrap: wrap; margin-left: -16px; row-gap: 2px; }
.sajt-review__row > * { position: relative; padding-left: 16px; }
.sajt-review__dot { position: absolute; left: 6px; top: 0; }
.sajt-review__part { white-space: nowrap; }
.sajt-review__date { font-variant-numeric: tabular-nums; }
.sajt-review__stars { font-size: 12px; letter-spacing: .12em; }
.sajt-review__off { opacity: .3; text-shadow: none; }
.sajt-review__src { margin-left: 0; color: var(--ink-soft); text-decoration: underline; text-decoration-color: var(--line-control); text-underline-offset: 3px; }
.sajt-review__src:hover { color: var(--ice-bright); text-decoration-color: var(--ice); }

/* ── Заявки: звонок из шапки, телефон, VIN, подсказки (30.10, задание 2026-10-30-zayavki-forma-zvonok-baza-obrashcheniy; решения № 37 и № 38) ─────────────────────────────── */

/* «Заказать звонок» в шапке — на всех страницах и ширинах. Система прячет всё .halo-msg шапки уже при 760 px (@container halo-header), а эта кнопка не .halo-msg:
   на телефоне она делит строку с логотипом и бургером. Ниже 440 px значок в кнопке снят, логотип и поля уже, ниже 340 px — ещё чуть уже: логотип, кнопка и бургер
   помещаются в окно до 320 px, страница вбок не едет. Слова кнопки — штаба, они остаются целиком. */
.sajt-callreq { white-space: nowrap; flex: none; }
@container halo-header (max-width: 600px) {
  .halo-header__aside { gap: var(--space-2); }
  .sajt-callreq { padding-inline: var(--space-3); gap: var(--space-2); }
}
/* 601–740 px: номер, «Заказать звонок» и бургер вместе требуют 684 px, а система прячет номер только ниже 600 — шапка выходила за окно, страница ехала вбок (пойман проверкой
   кнопок под плитками цен на 601 px). Номер в этом промежутке уходит из шапки: он остаётся в нижней панели телефона и в блоках страницы. */
@container halo-header (max-width: 740px) { .halo-header__phone { display: none; } }
@container halo-header (max-width: 440px) {
  .halo-header__inner { gap: var(--space-2); }
  .halo-header .halo-wordmark { --halo-wm-size: 11px; }
  .halo-header__aside { gap: 6px; }
  .sajt-callreq { padding-inline: 12px; gap: 0; font-size: 13px; }
  .sajt-callreq .halo-icon { display: none; }
  .halo-header__burger { width: 40px; }
}
/* Ступень «ещё чуть уже» начинается с 358 px, а не с 340: знак 11 px, кнопка 13 px и бургер вместе требуют 354 px, и на 341–353 px кнопка сжималась до двух строк (теперь — одна строка). */
@container halo-header (max-width: 358px) {
  .halo-header .halo-wordmark { --halo-wm-size: 9px; }
  .sajt-callreq { padding-inline: 10px; font-size: 12px; }
}
/* Тесно — два ряда, а не наезд (находка рецензента 30.10, № 18): при увеличении текста на +50…+100 % в окне 360 px знак (его слова — живой текст) вырастал с 136 до 203–271 px и не сжимался,
   кнопка переходила на две строки, а бургер уезжал за край окна (на +100 % — целиком, страница прокручивалась вбок на 160 px). Пока всё помещается в одну строку, шапка прежняя (72 px). Не помещается —
   действия («Заказать звонок», бургер) переходят вторым рядом под знак, к правому краю: шапка растёт в высоту, а не в ширину; кнопка при этом в одну строку. Какой бы ни был текст и ширина, ряд
   сам решает, куда встать, — ширина окна и размер шрифта скриптом не меряются. Высота шапки вместо жёсткой — не ниже системной 72 px; два ряда занимают 90–110 px, меню под ней начинается с 96 px. */
.halo-header { height: auto; min-height: var(--header-h); }
@container halo-header (max-width: 70em) {
  .halo-header__inner { flex-wrap: wrap; row-gap: var(--space-2); padding-block: var(--space-2); }
  .halo-wordmark { max-width: 100%; }
}

/* Ошибка номера — слова штаба под полем (разметка: .halo-field__hint в подписи поля; рамка и цвет — halo-field--error системы) */
.halo-field__hint[hidden] { display: none; }

/* VIN: под полем слева подсказка штаба («17 знаков — в СТС, ПТС и под лобовым стеклом» — она видна и пока вводят, в поле она бы пропала), справа счётчик «N из 17» */
.sajt-vin__foot { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4); }
.sajt-vin__foot .halo-field__hint { display: block; }
.sajt-vin__foot .halo-vin__count { flex: none; margin-left: auto; }
/* VIN не обязателен и неполный не мешает отправке: красным у неполного остаётся счётчик, рамка поля — обычная (система красила и её) */
.halo-vin.is-invalid .halo-input { border-color: var(--line-control); }

/* Окно «Заказать звонок»: один заголовок, одно поле, согласие, кнопка. После отправки в окне стоит ответ штаба вместо поля. */
.sajt-call { width: min(440px, calc(100vw - 32px)); }
.sajt-call .halo-form { gap: var(--space-4); }
.sajt-call .halo-form__foot { justify-content: flex-start; gap: var(--space-3); }
.sajt-call .halo-form__ok { padding: var(--space-5); gap: var(--space-4); }
/* На телефоне окно стоит у верхнего края, а не по центру: экранная клавиатура занимает низ окна, и кнопка «Перезвоните мне» по центру оказалась бы под ней */
@media (max-width: 600px) { .sajt-call { margin: var(--space-4) auto auto; } }

/* Подсказки в полях «Модель и кузов» и «Имя»: плашка стекла системы под полем (над ним, если снизу не помещается). Строка — не ниже 44 px для пальца. */
.sajt-sg { position: fixed; z-index: var(--z-menu); max-height: min(340px, 50vh); overflow-y: auto; overscroll-behavior: contain; padding: var(--space-2); border-radius: var(--radius-md); }
.sajt-sg[hidden] { display: none; }
.sajt-sg__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.sajt-sg__list li { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); min-height: 44px; padding: 10px var(--space-3); border-radius: var(--radius-sm); font-size: 15px; line-height: 22px; color: var(--ink); cursor: pointer; }
.sajt-sg__list li:hover, .sajt-sg__list li[aria-selected="true"] { background: color-mix(in srgb, var(--ice) 18%, transparent); }
.sajt-sg__hint { flex: none; font-size: 13px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }

/* ── Правки по независимой рецензии фронта 30.10 ─────────────────────────────────────────────────────────────────────────────────────────────────────── */

/* VIN: система ставит полю 15 px, а Safari на iPhone приближает страницу при фокусе в поле меньше 16 px */
.halo-vin__row .halo-input { font-size: 16px; }

/* Отправка идёт — кнопка серая и с кружком: форма ждёт подпись времени до трёх секунд (сервер считает слишком быструю отправку ботом), и без знака это выглядело бы зависанием */
.halo-form[aria-busy="true"] [type="submit"] { cursor: progress; }
.halo-form[aria-busy="true"] [type="submit"]::after { content: ""; flex: none; width: 14px; height: 14px; margin-left: var(--space-2); border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: sajt-spin .8s linear infinite; }
@keyframes sajt-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .halo-form[aria-busy="true"] [type="submit"]::after { animation: none; border-right-color: currentColor; opacity: .6; } }

/* Подсказки: в режиме высокой контрастности активная строка видна рамкой, а не только цветом подложки */
@media (forced-colors: active) { .sajt-sg__list li[aria-selected="true"] { outline: 2px solid Highlight; outline-offset: -2px; } }

/* Тост «Номер скопирован» и подсказка «Скопировать номер» показываются в верхнем слое (popover), чтобы быть видными над открытым окном звонка: свои положение и поля вместо стилей popover по умолчанию */
.sajt-toast[popover], .sajt-tip[popover] { inset: auto; margin: 0; border: 0; overflow: visible; }

/* Крупный шрифт в телефоне (системная настройка 150–200 %): подпись кнопки «Заказать звонок» в шапке может перейти на вторую строку, а не вытолкнуть бургер за край окна */
@container halo-header (max-width: 440px) {
  .sajt-callreq { flex: 0 1 auto; min-width: 0; height: auto; min-height: var(--h); padding-block: 4px; white-space: normal; text-align: center; line-height: 1.15; }
}

/* «Контакты»: кадр здания рядом с картой на 901–960 px выходил за свою колонку (на 13–23 px за окно — страница ехала вбок). У кадра систему задано отношение сторон 4 / 3, а высоту ему
   даёт ряд (она равна карте): ширину же при «auto» берёт из высоты (340 × 4/3 = 453 px при колонке 416). Ширина по колонке — высота та же, кадр обрезается по краю, как и выше 1024 px
   (находка независимого рецензента фронта 30.10; та же прокрутка вбок была и до задания — коммит 7251d3a). */
.halo-split > .halo-gate { width: 100%; min-width: 0; }

/* ── Крупный текст: страницы не едут вбок (31.10, задание 2026-10-31z-stranicy-pri-krupnom-tekste; находки отчёта 2026-10-30z-shapka-i-zhuchok-poverh-okon, § 3) ──────────────────────
   Увеличение «только текста» (Safari на iPhone «aA», Firefox, Samsung Internet; +50…+100 %) раздувает слова и поля, а система кладёт одну колонку как «1fr» (= minmax(auto, 1fr)): колонка
   не уже самого длинного слова или самой широкой строки без переноса, и вместе с ней уезжает вся страница. Здесь колонка может сжаться (minmax(0, …)), слово длиннее строки переносится,
   плашки и нижняя панель встают в несколько строк. Обычный текст эти правила не меняют: колонка и так шире содержимого. Правила — для телефона и планшета (до 900 px: там сайт живёт с крупным текстом); окна шире — как были.
   Систему не правим — список для пачки дизайнеру в отчёте. */
@media (max-width: 900px) {
  body { overflow-wrap: break-word; }
  /* таблица цен: слово, которое лишь на пару px шире ячейки (на 320 px «кондиционера» — 110,5 при 108 px), не рвётся посреди слова, как не рвалось до сих пор */
  .halo-prices th, .halo-prices td { overflow-wrap: normal; }
  /* одна колонка не по самому широкому содержимому: подвал, сетки, блоки «слева-справа» и «Контактов», форма заявки, отзыв */
  .halo-form, .halo-article, .halo-article__body, .halo-hero__copy, .halo-cta__phones, .halo-review, .sajt-ol { grid-template-columns: minmax(0, 1fr); }
  /* блоки первого экрана и рассказа собраны со своим style="display: grid" и без класса (src/sajt/pages.ts, render.ts, otvet.ts): колонка у них тоже одна и тоже не по самому длинному слову заголовка */
  [style*="display: grid"] { grid-template-columns: minmax(0, 1fr); }
  .halo-split, .halo-trust, .halo-article__sec, .halo-footer__brand, .halo-hero--split .halo-hero__inner { grid-template-columns: minmax(0, 1fr); }
  .halo-footer__cols, .halo-links--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* поле ввода шире панели (телефон и VIN на ×1,5 до 12 px, на ×2 до 85 px): своя ширина поля (size = 20 знаков) не держит колонку */
  .halo-input, .halo-select select, .halo-textarea { min-width: 0; max-width: 100%; }
  /* кнопка с подписью длиннее окна («Отправить заявку» на ×2): подпись в две строки, кнопка растёт по высоте, а не за край; при обычном тексте высота кнопки та же (36 / 46 / 56 px) */
  .halo-btn:not(.halo-btn--icon):not(.halo-header *) { max-width: 100%; height: auto; min-height: var(--h); padding-block: var(--space-2); white-space: normal; text-align: center; }
  /* «Отправить заявку» на 360 px при обычном тексте нужны 236,7 px, а колонка формы 232: кнопка выступала из панели на 4,7 px (в поле панели) и подпись не переносилась. Отрицательное поле справа держит эту же картину —
     кнопка не сжимается и подпись остаётся в одной строке; на узкой колонке и на крупном тексте она сжимается, подпись переносится, и не дальше чем на эти 6 px за колонку */
  .halo-form__foot > .halo-btn { margin-right: -6px; }
  /* плашки с подписью в одну строку («Берём только BMW и MINI», «Откроемся в пн в 10:00») — подпись переносится, плашка растёт по высоте; высота плашки при обычном тексте та же (28, 32 и 40 px) */
  .halo-chip, .halo-only { white-space: normal; height: auto; }
  .halo-chip { min-height: 28px; padding-block: 6px; }
  .halo-only { min-height: 32px; padding-block: 8px; }
  .halo-only--lg { min-height: 40px; }
  /* у плашек-ссылок подвала система задаёт строке 30 px (.halo-footer__col a): надпись стояла на 1 px ниже середины плашки в 28 px — отступы 7 + 16 + 5 держат те же 28 px и то же место надписи */
  .halo-footer__links .halo-chip { line-height: 16px; padding-block: 7px 5px; }
}
@media (max-width: 600px) {
  .halo-footer__cols, .halo-grid--2, .halo-grid--3, .halo-grid--4, .halo-grid--5, .halo-links--3, .halo-checks--cols, .halo-form__row, .halo-service--wide { grid-template-columns: minmax(0, 1fr); }
}
/* знак подвала с лампами: уже окна, если надпись в одну строку не помещается, — надпись встаёт в две строки между лампами. Совсем тесно (колонка уже 12 кеглей: +75…+100 % на 360 px) —
   зазоры и разрядка уже, строки надписи вплотную, иначе «SERVICE» рвалось бы посреди слова */
@media (max-width: 900px) {
  .halo-footer__brand { container: sajt-brand / inline-size; }
  .halo-stern { max-width: 100%; }
  .halo-stern__name { white-space: normal; min-width: 0; }
}
@container sajt-brand (max-width: 12em) {
  .halo-stern { gap: .5em; }
  .halo-stern__name { letter-spacing: .15em; margin-right: -.15em; line-height: 1; }
}
/* меню телефона: колонка не по самому длинному слову, а пункты — выше окна на крупном тексте (при ×2 их 2400 px) — прокручиваются внутри меню, а не уходят за нижний край; верхний отступ — от настоящей высоты шапки
   (--sajt-header-h ставит sajt.js: на крупном тексте шапка в два ряда, 93–101 px, а токен системы --header-h — 72 px, первые 5 px первого пункта оказывались под шапкой) */
.halo-menu { grid-template-columns: minmax(0, 1fr); overflow-y: auto; overscroll-behavior: contain; padding-top: calc(var(--sajt-header-h, var(--header-h)) + var(--space-6)); padding-bottom: calc(var(--bar-h) + var(--space-6)); }
.halo-form-panel { scroll-margin-top: calc(var(--sajt-header-h, var(--header-h, 72px)) + var(--space-6)); }
/* нижняя панель на телефоне: «Позвонить», «Написать», «Маршрут» в одну строку, пока помещаются подписями целиком; не помещаются — звонок на всю ширину, две другие кнопки под ним */
/* Ширина — те же доли 2 : 1 : 1 (на 340 px и уже 1,6 : 1 : 1), что были у сетки: доля задана основой flex, а не ростом от нуля (у ссылки «Маршрут» есть поля, у обёртки «Написать» нет, и рост от нуля делил бы
   не поровну). Поля у номера сняты (он по центру — вид тот же), чтобы запас до переноса был не в 1,5 px, а в 13: пока подписи помещаются, строка одна и размеры прежние. */
@media (max-width: 900px) {
  .halo-bar { display: flex; flex-wrap: wrap; }
  .halo-bar > .halo-bar__cookie { flex: 1 0 100%; flex-wrap: wrap; }
  .halo-bar > .halo-bar__btn--call { flex: 2 1 calc((100% - 12px) / 2); min-width: max-content; padding-inline: 0; }
  .halo-bar > .halo-bar__msg, .halo-bar > .halo-bar__btn:not(.halo-bar__btn--call) { flex: 1 1 calc((100% - 12px) / 4); min-width: min-content; }
}
@media (max-width: 340px) {
  .halo-bar > .halo-bar__btn--call { flex-basis: calc((100% - 8px) * 1.6 / 3.6); }
  .halo-bar > .halo-bar__msg, .halo-bar > .halo-bar__btn:not(.halo-bar__btn--call) { flex-basis: calc((100% - 8px) / 3.6); }
}
/* плитки цен в первом экране работы: в две колонки цена с «от» и «₽» («от 15 200 ₽» — 134 px при 118 px внутри плитки на 360 px, она и сейчас заходит в поле плитки) на крупном тексте уже не помещается и режется краем первого экрана
   (там overflow: clip) — тогда по одной в ряд. Порог — 20 кеглей колонки: на 360 px при обычном тексте колонка 20,5 кегля (две колонки, как были), на 390 и шире — больше */
@container sajt-copy (max-width: 20em) {
  .halo-hero--split .halo-facts--work, .halo-hero--split .halo-facts--work.sajt-n3 { grid-template-columns: minmax(0, 1fr); }
}

/* ── Крупный текст, часть вторая (1.11, задание 2026-10-31z-zum-teksta-plitki-nomer-metki; находки отчёта 2026-10-31z-stranicy-pri-krupnom-tekste, § 2–3) ─────────────────────────────────────────────
   Класс html.sajt-krupno и число --sajt-k ставит sajt.js (krupno(): замер, во сколько раз увеличен текст). Не по ширине колонки в em: при увеличении «только текста» (iPhone «aA») колонка не растёт, и запрос в em выше не срабатывает.
   Почти всё ниже — только под этим классом: при обычном тексте страницы те же, что были (геометрия всех элементов совпала со старой), и переносы слов те же. Без класса (нет скрипта) — как до задания.
   Систему не правим — список для пачки дизайнеру в отчёте. */

/* Пробная надпись замера увеличения (sajt.js, krupno()): слово рисуется здесь, а не лежит в DOM страницы (поиск и чтение с экрана его не видят); размер шрифта ей ставит скрипт.
   Слово то же, что STR в sajt.js (по нему считается ширина на холсте): разойдутся — отношение ширин поедет, поэтому менять только вместе. */
.sajt-zamer::before { content: "mmmmmmmmmm"; }

/* Номер-ссылка в тексте — строчный блок: <wbr> между группами цифр (shell.ts) рвёт номер и при white-space: nowrap (Chrome), если ссылка строчная и стоит в конце строки, — а как блок она переходит на новую строку целиком,
   как и прежде, и рвётся по группам, только когда не помещается в строку сама (шире колонки). Подвал — блок системы (display: block) и так. */
a.halo-tnum[href^="tel:"]:not(.halo-footer__col > a) { display: inline-block; max-width: 100%; }

/* Метка на фото «Контактов» («Вывеска «BMW Service»») привязана правым краем (82 % кадра и ещё 12 px), а не левым краем со сдвигом на свою ширину: длинная подпись шла за левый край кадра и срезалась его рамкой
   (вместе с pages.ts: right вместо left, top — здесь). Подпись переносится в строки, а не режется; при обычном тексте она в одну строку, и место то же. Крупный текст: метка вместе с чертой вдвое выше места над точкой
   (19 % кадра — 47 px на 360 px, а метка при ×1,15 уже 75 px) и уходила за верхний край кадра — тогда она сидит у верхнего края кадра, черта под ней. Это правило — пока вид метки не назначен (нет скрипта или он не отработал):
   при крупном тексте вид ставит sajt.js (при обычном и без скрипта класса нет, и это правило не действует), его правила — в конце блока метки ниже. */
.halo-gate__mark--end { top: 19%; transform: translateY(-100%); }
.halo-gate__mark span { white-space: normal; text-align: center; }
html.sajt-krupno .halo-gate__mark--end { top: 8px; transform: none; }

/* Метка на низком кадре при обычном тексте (1.11, задание 2026-11-01-metka-vyveska-v-kadre-na-telefone; находка отчёта 2026-10-31z-zum-teksta-plitki-nomer-metki, § 2, п. 5).
   Метка с чертой — 70 px (таблетка 30, зазор 6, черта 34), и стоит она над точкой на 19 % высоты кадра: кадру ниже 370 px места не хватает, и верх таблетки уходил за край кадра, где его режет рамка.
   Так было на телефоне (кадр 216–287 px на 320–414 px, на 360 — 246: видна нижняя кромка таблетки) и в окнах 901–1070 px, где колонки в два ряда, а кадр ниже 370 px (у карты 340).
   Кадр — контейнер по высоте. Ниже 378 px таблетка прижата к верху (2 px), а черта занимает остаток до той же точки (19 %) — короче, но показывает туда же. Ниже 300 px (телефон, окно до 430 px) черты по остатку
   меньше 19 px, и таблетка встаёт слева от черты: черта выходит из её правого конца и идёт вниз к вывеске. Выше 378 px всё как было (768 и 1440 px те же). Крупный текст (класс от sajt.js) — своё правило выше,
   его не трогаем. Движки без контейнерных запросов (Safari до 16, Chrome до 105) видят прежнюю метку. Точка черты — над плашкой «BMW Service» на снимке (x 69–96 %, верх 21,6 % при пропорции 4 : 3). */
.halo-gate { container-type: size; container-name: gate; }
@container gate (max-height: 378px) {
  html:not(.sajt-krupno) .halo-gate__mark--end { top: 2px; transform: none; height: calc(19cqh - 2px); grid-template-rows: auto minmax(0, 1fr); }
  html:not(.sajt-krupno) .halo-gate__mark--end::after { height: auto; }
}
@container gate (max-height: 299px) {
  /* 15 px — половина таблетки (30 px): черта выходит из её правого конца на середине высоты. Черта короче (20–40 px), и по системному затуханию до нуля глаз видит от неё первые 10–15 px — конец оставляем наполовину яркий */
  html:not(.sajt-krupno) .halo-gate__mark--end { top: 4px; height: calc(19cqh - 4px); grid-template: minmax(0, 1fr) / auto auto; gap: 0; }
  html:not(.sajt-krupno) .halo-gate__mark--end span { align-self: start; }
  html:not(.sajt-krupno) .halo-gate__mark--end::after { margin-top: 15px; background: linear-gradient(180deg, var(--ice-bright), color-mix(in srgb, var(--ice-bright) 50%, transparent)); }
}

/* Метка при крупном тексте (1.11, задание 2026-11-01zz-metka-pri-krupnom-tekste-na-vyvesku; находка отчёта 2026-11-01-metka-vyveska-v-kadre-na-telefone, § 4, п. 1) и подпись фото
   (задание 2026-11-01zzzzz-metka-ne-zakryvaet-podpis-foto; находка отчёта 2026-11-01zz-metka-pri-krupnom-tekste-na-vyvesku, § 3, пп. 2 и 5: метка закрывала подпись фото).
   Таблетка растёт вместе с текстом (кегль, число строк), а черта была 34 px от верха кадра на 8 px: низ метки уходил на 83–132 px и черта упиралась в окна и ворота под вывеской.
   Теперь точка черты, как при обычном тексте, — на 19 % кадра, над плашкой «BMW Service». Места под черту хватает не везде и не всегда, и сравнивает его скрипт, а не CSS (sajt.js, metka(): замер таблетки и кадра),
   он ставит кадру вид метки в data-sajt-metka — первый из трёх, где всё сходится:
     stopka  — таблетка над чертой, как при обычном тексте на высоком кадре: метка стоит так, что её низ (точка) на 19 % кадра, а черта — сколько осталось от 34 px (скрипт берёт этот вид, если черта ≥ 17,5 px);
     flazhok — таблетка слева от черты, черта идёт от середины таблетки вниз до той же точки (псевдоэлемент самой таблетки: 50 % её высоты считается по любой высоте); скрипт берёт этот вид, если черта ≥ 17,5 px
               и таблетка кончается выше плашки (иначе она закрыла бы вывеску);
     bez-cherty — черты нет совсем, таблетка у верха кадра; если и так закрывала бы плашку или не лезла в кадр — bez-cherty-levo: правым краем левее плашки (--sajt-vyveska-l — левый край плашки в кадре, ставит скрипт);
     bez-podpisi — и левее плашки таблетка не помещается в кадр (телефон 320 px на ×3,25 и крупнее) или легла бы на подпись фото (×2 на 320 px): метка не показывается, те же слова стоят в подписи фото (figcaption).
   Без скрипта класса sajt-krupno нет вовсе (его ставит sajt.js) — работают правила обычного текста выше; правило крупного текста без вида (выше) достижимо, только пока скрипт не успел назначить вид (кадр нулевого размера и т. п.).
   Точка черты и плашка — те же 19 % и 21,6 %, что в проверке 21 (SIGN) и в sajt.js. */
html.sajt-krupno .halo-gate[data-sajt-metka="stopka"] .halo-gate__mark--end { top: 2px; height: calc(.19 * var(--sajt-kadr) - 2px); transform: none; grid-template-rows: auto minmax(0, 34px); align-content: end; }
html.sajt-krupno .halo-gate[data-sajt-metka="stopka"] .halo-gate__mark--end::after { height: auto; }
html.sajt-krupno .halo-gate[data-sajt-metka="flazhok"] .halo-gate__mark--end { top: 4px; transform: none; }
html.sajt-krupno .halo-gate[data-sajt-metka="flazhok"] .halo-gate__mark--end::after { display: none; }
html.sajt-krupno .halo-gate[data-sajt-metka="flazhok"] .halo-gate__mark--end span { position: relative; margin-right: 13px; }
html.sajt-krupno .halo-gate[data-sajt-metka="flazhok"] .halo-gate__mark--end span::after {
  content: ""; position: absolute; left: 100%; top: 50%; width: 2px; height: calc(.19 * var(--sajt-kadr) - 4px - 50%);
  background: linear-gradient(180deg, var(--ice-bright), color-mix(in srgb, var(--ice-bright) 50%, transparent)); box-shadow: 0 0 10px var(--ice-glow);
}
html.sajt-krupno .halo-gate[data-sajt-metka^="bez-cherty"] .halo-gate__mark--end { top: 4px; transform: none; }
html.sajt-krupno .halo-gate[data-sajt-metka^="bez-cherty"] .halo-gate__mark--end::after { display: none; }
html.sajt-krupno .halo-gate[data-sajt-metka="bez-podpisi"] .halo-gate__mark--end { display: none; }
/* right у метки — в разметке (pages.ts, style), поэтому здесь !important */
html.sajt-krupno .halo-gate[data-sajt-metka="bez-cherty-levo"] .halo-gate__mark--end { left: 4px; right: calc(100% - var(--sajt-vyveska-l, 69.3%) + 6px) !important; }

/* Подпись фото на «Контактах» при крупном тексте. Подпись — figcaption системы: лежит на кадре у нижнего края (left/right 16, bottom 12) и растёт вверх вместе с текстом, а кадр 4 : 3 остаётся прежним.
   Читается подпись фото (те же слова, что в метке, и ещё адрес), поэтому метке приходится уступать ей место (sajt.js, metka(): вид метки не ложится на подпись, нет места — метки нет). Но подпись может не поместиться
   на кадре вовсе: ×3 и крупнее на телефоне — 6–9 строк против кадра 216–287 px, рамка кадра срезала бы её сверху, а плашка «BMW Service» оказалась бы под текстом. Тогда скрипт ставит кадру
   data-sajt-podpis="nizhe", и подпись стоит под снимком: фигура выше кадра на высоту подписи, кадр — сам снимок 4 : 3, метка и плашка считаются по нему. Пока подписи на кадре есть место, всё как у системы.
   Высота кадра для черты метки — --sajt-kadr: на кадре (фигура — контейнер по высоте) это 100cqh, под снимком фигура контейнер только по ширине, и кадр — 3/4 её ширины (75cqw). */
html.sajt-krupno .halo-gate { --sajt-kadr: 100cqh; }
html.sajt-krupno .halo-gate[data-sajt-podpis="nizhe"] { --sajt-kadr: 75cqw; aspect-ratio: auto !important; container-type: inline-size; }   /* aspect-ratio 4 / 3 стоит в разметке (pages.ts, style) — отсюда !important */
html.sajt-krupno .halo-gate[data-sajt-podpis="nizhe"] > img { height: auto; aspect-ratio: 4 / 3; }
html.sajt-krupno .halo-gate[data-sajt-podpis="nizhe"]::after { bottom: auto; height: auto; aspect-ratio: 4 / 3; }   /* затемнение системы — на кадре, а не на подписи под ним */
html.sajt-krupno .halo-gate[data-sajt-podpis="nizhe"] > .halo-photo__cap { position: relative; left: auto; right: auto; bottom: auto; padding: var(--space-3) var(--space-4) var(--space-4); text-shadow: none; }

@media (max-width: 900px) {
  /* Слово, которое не помещается в строку, переносится с дефисом, как в книге (lang=ru у страницы стоит; нет словаря у движка — по-прежнему рвётся без дефиса; Firefox не переносит по слогам слова с заглавной буквы).
     Номер телефона и адрес в скобках по слогам не рвутся. Окна шире 900 px — как были. */
  html.sajt-krupno body { -webkit-hyphens: auto; hyphens: auto; }
  html.sajt-krupno a[href^="tel:"], html.sajt-krupno .sajt-nowrap { -webkit-hyphens: manual; hyphens: manual; }
  /* Номер телефона: в разметке между группами цифр стоит <wbr> (shell.ts: PHONE_H, phoneText), и номер, которому не хватило строки, переходит на следующую по группам, не посреди группы. Ссылка в тексте — строчный блок (выше),
     в подвале — блок колонки; при крупном тексте она переносится по группам, когда шире колонки. Баланс строк даёт «+7 953 / 997-50-75», а не «+7 953 997- / 50-75». */
  html.sajt-krupno a.halo-tnum[href^="tel:"] { white-space: normal; text-wrap: balance; }
  html.sajt-krupno .halo-cta__phones a { text-wrap: balance; }
  /* адрес в скобках («(Восточный мост)») на плашке карты и в подвале: скобка не отрывается от адреса, пока помещается; шире строки — переносится внутри, а не режется рамкой плашки */
  html.sajt-krupno .sajt-nowrap { display: inline-block; max-width: 100%; white-space: normal; }
  /* тело карточек услуг и кейсов — сетка из одной колонки «auto»: она росла по самому длинному слову заголовка («Диагностика» на ×2 — 278 px при 250 внутри карточки) и срезалась краем карточки */
  .halo-service__body, .halo-case__body { grid-template-columns: minmax(0, 1fr); }
  /* подпись отзыва: часть «· сайт сервиса, 2025» целой уходит на новую строку, а шире подписи — переносится внутри; на ×2 и 320 px она не помещалась и резалась краем подписи */
  html.sajt-krupno .sajt-review__part { white-space: normal; max-width: 100%; }
  /* плитки цен первого экрана работы: сколько колонок помещается при нынешнем размере текста. Число колонок даёт мера плитки — 154 px (до 600 px: цена «от 15 200 ₽» 134 px и 20 px поля) × --sajt-k;
     запрос в em выше работает там, где колонка растёт вместе с текстом, а в «только тексте» не работает — плитки режутся краем первого экрана (там overflow: clip) */
  html.sajt-krupno .halo-hero--split .halo-facts--work, html.sajt-krupno .halo-hero--split .halo-facts--work.sajt-n3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(var(--sajt-k, 1) * 154px)), 1fr)); }
}
@media (max-width: 600px) {
  /* таблица цен в две колонки («Цены»): колонка цены у системы фиксированная (104–136 px), а цена с «от» и «₽» не переносится и на ×2 шире ячейки — выходила за правый край окна на 320 и 340 px.
     Строка — одна колонка: название, под ним цена (как у таблицы со сроком выше) */
  html.sajt-krupno .halo-prices--two tbody tr:not(.halo-prices__group) { display: grid; grid-template-columns: minmax(0, 1fr); border-bottom: 1px solid var(--line); }
  html.sajt-krupno .halo-prices--two tbody tr:not(.halo-prices__group) > * { border-bottom: 0; }
  html.sajt-krupno .halo-prices--two tbody tr:not(.halo-prices__group) > th { padding-bottom: 0; }
  html.sajt-krupno .halo-prices--two .halo-prices__price { width: auto; text-align: left !important; }
}
@media (min-width: 601px) and (max-width: 900px) {
  /* альбомный телефон и планшет: цена крупнее (32 px, «от 15 200 ₽» — 150 px) — мера плитки 174 px. Строка рейтинга «Контактов» шире окна уже на ×1,5: части переносятся на новую строку целыми (до 600 px это делает система),
     скругление 18 px — половина высоты строки в 36 px, то есть та же «таблетка», пока строка одна */
  html.sajt-krupno .halo-hero--split .halo-facts--work, html.sajt-krupno .halo-hero--split .halo-facts--work.sajt-n3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(var(--sajt-k, 1) * 174px)), 1fr)); }
  html.sajt-krupno .halo-rating { flex-wrap: wrap; max-width: 100%; row-gap: 2px; border-radius: min(var(--radius-full), 18px); }
}

/* ── Замечания владельца 02.11 (09:14–09:30; задание 2026-11-02-zamechaniya-02-11-chipy-zhuchok-skroll) ───────────────────────────────────────────────── */

/* Блок записи (#napisat — на каждой странице, где он стоит) без света, бегущего за курсором (09:14: «Убрать светлечка который двигается за курсором — блок от этого
   кажется слишком перегруженым эффектами»). Таких света в блоке два, оба рисует система одним приёмом (скрипт ведёт --mx/--my): антиблик стекла блока (.halo-glass::after,
   круг 520 px) и «ворс» алькантары формы (.halo-alcantara::before, круг 380 px). Фон остаётся тем же, без пятна: свойства не трогаем, гасим только само пятно. Блик кнопок —
   отклик кнопки на наведение, он общий у всех кнопок сайта и остаётся. Свечение плиток цен на первом экране (14:24 28.10) остаётся — убрано только у блока записи. */
.halo-cta.halo-glass::after { background: none; }
.halo-form-panel.halo-alcantara::before { background: none; }   /* карточка формы — везде, где стоит: в блоке записи и отдельно («Контакты», «Политика», «Согласие»; слово владельца 12:31: «убрать "светлячок за курсором" … на всех страницах») */

/* Срок работы — чип одного размера везде (09:19, 09:20, 09:23, 09:29: «чипы разного размера», «свистопляска размеров чипов»). Ширина не по тексту, а общая: по самому длинному
   сроку («от 3 дней» — 87 px при 13 px) с запасом, в em — чтобы росла вместе с текстом; текст по центру. Высоту (28 px) и вид задаёт система. Срок длиннее общей ширины
   растёт сам (min-, а не фиксированная), а не вылезает за чип. Одинаково в плитках первого экрана и в таблицах цен (.sajt-term — единственная разметка срока, pages.ts, term()). */
.sajt-term { box-sizing: border-box; min-inline-size: 7em; justify-content: center; text-align: center; }
/* Крупный текст (html.sajt-krupno): колонка срока в таблице (148 px) и плитки считаются в px и с текстом не растут, а 7em растёт — чип ×2 наезжал на название и цену (находка рецензента, настоящий
   Firefox 159 «Масштаб → только текст» ×2, 360 px и 1024 px). Одинаковый размер нужен при обычном тексте; при крупном чип такой, какой по тексту, как было до 02.11. */
html.sajt-krupno .sajt-term { min-inline-size: 0; }

/* Плитки цен первого экрана: чип срока стоит на одной высоте во всём ряду плиток, сколько бы строк ни занимало название (09:19: «у первой плитки название в две строки, у
   соседних — в одну, чипы на разной высоте»). Плитки ряда равны по высоте (сетка), чип прижат к низу плитки: последняя строка плитки забирает свободную высоту, остальные
   (цена, название, примечание) стоят сверху как были. Название и чип разделяют те же 8 px (4 зазора + 4 пустой третьей строки, а с примечанием — полем чипа). */
.halo-facts--work > div:has(> .sajt-term) { grid-template-rows: auto auto auto 1fr; }
.halo-facts--work > div > .sajt-term { grid-row: 4; align-self: end; margin-top: 0; }
.halo-facts--work > div > .halo-facts__note ~ .sajt-term { margin-top: var(--space-1); }

/* Подвал: «Разработчик:» со значком — по центру строки, на всех ширинах (09:15: «В середину»). Отдельная строка под юридической и ссылками во всю ширину подвала, подпись
   посередине: середина строки не зависит ни от ширины окна, ни от длины реквизитов и ссылок слева и справа. */
.halo-footer__legal > .sajt-legal__dev { flex: 0 0 100%; justify-content: center; }
