/* ── СЛОЙ 4: СТРАНИЦЫ ───────────────────────────────────────────────────
   Всё, что живёт на одной странице: герой и «живой остров» районов на
   главной, шапка и колонка фильтров на аренде, секции карточки объекта,
   страничные героя «О компании» и «Контакты».

   Этот слой подключается последним и потому перебивает компоненты при
   равной специфичности.

   Порядок слоёв и таблица точек перелома — в шапке tokens.css. */


/* ── Поисковая планка в герое главной ─────────────────────────────────
   Переехало из утилит разметки (рефакторинг 11.09): на самой планке было
   пятнадцать утилит, восемь из них адаптивные, плюс три одинаковые ячейки,
   три подписи, два разделителя и два контрола.

   На широком экране планка наезжает на низ героя (absolute, -2.25rem), на
   узком просто идёт следом. Значения из сборки один в один. */
[data-role="hero-search"] {
    position: relative;
    width: 100%;
    margin-top: 12px;
    border-radius: 20px;
    padding: 8px;
    background: var(--surface);
    box-shadow: var(--sh-card);
}

@media (min-width: 768px) {
    [data-role="hero-search"] {
        position: absolute;
        bottom: -36px;
        left: 50%;
        translate: -50% 0;
        width: calc(100% - 32px);
        max-width: var(--container-5xl);
        margin-top: 0;
        box-shadow: var(--sh-modal);
    }
}

/* Ряд ячеек: на узком экране в столбец, на широком в строку. */
.hs-row {
    display: flex;
    flex-direction: column;
}

@media (min-width: 768px) {
    .hs-row {
        flex-direction: row;
        align-items: stretch;
    }
}

/* Ячейка планки: подпись и контрол под ней. Их три — район, гости, даты. */
.hs-cell {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 2px;
    padding-inline: 16px;
    padding-block: 10px;
}

.hs-cap {
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    letter-spacing: 0;
    font-weight: var(--font-weight-medium);
    color: var(--fg-muted);
}

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

   Утилита outline-none намеренно ОСТАЛАСЬ в разметке. Первый заход перенёс её
   сюда как outline-style: none — и селект потерял видимую обводку фокуса.
   Причина в порядке: фирменный фокус задаёт сборка через :focus-visible, и
   слоевая утилита ему проигрывала, а правило из pages.css, идущего последним,
   уже выигрывает. Гасить фокус с клавиатуры нельзя, поэтому утилита остаётся
   там, где была. */
.hs-control {
    width: 100%;
    background: transparent;
    color: var(--fg);
    cursor: pointer;
}

/* Подпись в поле дат планки. Было утилитой placeholder:text-fg-subtle: из
   трёх контролов планки текстовый только он. */
.hs-control::placeholder {
    color: var(--fg-subtle);
}

/* Кнопка поиска: на узком экране своя высота, от планшета тянется по высоте
   планки. Было утилитой md:h-auto, которая рядом с .btn проиграла бы:
   правила компонента безслойные. */
@media (min-width: 768px) {
    .hs-submit {
        height: auto;
    }
}

/* Разделитель между ячейками: на узком экране линия сверху, на широком слева. */
.hs-sep {
    border-top: 1px solid var(--border);
}

@media (min-width: 768px) {
    .hs-sep {
        border-top-width: 0;
        border-left: 1px solid var(--border);
    }
}

/* В колонке каталога календарь двумя месяцами выезжает вправо поверх выдачи
   (мокап автора 07.09). Колонка скроллится сама (overflow-y) и обрезала бы
   его, поэтому попап позиционируется от окна: top/left ставит site.js по
   координатам поля и двигает за скроллом. */
.filters-rail .rp-pop {
    position: fixed;
    right: auto;
    width: 540px;
    max-width: calc(100vw - 32px);
    z-index: 40;
}

/* ── календарь дат ────────────────────────────────────────────────────── */

.rp-pop {
    position: absolute;
    z-index: 30;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    padding: 12px;
    border: 1px solid var(--border-strong, #d4d4d8);
    border-radius: 8px;
    background: var(--surface, #fff);
    box-shadow: 0 12px 28px rgba(0, 0, 0, .18);
}

.rp-pop[hidden] { display: none; }

/* Календарь в поиск-планке главной: ячейка «Даты» узкая, а .rp-pop по
   умолчанию растягивается по обёртке (left/right:0) — два месяца не влезали.
   Даём попапу собственную ширину; на узких экранах — не шире вьюпорта.

   Прижат к правому краю самой планки, а не ячейки (замечание автора 04.09:
   «месяца съехали»). Попап на 34rem, привязанный к левому краю ячейки «Даты»,
   торчал за правый край планки на ~110px, а на ноутбуках до 1200px — и за край
   экрана. Обёртку ячейки делаем static, и точкой отсчёта становится сама
   планка (у формы есть relative): правые края попапа и планки совпадают, два
   месяца ложатся под ячейки «Гостей» и «Дат». На телефоне планка на всю ширину,
   попап открывается под ней целиком, а не поверх кнопки «Найти». */
[data-role="hero-search"] .rp {
    position: static;
}

[data-role="hero-search"] .rp-pop {
    left: auto;
    right: 0;
    width: min(544px, calc(100vw - 40px));
}

/* Календарь в сайдбаре карточки объекта: на всю ширину карточки (правка автора
   04.09). По умолчанию попап растягивается по обёртке полей дат, то есть по
   внутренней ширине карточки, и два месяца стояли тесно, а по бокам оставались
   поля в 20px. Выносим попап за паддинг карточки (p-5 = 1.25rem) и ещё на 1px
   рамки — его внешние края совпадают с краями карточки. Только эта страница:
   у формы расчёта свой data-role. */
[data-role="quote-form"] .rp-pop {
    left: calc(-20px - 1px);
    right: calc(-20px - 1px);
}

/* Планка поиска — поверх следующих секций, пока открыт календарь: у формы
   есть transform (центрирование), он создаёт stacking context, и z-index
   попапа заперт внутри — карточки «Избранных» перехватывали клики по дням. */
[data-role="hero-search"] {
    z-index: 20;
}

/* ── Районы: «живой остров» (главная) ─────────────────────────────────
   Редизайн 31.08 по мокапам: десктоп — В1 (чипы слева, остров в «море»
   справа, пульс у района-лидера), мобайл — В5 (карта сверху, районы
   строками, хвост за «Показать все»). Всё своими классами: замороженный
   main.css нужных утилит не содержит. */
.districts-live {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.districts-lead {
    margin-top: 8px;
    color: var(--fg-muted);
}

/* Фото-карта (правка автора 01.09, финальный мокап): акварельный остров
   вместо SVG-контура, море уже в картинке. Пины — HTML поверх, якорь
   каждого — центр точки. */
.districts-photo {
    position: relative;
    /* 2.5rem — как у остальных крупных блоков: герой, плашка CTA, фото офиса,
       карточка формы (в билде вёрстки это rounded-2xl = 40px). На 1rem карта
       выбивалась из ряда и читалась почти прямоугольной (правка автора 07.09).
       Скругление режет и приближение: зум-слой внутри, а overflow здесь. */
    border-radius: 40px;
    overflow: hidden;
    background: #BFD7EA; /* цвет моря фото — на время загрузки */
}

.districts-photo-zoom > img {
    display: block;
    width: 100%;
    height: auto;
}

/* Приближение к району при наведении (правка автора 03.09, сглаживание 04.09).
   Двигаем слой целиком: scale + translate, а не transform-origin — origin не
   интерполируется. Транзишена здесь НЕТ намеренно: он перезапускал свою кривую
   на каждой смене наведения, и при быстром переборе районов карта дёргалась.
   Вместо него site.js каждый кадр подтягивает камеру к цели с затуханием —
   скорость не сбрасывается, сколько бы раз цель ни менялась. */
.districts-photo-zoom {
    position: relative;
    transform-origin: 50% 50%;
    will-change: transform;
}

/* Пины едут вместе с картой, но сами не растут: обратный масштаб с якорем
   в точке (8px — центр точки, как и у базового translate). */
/* Пины едут вместе с картой, но не растут: обратный масштаб держит site.js
   в --pk, кадр за кадром вместе с камерой. Якорь — центр точки (8px). */
.districts-photo.is-zoomed .map-pin-ph {
    transform: translate(-8px, -50%) scale(var(--pk, 1));
}

.districts-photo.is-zoomed .map-pin-ph.is-rev {
    transform: translate(calc(-100% + 8px), -50%) scale(var(--pk, 1));
}

.districts-photo.is-zoomed .map-pin-ph.is-under {
    transform: translate(-50%, -8px) scale(var(--pk, 1));
}

@media (prefers-reduced-motion: reduce) {
    .districts-photo:not(.districts-photo--card) .districts-photo-zoom {
        transform: none;
    }

    .districts-photo:not(.districts-photo--card).is-zoomed .map-pin-ph,
    .districts-photo:not(.districts-photo--card).is-zoomed .map-pin-ph.is-rev,
    .districts-photo:not(.districts-photo--card).is-zoomed .map-pin-ph.is-under {
        transform: translate(-8px, -50%);
    }
}

.map-pin-ph {
    position: absolute;
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    /* Якорь — центр точки (12px + рамка 2×2 = 16, половина 8): иначе пин
       съезжает на пол-ширины подписи. */
    transform: translate(-8px, -50%);
    transform-origin: 8px 50%;
    color: var(--fg);
}

.map-pin-ph.is-rev {
    flex-direction: row-reverse;
    transform: translate(calc(-100% + 8px), -50%);
    transform-origin: calc(100% - 8px) 50%;
}

/* Подпись под точкой, а не сбоку: нужна там, где соседи стоят по обе стороны
   и подпись некуда положить по горизонтали (Таланг зажат между Лаяном и Па
   Клоком). Якорь тот же — центр точки, но теперь по горизонтали это середина
   блока, а по вертикали — половина высоты точки. */
.map-pin-ph.is-under {
    flex-direction: column;
    gap: 2px;
    transform: translate(-50%, -8px);
    transform-origin: 50% 8px;
}

.map-pin-ph:hover,
.map-pin-ph:focus-visible,
.map-pin-ph.is-active {
    z-index: 3;
    color: var(--fg);
}

.map-ph-dot {
    width: 12px;
    height: 12px;
    border-radius: 99px;
    background: var(--accent);
    border: 2px solid #fff;
    box-shadow: 0 1px 4px rgba(34, 39, 44, .3);
    flex: 0 0 auto;
    transition: transform .3s ease;
}

.map-pin-ph:hover .map-ph-dot,
.map-pin-ph.is-active .map-ph-dot {
    transform: scale(1.45);
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 22%, transparent), 0 1px 4px rgba(34, 39, 44, .35);
}

/* Карта на карточке объекта (districts-photo--card): приближена к району
   объекта статичным transform из разметки (масштаб 2.2, как ховер-зум главной),
   район обведён полупрозрачным кругом, в центре домик, подпись района под ним
   (выбор автора 08.09, мокап «Вариант 1»). Остальные пины — мелкие подписи-
   ссылки в каталог. Круг едет и растёт вместе с картой: это площадь, а не
   метка; пины и домик держат обратный масштаб через --pk. */
.map-ph-area {
    position: absolute;
    width: 9.5%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border-radius: 99px;
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
    pointer-events: none;
}

.districts-photo--card .map-pin-ph.is-active,
.districts-photo--card .map-pin-ph.is-active.is-rev {
    flex-direction: column;
    gap: 6px;
    /* Якорь — центр домика 38px. */
    transform: translate(-19px, -19px) scale(var(--pk, 1));
    transform-origin: 19px 19px;
}

.districts-photo--card .map-pin-ph.is-active .map-ph-dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 0;
    color: #fff;
    transform: none;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 45%, transparent);
}

.districts-photo--card .map-pin-ph.is-active .map-ph-dot svg {
    width: 18px;
    height: 18px;
}

.districts-photo--card .map-pin-ph.is-active .map-ph-name {
    color: var(--accent);
    font-weight: 700;
    font-size: 12.5px;
}

/* Внутри карточки секции карта скруглена как соседние плитки, а не 2.5rem. */
.obj-card .districts-photo {
    border-radius: 12px;
}

/* Подпись читается на любом рельефе фото за счёт светлого ореола.
   Цвета фиксированные: фото светлое и в тёмной теме. Серые — нейтральные,
   под палитру 04.09 (были тёплые из прежней). */
.map-ph-name {
    font-size: 11.5px;
    font-weight: 600;
    color: #3A3F45;
    text-shadow: 0 1px 0 rgba(255, 255, 255, .9), 0 -1px 0 rgba(255, 255, 255, .9), 1px 0 0 rgba(255, 255, 255, .9), -1px 0 0 rgba(255, 255, 255, .9), 0 0 6px rgba(255, 255, 255, .8);
}

.map-pin-ph.is-poi .map-ph-dot {
    width: 8px;
    height: 8px;
    background: #9AA0A8;
    border-width: 1.5px;
    box-shadow: none;
}

.map-pin-ph.is-poi .map-ph-name {
    color: #8A9098;
    font-weight: 500;
}

/* Пульс у района-лидера — то же кольцо, что было у SVG-пина.
   Смещение −2px по обеим осям — половина разницы между кольцом (16) и точкой
   (12): так их центры совпадают. */
.map-ph-pulse {
    position: absolute;
    left: -2px;
    top: 50%;
    width: 16px;
    height: 16px;
    margin-top: -8px;
    border-radius: 99px;
    background: rgba(47, 107, 240, .45);
    animation: district-pulse 2.4s ease-out infinite;
    pointer-events: none;
}

/* Кольцо садится на ТОЧКУ, а у точки три разных места в пине.
   Одного left: 0 хватало только обычному пину; у перевёрнутого точка справа,
   и кольцо уезжало от неё на всю длину подписи — у Банг Тао оно мигало
   посреди моря (замечание автора 16.09). */
.map-pin-ph.is-rev .map-ph-pulse {
    left: auto;
    right: -2px;
}

/* Подпись снизу: точка сверху по центру блока. */
.map-pin-ph.is-under .map-ph-pulse {
    left: 50%;
    right: auto;
    top: -2px;
    margin: 0 0 0 -8px;
}

/* Каллаут района (ховер-вариант 3): всплывает над точкой, весь пин —
   одна ссылка в каталог, so и каллаут кликабелен. */
.map-ph-callout {
    position: absolute;
    left: 8px;
    bottom: calc(50% + 16px);
    transform: translate(-50%, 6px);
    width: 186px;
    background: var(--surface);
    border-radius: 12px;
    box-shadow: var(--sh-modal);
    padding: 12px 14px;
    white-space: normal;
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s ease, transform .3s cubic-bezier(.16, 1, .3, 1);
}

.map-ph-callout::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -6px;
    width: 12px;
    height: 12px;
    background: var(--surface);
    transform: translateX(-50%) rotate(45deg);
}

.map-pin-ph.is-rev .map-ph-callout {
    left: auto;
    right: 8px;
    transform: translate(50%, 6px);
}

/* Показанный каллаут ловит курсор и клик (правка автора 04.09): он внутри
   ссылки пина, так что нажатие на «Смотреть объекты» ведёт в каталог района.
   Скрытый остаётся прозрачным для курсора, иначе невидимые карточки
   перекрывали бы соседние пины. */
.map-pin-ph:hover .map-ph-callout,
.map-pin-ph:focus-visible .map-ph-callout,
.map-pin-ph.is-active .map-ph-callout {
    opacity: 1;
    transform: translate(-50%, 0);
    pointer-events: auto;
}

.map-pin-ph.is-rev:hover .map-ph-callout,
.map-pin-ph.is-rev:focus-visible .map-ph-callout,
.map-pin-ph.is-rev.is-active .map-ph-callout {
    transform: translate(50%, 0);
}

.map-ph-callout b {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--fg);
}

.map-ph-callout > span {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--fg-muted);
}

.map-ph-callout .go {
    margin-top: 6px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--accent);
    transition: color .2s ease;
}

/* Ховер по самому каллауту: ссылка темнеет и подчёркивается, стрелка уезжает
   вправо — видно, что это кнопка, а не подпись. */
.map-ph-callout .go-arrow {
    display: inline-block;
    transition: transform .25s cubic-bezier(.25, 1, .5, 1);
}

.map-ph-callout:hover .go {
    color: var(--accent-hover);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.map-ph-callout:hover .go-arrow {
    transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
    .map-ph-callout {
        transition: opacity .3s ease;
    }

    .map-ph-callout .go-arrow {
        transition: none;
    }
}

/* Мобайл (выбор автора 08.09, мокап «Вариант 2»): карта крупнее и с
   подписями. Контейнер 5:6, слой карты по центру и приближен к острову
   (масштаб 1.7, море обрезано), пины в обратном масштабе через --pk, у пина
   видны название и число объектов. Раньше подписи прятали, и карта читалась
   как набор безымянных точек. Карта карточки объекта (--card) со своим
   приближением не затронута. */
@media (max-width: 1023px) {
    .districts-photo:not(.districts-photo--card) {
        --pk: 0.588;
        display: flex;
        align-items: center;
        aspect-ratio: 5 / 6;
    }

    .districts-photo:not(.districts-photo--card) .districts-photo-zoom {
        width: 100%;
        transform: scale(1.7) translate(5.5%, -2%);
    }

    .districts-photo:not(.districts-photo--card) .map-pin-ph {
        transform: translate(-8px, -50%) scale(var(--pk));
    }

    .districts-photo:not(.districts-photo--card) .map-pin-ph.is-rev {
        transform: translate(calc(-100% + 8px), -50%) scale(var(--pk));
    }

    .map-ph-dot {
        width: 14px;
        height: 14px;
    }
}

/* Мобайл (выбор автора 08.09, мокап «Вариант 2»): чипы районов одной
   горизонтальной каруселью под картой, все сразу (прежний свёрнутый список с
   кнопкой «Показать все» убран целиком 08.09). Полоса прокрутки скрыта,
   подсказка под чипами объясняет жест. */
.districts-hint {
    display: none;
}

@media (max-width: 1023px) {
    .district-chips {
        flex-direction: row;
        gap: 8px;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
        /* Горизонтальный скролл режет кольцо фокуса у чипов сверху и по
           краям (замечание автора 08.09): 4px внутреннего поля под кольцо и
           отрицательное поле снаружи, чтобы чипы визуально не сдвинулись
           (12px до карты как раньше). scroll-padding — чтобы прилипание
           ставило чип к краю текста, а не к краю поля. */
        margin: 8px -4px 0;
        padding: 4px 4px 8px;
        scroll-padding-inline: 4px;
    }

    .district-chips::-webkit-scrollbar {
        display: none;
    }

    .district-chips li {
        flex: 0 0 auto;
        scroll-snap-align: start;
    }

    .district-chip {
        gap: 6px;
        min-height: 38px;
        padding: 0 12px;
        border: 1px solid var(--border-strong);
        border-radius: 99px;
        background: var(--surface);
        font-size: 13.5px;
        font-weight: 500;
        white-space: nowrap;
    }

    .district-chip-n {
        padding: 0;
        background: transparent;
        font-size: 13px;
        font-weight: 400;
        color: var(--fg-subtle);
    }

    .districts-hint {
        display: block;
        margin: 6px 0 0; /* 10px до чипов: их поле снизу теперь 8px, а не 4 */
        font-size: 13px;
        color: var(--fg-subtle);
    }
}

/* Десктоп: сетка «заголовок и чипы слева, море справа», чипы в 2 колонки
   карточками (В1). */
@media (min-width: 1024px) {
    /* Список и карта делят полосу в ДОЛЯХ, а не в пикселях (выбор автора
       16.09, стратегия D): пропорция одна на любой ширине, и остров растёт
       плавно, а не ступенькой в 142 px.

       По умолчанию список в одну колонку — и когда районов мало, и когда их
       много, но полоса узкая. Вторую колонку добавляет условие ниже. */
    .districts-live {
        display: grid;
        grid-template-columns: minmax(0, .34fr) minmax(0, 1fr);
        grid-template-rows: auto 1fr;
        column-gap: 44px;
        row-gap: 24px;
    }

    .districts-head { grid-column: 1; }
    .districts-listwrap { grid-column: 1; }

    .districts-photo {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: center;
    }

    .district-chips {
        display: grid;
        grid-template-columns: 1fr;
        gap: 10px;
    }

    /* Две колонки — только когда районов много И полосе есть где развернуться.

       Районов семь и меньше (класс is-short от шаблона) — вторая колонка не
       нужна никогда: семь названий дают в ней 4 + 3, половина пустует, а левая
       часть кончается на середине карты (мокап «Вариант 1»).

       Порог по вьюпорту, а не контейнерным запросом: до потолка .shell
       (--shell-max) ширина полосы — простая функция от вьюпорта, и containment
       ради того же числа только добавил бы побочных эффектов. Порог считается
       от узкого края, поэтому расширение колонки до 1480 (18.09) его не сдвинуло.

       1240 px вьюпорта — это 1176 px полосы: ниже двум колонкам чипов остаётся
       меньше 190 px на каждую, и длинные названия («Чернг Талай», «Phuket Town»)
       начинают переноситься на вторую строку. */
    @media (min-width: 1240px) {
        .districts-live:not(.is-short) {
            grid-template-columns: minmax(0, .52fr) minmax(0, 1fr);
        }

        .districts-live:not(.is-short) .district-chips {
            grid-template-columns: 1fr 1fr;
        }
    }

    .district-chip {
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: 12px;
        padding: 12px 14px;
        font-size: 15px;
    }

    .district-chip:hover,
    .district-chip.is-active {
        border-color: var(--accent);
        box-shadow: var(--sh-card);
    }

}

/* Фото-герой «О компании»: кадр заливкой, а не потоком ───────────────────
   На мобильном высота блока задана через min-height (520px), а height:100%
   у картинки считается от height родителя — от min-height не считается и
   схлопывается в auto. Кадр вставал в свои пропорции 1200×720 и накрывал
   только верхние 233px из 520, ниже оставался тинт на фоне страницы
   (замечание автора 09.09). На десктопе высота фиксированная, там было
   верно, поэтому проблему и не видели.

   Кладём кадр абсолютной заливкой: высота блока перестаёт иметь значение,
   а ken-burns и object-fit работают как раньше. Тинт и текстовый слой уже
   absolute, порядок наложения не меняется. */
/* Заливка кадра — общее правило .hero-zoom img (с 18.09 картинка внутри слоя). */

/* ── шапка аренды ─────────────────────────────────────────────────────── */

/* ── Каталог: компактный герой раздела ─────────────────────────────────────
   Выбор автора 09.09: сначала мокап «Вариант 5» (ни плашки, ни кадра), затем
   «Вариант 4» — заголовок в одну строку крупно, описание под ним мельче.
   Раздел начинается сразу с дела: строка выдачи и карточки поднимаются выше,
   чем при любом варианте с картинкой.

   Кегль заголовка живёт здесь, а не утилитами: нужна лестница 28 → 32 →
   36px, а у text-h2 сборки это плавный clamp, который на 1024 даёт 30,7px.
   36px на десктопе — правка автора 09.09 (было 56). Вводный абзац под
   заголовком автор убрал там же: описание раздела осталось только в мете.

   Линия и подложка на самой секции: полоса идёт от края до края экрана,
   текст внутри остаётся в полях контента. */
/* Секция: фон страницы, поля по краям экрана и зазор под шапкой сайта.
   Раскладка переехала сюда из утилит разметки (px-5 pt-4 md:px-8) —
   рефакторинг 11.09: геометрия блока должна читаться в одном месте. */
.rent-head {
    background: var(--bg);
    padding: 16px 20px 0;
}

@media (min-width: 768px) {
    .rent-head {
        padding-inline: 32px;
    }
}

.rent-head-rect {
    /* Геометрия переехала из утилит разметки (relative mx-auto w-full
       max-w-[1280px] overflow-hidden) — рефакторинг 11.09. */
    position: relative;
    width: 100%;
    max-width: var(--shell-max);
    margin-inline: auto;
    overflow: hidden;

    /* Прямоугольник вместо полосы во всю ширину (выбор автора 09.09, мокап
       «Вариант B» из набора про оформление): кадр в скруглённом
       прямоугольнике по ширине контента, как герой главной. До этого полоса
       шла от края до края и отделялась от серого фона страницы светом
       (мокап «Вариант 3» из набора про ширину).

       Радиус 20px: у героя главной стоит rounded-2xl, а в этой сборке это
       40px — на прямоугольнике высотой 224px такой радиус съедает углы.
       Мокап рисовал 16px, но такого шага в шкале сборки нет, а заводить свой
       радиус мимо шкалы (12/20/28/40) незачем.

       Заливка остаётся под кадром: пока кадр не загрузился (и если он не
       загрузится), прямоугольник выглядит как белая плашка. Линия по низу
       снята — у прямоугольника есть край. */
    border-radius: 20px;
    background: var(--surface);
    /* Отступы полосы — мокап «Вариант C» из набора про высоту, затем
       «Вариант A» из набора про рост вверх (выбор автора 09.09). Снизу
       по-прежнему 32px на мобильном и 36 на десктопе: текст привязан к низу
       полосы и с места не двигается. Сверху прибавлено 29px, полоса выходит
       232px на мобильном и 224 на десктопе, первая карточка опускается на
       393px от верха страницы. Выше не поднимаемся: это каталог, и первый ряд
       карточек должен целиком попадать в экран ноутбука 1280×800.

       Горизонтальные поля теперь свои: текст отступает от края кадра, а не
       от края экрана. Зазор под шапкой сайта даёт секция (pt-4 в разметке,
       как у героя главной).

       На мобильном поле по бокам 16px, а не 20: прямоугольник и так
       отступает от края экрана на 20, и при 20+20 заголовок 28px переставал
       влезать в две строки.

       Верхнее поле 244px — это высота прямоугольника 420px минус текст
       (заголовок 63 + 14 + описание 81) и минус нижнее поле 18 (мокапы
       «Вариант A» и «Вариант 1», выбор автора 09.09). Кадр на телефоне
       перестал быть полосой: вертикальный кадр автора ложится в него почти
       целиком, а текст лежит поверх кадра, как в герое главной. */
    padding: 244px 16px 18px;
}

/* Кадр прижат к нижней границе полосы (правка автора 09.09): вниз уходят
   бассейн и терраса, а прибавка высоты открывает небо сверху, а не срезает
   передний план. Нарезки под «Вариант A» перерезаны выше: 1920x336 и
   780x464: соотношения ровно под высоту полосы, иначе cover увеличил бы
   кадр и срезал берег справа. Запас на рост высоты в кадре есть: на 1280
   картинка ложится 259px в полосу 224. */
/* Кадр на телефоне показывается целиком по центру: нарезка режется ровно
   под прямоугольник 350x420, и обрезать нечего. От планшета кадр снова
   полоса, и его прижимаем к нижнему краю. */
.rent-head-rect img {
    object-position: center;
}

@media (min-width: 768px) {
    .rent-head-rect img {
        object-position: bottom;
    }
}

/* Вуаль над кадром — своя на каждую ширину и тему.

   Телефон. Текст белый в обеих темах. Ночью вуали нет совсем — кадр и так
   тёмный, заголовок держит 3,0:1 при норме 3, описание 7,6:1 при норме 4,5.
   Днём слабое затемнение в нижней трети: 53 → 34 к 35% → прозрачный к 60%.
   Это «Вариант 4» на 30% слабее того, что стояло до снятия (было 76 → 48;
   правка автора 10.09 — сначала снять совсем, потом вернуть, но слабее).
   Замер: заголовок 2,9:1, описание 4,6:1. Описание норму держит, заголовок
   не дотягивает до 3:1 самую малость — на прежних 76 → 48 было 3,9. Если днём понадобится читаемость без затемнения,
   рабочих путей три — тёмный текст вместо белого, плашка под текстом или
   дневной кадр с тёмным низом (как закатный 1.jfif, на нём белый текст
   давал 10,5:1 без всякой вуали).

   Планшет и десктоп. Картина обратная: кадр там полоса, текст тёмный, и
   вуаль белая, гуще слева, где лежит текст. Без неё тёмный заголовок держит
   13:1, а описание проваливается до 2:1. Плотность — мокап «Вариант B» из
   набора про засветление (выбор автора 09.09): 55% слева вместо 40%, правая
   половина кадра с виллой и бассейном остаётся как есть. В тёмной теме там
   ровное затемнение 0.35 под светлый текст: гасит окна виллы и подсветку
   бассейна, а не спасает от светлого кадра.

   Норма 3:1 для крупного заголовка и 4,5:1 для описания. Все числа — замер
   по рендеру страницы со скрытым текстом, зоны берутся настоящими границами
   текста из DOM, худшее место фона это 5-й процентиль яркости для тёмного
   текста и 95-й для светлого. */
/* Дневное затемнение живёт на базовом правиле, потому что на телефоне оно
   нужно только светлой теме; тёмная тема ниже его снимает. */
.rent-head-veil {
    background: linear-gradient(to top,
        rgba(19, 23, 27, .53) 0%,
        rgba(19, 23, 27, .34) 35%,
        transparent 60%);
}

[data-theme="dark"] .rent-head-veil {
    background: none;
}

@media (min-width: 768px) {
    /* Широкая полоса: текст тёмный, вуаль белая, слева гуще — там текст,
       справа кадр открыт. */
    .rent-head-veil {
        background: linear-gradient(to right,
            rgba(255, 255, 255, .55) 0%,
            rgba(255, 255, 255, .22) 55%,
            transparent 100%);
    }
}

/* От планшета тёмная тема расходится со светлой по-настоящему: там текст
   светлый, а вуаль это ровное затемнение, а не тинт снизу. */
@media (min-width: 768px) {
    [data-theme="dark"] .rent-head-veil {
        background: rgba(14, 15, 17, .35);
    }
}

.rent-head-rect h1 {
    margin: 0;
    font-size: 28px; /* 28px: на 390px заголовок и так в две строки */
    line-height: 1.12;
}

.rent-head-rect p {
    margin: 14px 0 0;
    /* Мобайл — 14px (правка автора 09.09): на 390px описание в 16px забирало
       четыре строки и спорило с заголовком. В герое главной подпись осталась
       16px (правка автора 08.09) — там она лежит на кадре и мельче нельзя. */
    font-size: 14px;
    line-height: 1.45;
    /* 56 знаков в строке — норма для комфортного чтения (50–75). Без этого
       описание растянулось бы на всю ширину контейнера. */
    max-width: 56ch;
    /* Цветом текста, а не приглушённым (правка автора 09.09; до этого была
       смесь --fg с --fg-muted, а в разметке стоит text-fg-muted). На кадре
       серому не хватало контраста, и автор попросил просто чёрный. Тише
       заголовка описание держится кеглем и начертанием, а не цветом.
       На телефоне цвет перебивается ниже: там текст белый. */
    color: var(--fg);
}

/* Белый текст на телефоне — в обеих темах: под ним тёмный тинт, а не кадр
   (мокапы «Вариант A», «Вариант 1» и «Вариант 4», выбор автора 09.09).
   Не --fg-inverse: в тёмной теме этот токен тёмный.

   Правило стоит НИЖЕ цвета описания не случайно: специфичность у них
   одинаковая, и сначала оно лежало выше — заголовок белел, а описание
   оставалось тёмным (замечание автора 09.09). */
@media (max-width: 767px) {
    .rent-head-rect h1,
    .rent-head-rect p {
        color: #FFFFFF;
    }
}

@media (min-width: 768px) {
    /* От планшета прямоугольник снова полоса с тёмным текстом на светлом
       кадре: прежние поля, которые до 09.09 были общими с мобильным. */
    .rent-head-rect {
        padding: 42px 16px 32px;
    }

    .rent-head-rect h1 {
        font-size: 32px; /* 32px: планшет */
    }

    .rent-head-rect p {
        font-size: 16px; /* 16px от планшета и выше */
        line-height: 1.5;
    }
}

@media (min-width: 1024px) {
    .rent-head-rect {
        padding: 85px 28px 36px;
    }

    .rent-head-rect h1 {
        font-size: 36px; /* 36px (правка автора 09.09): одна строка с запасом */
    }
}

/* ── верхняя строка каталога ──────────────────────────────────────────── */

/* ── Каталог: мобильная верхняя строка и плавающая кнопка фильтров ────
   Правка автора 09.09. Было три строки в столбик: крошки, кнопка фильтров
   во всю ширину, счётчик с сортировкой. Стало две: крошки и счётчик в одну
   строку, сортировка во всю ширину под ними. Кнопка фильтров ушла из потока
   в плавающую кнопку внизу экрана — так она под большим пальцем и не тратит
   высоту первого экрана.

   Раскладка сеткой, а не флексом: порядок в разметке остаётся прежним
   (крошки → шит → счётчик и сортировка), а на мобильном элементы надо
   разложить по двум строкам через один общий контейнер. display: contents
   на обёртке счётчика и на details поднимает их детей в ту же сетку. */
@media (max-width: 1023px) {
    /* Раскладка сеткой, а не флексом (правка автора 09.09): порядок в
       разметке прежний (крошки → шит → счётчик и сортировка), а на
       мобильном элементы надо разложить по двум строкам через один общий
       контейнер. display: contents на обёртке счётчика и на details
       поднимает их детей в ту же сетку. Кнопка фильтров в потоке ничего не
       занимает: она плавающая (fixed), а подложка шита появляется только
       по open. */
    .catalog-topbar {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 14px 12px;
    }

    .catalog-topbar-crumbs {
        grid-area: 1 / 1;
    }

    .catalog-topbar-meta,
    [data-role="filter-sheet"] {
        display: contents;
    }

    .catalog-topbar [data-role="results-label"] {
        grid-area: 1 / 2;
        justify-self: end;
        white-space: nowrap;
    }

    .catalog-sort {
        grid-area: 2 / 1 / 3 / -1;
        min-width: 0;
    }

    /* Подпись «Сортировка» переезжает внутрь поля (правка автора 09.09):
       рядом с полем она скрыта утилитой hidden sm:inline, и на телефоне
       поле оставалось без объяснения — просто «Рекомендуемые». Теперь
       рамка и фон живут на label, а селект внутри без них, и поле читается
       как «Сортировка: Рекомендуемые», подставляя выбранный пункт.

       Двоеточие рисуем в CSS, а не в переводе: на десктопе подпись стоит
       перед полем и двоеточие там не нужно. */
    .catalog-sort > label {
        flex: 1;
        min-width: 0;
        gap: 0;
        /* По базовой линии, а не по центру: у подписи и у значения селекта
           одинаковый кегль, и по базовой линии они встают ровно, тогда как
           центрирование ставило значение на пару пикселей выше (замечание
           автора 09.09). */
        align-items: baseline;
        padding-top: 10px;
        padding-bottom: 10px;
        height: 40px;
        padding-left: 12px;
        border: 1px solid var(--border-strong);
        border-radius: 12px;
        /* Подложка та же, что у полей фильтра (правка автора 10.09): на
           десктопе её несёт сам селект, а здесь видимая рамка на label. */
        background: var(--field-bg);
    }

    .catalog-sort > label > span {
        display: inline;
        color: var(--fg);
    }

    .catalog-sort > label > span::after {
        content: ":";
    }

    .catalog-sort [data-role="sort-select"] {
        flex: 1;
        min-width: 0;
        width: 100%;
        padding-left: 6px;
        border: 0;
        background-color: transparent;
        /* Высоту селекту не задаём: рамка теперь на label, а по центру его
           ставит сам флекс. С height: 100% и отступом .4rem из
           .apple-select значение вставало выше подписи. */
        height: auto;
        padding-top: 0;
        padding-bottom: 0;
        line-height: 1.45;
    }
}

/* ── Каталог: верхняя строка «крошки · Показано · сортировка» ─────────
   Правка автора 01.09 (мокап согласован): строка счётчика и сортировки
   поднята на уровень крошек, сетка — выше на высоту бывшей строки.
   Раскладка повторяет колонки ниже (сайдбар 16rem + gap 2.5rem), поэтому
   «Показано» стоит ровно над началом карточек. Чипы активных фильтров
   остаются в секции — всегда под этой строкой. */
.catalog-topbar [data-role="breadcrumbs"] {
    margin-bottom: 0; /* mb-6 партиала — для одиночного использования */
    min-width: 0;
}

@media (min-width: 1024px) {
    .catalog-topbar {
        flex-direction: row;
        align-items: center;
        gap: 40px;
        margin-bottom: 28px;
    }

    .catalog-topbar-crumbs {
        width: 256px;
        flex-shrink: 0;
        padding-right: 24px;
    }

    /* Длинные крошки не переносятся и не толкают «Показано» — хвост
       обрезается многоточием. Тот же overflow резал кольцо фокуса на ссылке
       «Главная» слева и сверху (замечание автора 08.09): даём списку 4px
       внутреннего поля под кольцо (2px смещение + 2px обводка) и столько же
       отрицательного поля снаружи, чтобы текст остался на своём месте. */
    .catalog-topbar [data-role="breadcrumbs"] ol {
        flex-wrap: nowrap;
        overflow: hidden;
        padding: 4px;
        margin: -4px;
    }

    .catalog-topbar [data-role="breadcrumbs"] ol li:last-child {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

/* Якоря секций главной (пункты подвала «Как мы работаем»/«Районы Пхукета»):
   отступ под липкую шапку 60px + воздух, иначе заголовок ныряет под неё. */
#how,
#districts {
    scroll-margin-top: 80px;
}

/* ── как это работает ─────────────────────────────────────────────────── */

/* ── «Как это работает»: фото-шаги + чипы времени ─────────────────────
   Редизайн 31.08 по мокапу Ш4. Свои классы: замороженный main.css нужных
   утилит не содержит. Появление — существующий reveal, здесь только вид. */
.hiw-chips {
    display: none;
    position: relative;
    margin: 26px 0 22px;
}

/* Сквозной пунктир позади чипов: от центра первой колонки до центра
   последней (1/6 ширины с каждого края при трёх равных колонках). */
.hiw-chips::before {
    content: "";
    position: absolute;
    left: 16.66%;
    right: 16.66%;
    top: 50%;
    border-top: 2px dotted var(--border-strong);
}

.hiw-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 99px;
    padding: 7px 14px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--fg);
    white-space: nowrap;
}

.hiw-chip b {
    color: var(--accent);
}

/* Мобайл: карусель со снапом; чип срока живёт внутри карточки. */
.hiw-grid {
    display: flex;
    gap: 12px;
    /* Снизу запас под тень карточки: overflow её режет, 8px не хватало. Запас
       компенсируем отрицательным полем, иначе до плашки CTA выходило 84px
       вместо 64, как под ней (правка автора 08.09). */
    margin: 20px -20px -20px;
    padding: 0 20px 20px;
    list-style: none;
    /* Только горизонтальная прокрутка (замечание автора 04.09). overflow-x: auto
       делает вторую ось тоже auto, и на время появления карточек (reveal
       сдвигает их на 20px вниз) справа вырастала вертикальная полоса. */
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    /* Снап равняет карточку по краю скролл-порта, а не по внутреннему отступу:
       без scroll-padding первая карточка прилипала к краю экрана, а заголовок
       секции стоял на 20px правее (замечание автора 04.09). Отступ снапа равен
       паддингу, и карточка встаёт под заголовок. */
    scroll-padding: 0 20px;
    -webkit-overflow-scrolling: touch;
}

.hiw-card {
    flex: 0 0 260px;
    scroll-snap-align: start;
    border-radius: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    overflow: hidden;
    /* Мягкий подъём (просьба автора: «анимацию ховера плавную»). */
    transition: transform .45s cubic-bezier(.16, 1, .3, 1), box-shadow .45s cubic-bezier(.16, 1, .3, 1);
}

.hiw-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--sh-hover);
}

@media (prefers-reduced-motion: reduce) {
    .hiw-card,
    .hiw-card:hover {
        transform: none;
        transition: none;
    }
}

/* Фото-шапка: квадратный ратио (правка автора 01.09), кадрирование по
   центру. Фолбэк-фон на время загрузки. Скругление на все четыре угла,
   радиусом карточки (правка автора 02.09) — overflow здесь свой, картинку
   карточка не режет: она внутри .hiw-ph. */
.hiw-ph {
    aspect-ratio: 1 / 1;
    background: var(--tint);
    border-radius: 14px;
    overflow: hidden;
}

.hiw-ph img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hiw-bd {
    padding: 18px 20px 22px;
}

.hiw-chip--card {
    margin-bottom: 10px;
    padding: 5px 10px;
    font-size: 11.5px;
}

/* Десктоп: чипы с пунктиром над сеткой из трёх карточек; чипы в карточках
   не нужны — срок уже назван строкой выше. */
@media (min-width: 768px) {
    /* Сетка чипов повторяет сетку карточек (правка автора 01.09):
       каждый чип стоит ровно по центру своей карточки. */
    .hiw-chips {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 18px;
    }

    .hiw-chips .hiw-chip {
        justify-self: center;
        position: relative;
        z-index: 1;
    }

    .hiw-grid {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 18px;
        margin: 0;
        padding: 0;
        overflow: visible;
    }

    .hiw-card { flex: none; }

    .hiw-chip--card { display: none; }
}

/* Тёмная тема: фото остаётся светлым по замыслу (акварельная карта),
   лишь слегка гасим яркость, чтобы не слепило на тёмной странице. */
[data-theme="dark"] .districts-photo > img {
    filter: brightness(.88) saturate(.95);
}

/* ── Выравнивание ряда карточек по самому длинному названию ───────────
   Правка автора 01.09: «если у виллы длинное название — переносим на
   вторую строку и все карточки в ряду равняем под это; строка состояния
   должна быть на одной линии». Резерв под вторую строку нужен ТОЛЬКО в
   тех рядах, где длинное название есть: min-height у заголовка так не
   умеет — он растит каждую карточку, даже в ряду сплошь коротких имён
   (это и раздувало лайв).

   Умеет subgrid: карточка занимает 5 треков сетки списка (фото, название,
   подпись, факты, подвал) и наследует их, поэтому высоту каждой строки
   задаёт самая длинная карточка РЯДА. Цепочка идёт через все уровни
   разметки: ul → li → article → .obj-body, каждый объявляет subgrid.

   Вертикальный зазор списка (gap-y-10) при этом обнуляется: иначе он
   встал бы между треками ВНУТРИ карточки. Расстояние между рядами даёт
   padding-bottom карточки, а отрицательный margin списка снимает лишний
   хвост под последним рядом.

   Без subgrid (браузеры до Chrome 117 / Safari 16) остаётся поведение
   базовых правил выше: факты и подвал прижаты книзу через margin-top. */
@supports (grid-template-rows: subgrid) {
    [data-testid="catalog-list"],
    [data-role="featured-grid"] {
        row-gap: 0;
        margin-bottom: calc(var(--spacing) * -10);
    }

    [data-testid="catalog-list"] > li,
    [data-role="featured-grid"] > li {
        grid-row: span 5;
        display: grid;
        grid-template-rows: subgrid;
        padding-bottom: calc(var(--spacing) * 10);
    }

    /* Специфичность выше утилит демо-билда: article несёт flex-классы. */
    [data-testid="catalog-list"] > li > [data-role="object-card"],
    [data-role="featured-grid"] > li > [data-role="object-card"] {
        display: grid;
        grid-row: span 5;
        grid-template-rows: subgrid;
    }

    /* Явные номера треков: у объекта может не быть фактов, и без них
       подвал уехал бы на строку выше — мимо линии соседей. */
    [data-testid="catalog-list"] .obj-photo,
    [data-role="featured-grid"] .obj-photo {
        grid-row: 1;
    }

    [data-testid="catalog-list"] .obj-body,
    [data-role="featured-grid"] .obj-body {
        display: grid;
        grid-row: 2 / span 3;
        grid-template-rows: subgrid;
    }

    [data-testid="catalog-list"] .obj-title,
    [data-role="featured-grid"] .obj-title {
        grid-row: 1;
    }

    [data-testid="catalog-list"] .obj-sub,
    [data-role="featured-grid"] .obj-sub {
        grid-row: 2;
    }

    /* Прижимать книзу больше нечего — линию держит сетка. */
    [data-testid="catalog-list"] .obj-facts,
    [data-role="featured-grid"] .obj-facts {
        grid-row: 3;
        margin-top: 0;
    }

    [data-testid="catalog-list"] .obj-foot,
    [data-role="featured-grid"] .obj-foot {
        grid-row: 5;
        margin-top: 0;
    }
}

/* ── герой страницы ───────────────────────────────────────────────────── */

/* Герой страницы боксом (выбор автора 04.09, «Контакты»). Высота и отступы
   здесь, а не утилитами: замороженный билд вёрстки нужных значений не знает.
   Пропорции — как в мокапе: 320px на телефоне, 420px от планшета. */
.page-hero {
    height: 320px;
}

.page-hero-body {
    padding: 24px 24px 28px;
}

@media (min-width: 768px) {
    .page-hero {
        height: 420px;
    }

    .page-hero-body {
        padding: 40px 48px 44px;
    }
}

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

   Тинт (выбор автора 04.09, мокап «Холод 3»): кадр тёплый — бежевый камень и
   вечерний свет; акцентный синий в режиме soft-light на 18% холодит тени и
   камень под палитру сайта, светлые окна почти не трогает. Лежит под вуалью. */
.office-cool {
    background: var(--accent);
    opacity: .18;
    mix-blend-mode: soft-light;
    pointer-events: none;
}

/* Ссылка в каллауте района — цветом ссылок. Рядом стояли ещё два селектора
   под утилиту text-accent: в билде ссылки шли ею, и цвет подменялся только
   у <a>. Носителей этой утилиты в разметке больше нет (рефакторинг 13.09). */
.map-ph-callout .go {
    color: var(--link);
}

/* Тёмная тема: весь синий текст становится красным (решение автора 07.09).
   Токен --link выше — красный, осветлённый под тёмный фон ради читаемости
   (#FF4D7D, контраст к #0E0F11 около 6:1; фирменный #DA1249 даёт лишь 3.8:1).
   Кнопки и графика (кривая цены, пины, рамки фокуса) остаются синими. */
[data-theme="dark"] .district-chip-n,
[data-theme="dark"] .hiw-chip b,
[data-theme="dark"] .obj-more,
[data-theme="dark"] .map-ph-callout .go,
[data-theme="dark"] .districts-photo--card .map-pin-ph.is-active .map-ph-name {
    color: var(--link);
}

@media (hover: hover) {
    [data-theme="dark"] .lnk-pill:hover,
    [data-theme="dark"] .map-ph-callout .go:hover {
        color: var(--link-hover);
    }
}

/* ── hero-tint ────────────────────────────────────────────────────────── */

/* Заголовок секции «Похожие объекты» на странице объекта. Было утилитами
   text-h2 font-tight font-bold (рефакторинг 13.09).

   Свой класс, а не общий .sec-title: у заголовков секций межбуквенное -.03em,
   потому что в разметке рядом с ними всегда стояла tracking-[-0.03em], а тут
   её не было и работало собственное -.025em из сборки. Разница 0.005em при
   36px это 3–4px на строку, сводить их — изменение вида, а не раскладки.

   Про шрифт: утилита font-tight просила "Inter Tight", но файлов этого шрифта
   в проекте нет, стек всегда падал на Inter, и браузер на каждый показ делал
   два запроса с ответом 404. Имя убрано, вид не изменился. Объявления
   @font-face в замороженной сборке не тронуты: появятся файлы — вернуть шрифт
   сюда и в заголовок объекта это одна строка. */
.obj-similar-title {
    font-size: clamp(24px, 3vw, 36px);
    line-height: 1.15;
    letter-spacing: -.025em;
    font-weight: var(--font-weight-bold);
}

/* Пустая выдача каталога: подсказка вместо карточек. bg-tint остаётся в
   разметке — у него подписка на рамку в тёмной теме. */
.empty-box {
    border-radius: 40px;
    padding-inline: 24px;
    padding-block: 80px;
    text-align: center;
}

.empty-icon {
    width: 40px;
    height: 40px;
    color: var(--fg-subtle);
}

/* Цифры «О компании»: название факта и подпись под ним. */
.fact-name {
    display: block;
    font-weight: var(--font-weight-semibold);
}

.fact-note {
    display: block;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

.about-text {
    line-height: var(--leading-relaxed);
    color: var(--fg);
}

/* Вводный текст статичных страниц: тело страницы из редактора, текст раздела
   «Услуг». Было утилитами text-lg leading-relaxed text-fg-muted в трёх местах
   (рефакторинг 13.09). Межбуквенное не задаём: у класса .text-lg подписки на
   ноль в сборке нет, и текст наследует его от body. */
.page-text {
    font-size: var(--text-lg);
    line-height: var(--leading-relaxed);
    color: var(--fg-muted);
}

/* Фото раздела на «Услугах». */
.svc-photo {
    aspect-ratio: 4 / 3;
    border-radius: 40px;
    object-fit: cover;
}

/* Подпись отзыва на «О компании»: линия сверху и портрет. Цвет линии пишем
   тот, что рисовался: утилита border-accent/15 в сборке мертва, её гасит
   безслойное * { border-color: var(--border) }. */
.quote-foot {
    border-top: 1px solid var(--border);
    padding-top: 20px;
}

.quote-avatar {
    width: 44px;
    height: 44px;
    border-radius: 3.40282e38px;
    object-fit: cover;
}

/* Коробка формы заявки на «Инвестициях». */
.lead-form-box {
    border-radius: 40px;
    padding: 24px;
}

@media (min-width: 768px) {
    .lead-form-box {
        padding: 32px;
    }
}

/* Плашка с акцентной подложкой под списком тарифа: «Управление»,
   «Партнёрство». Было утилитами bg-accent-subtle text-accent. В тёмной теме
   текст белый — так рисовало правило сборки для пары этих утилит, повторяем
   его явно, иначе плашка поменяла бы цвет. */
.pt-note--accent {
    background-color: var(--accent-subtle);
    color: var(--accent);
}

[data-theme="dark"] .pt-note--accent {
    color: var(--accent-fg);
}

/* ── Каналы связи на «Контактах» ──────────────────────────────────────
   Строка списка: кружок со значком, подпись капсом, значение, пояснение и
   стрелка, которая едет вправо на наведении. Было десять утилит на четырёх
   вложенных узлах (рефакторинг 13.09). */
.ch-item {
    border-top: 1px solid var(--border);
}

.ch-item:first-child {
    border-top-width: 0;
}

.ch-link {
    min-height: 80px;
    padding-block: 20px;
}

/* bg-tint остаётся в разметке: у него подписка на рамку в тёмной теме. */
.ch-icon {
    display: flex;
    width: 40px;
    height: 40px;
    align-items: center;
    justify-content: center;
    border-radius: 3.40282e38px;
    color: var(--fg-muted);
}

.ch-label {
    display: block;
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    letter-spacing: 0;
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    color: var(--fg-subtle);
}

.ch-value {
    display: block;
    font-size: var(--text-lg);
    line-height: var(--text-lg--line-height);
    font-weight: var(--font-weight-semibold);
}

.ch-note {
    display: block;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

/* Стрелка едет вправо, когда наводят на всю строку. Только там, где ховер
   настоящий: в сборке этот сдвиг тоже стоял под @media (hover: hover), иначе
   на тач-экранах он залипает после касания. */
.ch-arrow {
    color: var(--fg-subtle);
    transition-property: transform, translate, scale, rotate;
    transition-duration: var(--tr-duration);
    transition-timing-function: var(--tr-ease);
}

@media (hover: hover) {
    .ch-link:hover .ch-arrow {
        translate: 4px 0;
    }
}

/* Рамка фотографии офиса. На телефоне кадр квадратный (просьба автора 17.09:
   при 21/9 на 375px он схлопывался до 160px, и плашка адреса закрывала его
   целиком); широкая кинолента — от планшета. */
.office-frame {
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: 40px;
    background: var(--bg-subtle);
}

@media (min-width: 768px) {
    .office-frame {
        aspect-ratio: 21 / 9;
    }
}

/* ── Пункты со списком на служебных страницах ─────────────────────────
   «Управление», «Партнёрство», «Инвестиции»: один и тот же блок на трёх
   страницах. */
.pt-item {
    border-top: 1px solid var(--border);
    padding-block: 16px;
    color: var(--fg-muted);
}

.pt-item:first-child {
    border-top-width: 0;
    padding-top: 0;
}

.pt-check {
    width: 16px;
    height: 16px;
    color: var(--success);
}

/* Заметка под списком. Утилиты bg-accent-subtle и text-accent оставлены в
   разметке намеренно: их ловит правило [data-theme="dark"]
   .bg-accent-subtle.text-accent в base.css, которое в тёмной теме красит текст
   белым. Снять их значит потерять этот цвет. */
.pt-note {
    border-radius: 12px;
    padding: 16px;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
}

/* ── Герой на кадре ───────────────────────────────────────────────────
   Три страницы, один компонент: кадр во всю ширину, тинт поверх, текст прижат
   к низу. Переехало из утилит разметки (рефакторинг 13.09).

   Размеры заголовка у главной и «О компании» разные, и это разные решения
   дизайна: сводить их значит менять вид. Поэтому размер задаётся владельцем
   героя, а общее у заголовков — начертание, плотность и цвет. */
.hero-title {
    line-height: 1.05;
    letter-spacing: -.035em;
    font-weight: var(--font-weight-bold);
    text-wrap: balance;
    color: var(--color-white);
}

.hero-copy .hero-title {
    font-size: clamp(32px, 5vw, 60px);
}

[data-role="about-hero"] .hero-title {
    font-size: clamp(28px, 4.5vw, 56px);
}

/* Подпись под заголовком. У главной межстрочное увеличено, у «Контактов» нет:
   так в исходной вёрстке. Мобильные значения задаёт правило ниже по файлу. */
.hero-lead {
    font-size: var(--text-lg);
    line-height: var(--text-lg--line-height);
    color: color-mix(in oklab, var(--color-white) 85%, transparent);
}

/* Модификатор, а не селектор .hero-copy .hero-lead: у подписи ниже по файлу
   есть мобильное правило со своим межстрочным 1.45, и потомок из двух классов
   перебил бы его специфичностью. Модификатор той же специфичности, что и
   мобильное правило, и стоит раньше — значит на телефоне выигрывает оно. */
.hero-lead--relaxed {
    line-height: var(--leading-relaxed);
}

/* Кадр главной: высота ступенькой по ширине экрана. Мобильная высота своя,
   правилом ниже по файлу. */
.hero-media {
    position: relative;
    height: 420px;
    overflow: hidden;
    border-radius: 40px;
}

@media (min-width: 640px) {
    .hero-media {
        height: 480px;
    }
}

@media (min-width: 768px) {
    .hero-media {
        height: 600px;
    }
}

/* Поля текста поверх кадра. Мобильные меньше, правилом ниже по файлу. */
.hero-copy {
    padding: 24px 24px 40px;
}

@media (min-width: 768px) {
    .hero-copy {
        padding: 48px 48px 80px;
    }
}

/* Герой «О компании»: рамка кадра и своя высота. Текстовый блок у него свой,
   а не общий .hero-copy: у того на телефоне поля меньше, и переиспользование
   изменило бы отступы этого героя. Поля тут одинаковые со всех сторон. */
.hero-frame {
    overflow: hidden;
    border-radius: 40px;
}

[data-role="about-hero"] {
    min-height: 520px;
}

.about-hero-copy {
    padding: 24px;
}

@media (min-width: 768px) {
    [data-role="about-hero"] {
        height: 560px;
    }

    .about-hero-copy {
        padding: 48px;
    }
}

/* Цифры под заголовком «О компании». */
.about-stats {
    border-top: 1px solid color-mix(in oklab, var(--color-white) 20%, transparent);
    padding-top: 28px;
}

.about-stat-n {
    font-size: 32px;
    line-height: 1;
    letter-spacing: -.04em;
    font-weight: var(--font-weight-bold);
    color: var(--color-white);
}

.about-stat-l {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: color-mix(in oklab, var(--color-white) 70%, transparent);
}

/* ── Страница объекта: шапка и кадр ───────────────────────────────────
   Переехало из утилит разметки (рефакторинг 13.09). */

/* Плашка «объект недоступен на эти даты»: показывается вместо цены, когда
   период занят. */
.obj-warn {
    border-radius: 40px;
    padding: 32px;
    background: var(--warning-subtle);
}

.obj-warn-title {
    font-size: 24px;
    line-height: 1.25;
    letter-spacing: -.02em;
    font-weight: var(--font-weight-semibold);
    color: var(--warning);
}

.obj-warn-lead {
    color: var(--fg-muted);
}

/* Бейдж типа жилья рядом с районом. */
.obj-type {
    border-radius: 3.40282e38px;
    padding-inline: 12px;
    padding-block: 4px;
    background: var(--accent-subtle);
    color: var(--accent);
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    font-weight: var(--font-weight-medium);
}

/* В тёмной теме текст бейджа белый: так его красит правило
   [data-theme="dark"] .bg-accent-subtle.text-accent в base.css. Оно служит ещё
   заметкам на служебных страницах, поэтому остаётся там, а бейджу цвет задаём
   здесь. В светлой теме цвет акцентный: правило a.text-accent, из-за которого
   чип фильтра ссылочный, сюда не достаёт — это <span>, а не ссылка. */
[data-theme="dark"] .obj-type {
    color: var(--accent-fg);
}

.obj-place {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

/* Рамка кадра: одна и та же у галереи и у одиночной картинки. bg-tint
   остаётся в разметке — у него подписка на рамку в тёмной теме. */
.obj-frame {
    position: relative;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    border-radius: 28px;
}

@media (min-width: 640px) {
    .obj-frame {
        aspect-ratio: 16 / 9;
    }
}

/* Лента миниатюр рядом с кадром — только на десктопе от 1280 (выбор автора
   18.09, мокап «Вариант 1»); телефон и планшет — как прежде, без неё. Сама
   раскладка .hero-strip описана в десктопном блоке в конце файла. */
.hero-thumbs {
    display: none;
}

/* Заглушка, когда фотографий ещё нет. */
.obj-frame-empty {
    display: flex;
    width: 100%;
    height: 100%;
    align-items: center;
    justify-content: center;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-subtle);
}

/* Список свободных периодов. */
.obj-dates {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

/* Крупная сумма над формой брони. */
.obj-total {
    font-size: var(--text-2xl);
    line-height: var(--text-2xl--line-height);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

/* ── Планка брони на телефоне ─────────────────────────────────────────
   Прижата к низу экрана, поверх содержимого. Было десять утилит на двух узлах
   (рефакторинг 13.09). Прозрачность фона в сборке у bg-bg/95 появляется только
   там, где браузер умеет color-mix, — повторяем обе ветки, как у шапки. */
.bk-bar {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: 40;
    border-top: 1px solid var(--border);
    background-color: var(--bg);
    -webkit-backdrop-filter: blur(var(--blur-md));
    backdrop-filter: blur(var(--blur-md));
}

@supports (color: color-mix(in lab, red, red)) {
    .bk-bar {
        background-color: color-mix(in oklab, var(--bg) 95%, transparent);
    }
}

/* Кнопка в планке: цвета у неё были в base.css, перенесены сюда, чтобы
   компонент лежал в одном месте (§5 контракта: не разносить стили одного
   компонента по файлам). Порядок от этого не меняется: ничто эти правила не
   перекрывало. */
.bar-cta {
    display: flex;
    height: 48px;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
    padding-inline: 16px;
    background: var(--cta);
    color: var(--cta-fg);
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

.bar-cta:active {
    background: var(--cta-hover);
}

/* Текст из редактора на странице объекта: описание и правила. У описания
   межстрочное увеличено, у правил нет — так в исходной вёрстке. */
.obj-text {
    color: var(--fg-muted);
}

.obj-text--relaxed {
    line-height: var(--leading-relaxed);
}

.obj-amenity {
    color: var(--fg);
}

/* Ролик объекта. */
.obj-video {
    aspect-ratio: 16 / 9;
    border-radius: 20px;
}

/* ── Блок брони на странице объекта ───────────────────────────────────
   Переехало из утилит разметки (рефакторинг 13.09). Внутри повторялось одно и
   то же: линия перед блоком шесть раз, строка «название слева, сумма справа»
   пять раз, моноширинные цифры девять раз.

   Расчёт владеет своими детьми селектором в один уровень: класс только там,
   где у элемента своя роль (§12 контракта). */

/* Линия перед блоком. Стоит на шести разных по смыслу блоках: заметка о
   занятых датах, расчёт, форма заявки, кнопки мессенджеров. Общее у них ровно
   эта линия, поэтому отдельный класс, а не свойство каждого. */
.bk-sep {
    border-top: 1px solid var(--border);
    padding-top: 12px;
}

/* Приглушённая заметка: занятые даты, ошибка расчёта, цена «от». */
.bk-note {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

/* Мелкий приглушённый текст: пояснения под расчётом и списком доплат. */
.bk-fine {
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    letter-spacing: 0;
    color: var(--fg-muted);
}

/* Пояснение под списком доплат по выбору: тот же кегль, но цвет светлее
   соседних мелких текстов. В разметке у него стояло text-fg-subtle, а не
   text-fg-muted; разница невелика, но она есть. */
.bk-fine--subtle {
    color: var(--fg-subtle);
}

/* Подпись над группой: «Доплаты по выбору», «Входят в итог».

   Без капса, подзаголовком (выбор автора 19.09, мокап «Вариант B»):
   14px полужирным цветом текста — тот же кегль, что у названий доплат, но
   жирнее и чёрным: группа читается как раздел карточки, а не как служебная
   пометка над списком. Капса в карточке бронирования больше нет нигде. */
.bk-label {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
    font-weight: var(--font-weight-semibold);
    color: var(--fg);
    /* С gap: 4px у группы выходят 6px до первой строки. */
    margin-bottom: 2px;
}

/* Подсказка под полями дат — цветом текста (правка автора 19.09).

   Это единственная строка в карточке, которая говорит, что сделать; светло-серым
   она читалась как сноска и терялась рядом с «Минимальным сроком». Класс
   проставляет site.js (guardQuoteButton) — самой подсказки в разметке нет. */
.bk-hint {
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    letter-spacing: 0;
    color: var(--fg);
}

/* ── «Управление недвижимостью»: люкс-система (выбор автора 20.09, мокап
   «Люкс-система по референсу Phuket Estate», management.blade) ──────────

   Страница — крупные скруглённые блоки внутри shell: ничего не выходит за
   ширину шапки. Фотографии только со скруглёнными углами. Общие куски
   (mg-cap, mg-tint, mg-repcard, mg-faq, mg-dark, mg-fee, форма в тёмном)
   ниже, специфика секций — mgx-*. */

.mg-cap {
    margin: 0 0 6px;
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    font-weight: var(--font-weight-semibold);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--fg-subtle);
}

.mgx-cap-light { color: rgba(241, 242, 244, .55); }

.mg-tint { background: color-mix(in srgb, var(--bg) 65%, var(--surface)); }

/* Ритм секций люкс-страницы: mt-14 md:mt-20 и pb-14 в замороженном билде
   нет (VerstkaClassesTest), поэтому вертикаль задана своим классом:
   56px, от 768 — 80px, как у секций «Услуг» (py-14 md:py-20). */
.mgx-sec { margin-top: 72px; }
.mgx-sec--end { padding-bottom: 72px; }

/* Ритм приближен к главной (py-16 md:pt-28 md:pb-24): 80px было тесно
   (замечание автора 21.09). */
@media (min-width: 768px) {
    .mgx-sec { margin-top: 128px; }
    .mgx-sec--end { padding-bottom: 96px; }
}

/* ── Hero-карточка ── */
.mgx-hero {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 420px;
    border-radius: 40px;
    overflow: hidden;
    color: #fff;
}

/* Высота и радиус — как у .hero-media главной (бест-практис, 21.09). */
@media (min-width: 768px) {
    .mgx-hero { min-height: 600px; }
}

.mgx-hero-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.mgx-veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(96deg,
        rgba(19, 23, 32, .9) 0%,
        rgba(19, 23, 32, .66) 42%,
        rgba(19, 23, 32, .2) 75%,
        rgba(19, 23, 32, .08) 100%);
}

.mgx-hero-copy {
    position: relative;
    padding: 52px 44px 30px;
    max-width: 640px;
}

.mgx-h1 {
    margin: 10px 0 14px;
    max-width: 16ch;
    font-size: 48px;
    line-height: 1.08;
    font-weight: var(--font-weight-extrabold, 800);
    letter-spacing: -.025em;
}

.mgx-lead {
    max-width: 46ch;
    margin: 0 0 22px;
    color: rgba(241, 242, 244, .78);
}

.mgx-actions {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
}

/* Главная кнопка страницы — фирменная CTA поверх штатного btn-shine:
   блик и ховер сайта остаются, меняется только заливка. */
.mgx-cta {
    background: var(--cta);
}

.mgx-cta:hover {
    background: var(--cta-hover);
}

.mgx-howlink {
    color: rgba(241, 242, 244, .85);
    font-size: var(--text-base);
    font-weight: var(--font-weight-medium);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    transition: var(--tr-colors) var(--tr-duration) var(--tr-ease);
}

.mgx-howlink:hover { color: #fff; }

/* Строка цифр нижним рядом hero-карточки. */
.mgx-statbar {
    position: relative;
    display: flex;
    margin: 26px 0 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid rgba(255, 255, 255, .18);
    /* Кадр бывает светлым у нижней кромки, и белые цифры терялись
       (замечание автора 21.09) — своя тёмная подложка с блюром. */
    background: rgba(19, 23, 32, .5);
    backdrop-filter: blur(8px);
}

.mgx-statbar li {
    flex: 1;
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center; /* по центру колонки (правка автора 21.09) */
    text-align: center;
    padding: 16px 24px 20px;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    color: rgba(241, 242, 244, .75);
}

.mgx-statbar li + li { border-left: 1px solid rgba(255, 255, 255, .18); }

.mgx-statbar b {
    font-size: 17px;
    color: #fff;
    font-weight: var(--font-weight-extrabold, 800);
    letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── Калькулятор-ориентир ── */
.mgx-calc {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px 300px;
    gap: 34px;
    align-items: start;
    padding: 34px 38px;
    border: 1px solid var(--border);
    border-radius: 20px;
    background: var(--surface);
    box-shadow: var(--sh-card);
}

.mgx-calc-fields {
    display: grid;
    gap: 12px;
}

.mgx-calc-fields label > span {
    display: block;
    margin-bottom: 5px;
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

/* Карта результата — по мокапу (вариант B, 21.09): голубая подложка,
   капс сине-серый, строки «от/до» с тонкими синими разделителями. */
.mgx-calc-res {
    padding: 22px 24px;
    border: 1px solid rgba(45, 91, 242, .18);
    border-radius: 12px;
    background: #EDF0FE;
}

.mgx-calc-res .mg-cap { margin: 0 0 4px; color: #5B6BB5; }

.mgx-calc .page-text { font-size: var(--text-base); max-width: 44ch; }

/* Диапазон стеком «от/до» (выбор автора 21.09): короткие строки с крупной
   цифрой по правому краю — не переносится ни на какой ширине карточки. */
.mgx-range-rows > div {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    padding: 9px 0;
}

.mgx-range-rows > div + div { border-top: 1px solid rgba(45, 91, 242, .14); }

.mgx-range-rows span {
    font-size: 14px;
    color: var(--fg-muted);
}

.mgx-range-rows b {
    font-size: 24px;
    font-weight: var(--font-weight-extrabold, 800);
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--accent);
    white-space: nowrap;
}

.mgx-range-note {
    margin: 8px 0 14px;
    font-size: 13px;
    color: var(--fg-muted);
}

/* ── Тёмная сетка «одна система» ── */
.mgx-sys {
    display: grid;
    grid-template-columns: 280px minmax(0, 1fr);
    gap: 40px;
    padding: 38px 44px;
    border-radius: 20px;
    background: var(--contrast);
    color: var(--on-contrast);
}

.mgx-sys .sec-title { color: #fff; }
.mgx-sys .mgx-sys-intro p { color: rgba(241, 242, 244, .66); font-size: var(--text-base); }
.mgx-sys .mgx-howlink { display: inline-block; margin-top: 16px; }

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

.mgx-sys-grid img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: 12px;
}

.mgx-n {
    display: block;
    margin: 9px 0 1px;
    font-size: var(--text-sm);
    font-weight: var(--font-weight-extrabold, 800);
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

/* «Система»: номер и название пункта в одну строку, номер красный и крупный
   (выбор автора 21.09, вариант A). Красный светлее CTA — на тёмном фоне
   #DA1249 проваливается, у мокапа был #FF3D6E. */
.mgx-sys-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 12px;
}

.mgx-sys-row .mgx-n {
    margin: 0;
    font-size: 24px;
    line-height: 1;
    color: #FF3D6E;
}

.mgx-sys-grid b {
    font-size: var(--text-base);
    font-weight: var(--font-weight-semibold);
}

.mgx-sys-grid p {
    margin: 3px 0 0;
    font-size: var(--text-sm);
    line-height: 1.45;
    color: rgba(241, 242, 244, .6);
}

/* ── Прозрачные финансы ── */
.mgx-fin {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr) 340px;
    gap: 34px;
    align-items: center;
    padding: 30px 34px;
    border-radius: 20px;
    background: color-mix(in srgb, var(--bg) 65%, var(--surface));
    border: 1px solid var(--border);
}

.mgx-fin-photo {
    width: 100%;
    height: 100%;
    min-height: 200px;
    max-height: 260px;
    object-fit: cover;
    border-radius: 14px;
}

.mg-repcard {
    border: 1px solid var(--border);
    border-radius: 16px;
    background: var(--surface);
    box-shadow: var(--sh-card);
    overflow: hidden;
}

.mg-rephead {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-base);
}

.mg-rephead span { color: var(--fg-subtle); }

.mg-reprows {
    margin: 0;
    padding: 10px 18px 16px;
    font-size: var(--text-base);
}

.mg-reprows > div {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    color: var(--fg-muted);
}

.mg-reprows dt, .mg-reprows dd { margin: 0; }
.mg-reprows dd { font-variant-numeric: tabular-nums; white-space: nowrap; }

.mg-reprows > .mg-reptotal {
    margin-top: 6px;
    padding-top: 11px;
    border-top: 1px solid var(--border-strong);
    color: var(--fg);
    font-weight: var(--font-weight-semibold);
    font-size: 16px;
}

/* ── Сплит контроль/забота ── */
.mgx-ctrl {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    border-radius: 20px;
    overflow: hidden;
    border: 1px solid var(--border);
}

/* Панель контроля: атмосферное фото под вуалью вместо чёрной заливки
   (выбор автора 21.09, вариант A), текст прижат к низу как в hero. */
.mgx-ctrl-dark {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 420px;
    overflow: hidden;
    color: var(--on-contrast);
}

.mgx-ctrl-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.mgx-ctrl-veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(200deg, rgba(20, 24, 31, .18), rgba(20, 24, 31, .78) 70%);
}

.mgx-ctrl-inner {
    position: relative;
    padding: 34px 38px;
}

.mgx-ctrl-dark .sec-title { color: #fff; }
.mgx-ctrl-dark p { color: rgba(241, 242, 244, .66); font-size: var(--text-base); }

.mgx-soon {
    display: inline-block;
    margin-top: 16px;
    padding: 9px 13px;
    border: 1px dashed rgba(255, 255, 255, .3);
    border-radius: 10px;
    font-size: var(--text-sm);
    color: rgba(241, 242, 244, .55) !important;
}

.mgx-ctrl-light {
    padding: 26px 30px 30px;
    background: var(--surface);
}

.mgx-ctrl-light img {
    width: 100%;
    aspect-ratio: 16 / 7;
    object-fit: cover;
    border-radius: 12px;
    margin-bottom: 16px;
}

.mgx-h3 {
    margin: 2px 0 0;
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -.01em;
}

.mgx-care {
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 8px;
    font-size: var(--text-base);
}

.mgx-care li::before {
    content: '✓';
    margin-right: 9px;
    color: #1E7F46;
    font-weight: 700;
}

/* ── Путь 01–04: каскад штатного .reveal + отклик на ховер ── */
.mgx-pgrid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}

/* Плашка-этап: отрастает слева направо (scaleX, движок svc-fx), сверху
   синяя черта прорастает следом, длительность — пилюлей. Финал синий. */
.mgx-pbar {
    position: relative;
    overflow: hidden;
    padding: 16px 18px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--sh-card);
}

.mgx-pbar::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    height: 3px;
    width: 100%;
    background: var(--accent);
}

.mgx-pn {
    font-size: var(--text-sm);
    font-weight: var(--font-weight-extrabold, 800);
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

.mgx-pbar b {
    display: block;
    margin-top: 2px;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
}

.mgx-pbar p {
    margin: 4px 0 0;
    font-size: var(--text-sm);
    color: var(--fg-muted);
}

.mgx-plen {
    display: inline-block;
    margin-top: 10px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: .08em;
    color: var(--accent);
    background: var(--accent-subtle);
}

.mgx-pbar--acc {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-fg);
}

.mgx-pbar--acc .mgx-pn { color: var(--accent-fg); }
.mgx-pbar--acc p { color: rgba(255, 255, 255, .8); }

.mgx-pbar--acc .mgx-plen {
    color: var(--accent-fg);
    background: rgba(255, 255, 255, .16);
}

/* Появление — тот же движок, что у «Услуг»: html.js + .svc-in. */
html.js [data-role="svc-fx"] .mgx-pbar {
    transform-origin: left;
    transform: scaleX(0);
    transition: transform .9s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .mgx-pbar > * {
    opacity: 0;
    transition: opacity .5s ease calc(var(--svc-d, 0s) + .45s);
}

html.js [data-role="svc-fx"] .mgx-pbar.svc-in { transform: none; }
html.js [data-role="svc-fx"] .mgx-pbar.svc-in > * { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    html.js [data-role="svc-fx"] .mgx-pbar,
    html.js [data-role="svc-fx"] .mgx-pbar > * {
        transition: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ── FAQ ── */
.mg-faq {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 40px;
    margin-top: 18px;
}

.mg-faqrow { border-bottom: 1px solid var(--border); }

.mg-faqrow summary {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    padding: 14px 0;
    font-size: var(--text-base);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    list-style: none;
}

.mg-faqrow summary::-webkit-details-marker { display: none; }
.mg-faqrow summary::after { content: '+'; color: var(--fg-subtle); font-weight: 400; }
.mg-faqrow[open] summary::after { content: '−'; }

.mg-faqrow p {
    margin: 0;
    padding: 0 0 14px;
    font-size: var(--text-base);
    color: var(--fg-muted);
    max-width: 60ch;
}

/* ── Тёмный финал с формой — компактный ── */
.mg-dark {
    background: var(--contrast);
    color: var(--on-contrast);
}

.mgx-final { border-radius: 20px; }

.mg-dark .mg-cap { color: rgba(241, 242, 244, .55); }
.mg-dark .sec-title { color: #fff; }
.mg-dark .page-text { color: rgba(241, 242, 244, .72); }

.mg-fee {
    display: inline-block;
    padding: 10px 14px;
    border-radius: 10px;
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .14);
    font-size: var(--text-base);
    color: rgba(241, 242, 244, .85);
}

.mg-ctagrid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 420px;
    gap: 44px;
    align-items: center;
}

/* Компактный вариант финала (просьба автора 20.09): паддинги блока и шаг
   полей ужаты, зоны нажатия полей не тронуты. */
.mgx-final-grid {
    grid-template-columns: .7fr 1.3fr;
    gap: 44px;
    align-items: start;
    padding: 36px 40px;
}
.mgx-compact form { gap: 10px !important; }
.mgx-compact .form-title { font-size: 17px; }
.mgx-compact .form-hint { margin-bottom: 2px; }

.mg-formcard { color: var(--on-contrast); }
.mg-formcard .form-title { color: #fff; }
.mg-formcard .form-hint { color: rgba(241, 242, 244, .6); }
.mg-formcard .form-label { color: rgba(241, 242, 244, .8); }

.mg-formcard .field,
.mg-formcard select.apple-select,
.mg-formcard .phone-code-btn {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .18);
    color: #fff;
}

.mg-formcard .field::placeholder { color: rgba(241, 242, 244, .45); }
.mg-formcard .consent-row { color: rgba(241, 242, 244, .7); }
.mg-formcard .consent-row a { color: #fff; }

.mg-formcard .btn { background: var(--cta); }
.mg-formcard .btn:hover { background: var(--cta-hover); }

/* ── Планшет и телефон ── */
@media (max-width: 1023px) {
    .mgx-h1 { font-size: 38px; }
    .mgx-calc { grid-template-columns: 1fr 1fr; }
    .mgx-calc-res { grid-column: 2; }
    .mgx-sys { grid-template-columns: 1fr; gap: 24px; }
    .mgx-sys-grid { grid-template-columns: repeat(2, 1fr); }
    .mgx-fin { grid-template-columns: 1fr 1fr; }
    .mgx-fin-photo { display: none; }
    .mgx-path { grid-template-columns: 1fr 1fr; }
    .mgx-path > div:first-child { grid-column: 1 / -1; }
    .mg-ctagrid { grid-template-columns: 1fr; }
}

@media (max-width: 767px) {
    .mgx-hero { min-height: 420px; }
    .mgx-hero-copy { padding: 34px 22px 20px; }
    .mgx-h1 { font-size: 30px; }
    .mgx-statbar { flex-direction: column; }
    .mgx-statbar li { padding: 10px 22px; }
    .mgx-statbar li + li { border-left: 0; border-top: 1px solid rgba(255,255,255,.14); }
    .mgx-calc, .mgx-fin { grid-template-columns: 1fr; padding: 22px; }
    .mgx-calc-res { grid-column: auto; }
    .mgx-sys { padding: 26px 22px; }
    .mgx-sys-grid { grid-template-columns: 1fr; }
    .mgx-ctrl { grid-template-columns: 1fr; }
    .mgx-pgrid { grid-template-columns: repeat(2, 1fr); }
    .mg-faq { grid-template-columns: 1fr; }
    .mgx-final-grid { padding: 24px 20px 28px; }
}

/* Свой список кодов (замечание автора 20.09): карточка как у share-меню —
   белая, радиус 12, тень --sh-modal, ховеры строк. Нативный select остаётся
   в форме значением (phone-code--native), видимой становится кнопка. */
.phone-duo {
    position: relative;
}

.phone-code--native {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.phone-code-btn {
    cursor: pointer;
    text-align: left;
    color: var(--fg);
}

.phone-code-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 30;
    width: 224px;
    max-height: 264px;
    overflow-y: auto;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--sh-modal);
}

.phone-code-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--fg);
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    cursor: pointer;
    transition: var(--tr-colors) var(--tr-duration) var(--tr-ease);
}

.phone-code-item:hover {
    background: var(--surface-hover);
}

.phone-code-item b {
    min-width: 44px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.phone-code-item span {
    color: var(--fg-muted);
    font-size: var(--text-xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.phone-code-item.is-on {
    background: var(--accent-subtle);
}

/* «Поделиться» у заголовка объекта (выбор автора 20.09, мокап «Вариант 3»).

   Кнопка — подчёркнутый текст со значком, как у Airbnb: действие второго
   плана, не спорящее с CTA брони. Меню — компактный дропдаун под кнопкой,
   выровнен по её правому краю; на телефоне вместо него системное окно
   (см. bindShare в site.js). */
.share-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
}

.share {
    position: relative;
    flex: none;
    /* На линии первой строки заголовка, а не по верху блока. */
    margin-top: 6px;
}

.share-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 10px;
    border: 0;
    border-radius: 9px;
    background: none;
    color: var(--fg);
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    font-weight: var(--font-weight-medium);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
    cursor: pointer;
    transition: var(--tr-colors) var(--tr-duration) var(--tr-ease);
}

.share-btn:hover {
    background: var(--surface-hover);
}

.share-btn svg {
    width: 16px;
    height: 16px;
}

.share-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    width: 232px;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: var(--sh-modal);
}

.share-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--fg);
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
    cursor: pointer;
    transition: var(--tr-colors) var(--tr-duration) var(--tr-ease);
}

.share-item:hover {
    background: var(--surface-hover);
}

.share-item svg {
    width: 17px;
    height: 17px;
    flex: none;
    color: var(--fg-muted);
}

/* Подтверждение «Скопировано»: кнопка на секунду зеленеет текстом. */
.share-item.is-done,
.share-item.is-done svg {
    color: #1E7F46;
}

/* Телефон с кодом страны (задача автора 20.09, п. 3): выпадающий код слева,
   номер справа. Ширину держит код — он всегда «+NNN», а номер тянется. В
   списке у кода подпись «+66 · Таиланд», в свёрнутом виде браузер показывает
   её же начало — кода хватает, чтобы понять выбор. */
.phone-duo {
    display: flex;
    gap: 8px;
    min-width: 0;
}

/* Стрелка — свой шеврон, как у остальных селектов сайта (apple-select):
   нативная прижималась вплотную к правому краю (замечание автора 20.09).
   Тот же data-URI и те же 10px от края, только размер под компактное поле. */
.phone-duo .phone-code {
    flex: 0 0 84px;
    min-width: 0;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 13px 13px;
    padding-right: 28px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
}

.phone-duo .phone-number {
    flex: 1;
    min-width: 0;
}

/* Вариант фильтра, под который при текущих условиях ничего нет (задача автора
   20.09): прячем, а не гасим. Смысл живых фасетов — чтобы гость физически не
   мог собрать набор галочек, дающий пустую выдачу; серая, но нажимаемая
   строка этой гарантии не даёт. Выбранный вариант класс не получает никогда —
   иначе снять свою же галочку было бы нечем (ставит blade и site.js). */
.dist-row.is-empty,
.tile-opt.is-empty {
    display: none;
}

/* Группа, в которой не осталось ни одного доступного варианта, уходит целиком
   (замечание автора 20.09): заголовок «Удобства» над пустотой ничего не
   говорит, а кнопка «Показать все 78» под ним обещала то, чего при текущем
   фильтре нет. */
.filter-group.is-empty {
    display: none;
}

/* Пока идёт запрос — выдача чуть гаснет: движение фильтра должно отзываться
   сразу, даже если ответ идёт четверть секунды. */
[data-role="catalog-list-slot"][aria-busy="true"] {
    opacity: .55;
    transition: opacity .15s ease;
}

/* Карточка бронирования проявляется расфокусом при загрузке (выбор автора
   19.09, мокап «Вариант 7»).

   Кадр наводится на резкость: blur 7px → 0 со сдвигом на 18px справа.

   Старт отложен до готовности страницы, а не привязан к первой отрисовке
   (просьба автора 19.09). Анимация объявлена с animation-play-state: paused —
   при fill-mode backwards это держит карточку в начальном кадре, — и
   запускается, когда site.js ставит на <html> класс bk-ready: после стилей и
   шрифтов. Иначе расфокус успевал отыграть по резервному шрифту, и текст
   внутри карточки подменялся уже после её появления.

   Всё это включается ТОЛЬКО при html.js — класс ставит строчка в <head>
   лейаута. Без скрипта класса нет, анимации нет, и карточка просто видна:
   элемент никогда не остаётся невидимым из-за неотработавшего js.

   fill-mode backwards, а НЕ both: с both конечный filter остался бы на
   элементе навсегда, а постоянный filter на карточке с формой — это лишний
   композитный слой на всю жизнь страницы. При backwards свойство снимается
   сразу после анимации.

   Только от 1024px: ниже карточка живёт не в колонке, а в шторке, которую
   гость открывает кнопкой снизу, — у неё своё появление и свой момент. Это
   же снимает вопрос стоимости blur: на телефонах он не включается вовсе. */
@media (min-width: 1024px) {
    html.js [data-role="booking-box"] {
        animation: bk-focus .7s var(--ease-out-quart, cubic-bezier(.25, 1, .5, 1)) backwards;
        animation-play-state: paused;
    }

    html.js.bk-ready [data-role="booking-box"] {
        animation-play-state: running;
    }
}

@keyframes bk-focus {
    from {
        opacity: 0;
        filter: blur(7px);
        transform: translate3d(18px, 0, 0);
    }

    to {
        opacity: 1;
        filter: blur(0);
        transform: none;
    }
}

/* Системная настройка «меньше движения» гасит появление целиком: карточка
   просто стоит на месте с первого кадра. */
@media (prefers-reduced-motion: reduce) {
    html.js [data-role="booking-box"] {
        animation: none;
    }
}

/* Разделитель перед группой доплат (правка автора 19.09).

   Линии стоят только там, где меняется смысл блока: даты → обязательные
   доплаты → доплаты по выбору, и дальше уже готовые .bk-sep перед
   расчётом, формой и мессенджерами. Внутри группы строки не разделяются:
   разделитель между однородными строками превращает карточку в таблицу. */
.bk-group {
    border-top: 1px solid var(--border);
    padding-top: 14px;
}

/* Строка удобства с чекбоксом: зона нажатия во всю ширину. */
.bk-extra {
    display: flex;
    min-height: 44px;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    color: var(--fg);
}

/* Под мышью строки плотнее — 36px вместо 44 (просьба автора 19.09):
   две-три доплаты с шагом 44px растягивали список на полкарточки. Граница
   по способу ввода, а не по ширине окна: 44px — это палец, и на сенсорном
   экране любой ширины сжимать его нельзя. Гибридные ноутбуки с сенсором
   отвечают на pointer: fine по основному указателю — там мышь. */
@media (pointer: fine) {
    .bk-extra {
        min-height: 36px;
    }
}

/* Обязательная доплата: та же строка, но без контрола, поэтому без курсора.
   Вместо чекбокса галочка тем же размером. */
.bk-extra--static {
    cursor: auto;
}

.bk-extra-check {
    width: 16px;
    height: 16px;
    text-align: center;
    font-size: var(--text-xs);
    line-height: var(--text-xs--line-height);
    letter-spacing: 0;
    color: var(--fg-subtle);
}

.bk-extra-row {
    display: flex;
    width: 100%;
    justify-content: space-between;
    gap: 8px;
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
}

/* Расчёт: каждая строка это название слева и сумма справа. */
.bk-quote {
    font-size: var(--text-sm);
    line-height: var(--text-sm--line-height);
    letter-spacing: 0;
}

.bk-quote > div,
.bk-row {
    display: flex;
    justify-content: space-between;
}

.bk-row {
    gap: 8px;
}

.bk-quote > .is-muted {
    color: var(--fg-muted);
}

/* Итог выделен кеглем и начертанием, а не линией (выбор автора 19.09).

   Разделители у блока расчёта теперь только по краям — сверху .bk-sep
   у самого списка, снизу .bk-sep у формы заявки. Линия внутри, над
   самим итогом, делила однородный список сумм надвое и читалась как
   граница блока, которой там нет. Класс стоит на итоге всегда, а не
   только при разбивке: выделять главную сумму нужно и у объекта из CRM,
   где строк выше нет вовсе. */
.bk-quote > .bk-quote-total {
    font-size: 15px;
    line-height: 22px;
    font-weight: var(--font-weight-semibold);
}

/* Суммы моноширинными цифрами, иначе колонка справа пляшет. */
.bk-quote dd,
.bk-num-subtle {
    font-variant-numeric: tabular-nums;
}

.bk-quote dd.is-total {
    font-weight: var(--font-weight-semibold);
}

.bk-num-subtle {
    color: var(--fg-subtle);
}

/* Сумма рядом с чекбоксом доплаты: тот же приглушённый цвет, но БЕЗ
   моноширинных цифр. В разметке у неё tabular-nums не стояло, в отличие от
   сумм в списке, и табличные цифры шире, поэтому строка разъезжалась. */
.bk-extra-sum {
    color: var(--fg-subtle);
}

/* ── Страницы ошибок ──────────────────────────────────────────────────
   404 и 500, разметка у них одинаковая. Раньше обе подключали только
   замороженную сборку и жили вне архитектуры; слои подключены 13.09.

   Контейнер не .shell: у него от планшета поля 2rem, а здесь всегда 1.25rem.
   Подменять это значит менять вид. */
.error-page {
    display: flex;
    min-height: 100vh;
    width: 100%;
    max-width: var(--shell-max);
    margin-inline: auto;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding-inline: 20px;
    text-align: center;
}

/* Крупный номер ошибки: своё межбуквенное -.035em, плотнее заголовков. */
.error-code {
    font-size: clamp(32px, 4vw, 48px);
    line-height: 1;
    letter-spacing: -.035em;
    font-weight: var(--font-weight-bold);
    color: var(--fg-subtle);
}

.error-lead {
    max-width: 448px;
    color: var(--fg-muted);
}

/* ── Повторяющиеся блоки страниц ──────────────────────────────────────
   Переехало из утилит разметки (рефакторинг 11.09). bg-tint у первых двух
   ОСТАЁТСЯ в разметке: у него подписка [data-theme=dark] .bg-tint с рамкой,
   и снять её значит изменить геометрию блока в тёмной теме. */

/* Шапка-плашка служебных страниц: инвестиции, управление, партнёрство,
   услуги. Было утилитами border-b border-border — цвет рамки в разметке всё
   равно не работал, его задаёт безслойное правило в хвосте main.css. */
.page-head {
    border-bottom: 1px solid var(--border);
}

/* Карточка на подложке: «Контакты», управление, партнёрство. */
.tint-card {
    border-radius: 40px;
    padding: 24px;
}

@media (min-width: 768px) {
    .tint-card {
        padding: 32px;
    }
}

/* Узкая колонка чтения у текстовых страниц: страница из админки и политика. */
.read-col {
    max-width: var(--container-3xl);
    margin-inline: auto;
    padding-block: 32px;
}

/* Кадр героя: приближение (keyframes ken-burns из сборки) несёт слой-обёртка
   .hero-zoom, а картинка внутри лежит статичной заливкой с object-fit.

   Раньше класс .ken-burns стоял на самом <img>. В Firefox (замечание автора
   18.09) это давало рывки и движение «по кривой»: трансформация на
   replaced-элементе с object-fit там не уходит на композитор, кадр
   пересчитывается каждый шаг, и точка масштабирования плавает вместе с
   пересчётом object-fit. Подсказки will-change/transform-origin на самом
   <img> не помогли. Трансформация на обычном блоке композитится во всех
   браузерах одинаково; картинка внутри не трансформируется вовсе.

   Слой абсолютный на всю площадь рамки: все пять рамок позиционированы и
   режут содержимое (overflow: hidden + скругление). */
.hero-zoom {
    position: absolute;
    inset: 0;
    animation: hero-zoom 20s var(--ease-out-quart) forwards;
    transform-origin: 50% 50%;
    will-change: transform;
}

/* Без приближения: герой каталога (правка автора 21.09) — кадр статичен
   в обеих темах, слой остаётся ради общей геометрии заливки. */
.hero-zoom--still {
    animation: none;
    will-change: auto;
}

/* Свои ключевые кадры вместо ken-burns из сборки (scale(1) → scale(1.06)):
   Firefox привязывает плоский осевой transform к целым пикселям (pixel
   snapping), и к концу ease-out-кривой, когда кадр движется на доли пикселя
   в секунду, приближение идёт скачками по пикселю, а X и Y перещёлкиваются
   в разные моменты — то самое «рывками и по кривой» (замечание автора 18.09,
   перенос анимации на обёртку сам по себе не помог). Привязку Firefox делает
   только для 2D-трансформаций без поворота: 3D-масштаб с translateZ и
   микроповорот на 0.0001° заставляют его интерполировать субпиксельно, как
   Chrome. Визуально поворот — ноль. */
@keyframes hero-zoom {
    from {
        transform: translateZ(0) scale3d(1, 1, 1) rotate(.0001deg);
    }

    to {
        transform: translateZ(0) scale3d(1.06, 1.06, 1) rotate(.0001deg);
    }
}

.hero-zoom img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Низкие герои — «Контакты» и посадочные (.page-hero, 486px) и полоса
   каталога (.rent-head-rect, 232px) — приближаются мягче: 1.035 вместо 1.06
   при тех же 20 с (просьба автора 18.09). Процент везде был одинаковый, но в
   узком кадре те же 44px сдвига края читались как «наезд», а в крупном кадре
   главной и «О компании» растворялись. Путь сокращён на 40%, ритм и кривая —
   общие с главной. */
@keyframes hero-zoom-soft {
    from {
        transform: translateZ(0) scale3d(1, 1, 1) rotate(.0001deg);
    }

    to {
        transform: translateZ(0) scale3d(1.035, 1.035, 1) rotate(.0001deg);
    }
}

.page-hero .hero-zoom,
.rent-head-rect .hero-zoom {
    animation-name: hero-zoom-soft;
}

/* Firefox приближение не получает вовсе (решение автора 18.09): на его
   машине рвались даже простейшие трансформации — дело в браузере, а не в
   коде (тест _ff-zoom-test), но гостю это не объяснишь, и статичный кадр
   лучше дёргающегося. Узнаём Firefox по свойству, которое понимает только
   Gecko: @supports с -moz-appearance в Chrome/Safari ложно. Без JS и без
   разбора user-agent. */
@supports (-moz-appearance: none) {
    .hero-zoom {
        animation: none;
    }
}

/* Кадр ниже первого экрана (фото офиса на «Контактах»): та же анимация, но
   на паузе, пока reveal (main.js) не отметит блок показанным — иначе к
   моменту прокрутки движение уже кончилось бы. Без JS класса .js-anim нет —
   анимация идёт сразу; при prefers-reduced-motion общий сброс сборки
   (animation-duration: .01ms) оставляет статичный кадр. */
.hero-zoom--view {
    animation-play-state: paused;
}

.reveal[data-reveal="in"] .hero-zoom--view,
html:not(.js-anim) .hero-zoom--view {
    animation-play-state: running;
}

/* ── Тинт над кадром героя (выбор автора 04.09, мокап «Тинт 2») ──────────
   Градиент снизу вверх графитом #13171B, на треть прозрачнее прежнего
   (было 85 → 35 → 0 утилитами билда, стало 60 → 25 → 0): фото заметно ярче,
   заголовок и подпись на нём читаются. Стоит на всех героях с фото: главная,
   «Контакты», «О компании» (решение автора 04.09 — один эффект везде). Свой
   класс, потому что утилит с такими стопами в замороженном билде нет. */
.hero-tint {
    /* было утилитами absolute inset-0 во всех трёх местах */
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(19, 23, 27, .6) 0%, rgba(19, 23, 27, .25) 50%, transparent 100%);
}

/* Затемнение героя главной — как на стенде dev, то есть как в мастере
   (правка автора 09.09): #13171B 85 → 35 → 0. В этой ветке 04.09 тинт
   облегчили до 60 → 25 → 0, и на дневном кадре белый текст стал читаться
   неровно — в самых светлых местах заголовок падал до 2,7:1 при норме 3.
   Возвращаем прежнюю плотность.

   Только на светлой теме и только на главной: .hero-tint общий для героев
   «Контактов» и «О компании» (решение автора 04.09 — один эффект везде), а
   ночному кадру тёмной темы затемнения хватает. Грейд самого кадра, который
   стоял здесь до этой правки, снят: две меры затемнения сразу — перебор. */
[data-theme="light"] [data-role="hero"] .hero-tint {
    background: linear-gradient(to top,
        rgba(19, 23, 27, .85) 0%,
        rgba(19, 23, 27, .35) 50%,
        transparent 100%);
}

/* ── Карточка объекта: информация секциями-карточками ─────────────────────
   Выбор автора 08.09 (мокап «Вариант 1»): каждая секция в белой карточке с
   одинаковым отступом, ритм задают карточки, а не заголовки. Характеристики и
   факты правил — плитками на подложке tint, доплаты — таблицей с рамкой.
   Живёт здесь: в замороженной сборке таких утилит нет. */
.obj-card {
    border: 1px solid var(--border);
    border-radius: 16px;
    background: var(--surface);
    padding: 22px 24px;
}

.obj-card + .obj-card {
    margin-top: 14px;
}

.obj-card-title {
    font-size: 20px;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: -.01em;
}

/* Заголовок карточки → плитки фактов: 20px (замечание автора 08.09: плитки
   правил прилипали к заголовку — margin: 0 у сетки перебивал утилиту mt-4). */
.obj-card-title + .obj-rules,
.obj-card-title + .obj-extras {
    margin-top: 20px;
}

/* ── Hero главной на телефоне (правка автора 10.09): кадр больше не
   подстраивается под высоту окна, а берёт свою высоту из разметки —
   h-[420px], как прямоугольник в шапке аренды. Планка поиска просто стоит
   под кадром в потоке (mt-3 в разметке); на md и выше она по-прежнему
   наезжает на низ кадра абсолютом.

   С 08.09 здесь было наоборот: секция занимала весь экран без шапки
   (100dvh - 73px), а кадр тянулся на остаток высоты флексом. От этого кадр
   был разной высоты на каждом телефоне, и на коротких экранах приходилось
   прятать подпись под заголовком. */
/* На телефоне кадр выше, чем даёт разметка: 508px вместо 420 (правка автора
   10.09 — сначала 462, затем ещё +10%). Правило на весь диапазон до 768px, а
   не только до 640: разметка от sm поднимает высоту всего до 480, и на 640px
   кадр оказался бы ниже, чем на 390. Ступенька остаётся возрастающей:
   508 на телефоне и планшете до 768, дальше 600 из разметки. */
@media (max-width: 767px) {
    .hero-media {
        height: 508px;
    }
}

@media (max-width: 767px) {
    /* Текст поверх кадра компактнее: кадр на телефоне ниже, чем на десктопе. */
    .hero-copy {
        padding: 20px 20px 24px;
    }

    /* Только герой главной: подпись «Контактов» пользуется тем же классом, но
       кегль на телефоне у неё свой. Раньше правило было просто .hero-lead и
       работало верно лишь потому, что класс стоял в одном месте. */
    .hero-copy .hero-lead {
        margin-top: 10px;
        font-size: 16px; /* 16px — правка автора 08.09 */
        line-height: 1.45;
    }
}

/* ── Кегли для широкой колонки (решения автора 18.09) ─────────────────
   Колонка стала 1480 вместо 1280, и прежние кегли на ней читались мельче.
   Подняты точечно, по таблице автора, — и ТОЛЬКО от 1280px: ниже колонка
   упирается во вьюпорт, телефон и планшет остаются как в main (уточнение
   автора 18.09). Шкала на десктопе: 12 примечания · 14 подписи · 16 текст и
   всё нажимаемое · 18 лиды и заголовки карточек; дробных кеглей нет.
   Блок стоит последним в файле нарочно: при равной специфичности побеждает
   он. */
@media (min-width: 1280px) {
    /* Кадры с фиксированной высотой растут вместе с колонкой (1280 → 1480,
       коэффициент 1.156; решение автора 18.09): герой главной 600→694,
       герой страниц 420→486, герой «О компании» 560→648. Кадры на
       aspect-ratio (карточки, объект, офис, мозаика) вытянулись сами. */
    .hero-media {
        height: 694px;
    }

    .page-hero {
        height: 486px;
    }

    [data-role="about-hero"] {
        height: 648px;
    }

    /* Герой объекта (мокап «Вариант 1», 18.09): кадр на 15% уже, справа
       вертикальная лента из четырёх миниатюр. Полоса держит прежние 16/9 по
       ширине колонки, чтобы высота кадра не изменилась; кадр внутри тянется
       на всю высоту полосы, миниатюры делят её поровну. Колонка миниатюр —
       140px: это и есть 15% от 996px кадра минус зазор. */
    .hero-strip:has(.hero-thumbs) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 140px;
        grid-template-rows: minmax(0, 1fr);
        gap: 12px;
        aspect-ratio: 16 / 9;
    }

    .hero-strip:has(.hero-thumbs) .obj-frame {
        aspect-ratio: auto;
        height: 100%;
    }

    .hero-thumbs {
        display: grid;
        grid-auto-rows: minmax(0, 1fr);
        gap: 12px;
        margin: 0;
        padding: 0;
        list-style: none;
        min-height: 0;
    }

    .hero-thumbs li {
        min-height: 0;
    }

    .hero-thumbs button {
        position: relative;
        display: block;
        width: 100%;
        height: 100%;
        padding: 0;
        border: 0;
        border-radius: 14px;
        overflow: hidden;
        background: var(--bg-subtle);
        cursor: pointer;
    }

    .hero-thumbs img {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: cover;
        transition: transform .45s cubic-bezier(.16, 1, .3, 1);
    }

    .hero-thumbs button:hover img {
        transform: scale(1.04);
    }

    .hero-thumbs button:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
    }

    /* Миниатюра ролика (выбор автора 19.09, мокап «Вариант 4»): тот же кадр,
       что и у снимков, плюс значок проигрывания по центру. Тёмная подложка —
       на случай, когда обложки ещё нет: очередь считает кадр около минуты, и
       до этого плитка не должна выглядеть сломанной. */
    .hero-thumb-video {
        background: #0b0e12;
    }

    .hero-thumb-video img {
        opacity: .85;
    }

    .hero-thumb-play {
        position: absolute;
        inset: 0;
        display: grid;
        place-items: center;
        pointer-events: none;
    }

    .hero-thumb-play svg {
        width: 28px;
        height: 28px;
        padding: 6px;
        border-radius: 50%;
        background: rgba(255, 255, 255, .92);
        color: #13171b;
        box-shadow: 0 4px 14px rgba(0, 0, 0, .28);
    }

    /* «+N» на последней миниатюре — сколько фотографий ещё не показано. */
    .hero-thumbs-more {
        position: absolute;
        inset: 0;
        display: grid;
        place-items: center;
        background: rgba(12, 16, 22, .55);
        color: #fff;
        font-size: 18px;
        font-weight: 600;
    }

    /* H1 на всех страницах — 64px (решение автора 18.09), см. components.css:
       герой главной (был 60), герой «О компании» (56). Каталог — исключение
       по правке автора того же дня: его компактный заголовок остаётся 36. */
    .hero-copy .hero-title,
    [data-role="about-hero"] .hero-title {
        font-size: 64px;
        line-height: 1.05;
        letter-spacing: -.03em;
    }

    /* H1 каталога 36→38 (правка автора 18.09): чуть крупнее общего H2, но не
       64, как у остальных H1 — герой здесь компактный. */
    .rent-head-rect h1 {
        font-size: 38px;
    }

    /* Лид под заголовком каталога 16→18 — как лид героя. */
    .rent-head-rect p {
        font-size: 18px;
        line-height: 1.5;
    }

    /* Карта районов на главной: имена 11.5→14 (активное 12.5→16), выноска —
       имя 14→16, счётчик 12→14, «Смотреть объекты» 12.5→14; чип 15→16. */
    .map-ph-name {
        font-size: 14px;
    }

    .districts-photo--card .map-pin-ph.is-active .map-ph-name {
        font-size: 16px;
    }

    .map-ph-callout b {
        font-size: 16px;
    }

    .map-ph-callout > span,
    .map-ph-callout .go {
        font-size: 14px;
    }

    .district-chip {
        font-size: 16px;
    }

    /* Чипы «Как это работает» 12.5→16 (вторая правка автора 18.09: ещё +2). */
    .hiw-chip {
        font-size: 16px;
    }

    /* Фото шагов: кадр на 20% ниже квадрата (просьба автора 18.09 — минус
       10% сверху и минус 10% снизу). object-fit: cover центрирует, так что
       срезаются ровно верхняя и нижняя десятые доли снимка. */
    .hiw-ph {
        aspect-ratio: 5 / 4;
    }
}


/* ── «Услуги»: хаб по референсу 1Solar/Framer (выборы автора 20.09,
   мокапы _mock-services3/4: hero-занавес, count-up, услуги с заливкой,
   спека линиями, таймлайн-полосы, кейсы clip-path, звёзды по одной,
   дышащее пятно CTA, FAQ grid-rows, форма справа) ─────────────────────
   Текст hero — родные .hero-copy/.hero-title главной. Все появления
   включаются ТОЛЬКО при html.js (класс ставит строчка в <head>): без
   скрипта страница просто видна целиком. Движок — data-role="svc-fx",
   site.js вешает .svc-in (bindServicesFx). Изинг референса один: --svc-e. */

.svc-hero {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 420px;
    border-radius: 40px;
    overflow: hidden;
    background: #20242C;
    color: var(--color-white);
}

/* Высота и радиус — как у .hero-media главной (бест-практис, 21.09). */
@media (min-width: 768px) {
    .svc-hero { min-height: 600px; }
}

.svc-hero-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.svc-hero-veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 24, 31, .3), rgba(20, 24, 31, .12) 40%, rgba(20, 24, 31, .82) 92%);
}

.svc-hero .hero-copy { position: relative; z-index: 2; }

.svc-hero-em { color: var(--color-white); }

.svc-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 24px;
}

.svc-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 52px;
    padding-inline: 28px;
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: 12px;
    font-size: var(--text-base);
    line-height: var(--text-base--line-height);
    font-weight: var(--font-weight-medium);
    color: var(--color-white);
    transition-property: var(--tr-colors);
    transition-duration: var(--tr-duration);
    transition-timing-function: var(--tr-ease);
}

.svc-ghost:hover { background: rgba(255, 255, 255, .14); }

/* Цифры под hero: по центру ряда и внутри колонок (правка автора 20.09). */
.svc-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    padding-top: 26px;
    text-align: center;
}

/* Тонкие разделители-колонны, подписи капсом (выбор автора 21.09, вариант A). */
.svc-stats > div { padding: 10px 18px; }
.svc-stats > div + div { border-left: 1px solid rgba(12, 21, 42, .22); }

.svc-stats b {
    display: block;
    font-size: clamp(28px, 3vw, 42px);
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.svc-stats b em {
    font-style: normal;
    color: var(--accent);
}

.svc-stats span {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--fg-subtle);
}

/* Голова секции: заголовок слева, подводка справа по низу. */
.svc-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 40px;
    margin-bottom: 34px;
}

.svc-head .sec-title { max-width: 24ch; text-wrap: balance; }

.svc-side {
    max-width: 460px;
    color: var(--fg-muted);
    font-size: var(--text-base);
    line-height: 1.55;
}

/* «Восемь лет, посчитанные» — единая белая карта (выбор автора 21.09,
   мокап B): цифры стопкой слева за разделителем, факты справа. */
.svc-numcard {
    display: grid;
    grid-template-columns: .8fr 1.2fr;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 20px;
    box-shadow: var(--sh-card);
    overflow: hidden;
}

.svc-numcol { padding: 30px 34px; border-right: 1px solid var(--border); }
.svc-numcol > div { padding: 16px 0; }
.svc-numcol > div + div { border-top: 1px solid var(--border); }

.svc-numcol b {
    display: block;
    font-size: 40px;
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: 1.05;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.svc-numcol span {
    display: block;
    margin-top: 4px;
    font-size: 15px;
    color: var(--fg-muted);
}

.svc-facts { padding: 30px 34px; }
.svc-facts .mg-cap { margin-bottom: 10px; }

.svc-facts > div {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    border-bottom: 1px solid var(--border);
    padding: 14px 0;
    font-size: 15px;
}

.svc-facts > div:last-child { border-bottom: 0; }
.svc-facts span:last-child { color: var(--fg-muted); text-align: right; }

/* Услуги 01–06 — список + живое превью (выбор автора 21.09, мокап 3).
   Активный пункт подсвечен синим и сдвинут, у него виден кружок-стрелка;
   справа липкая фото-карта, кадры наложены и переключаются прозрачностью. */
.svc-dirs {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 520px;
    gap: 44px;
    align-items: start;
}

.svc-dirlist { border-top: 1px solid rgba(12, 21, 42, .22); }

.svc-dir {
    display: grid;
    grid-template-columns: 52px 1fr auto;
    gap: 18px;
    align-items: center;
    padding: 20px 8px;
    border-bottom: 1px solid var(--border);
    transition: padding-left .4s var(--svc-e);
}

.svc-dir.is-on { padding-left: 16px; }

.svc-n {
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    color: var(--fg-subtle);
    font-variant-numeric: tabular-nums;
    transition: color .3s ease;
}

.svc-dir b {
    font-size: 26px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -.025em;
    line-height: 1.15;
    transition: color .3s ease;
}

.svc-dir.is-on .svc-n, .svc-dir.is-on b { color: var(--accent); }

.svc-go {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    border: 1px solid rgba(12, 21, 42, .22);
    display: grid;
    place-items: center;
    flex: none;
    font-size: 18px;
    opacity: 0;
    transform: translateX(-8px);
    transition: opacity .4s var(--svc-e), transform .4s var(--svc-e),
        background-color var(--tr-duration) var(--tr-ease),
        border-color var(--tr-duration) var(--tr-ease),
        color var(--tr-duration) var(--tr-ease);
}

.svc-dir.is-on .svc-go {
    opacity: 1;
    transform: none;
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-fg);
}

.svc-dirprev {
    position: sticky;
    top: 90px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    aspect-ratio: 4 / 3.4;
    border-radius: 12px;
    overflow: hidden;
    padding: 26px;
    background: #20242C;
    color: var(--color-white);
}

.svc-dirimg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.06);
    transition: opacity .6s var(--svc-e), transform 1.2s var(--svc-e);
}

.svc-dirimg.is-on { opacity: 1; transform: none; }

.svc-dirprev::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 40%, rgba(20, 24, 31, .85));
}

.svc-dirtxt { position: relative; z-index: 2; }

.svc-dirtxt p:not(.mg-cap) {
    margin: 8px 0 18px;
    font-size: 17px;
    color: rgba(241, 242, 244, .9);
    max-width: 44ch;
}

/* «Считаем до покупки»: тёмная карта, спека 01–05. */
.svc-prod {
    display: grid;
    grid-template-columns: 1fr 1fr;
    border-radius: 20px;
    overflow: hidden;
    background: #1B1F2B;
    color: #F1F2F4;
}

.svc-prod-ph {
    position: relative;
    min-height: 380px;
    overflow: hidden;
}

.svc-prod-ph img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.svc-chip {
    position: absolute;
    left: 18px;
    top: 18px;
    background: rgba(20, 24, 31, .55);
    border: 1px solid rgba(255, 255, 255, .25);
    color: var(--color-white);
    border-radius: 999px;
    padding: 7px 13px;
    font-size: 13px;
    z-index: 2;
}

.svc-prod-in { padding: 40px 42px; }

.svc-prod-in .sec-title { color: var(--color-white); }

.svc-prod-lead {
    color: rgba(241, 242, 244, .66);
    font-size: var(--text-base);
    margin: 14px 0 6px;
}

.svc-spec > div {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: 18px;
    padding: 14px 4px;
    font-size: 17px; /* крупнее (правка автора 21.09) */
}

.svc-spec > div::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    height: 1px;
    width: 100%;
    background: rgba(255, 255, 255, .14);
}

.svc-spec span:first-child { color: rgba(241, 242, 244, .6); }

.svc-spec span:last-child {
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* Таймлайн недель: полосы диаграммы. */
/* Рамка-линейка (выбор автора 21.09, вариант A): недели со штрихами внутри
   общей белой карты, плашки на тинте и просторнее. */
.svc-tlcard {
    padding: 22px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 20px;
    box-shadow: var(--sh-card);
    overflow: hidden;
}

.svc-tl-weeks {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
    margin-bottom: 12px;
}

.svc-tl {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
}

.svc-wk {
    font-size: 12px;
    letter-spacing: .1em;
    color: var(--fg-subtle);
    text-transform: uppercase;
    border-left: 2px solid rgba(12, 21, 42, .22);
    padding-left: 8px;
}

.svc-bar {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px 16px;
}

/* Текст плашек крупнее (правка автора 21.09). */
.svc-bar b { display: block; font-size: 18px; margin-bottom: 4px; }

.svc-bar span {
    font-size: 13px;
    color: var(--accent);
    font-weight: var(--font-weight-bold);
    letter-spacing: .06em;
}

.svc-bar--w2 { grid-column: span 2; }

.svc-bar--acc {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-fg);
}

.svc-bar--acc span { color: rgba(255, 255, 255, .8); }

/* Кейсы: четыре плитки с тегами. */
.svc-cases {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.svc-case {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    aspect-ratio: 3 / 3.6;
    border-radius: 12px;
    overflow: hidden;
    padding: 16px;
    background: #20242C;
    color: var(--color-white);
}

.svc-case img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .8s var(--svc-e);
}

@media (hover: hover) {
    .svc-case:hover img { transform: scale(1.06); }
}

.svc-case::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 40%, rgba(20, 24, 31, .85));
}

.svc-case-tag {
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 2;
    background: rgba(20, 24, 31, .5);
    border-radius: 999px;
    padding: 5px 11px;
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.svc-case b, .svc-case .svc-case-sub {
    position: relative;
    z-index: 2;
}

.svc-case b { font-size: 16px; }

.svc-case .svc-case-sub {
    font-size: 13px;
    color: rgba(241, 242, 244, .75);
}

/* Отзывы. */
.svc-revs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
}

.svc-rev {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    box-shadow: var(--sh-card);
}

.svc-rev { position: relative; }

/* Кавычка-глиф в углу и футер «имя · роль» за разделителем (выбор автора
   21.09, вариант A). */
.svc-rev::after {
    content: '\201C';
    position: absolute;
    top: 2px;
    right: 18px;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 74px;
    line-height: 1;
    color: var(--accent-subtle);
    pointer-events: none;
}

.svc-rev p { position: relative; font-size: 16px; margin: 0 0 18px; }

.svc-rev-foot {
    display: flex;
    gap: 8px;
    align-items: baseline;
    border-top: 1px solid var(--border);
    padding-top: 12px;
}

.svc-rev-foot b { font-size: 15px; }
.svc-rev-foot span { color: var(--fg-muted); font-size: 13px; }

/* Звёзды синие и крупнее (правка автора 21.09). */
.svc-stars {
    color: var(--accent);
    letter-spacing: 3px;
    margin-bottom: 12px;
    font-size: 18px;
    line-height: 1;
}

.svc-stars i { font-style: normal; display: inline-block; }

/* Тёмный pre-CTA: дышащее синее пятно. */
.svc-precta {
    position: relative;
    overflow: hidden;
    background: #14181F;
    color: #F1F2F4;
    border-radius: 20px;
    padding: 56px 50px;
}

.svc-precta::before {
    content: '';
    position: absolute;
    right: -140px;
    top: -140px;
    width: 440px;
    height: 440px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(45, 91, 242, .35), transparent 65%);
    animation: svc-breathe 7s ease-in-out infinite;
}

@keyframes svc-breathe {
    50% { transform: scale(1.25) translate(-30px, 26px); }
}

.svc-precta .sec-title { color: var(--color-white); position: relative; }

.svc-precta-em { color: #6786FF; }

.svc-precta p {
    position: relative;
    max-width: 520px;
    color: rgba(241, 242, 244, .7);
    margin: 18px 0 26px;
}

/* Две колонки (выбор автора 21.09, вариант B): справа за разделителем —
   средний доход крупно и кнопка. */
.svc-precta-grid {
    position: relative;
    display: grid;
    grid-template-columns: 1.2fr .8fr;
    gap: 40px;
    align-items: center;
}

.svc-precta-box {
    border-left: 1px solid rgba(255, 255, 255, .16);
    padding-left: 36px;
}

.svc-money {
    display: block;
    margin: 8px 0 4px;
    font-size: clamp(30px, 3vw, 42px);
    font-weight: 800;
    letter-spacing: -.03em;
    color: #6786FF;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.svc-per {
    display: block;
    margin-bottom: 18px;
    font-size: 14px;
    color: rgba(241, 242, 244, .6);
}

.svc-tel {
    display: inline-block;
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    letter-spacing: .02em;
    color: var(--color-white);
}

/* FAQ: плавное раскрытие grid-rows, плюс поворачивается и синеет.
   Разметка details/summary — без скрипта работает нативно, скрипт
   только анимирует закрытие (site.js, bindServicesFx). */
/* Сплит (выбор автора 21.09, вариант A): заголовок и кнопка слева,
   аккордеон справа. */
.svc-faqsec {
    display: grid;
    grid-template-columns: .8fr 1.2fr;
    gap: 44px;
    align-items: start;
}

.svc-faqsec .page-text { max-width: 36ch; }

.svc-faqrow { border-bottom: 1px solid var(--border); }

.svc-faqrow summary {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 17px 2px;
    cursor: pointer;
    list-style: none;
    font-weight: 600;
    font-size: 16px;
}

.svc-faqrow summary::-webkit-details-marker { display: none; }

.svc-faqrow summary i {
    font-style: normal;
    color: var(--fg-subtle);
    transition: transform .5s var(--svc-e), color .3s ease;
}

.svc-faqrow[open] summary i {
    transform: rotate(45deg);
    color: var(--accent);
}

.svc-ans {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .55s var(--svc-e);
}

.svc-faqrow[open] .svc-ans { grid-template-rows: 1fr; }

.svc-ans > div { overflow: hidden; }

.svc-ans p {
    margin: 0;
    padding: 0 2px 16px;
    color: var(--fg-muted);
    font-size: var(--text-base);
    max-width: 62ch;
}

/* Финал с формой: текст слева, светлая карточка формы справа. */
.svc-formsec {
    display: grid;
    grid-template-columns: .7fr 1.3fr;
    gap: 44px;
    align-items: start;
}

.svc-contacts {
    display: flex;
    flex-wrap: wrap;
    gap: 22px;
    margin-top: 22px;
}

.svc-contacts a {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    border-bottom: 1px solid rgba(12, 21, 42, .22);
    padding-bottom: 2px;
    transition-property: var(--tr-colors);
    transition-duration: var(--tr-duration);
    transition-timing-function: var(--tr-ease);
}

.svc-contacts a:hover { color: var(--accent); border-color: var(--accent); }

/* Общая lead-form по два поля в ряд (выбор автора 21.09, мокап B для
   финала /management и формы /services). Партиал один на все страницы,
   поэтому сетка навешивается контейнером: заголовок, подводка, сводка
   ошибок и капча — на всю ширину, согласие слева, кнопка справа. Пустые
   заголовок/подводка (передан '') не занимают ячейку. */
.svc-form2 form {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px 16px;
}

.svc-form2 form > :not(.form-row):not(.btn):not(.consent-row) { grid-column: 1 / -1; }
.svc-form2 .form-title:empty, .svc-form2 .form-hint:empty { display: none; }
.svc-form2 .consent-row { grid-column: 1; }

.svc-form2 form > .btn {
    grid-column: 2;
    justify-self: end;
    align-self: center;
    min-width: 220px;
}

/* Комментарий — одной строкой, растянуть можно вручную. */
.svc-form2 .field--area { height: 48px; min-height: 48px; resize: vertical; }

/* Светлая карточка формы (у mg-formcard стили под тёмный финал —
   на светлом фоне текст был белым, правка 21.09). Сабмит — красный CTA. */
.svc-formcard {
    padding: 28px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 20px;
    box-shadow: var(--sh-card);
}

.svc-formcard .btn { background: var(--cta); }
.svc-formcard .btn:hover { background: var(--cta-hover); }

/* ── Анимации появления (только при html.js) ──
   .svc-in вешается НА САМ ЭЛЕМЕНТ, когда он входит в окно (правка
   автора 21.09): секционный триггер срабатывал по верхушке секции,
   и низкие элементы отыгрывали за фолдом. Геометрия наблюдения —
   как у родного .reveal (rootMargin -12% снизу). */
:root { --svc-e: cubic-bezier(.25, 1, .5, 1); }

html.js [data-role="svc-fx"] .svc-fx {
    opacity: 0;
    transform: translateY(30px);
    transition: opacity .9s var(--svc-e) var(--svc-d, 0s), transform .9s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .svc-fx--left { transform: translateX(-44px); }
html.js [data-role="svc-fx"] .svc-fx--right { transform: translateX(44px); }

html.js [data-role="svc-fx"] .svc-fx.svc-in {
    opacity: 1;
    transform: none;
}

/* hero-занавес */
html.js [data-role="svc-fx"] .svc-hero {
    clip-path: inset(6% 4% 6% 4% round 48px);
    transition: clip-path 1.3s var(--svc-e);
}

html.js [data-role="svc-fx"] .svc-hero.svc-in { clip-path: inset(0 0 0 0 round 40px); }

/* фото «считаем» из масштаба */
html.js [data-role="svc-fx"] .svc-prod-ph img {
    transform: scale(1.15);
    transition: transform 2.2s var(--svc-e);
}

html.js [data-role="svc-fx"] .svc-prod-ph.svc-in img { transform: scale(1); }

/* линии спеки прорастают по одной */
html.js [data-role="svc-fx"] .svc-spec > div::after {
    width: 0;
    transition: width .9s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .svc-spec > div.svc-in::after { width: 100%; }

/* плашки таймлайна отрастают слева направо */
html.js [data-role="svc-fx"] .svc-bar {
    transform-origin: left;
    transform: scaleX(0);
    transition: transform .9s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .svc-bar > * {
    opacity: 0;
    transition: opacity .5s ease calc(var(--svc-d, 0s) + .45s);
}

html.js [data-role="svc-fx"] .svc-bar.svc-in { transform: none; }
html.js [data-role="svc-fx"] .svc-bar.svc-in > * { opacity: 1; }

/* кейсы раскрываются снизу вверх, теги въезжают следом. Класс .svc-in
   ставится на сетку .svc-cases, а не на плитку: IntersectionObserver
   считает элемент с clip-path: inset(100%) невидимым и не срабатывает. */
html.js [data-role="svc-fx"] .svc-case {
    clip-path: inset(100% 0 0 0 round 12px);
    transition: clip-path 1s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .svc-cases.svc-in .svc-case { clip-path: inset(0 0 0 0 round 12px); }

html.js [data-role="svc-fx"] .svc-case .svc-case-tag {
    opacity: 0;
    transform: translateX(-10px);
    transition: opacity .5s var(--svc-e) calc(var(--svc-d, 0s) + .5s), transform .5s var(--svc-e) calc(var(--svc-d, 0s) + .5s);
}

html.js [data-role="svc-fx"] .svc-cases.svc-in .svc-case-tag {
    opacity: 1;
    transform: none;
}

/* звёзды зажигаются по одной */
html.js [data-role="svc-fx"] .svc-rev .svc-stars i {
    opacity: 0;
    transform: scale(.4);
    transition: opacity .35s var(--svc-e) var(--svc-d, 0s), transform .35s var(--svc-e) var(--svc-d, 0s);
}

html.js [data-role="svc-fx"] .svc-rev.svc-in .svc-stars i {
    opacity: 1;
    transform: none;
}

/* карточка формы въезжает справа */
html.js [data-role="svc-fx"] .svc-formcard-fx {
    opacity: 0;
    transform: translateX(56px);
    transition: opacity 1s var(--svc-e), transform 1s var(--svc-e);
}

html.js [data-role="svc-fx"] .svc-formcard-fx.svc-in {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    html.js [data-role="svc-fx"] .svc-fx,
    html.js [data-role="svc-fx"] .svc-hero,
    html.js [data-role="svc-fx"] .svc-prod-ph img,
    html.js [data-role="svc-fx"] .svc-bar,
    html.js [data-role="svc-fx"] .svc-bar > *,
    html.js [data-role="svc-fx"] .svc-case,
    html.js [data-role="svc-fx"] .svc-case .svc-case-tag,
    html.js [data-role="svc-fx"] .svc-rev .svc-stars i,
    html.js [data-role="svc-fx"] .svc-formcard-fx {
        transition: none !important;
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
    }

    html.js [data-role="svc-fx"] .svc-spec > div::after {
        transition: none !important;
        width: 100%;
    }

    .svc-precta::before { animation: none; }
}

/* Планшет и телефон. */
@media (max-width: 1023px) {
    .svc-cases { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 960px) {
    .svc-numcard, .svc-prod, .svc-revs, .svc-formsec, .svc-faqsec, .svc-precta-grid { grid-template-columns: 1fr; }
    .svc-numcol { border-right: 0; border-bottom: 1px solid var(--border); }
    .svc-form2 form { grid-template-columns: 1fr; }
    .svc-form2 form > .btn, .svc-form2 .consent-row { grid-column: 1; justify-self: stretch; }
    .svc-precta-box { border-left: 0; padding-left: 0; }
    .svc-stats { grid-template-columns: repeat(2, 1fr); }
    .svc-stats > div:nth-child(3) { border-left: 0; }
    .svc-stats > div:nth-child(n + 3) { border-top: 1px solid var(--border); }
    .svc-dirs { grid-template-columns: 1fr; }
    .svc-dirprev { position: static; }
    .svc-dir b { font-size: 22px; }
    .svc-tl { grid-template-columns: repeat(2, 1fr); }
    .svc-tl-weeks { display: none; }
    .svc-head { display: block; }
    .svc-head .svc-side { margin-top: 12px; }
    .svc-prod-in { padding: 26px 24px; }
}

@media (max-width: 640px) {
    .svc-hero { min-height: 460px; }
    .svc-hero-top { left: 16px; right: 16px; }
    .svc-cases { grid-template-columns: 1fr; }
    .svc-precta { padding: 34px 24px; }
    .svc-tl { grid-template-columns: 1fr; }
    .svc-bar--w2 { grid-column: auto; }
}
