/* ============================================================================
   Страница /111/ — оптовая посадочная. Собственные стили.
   Подключается последним, после всех сайтовых css.

   ПРОХОД 2 завершён. Страница собрана из компонентов сайта; здесь только то,
   без чего эти компоненты не встают на новую страницу, плюс два блока,
   которых на сайте нет вовсе.

   Правила проекта, которые здесь соблюдаются:
   - ни одного селектора без класса с префиксом opt-;
   - медиазапрос стоит сразу после правила, к которому относится;
   - порядок правил повторяет порядок секций на странице;
   - секции самодостаточны: ни одно правило не зависит от соседней секции
     и от порядка секций на странице. Это нужно потому, что поля админки
     будут нарезаться под эту разметку и секции смогут переставлять.

   Палитра, шрифт и размеры взяты с боевого сайта, а не из дизайн-системы:
     синий #102F97 · наведение #5D7DCF · текст #0F172A · серый #4F4F4F
     светлый фон #F0F5F9 · потемнее #E0EAF2 · линия #C5DBED · жёлтый #FFCB00

     Вторичный серый #4F4F4F — единственный цвет на странице, которого нет
     в палитре сайта. Сайтовый серый #5F5F5F, и до 25.08.2026 стоял он.

     Почему пришлось затемнить. С появлением ткани фоном сайтовый #5F5F5F над
     тёмными складками перестал читаться. И это не редкий случай: фон
     зафиксирован, а содержимое едет поверх, значит при какой-то прокрутке
     каждый абзац окажется над тёмной складкой. #4F4F4F темнее и держит лучше.

     ВНИМАНИЕ, ЗАМЕР ОТ 25.08.2026 НЕ СХОДИТСЯ С ТЕМ, ЧТО ЗДЕСЬ БЫЛО НАПИСАНО.
     Здесь стояло «#4F4F4F держит 4,9:1». Перемерено дважды — по самой тёмной
     точке контентной колонки и по самому тёмному пятну размером с росчерк
     буквы: при K = 2,0 выходило 2,61, после осветления фона до K = 1,6
     выходит 3,41. Норма 4,5 не берётся ни там, ни там. Каким способом
     получалось 4,9, восстановить не удалось.

     Осветление фона улучшило картину, но не закрыло вопрос. Восемь абзацев
     серого текста на странице лежат прямо на ткани (остальные пять — на белых
     карточках секций 5 и 6, там всё в порядке). Варианты, если решать:
     увести серый в #0F172A, подложить под эти абзацы светлую карточку,
     или осветлить ткань ещё сильнее. Решение за заказчиком, поэтому цвет
     пока оставлен как был.

     Если фон когда-нибудь снимут — серый надо вернуть на сайтовый #5F5F5F.
     фирменная тень 0 6px 40px 10px #C5DBED — она синяя, серая выглядит чужой
   ============================================================================ */


/* --- Ритм секций -----------------------------------------------------------
   Сайтовый .section даёт 60px сверху и снизу, на <=991px — 40px.
   Отступы всё равно заданы каждой секции явно, и это не дублирование.

   Секции должны переставляться свободно — под них будут нарезаться поля
   админки, и порядок может меняться. Явные отступы — гарантия, что ни одна
   секция не зависит от того, что стоит перед ней.

   24.08.2026: фон всех восьми секций стал белым по просьбе заказчика. Сайтовый
   класс .blue-bg снят с пяти секций в разметке, а не перекрыт цветом: класс с именем
   «светлый фон» при белом фоне вводит в заблуждение того, кто будет читать разметку.
   Вместе с классом отваливается сайтовое .blue-bg + .blue-bg { padding-top: 0 }
   (style-new.css:3064) — раньше оно обнуляло верхний отступ восьмой секции,
   а правила ниже его перебивали. Теперь перебивать нечего, но правила остаются:
   секция должна везти свой отступ с собой. */

.section.opt-hero,
.section.opt-reasons,
.section.opt-promo-slider,
.section.opt-fabrics,
.section.opt-prints,
.section.opt-steps,
.section.opt-reviews,
.section.opt-faq,
.section.opt-search {
    padding-top: 60px;
    padding-bottom: 60px;
}

/* Запас сверху для перехода по якорю на форму. Нужен, когда js не сработал:
   браузер про липкую шапку сайта не знает и поставил бы начало секции ровно
   под неё, спрятав заголовок. 100px — высота шапки плюс воздух.
   Когда js работает, отступ считает он сам, по замеру шапки на месте. */

.section.opt-search {
    scroll-margin-top: 100px;
}

@media (max-width: 991px) {
    .section.opt-hero,
    .section.opt-reasons,
    .section.opt-fabrics,
    .section.opt-prints,
    .section.opt-steps,
    .section.opt-reviews,
    .section.opt-faq,
    .section.opt-search {
        padding-top: 40px;
        padding-bottom: 40px;
    }
}


/* --- Фон секций ----------------------------------------------------------
   До 25.08.2026 здесь стоял явный белый: секции уедут в поля админки и могут
   оказаться внутри чужой окрашенной обёртки, и белым мы говорили прямо —
   так задумано.

   С 25.08.2026 фоном всей страницы работает ткань, и секции стали
   прозрачными: белая заливка закрывала бы её целиком. Прозрачность задана
   так же явно и по той же причине — чтобы её не приняли за забытое правило.

   Тёмных и цветных подложек на уровне секций нет ни одной. Цветные элементы
   остались внутри: промо-плашка секции 3, плитка-призыв секции 4, карточка
   формы секции 8 — они и должны читаться карточками поверх ткани. */

.section.opt-hero,
.section.opt-reasons,
.section.opt-promo-slider,
.section.opt-fabrics,
.section.opt-prints,
.section.opt-steps,
.section.opt-reviews,
.section.opt-faq,
.section.opt-search {
    background-color: transparent;
}


/* --- Жёлтая кнопка на тёмном фоне ------------------------------------------
   С 24.08.2026 используется один раз — промо-плашка в секции 3. С кнопки
   секции 4 класс снят: её подложка стала белой, и сайтовое наведение #00309d
   на белом видно нормально. Правило оставлено как есть — оно про подложку
   #102F97, а такая на странице ещё одна.

   Сайтовое .btn.btn--yellow:hover красит кнопку в #00309d (main.min.css:3100).
   На белом фоне каталога это нормально, а обе наши подложки — #102F97,
   практически тот же цвет: под курсором кнопка исчезала целиком.

   Берём второй сайтовый цвет наведения #5D7DCF: он с сайта, светлее подложки,
   приём тот же «жёлтая кнопка синеет». Перечислены и :focus с :active — иначе
   кнопка пропадала бы при переходе табом и в момент нажатия на телефоне.

   Класс общий, а не по одному на секцию: правило одно и то же, и при смене
   цвета его надо будет править в одном месте. Зависимости между секциями это
   не создаёт — класс ставится на элемент, а не на соседа.

   В селекторе обязателен .btn. Сайтовое правило записано как
   .btn.btn--yellow:hover — это специфичность (0,3,0). Одного своего класса
   с псевдоклассом хватает только на (0,2,0), и сайт побеждает независимо от
   порядка файлов: кнопка продолжала бы исчезать. С .btn получается (0,3,0),
   ничья, и дальше решает то, что opt.css подключён последним. */

.btn.opt-btn-yellow:hover,
.btn.opt-btn-yellow:focus,
.btn.opt-btn-yellow:active {
    background: #5D7DCF;
    border-color: #5D7DCF;
    color: #ffffff;
}


/* ============================================================================
   СЕКЦИЯ 1. Первый экран. Видео драпировки, карточка-стекло слева.
   Внедрено 25.08.2026
   ============================================================================
   Отменяет стену из квадратов ткани (вариант 2 от 23.08.2026). Фон первого
   экрана — зацикленный ролик драпировки, текст стоит слева на карточке
   из матового стекла.

   Блок перенесён с главной страницы art-texx.ru пакетом _peredacha/hero-video
   и там уже обкатан. Тексты — прежние, страницы 111: заголовок, лид, обе
   кнопки и три факта не менялись ни словом. Менялась только подложка под
   ними и место, где они стоят.

   Что уехало вместе со стеной: сетка плиток, подписи с ценами, овальная
   прогалина под текстом, тёмная вуаль на телефоне и перекраска кнопок под
   неё. Файлы 72 тканей opt/img/wall/ остались на диске, страницей больше
   не используются.

   ФАЙЛЫ РОЛИКА НЕ ТРОГАТЬ. Они лежат ровно в том виде, в каком пришли
   пакетом _peredacha/hero-video, побайтово. Пробовали осветлить ролик на 25%
   для этой страницы — отменено 25.08.2026: пересборка уже сжатого файла
   портит картинку. Осветление относится к фоновой картинке всей страницы,
   а не к ролику, см. .opt-bg в конце файла.

   Если ролик когда-нибудь всё же понадобится переделать, пересобирать надо
   из мастера 2560x1440 на 49 МБ, а не из этих файлов. Мастер лежит в соседнем
   проекте, _masters/silk/. Замер: пересборка из сжатого даёт SSIM 0,977
   при весе 1,53 МБ, а из мастера при том же весе — 0,982, и это заметно
   глазом на переливах шёлка.

   ЧТО ГРУЗИТ ПОСЕТИТЕЛЬ: 1,71 МБ на десктопе (ролик 1600x900 — 1,60 МБ,
   постер webp — 112 КБ), 0,64 МБ на телефоне (ролик 960x540 — 0,53 МБ).
   Браузер берёт одно видео из двух, а не оба. На экране высокой плотности
   постер тяжелее: 232 КБ вместо 112.
   ============================================================================ */

.section.opt-hero {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: flex-end;
    min-height: 620px;
}

/* Прижим к нижнему краю и высота 620 — из варианта 2 витрины. Смысл раскладки
   в том, что верх кадра остаётся чистым: ткань и манекен работают сами, а текст
   стоит внизу и им не мешает. При прежних 540px и выравнивании по центру текст
   ложился ровно на манекен. */

@media (max-width: 991px) {
    .section.opt-hero {
        min-height: 520px;
    }
}

/* ----------------------------------------------------------------------------
   Фон: картинка, поверх неё видео
   ----------------------------------------------------------------------------
   Картинка — первый кадр ролика, а не отдельный красивый снимок. Она лежит
   под видео и остаётся запасным вариантом: если ролик не включился, посетитель
   видит тот же самый кадр и подмены не замечает. Поэтому при замене видео
   постер пересобирается вместе с ним, иначе в момент запуска кадр дёрнется. */

.opt-hero__bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

/* РОЛИК НЕ РАСТЯГИВАЕТСЯ ШИРЕ СВОЕГО НАСТОЯЩЕГО РАЗМЕРА. Правило от 30.08.2026.

   Ролик снят шириной 1280 пикселей. Пока окно уже этого, он честно закрывает
   первый экран целиком. Дальше начиналось враньё: на мониторе 2560 кадр
   раздувался вдвое, каждый снятый пиксель растягивался на четыре, картинка
   мылилась, а манекен обрезался сверху и снизу — от кадра оставалось 47%
   высоты, голова и подставка уходили за край.

   Поэтому с 1281px слой встаёт ровно 1280 пикселей по центру окна и больше
   не растёт. По бокам открывается фон страницы — та же ткань, что лежит под
   всеми секциями, так что пустоты не возникает.

   Края растворяются маской, иначе ролик выглядел бы приклеенной заплатой:
   вертикальный шов между ним и тканью читается сразу. 8% с каждой стороны —
   это 102 пикселя перехода, достаточно, чтобы шва не было видно, и мало,
   чтобы манекен остался целым.

   Маска включается только на широких экранах. Ниже 1281px ролик и так занимает
   всю ширину, растворять его края там незачем и вредно: срезало бы картинку.

   ПОЧЕМУ НЕ УВЕЛИЧИТЬ САМ РОЛИК. Пикселей, которых нет, увеличением не
   получить: любая программа просто дорисует их по соседям, и мыло останется,
   а вес вырастет вчетверо. Нужен настоящий кадр 2560 — его надо
   пересгенерировать в исходном сервисе. */

@media (min-width: 1281px) {
    .opt-hero__bg {
        left: 50%;
        width: 1280px;
        transform: translateX(-50%);

        /* Много ступеней вместо двух — это плавная кривая, а не прямая.
           У прямого градиента яркость меняется с постоянной скоростью, и глаз
           ловит два места, где она включается и выключается: получаются две
           еле заметные вертикальные полосы по концам перехода. Ступени внизу
           повторяют S-образную кривую: переход начинается и заканчивается
           незаметно, вся смена происходит в середине.

           Слева растворение шире (15%), справа уже (12%): справа стоит манекен,
           и широкий переход начал бы съедать шлейф. Слева в кадре пусто. */

        -webkit-mask-image: linear-gradient(to right,
            rgba(0,0,0,0) 0%, rgba(0,0,0,.09) 3%, rgba(0,0,0,.32) 6%,
            rgba(0,0,0,.63) 9%, rgba(0,0,0,.87) 12%, #000 15%,
            #000 88%, rgba(0,0,0,.87) 91%, rgba(0,0,0,.63) 94%,
            rgba(0,0,0,.32) 96%, rgba(0,0,0,.09) 98%, rgba(0,0,0,0) 100%);
        mask-image: linear-gradient(to right,
            rgba(0,0,0,0) 0%, rgba(0,0,0,.09) 3%, rgba(0,0,0,.32) 6%,
            rgba(0,0,0,.63) 9%, rgba(0,0,0,.87) 12%, #000 15%,
            #000 88%, rgba(0,0,0,.87) 91%, rgba(0,0,0,.63) 94%,
            rgba(0,0,0,.32) 96%, rgba(0,0,0,.09) 98%, rgba(0,0,0,0) 100%);
    }

    /* ЕСТЬ ВО ЧТО РАСТВОРЯТЬСЯ. Без этой заливки ролик таял в фон страницы,
       а фон страницы — почти белая ткань, 249 из 255 по яркости. Край самого
       ролика серо-голубой, 156. Перепад в 93 единицы никаким растворением
       не спрячешь: глаз видит его как светлеющую полосу по краю.

       Заливка повторяет цвета краёв кадра: слева #9CAAB6, справа #C7D1D7 —
       это средний цвет левых и правых двадцати пикселей, замеренный по всем
       221 кадрам. По кадрам он почти не меняется (разброс 1 единица), поэтому
       заливка статичная и совпадает с роликом в любой момент цикла.

       Перепад на стыке становится нулевым, и переход пропадает совсем.
       Цена: в первом экране по бокам не видно фоновой ткани страницы. Она
       и раньше просматривалась там едва — растворение её перекрывало. */

    .section.opt-hero {
        background-image: linear-gradient(to right, #9CAAB6 0%, #B4BFC9 50%, #C7D1D7 100%);
    }
}

.opt-hero__img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

/* Видео повторяет картинку один в один — тот же object-fit: cover, иначе
   в момент подмены кадр сместился бы.

   Проявляется плавно: класс is-on ставит скрипт и только тогда, когда браузер
   сказал, что готов играть без задержек.

   Ролик не включается в трёх случаях, и все три не ломают блок: системная
   настройка «уменьшить движение», браузер не умеет mp4, браузер запретил
   автозапуск (например, включена экономия трафика). Под видео остаётся
   картинка. */

.opt-hero__video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    opacity: 0;
    transition: opacity .5s ease;
}

.opt-hero__video.is-on {
    opacity: 1;
}

/* НА УЗКИХ ЭКРАНАХ КАДР СДВИНУТ К ЛЕВОМУ КРАЮ. Замер 30.08.2026.

   Кадр горизонтальный, экран узкий: браузер приближает ролик, чтобы закрыть
   им блок, и показывает только середину — а в середине стоит манекен, который
   в одной из фаз становится тёмно-синим. Текст лежит поверх, и на этой фазе
   буквы теряются: контраст падал до 0,91 при норме 4,5, и так на 4% площади
   под текстом.

   Сдвиг к левому краю показывает светлую часть кадра — ткань в столбе света.
   Контраст под текстом становится 6,26 на всех ширинах вплоть до 320px.
   Манекен при этом уходит вправо и виден краем: на телефоне его всё равно
   почти закрывал текст.

   Правило одно на видео и на картинку под ним: иначе в момент запуска ролика
   кадр прыгнул бы вбок. */

@media (max-width: 1199px) {
    .opt-hero__video,
    .opt-hero__img {
        object-position: left center;
    }
}

/* НА ТЕЛЕФОНЕ КАДР ВОЗВРАЩАЕТСЯ В ЦЕНТР, А ПОВЕРХ ЛОЖИТСЯ СВЕТЛАЯ ВУАЛЬ.
   Правка 30.08.2026 по замечанию заказчика: со сдвинутым влево кадром
   на телефоне не было видно платья — только пустая ткань в столбе света.

   Замер объясняет, почему просто вернуть кадр нельзя. В центре стоит манекен,
   и в одной из фаз ткань на нём становится тёмно-синей. Тёмный текст поверх
   неё даёт 1,01 при норме 4,5, и так на 0,7% площади под буквами. Сдвиг
   решал это тем, что убирал платье с экрана совсем.

   Вуаль решает иначе: белая плёнка в половину плотности осветляет синее
   до бледно-голубого. Контраст под текстом становится 4,85 на самой тяжёлой
   ширине (575px) и 5,2-11 на остальных — норма выполняется везде, от 320
   до 767 пикселей. Платье при этом видно: приглушённое, но видно.

   Половина — не круглое число, а предел. При 45% на ширине 575px контраст
   падает под норму; при 60% шлейф выцветает почти в белое и смотреть уже
   не на что.

   Вуаль лежит внутри .opt-hero__bg, то есть поверх ролика и картинки,
   но под текстом: текст лежит в .opt-hero__inner с z-index 2. */

@media (max-width: 767px) {
    .opt-hero__video,
    .opt-hero__img {
        object-position: center center;
    }

    .opt-hero__bg::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(255, 255, 255, .5);
        pointer-events: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .opt-hero__video {
        display: none;
    }
}

/* ----------------------------------------------------------------------------
   Текст: нижняя треть экрана, без подложки
   ----------------------------------------------------------------------------
   Раскладка взята из варианта 2 витрины opt/hero-variants.html. Текст стоит
   слева внизу, шириной 760, верх кадра оставлен ролику: он показывает, как
   ткань ведёт себя в движении, и закрывать его текстом смысла нет.

   Полоса из трёх фактов идёт по самому низу во всю ширину контейнера
   и в текстовый блок не входит. */

.opt-hero__inner {
    position: relative;
    z-index: 2;
    width: 100%;
}

/* Сайтовая .section даёт 60px снизу. Здесь они лишние: полоса фактов должна
   стоять у нижнего края кадра, а не висеть над ним. Оставлены 24px — чтобы
   буквы не липли к границе ролика. Верхние 60px не трогаем: содержимое
   прижато к низу, и сверху они ни на что не влияют. */

.section.opt-hero {
    padding-bottom: 24px;
}

/* ПОДЛОЖКИ ПОД ТЕКСТОМ НЕТ. Решение от 30.08.2026, вариант 2 витрины.

   Прежде текст лежал на белой стеклянной карточке. Карточка была нужна
   прежнему ролику: слева в кадре стоял тёмный бархат, и без подложки тёмный
   текст на нём не читался — контраст падал до 2,66.

   Новый ролик светлый, и подложка стала лишней. Замер по всем 221 кадрам,
   по прямоугольнику, который текст занимает на кадре: самая тёмная точка под
   заголовком и лидом даёт контраст 6,79 при норме 4,5. Проверялся тёмный
   текст #0F172A — тот же, что стоял на карточке.

   Белый текст, как в самом макете витрины, здесь не годится: он не проходит
   норму нигде, ни на одном кадре — фон слишком светлый. Поэтому от варианта 2
   взята раскладка, а цвет остался тёмный.

   Единственное тёмное место в зоне текста — тень от подставки манекена
   в правом нижнем углу кадра. Она лежит за пределами 760px, которыми
   ограничен текстовый блок, и под буквы не попадает.

   На широких экранах текст частично выходит за край ролика на фон страницы.
   Там ткань светлее самого ролика: худший контраст 10,78 — с запасом.

   ПРАВИЛО НА БУДУЩЕЕ: замер привязан к конкретному ролику. Меняется видео —
   контраст считают заново, по всем кадрам, а не по первому. Если новый ролик
   окажется тёмным, вернуть карточку можно из истории правок. */

.opt-hero__text {
    max-width: 650px;
    padding-bottom: 32px;
}

/* ШИРИНА ТЕКСТА — НЕ ВКУСОВАЯ, А ПОСЧИТАННАЯ. Замер 30.08.2026.

   Кадр светлый почти весь, но в нём есть два тёмных места: синяя фаза платья
   и тень от подставки. Оба лежат правее середины кадра. Пока буквы не заходят
   на них, тёмный текст читается без всякой подложки.

   Граница посчитана по всем 221 кадрам: безопасны левые 650 пикселей кадра
   для заголовка с лидом и левые 740 для полосы фактов. Шаг вправо на десять
   пикселей — и контраст падает с 6,2 сразу до 2,3: край синего платья резкий.

   На широком экране ролик стоит 1:1, и эти пиксели кадра совпадают
   с пикселями страницы один в один. На узком браузер приближает кадр, чтобы
   закрыть им экран, — тогда те же 650 пикселей страницы попадают уже
   на середину кадра, прямо в платье. Поэтому ниже 1200px текст сужается,
   а кадр сдвигается влево, к светлому краю: см. .opt-hero__video ниже. */

@media (max-width: 1199px) {
    .opt-hero__text {
        max-width: 480px;
    }
}

@media (max-width: 991px) {
    .opt-hero__text {
        padding-bottom: 24px;
    }
}



/* Сайтовый .title-h1 — это флекс, и любой <br> или <span> внутри встанет
   в строку, а не столбиком. Возвращаем блочное поведение и свой размер.

   Цвет один на всех ширинах и на всех кадрах ролика: тёмный #0F172A. Прежде
   на телефоне заголовок был белым — под ним лежала тёмная вуаль поверх стены.
   Вуали больше нет, ролик светлый, и тёмный текст читается на нём везде. */

.opt-hero__title {
    display: block;
    margin: 0;
    font-size: 54px;
    font-weight: 600;
    line-height: 1.08;
    letter-spacing: -0.02em;
    color: #0F172A;
    text-wrap: balance;
}

/* На узких экранах текстовый блок сужен до 480px по замеру контраста, и
   пятьдесят четыре пикселя в него уже не помещаются: заголовок разъезжался
   на четыре строки. */

@media (max-width: 1199px) {
    .opt-hero__title {
        font-size: 40px;
    }
}

@media (max-width: 991px) {
    .opt-hero__title {
        font-size: 36px;
    }
}

@media (max-width: 575px) {
    .opt-hero__title {
        font-size: 27px;
    }
}

/* Лид тёмный #0F172A, а не вторичный серый #4F4F4F.

   Серый на стекле не проходит: над самой тёмной складкой цикла он даёт 2,36
   при норме 4,5, а сайтовый #5F5F5F — 1,84. Осветлять нечем: стекло и так
   на пределе прозрачности. Поэтому на карточке весь текст одного тёмного
   цвета, а разница между заголовком и пояснением держится размером
   и насыщенностью шрифта, а не цветом. */

.opt-hero__lead {
    margin: 16px 0 0;
    font-size: 18px;
    line-height: 150%;
    color: #0F172A;
    text-wrap: pretty;
}

@media (max-width: 575px) {
    .opt-hero__lead {
        font-size: 16px;
    }
}

.opt-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 991px) {
    .opt-hero__actions {
        margin-top: 24px;
    }
}

/* На телефоне кнопки встают столбиком, но не растягиваются во всю ширину:
   кнопка от края до края читается как полоса интерфейса, а не как действие,
   и рядом с таким же широким текстом первый экран становился похож на форму.
   Ширина у каждой своя, по её надписи. */

@media (max-width: 575px) {
    .opt-hero__actions {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* Вторая кнопка получает белую заливку.

   Сайтовая .btn-border прозрачная, синий текст #102F97 виден сквозь неё
   насквозь. На стекле над тёмной складкой этот синий даёт 3,23 при норме 4,5 —
   не проходит, и именно он, а не заголовок, упирался бы в порог и не давал
   сделать стекло прозрачнее. Белая заливка ставит синий текст на белое,
   и кнопка перестаёт зависеть от того, какая складка проплывает под ней.

   Наведение и нажатие сайтовые: #E0EAF2 и #C5DBED — обе светлые, синий текст
   на них читается, перекрывать нечего.

   Первая кнопка .btn-blue не трогается: у неё своя сплошная синяя заливка
   и белый текст, фон под ней ни на что не влияет. Прежняя перекраска
   в жёлтое на телефоне снята вместе с тёмной вуалью, ради которой делалась. */

.opt-hero .btn-border {
    background-color: #FFFFFF;
}

/* Факты — тонкие подписи с разделителями, приём andercore.com.

   Линии не сайтовые #C5DBED, а синие на прозрачности: светлая голубая линия
   пропадает на стекле, когда под ним оказывается светлая складка. Синяя
   на 25% видна и над тёмным, и над светлым. */

.opt-hero__facts {
    max-width: 740px;
    display: flex;
    flex-wrap: wrap;
    margin: 32px 0 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid rgba(16, 47, 151, .25);
}

@media (max-width: 1199px) {
    .opt-hero__facts {
        max-width: 560px;
    }
}

/* flex-basis 0 и min-width 0 — оба обязательны. При basis auto столбцы
   получают ширину своего текста, а он длинный: три подписи не влезают
   в 572px внутренней ширины карточки, и третья сваливается на вторую строку.
   С нулевым basis они делят ширину поровну, а текст переносится внутри
   столбца. min-width: 0 снимает флексовый запрет ужимать элемент уже
   собственного содержимого — без него basis не сработает. */

.opt-hero__facts li {
    flex: 1 1 0;
    min-width: 0;
    margin: 0;
    padding: 16px 18px 0;
    border-left: 1px solid rgba(16, 47, 151, .25);
    color: #0F172A;
    font-size: 14px;
    font-weight: 500;
    line-height: 140%;

    /* Значок слева от подписи, в одну строку с ней. Правка 30.08.2026
       по просьбе заказчика.

       Прежде значок стоял над подписью: полоса фактов была шире, столбец
       выходил 190px, и значок сбоку делал двухстрочную подпись трёхстрочной.
       Сейчас полоса ограничена 740px по замеру контраста, столбец стал 246,
       под текст остаётся 198 — двух строк хватает, и подпись не разъезжается.

       align-items: center держит значок по центру подписи независимо от того,
       в одну она строку или в две. */
    display: flex;
    flex-direction: row;
    gap: 10px;
    align-items: center;
}

/* Значок 22px, а не 32px, как в секции 2. Там он стоит рядом с заголовком
   в 20px, здесь — над подписью в 14px, и крупный значок перетягивал бы
   на себя всю строку фактов, которая по замыслу читается тихо.

   Цвет — сайтовый синий #102F97, тот же, что у значков секции 2: один смысл,
   один вид. На стекле над самой тёмной складкой цикла он даёт 3,23. Для
   текста порог 4,5 и синий его не проходит — из-за этого вторая кнопка выше
   получила белую заливку. Но для значка порог другой, 3,0, и синий проходит.
   Разница не в придирке: у буквы важен тонкий росчерк, у значка — узнаваемая
   форма целиком.

   Запас всё же невелик, поэтому линия здесь толще, чем в секции 2:
   1,75 против 1,5. При 22px это возвращает значку ту же видимость,
   что у 32px с полуторной линией. */

.opt-hero__fact-ico {
    display: block;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    color: #102F97;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.75;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Первый столбец прижат к левому краю карточки: иначе текст фактов
   не встаёт по одной линии с заголовком и лидом. */

.opt-hero__facts li:first-child {
    padding-left: 0;
    border-left: 0;
}

@media (max-width: 991px) {
    .opt-hero__facts {
        margin-top: 24px;
    }

    .opt-hero__facts li {
        padding: 14px 14px 0;
    }
}

/* На телефоне три подписи в ряд не помещаются без переносов — уходим
   в столбик.

   РАЗДЕЛИТЕЛЕЙ ЗДЕСЬ НЕТ. Снято 30.08.2026 по замечанию заказчика. В строку
   линии работают: они делят три равных столбца и держат ритм. В столбик они
   превращаются в три черты во всю ширину экрана поперёк первого экрана —
   подписи короткие, линия тянется далеко за последнюю букву и делит уже
   не факты, а сам экран.

   Верхняя линия снята по той же причине: одна она осталась бы висеть
   ни к чему. Факты отделены от кнопок отступом, этого хватает.

   Отступы вдвое меньше прежних: без линий шаг в 12 пикселей разваливал
   список на три отдельных блока вместо одной группы. */

@media (max-width: 575px) {
    .opt-hero__facts {
        border-top: 0;
    }

    .opt-hero__facts li {
        flex-basis: 100%;
        padding: 6px 0;
        border-left: 0;

    }

    .opt-hero__facts li:first-child {
        padding-top: 0;
    }

    .opt-hero__facts li:last-child {
        padding-bottom: 0;
    }
}


/* ============================================================================
   СЕКЦИЯ 2. Три причины. Компактный вариант 3, утверждён 24.08.2026
   ============================================================================
   Прежняя раскладка — три полосы во всю ширину, в каждой текст и фотография
   580×230, — снята. Причина в плотности: секция занимала 1186px на широком
   экране и 1460px на телефоне, а сообщений в ней три и каждое в одну строку.
   Замер после переделки: 510px и 800px.

   Стало: причины и факты лежат в одной рамке и разделены линией. Обещание
   «нужный метраж есть» и доказательство «3000 м² склада» подкрепляют друг
   друга, стоя рядом, — ради этого вариант и выбран.

   Фон белый, не серый: по общему правилу страницы серых подложек не остаётся.
   Роль подложки, которая держала блок вместе, взяла на себя рамка #C5DBED —
   та же линия, которой разделены факты первого экрана и полосы секции 5.
   Радиус 16px — как у карточки подбора и прежней панели фактов.

   Фотографий больше нет. В колонке втрое уже прежней полосы кадр 580×230
   превращается в марку, на которой ничего не разобрать. Файлы
   opt/img/reason-1..3 остались на диске, страницей не используются.
   ============================================================================ */

.opt-reasons__panel {
    margin-top: 40px;
    padding: 28px 32px;
    border: 1px solid #C5DBED;
    border-radius: 16px;
    background-color: transparent;
}

@media (max-width: 991px) {
    .opt-reasons__panel {
        margin-top: 25px;
        padding: 24px;
    }
}

@media (max-width: 767px) {
    .opt-reasons__panel {
        padding: 22px 20px;
    }
}

/* Три причины в строку. Ниже 768px встают столбцом: на 375px колонка
   шириной в треть экрана даёт заголовок в пять строк. */

.opt-reasons__list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 32px;
}

@media (max-width: 991px) {
    .opt-reasons__list {
        gap: 20px;
    }
}

@media (max-width: 767px) {
    .opt-reasons__list {
        grid-template-columns: 1fr;
        gap: 22px;
    }
}

/* Иконка слева от текста, а не над ним: горизонтальная пара занимает
   меньше высоты, а высота здесь и есть предмет правки. */

.opt-reasons__item {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 14px;
    align-items: start;
}

/* Иконки нарисованы линиями и лежат прямо в разметке.

   Почему не сайтовые: в спрайте сайта только интерфейсные значки — корзина,
   аккаунт, поиск, бургер, — а в иконочном шрифте по смыслу подходит один
   icon-car. Набора «склад — образцы — отгрузка» на сайте нет.

   Почему инлайновый svg, а не три файла: иконка красится currentColor
   и не тянет три запроса ради трёх картинок по полкилобайта. */

.opt-reasons__ico {
    display: block;
    width: 32px;
    height: 32px;
    margin-top: 2px;
    color: #102F97;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}

@media (max-width: 991px) {
    .opt-reasons__ico {
        width: 28px;
        height: 28px;
    }
}

/* 20px против прежних 22px: в колонке втрое уже старый размер ломался
   на четыре строки. */

.opt-reasons__h3 {
    margin: 0;
    font-size: 20px;
    line-height: 1.25;
    text-wrap: balance;
}

@media (max-width: 991px) {
    .opt-reasons__h3 {
        font-size: 17px;
    }
}

.opt-reasons__p {
    margin: 8px 0 0;
    color: #4F4F4F;
    font-size: 15px;
    line-height: 150%;
}

@media (max-width: 991px) {
    .opt-reasons__p {
        font-size: 14px;
    }
}

/* Факты. Прежде были отдельной серо-голубой панелью под секцией, теперь лежат
   в той же рамке, что и причины, и отделены линией.

   Селектор с тегом ul оставлен от прежней версии и по-прежнему нужен:
   сайтовое правило для списков имеет специфичность (0,1,1) и забивает
   голый класс (0,1,0). */

ul.opt-reasons__facts {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
    margin: 22px 0 0;
    padding: 20px 0 0;
    list-style: none;
    border-top: 1px solid #C5DBED;
}

@media (max-width: 991px) {
    ul.opt-reasons__facts {
        gap: 20px;
    }
}

@media (max-width: 767px) {
    ul.opt-reasons__facts {
        grid-template-columns: repeat(2, 1fr);
        gap: 18px 16px;
    }
}

/* У совсем узких телефонов четыре факта в два столбца не помещаются:
   на 320px «3000 м²» переносится и ломает строку. */

@media (max-width: 340px) {
    ul.opt-reasons__facts {
        grid-template-columns: 1fr;
    }
}

.opt-reasons__fact {
    margin: 0;
}

.opt-reasons__num {
    display: block;
    margin-bottom: 2px;
    color: #102F97;
    font-size: 30px;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.01em;
}

@media (max-width: 991px) {
    .opt-reasons__num {
        font-size: 24px;
    }
}

.opt-reasons__label {
    display: block;
    color: #4F4F4F;
    font-size: 14px;
    line-height: 140%;
}


/* ============================================================================
   СЕКЦИЯ 3. Ткани со склада
   ============================================================================ */

/* Тёмная промо-плашка — единственный блок уровня 2 на странице: живого аналога
   на сайте нет, проверено девятью поисками и повторно критиком. Композиция
   взята из дизайн-системы (layout/PromoBanner): скруглённая карточка, строка
   текста, одна жёлтая кнопка. Значения — сайтовые: синий #102F97,
   радиус 20px как у .promo-labels__label.

   Из PromoBanner НЕ перенесены: градиентная бежевая заливка, заглавные буквы
   в заголовке и картинка справа. Всё это принадлежит старому маркетинговому
   слою дизайн-системы, а страница держится нового слоя сайта. */

.opt-sale-promo {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 30px;
    padding: 28px 40px;
    border-radius: 20px;
    background-color: #102F97;
}

@media (max-width: 767px) {
    .opt-sale-promo {
        flex-direction: column;
        align-items: flex-start;
        gap: 20px;
        padding: 24px 20px;
    }
}

.opt-sale-promo__text {
    max-width: 800px;
    margin: 0;
    color: #ffffff;
    font-size: 22px;
    font-weight: 600;
    line-height: 140%;
}

@media (max-width: 991px) {
    .opt-sale-promo__text {
        font-size: 18px;
    }
}

@media (max-width: 575px) {
    .opt-sale-promo__text {
        font-size: 16px;
    }
}

/* Кнопка сайтовая, .btn.btn--md.btn--yellow, оформление не трогаем.
   Переопределён только один пункт — наведение.

   Причина: сайтовое .btn.btn--yellow:hover красит кнопку в #00309d
   (main.min.css:3100). На белом фоне каталога это нормально, а у нас плашка
   #102F97 — то есть практически тот же цвет, и под курсором кнопка исчезала бы
   целиком. Взят второй сайтовый цвет наведения #5D7DCF: он с сайта, светлее
   плашки и по смыслу тот же приём «синяя кнопка при наведении». */

.opt-sale-promo__btn {
    flex-shrink: 0;
}

/* Отступ до сетки карточек — не 40, а 16.

   Причина: сайтовое .product-grid .product несёт margin: 24px auto 0 — этот
   отступ разводит ряды карточек между собой, трогать его нельзя. Он же
   добавляется и сверху первого ряда. Поставь мы честные 40 — глазом получилось
   бы 64, и секция выпала бы из общего ритма страницы. 16 + 24 = 40.

   На узком экране собственного отступа карточки хватает: там шаг 24. */

.opt-fabrics__grid {
    margin-top: 16px;
}

@media (max-width: 991px) {
    .opt-fabrics__grid {
        margin-top: 0;
    }
}

/* Снизу у сетки сайтовое margin-bottom: 30px — .row.product-grid в ext/extended.css
   на ≤480px. Оно склеивалось с отступом ссылки в каталог и давало 30 вместо 24,
   то есть единственный выброс из мобильного шага.

   Специфичность считана, а не прикинута: сайтовое .row.product-grid — это (0,2,0),
   одного своего класса (0,1,0) не хватило бы. Два класса дают (0,2,0), ничья,
   дальше решает то, что opt.css подключён последним.
   Горизонтальные поля сайта не трогаем — это его собственный отбив колонок. */

.opt-fabrics__grid.product-grid {
    margin-bottom: 0;
}

.opt-fabrics__more {
    margin-top: 40px;
    text-align: center;
}

@media (max-width: 991px) {
    .opt-fabrics__more {
        margin-top: 24px;
    }
}


/* ============================================================================
   СЕКЦИЯ 4. Печать принта
   ============================================================================ */

/* Вариант 4, утверждён 23.08.2026: тёмная полоса во всю ширину.
   Референс подобран в Refero: groq.com — тёмная панель как редкий акцент
   среди светлых секций. Цвет полосы фирменный синий сайта.

   Полоса выходит за контейнер, поэтому фон вешается на саму секцию,
   а не на внутренний блок: на этой странице секции лежат прямо в div.content
   без сетки row/col, ширину ничто не режет. */

/* Фон секции белый, задан общим правилом выше вместе с остальными семью.
   Своей заливки у секции больше нет. */

/* Заголовок и кнопка в одной строке: главный аргумент «от одного рулона»
   и действие стоят рядом, а не через весь блок друг от друга. */

.opt-prints__head {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 40px;
    align-items: end;
    margin-bottom: 40px;
}

/* Шаг между блоками переключается на 991px — там же, где отступы секций.
   Перестроение самого блока остаётся на 767px: это про раскладку,
   а не про ритм, и границы у них разные. */

@media (max-width: 991px) {
    .opt-prints__head {
        margin-bottom: 24px;
    }
}

@media (max-width: 767px) {
    .opt-prints__head {
        grid-template-columns: 1fr;
        gap: 24px;
        align-items: start;
        margin-bottom: 24px;
    }
}

/* Сайтовый .title-h2 несёт цвет #0F172A и margin-bottom 40px — на синем
   он был бы нечитаем, а отступ развалил бы строку с кнопкой. */

/* Цвет заголовка не задаём: на белом работает сайтовый #0F172A, как
   у заголовков остальных секций. Раньше здесь стоял белый — под синюю полосу. */

.opt-prints__title {
    margin-bottom: 16px;
}

/* Подзаголовок. У сайтового .section__subtitle правил нет вообще — работает
   только тег p. Стилизованные подзаголовки на сайте называются иначе и живут
   в printing.css (.printing-form__subtitle, 20px/600). Он к нам не подключён,
   поэтому размер перенесён сюда под свой класс. Цвет — сайтовый #C5DBED:
   на синем он читается спокойнее белого и не спорит с заголовком. */

.opt-prints__desc {
    margin: 0;
    font-size: 20px;
    line-height: 140%;
    color: #4F4F4F;
}

@media (max-width: 991px) {
    .opt-prints__desc {
        font-size: 16px;
    }
}

.opt-prints__cta {
    justify-self: start;
}

/* Шесть плиток своей сеткой, а не бутстрап-колонками: так задаётся зазор
   и точная ширина плитки, под которую нарезаны картинки. */

.opt-prints__list {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 16px;
}

@media (max-width: 991px) {
    .opt-prints__list {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 575px) {
    .opt-prints__list {
        grid-template-columns: repeat(2, 1fr);
        gap: 12px;
    }
}

/* Карточка принта: кадр плюс название под ним. Ссылка — вся карточка целиком,
   поэтому по названию тоже можно кликнуть. */

.opt-prints__item {
    display: block;
    text-decoration: none;
}

/* Пропорция плитки задаётся здесь, и это не косметика.

   У сайтового компонента квадрат получался правилом
   .preview-banner:first-child:last-child { padding-bottom: 92.2% }
   (style-new.css:2918) — то есть форма держалась на том, что баннер был
   единственным ребёнком своей колонки. В общей сетке они стали соседями,
   правило перестало срабатывать, и все шестеро схлопнулись бы в широкие
   полоски 43% из базового .preview-banner.

   Задаём соотношение явно. Заодно снимается margin-bottom 36px, который
   базовый компонент носит для вертикального списка и который в сетке
   давал лишнюю дырку под каждым рядом. */

.opt-prints__tile {
    display: block;
    aspect-ratio: 1 / 1;
    padding-bottom: 0;
    margin-bottom: 0;
}

/* Название принта. Раньше оно жило только в alt — то есть посетитель его
   не видел вовсе, и шесть плиток читались как безымянная полоска. */

.opt-prints__name {
    display: block;
    margin-top: 10px;
    color: #0F172A;
    font-size: 14px;
    font-weight: 500;
    line-height: 130%;
    text-align: center;
}

@media (max-width: 575px) {
    .opt-prints__name {
        margin-top: 8px;
        font-size: 13px;
    }
}

/* --- Плитка-призыв: загрузить свой макет ------------------------------------
   Шестая плитка не принт, а действие. Задача — чтобы человек с одного взгляда
   понял: сюда можно положить свой файл и получить по нему напечатанную ткань.

   Поэтому взята узнаваемая форма зоны перетаскивания: пунктирная рамка,
   стрелка вверх над лотком, светлая подложка. Ровно так выглядит форма внизу
   страницы печати, куда плитка и ведёт, — иконка скопирована оттуда же
   (printing/index.html, .file-upload). Плитка и форма читаются одним действием.

   Плитка не использует сайтовый .preview-banner, в отличие от пяти соседних:
   у того чёрная заливка под фотографию, и без картинки он даёт чёрный квадрат.
   Пропорция 1:1 и радиус повторены вручную, чтобы плитка стояла в ряду ровно. */

.opt-prints__drop {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    aspect-ratio: 1 / 1;
    padding: 12px;
    border: 2px dashed #102F97;
    border-radius: 12px;
    background-color: #F0F5F9;
    text-align: center;
    transition: background-color .25s ease, border-color .25s ease;
}

/* Радиус повторяет сайтовый .preview-banner: 12px, на узких экранах 8px.
   Иначе плитка-призыв скруглена иначе, чем пять соседних. */

@media (max-width: 575px) {
    .opt-prints__drop {
        gap: 8px;
        padding: 10px;
        border-radius: 8px;
    }
}

.opt-prints__drop-ico {
    display: block;
    width: 40px;
    height: 40px;
    color: #102F97;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

@media (max-width: 575px) {
    .opt-prints__drop-ico {
        width: 32px;
        height: 32px;
    }
}

/* max-width обязателен. Плитка — флекс-столбец с align-items: center, и без
   ограничения ширины строка растягивается по содержимому и вылезает за рамку
   на узких телефонах вместо того, чтобы перенестись. Замер на 375px до правки:
   142px текста при 143px внутренней ширины — впритык. */

.opt-prints__drop-text {
    max-width: 100%;
    color: #102F97;
    font-size: 14px;
    font-weight: 600;
    line-height: 125%;
}

@media (max-width: 575px) {
    .opt-prints__drop-text {
        font-size: 13px;
    }
}

/* Подпись под плиткой у соседей — название принта, здесь обещание.
   Синим, чтобы читалось продолжением призыва, а не шестым названием ткани. */

.opt-prints__name--accent {
    color: #102F97;
    font-weight: 600;
}

/* Пульсация. Расходящаяся рамка поверх плитки: тот же приём, что у точки
   «онлайн» в интерфейсах, — глаз ловит движение, но оно не дёргает вёрстку.

   Анимируются только transform и opacity: обе считаются композитором и не
   заставляют браузер пересчитывать раскладку. Меняли бы ширину рамки или
   box-shadow — получили бы перерисовку по кругу, а плитка стоит в первом
   экране прокрутки на телефоне.

   pointer-events: none обязателен: рамка лежит поверх ссылки и без него
   перехватывала бы нажатие. */

.opt-prints__drop::after {
    content: '';
    position: absolute;
    top: -2px;
    right: -2px;
    bottom: -2px;
    left: -2px;
    border: 2px solid #102F97;
    border-radius: 14px;
    opacity: 0;
    pointer-events: none;
    animation: opt-prints-pulse 2.6s ease-out infinite;
}

@media (max-width: 575px) {
    .opt-prints__drop::after {
        border-radius: 10px;
    }
}

@keyframes opt-prints-pulse {
    0%   { transform: scale(1);    opacity: .5; }
    70%  { transform: scale(1.07); opacity: 0; }
    100% { transform: scale(1.07); opacity: 0; }
}

/* Стрелка заодно чуть приподнимается — подсказка о направлении «вверх,
   к загрузке». Тот же ритм 2.6s, чтобы два движения читались одним. */

.opt-prints__drop-ico {
    animation: opt-prints-lift 2.6s ease-in-out infinite;
}

@keyframes opt-prints-lift {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-4px); }
}

/* Человек попросил систему не анимировать — движение выключается полностью.
   Плитка остаётся пунктирной рамкой со стрелкой и работает так же.
   На странице это второе такое место после стены первого экрана. */

@media (prefers-reduced-motion: reduce) {
    .opt-prints__drop::after,
    .opt-prints__drop-ico {
        animation: none;
    }
}

/* Наведение: пунктир становится сплошным, подложка темнеет. Читается как
   «зона активна», тем же языком, что и настоящая форма загрузки. */

.opt-prints__item--upload:hover .opt-prints__drop,
.opt-prints__item--upload:focus-visible .opt-prints__drop {
    border-style: solid;
    background-color: #E0EAF2;
}


/* ============================================================================
   СЕКЦИЯ 5. Три шага
   ============================================================================
   Композиция снята с блока .steps на /printing/, но написана заново под свои
   классы: printing.css к нашей странице не подключается (решение №4).

   Отличия от сайтового блока, оба по прототипу: номер стоит слева, а не над
   карточкой, и у шага появился подзаголовок. Сетка на три колонки вместо
   шести — на /printing/ шагов шесть, у нас три.

   Номер рисуется css-счётчиком, как на сайте: в разметке его нет, поэтому
   он не задваивается в озвучке скринридером поверх нумерации самого ol. */

.opt-steps__list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: opt-step;
}

/* В одну колонку с 991px, а не с 767: так же ломается сайтовый .steps
   на /printing/ (printing.css:338). На 768px три колонки дают карточку
   в 227px — заголовок шага уходит в три строки и блок распухает вдвое. */

@media (max-width: 991px) {
    .opt-steps__list {
        grid-template-columns: 1fr;
        gap: 12px;
    }
}

/* Карточка белая на светлой полосе секции. Тень — фирменная сайтовая,
   но в том варианте, что стоит у .promo-labels__label: у большой
   0 6px 40px 10px разброс такой, что три соседние карточки сливаются
   в сплошную синюю дымку. */

.opt-steps__item {
    display: grid;
    grid-template-columns: 48px 1fr;
    column-gap: 16px;
    row-gap: 8px;
    align-content: start;
    margin: 0;
    padding: 24px;
    border-radius: 16px;
    background-color: #ffffff;
    box-shadow: 0 3.17647px 21.1765px 5.29412px #C5DBED;
    counter-increment: opt-step;
}

@media (max-width: 991px) {
    .opt-steps__item {
        padding: 20px;
    }
}

.opt-steps__item::before {
    content: counter(opt-step);
    grid-column: 1;
    grid-row: 1;
    align-self: start;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background-color: #102F97;
    color: #ffffff;
    font-size: 20px;
    font-weight: 700;
    line-height: 1;
}

@media (max-width: 991px) {
    .opt-steps__item::before {
        width: 40px;
        height: 40px;
        font-size: 18px;
    }
}

@media (max-width: 991px) {
    .opt-steps__item {
        grid-template-columns: 40px 1fr;
    }
}

.opt-steps__title {
    grid-column: 2;
    grid-row: 1;
    align-self: center;
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    line-height: 130%;
    color: #0F172A;
}

@media (max-width: 991px) {
    .opt-steps__title {
        font-size: 16px;
    }
}

.opt-steps__text {
    grid-column: 2;
    grid-row: 2;
    margin: 0;
    font-size: 16px;
    line-height: 150%;
    color: #4F4F4F;
}

@media (max-width: 991px) {
    .opt-steps__text {
        font-size: 15px;
    }
}

/* Появление карточек по очереди.

   Класс --ready вешает opt.js, и только он прячет карточки. Сделано так
   намеренно: если скрипт не отработал, разметка остаётся видимой, а не
   исчезает навсегда. Класс --in скрипт добавляет, когда блок доехал до экрана.

   Очередь задана модификаторами --2 и --3, а не :nth-child: правило проекта
   требует не привязывать вид к позиции элемента.

   Анимация выключена для тех, кто попросил систему не двигать картинку, —
   проверка стоит и в css, и в js: css страхует случай, когда настройку
   поменяли уже после загрузки страницы. */

.opt-steps__list--ready .opt-steps__item {
    opacity: 0;
    transform: scale(.94);
}

.opt-steps__list--in .opt-steps__item {
    opacity: 1;
    transform: scale(1);
    transition: opacity .45s ease-out, transform .45s cubic-bezier(.2, .8, .2, 1);
}

.opt-steps__list--in .opt-steps__item--2 {
    transition-delay: .16s;
}

.opt-steps__list--in .opt-steps__item--3 {
    transition-delay: .32s;
}

@media (prefers-reduced-motion: reduce) {
    .opt-steps__list--ready .opt-steps__item {
        opacity: 1;
        transform: none;
    }
    .opt-steps__list--in .opt-steps__item {
        transition: none;
    }
}


/* Чек-лист отделяется линией так же, как факты во второй секции.

   Селектор с тегом — ul.opt-steps__checklist — не для красоты: сайтовое правило
   ul.chekc-list { margin: 0; padding: 0 } (style-new.css:3068) имеет
   специфичность (0,1,1) и забивало наш (0,1,0). Отступ и линия не показывались
   вовсе. Уравниваем специфичность, дальше выигрывает порядок подключения. */

ul.opt-steps__checklist {
    margin-top: 40px;
    padding-top: 32px;
    border-top: 1px solid #C5DBED;
}

/* Шаг между блоками переключается на 991px — там же, где отступы секций.
   Перестроение самого блока остаётся на 767px: это про раскладку,
   а не про ритм, и границы у них разные. */

@media (max-width: 991px) {
    ul.opt-steps__checklist {
        margin-top: 24px;
    }
}

@media (max-width: 767px) {
    ul.opt-steps__checklist {
        margin-top: 24px;
        padding-top: 20px;
    }
}


/* ============================================================================
   СЕКЦИЯ 6. Отзывы и рейтинг
   ============================================================================ */

/* Вариант 4, утверждён 23.08.2026: мозаика с главным отзывом.
   Рейтинг слева, главный отзыв на две колонки тёмно-синим, два оставшихся —
   узкой парой справа. Референс подобран в Refero: groq.com.

   Сайтовые .reviews__item и .review не используются: у них серая заливка
   #F9F9F9, радиус 3px и типографика старого слоя. Подробности в разметке. */

.opt-reviews__mosaic {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    gap: 24px;
    align-items: stretch;
}

/* На двух колонках раскладку приходится собирать вручную. Автоматически
   выходило так: рейтинг занимает первую клетку, широкий отзыв не влезает
   в оставшуюся одну и уезжает на свою строку, пара уходит на третью —
   и справа зияют две дыры. Раскладываем явно: сверху рейтинг и пара,
   под ними главный отзыв во всю ширину. */

@media (max-width: 991px) {
    .opt-reviews__mosaic { grid-template-columns: 1fr 1fr; }
    .opt-reviews__pair { grid-column: 2; grid-row: 1; }
}

@media (max-width: 575px) {
    .opt-reviews__mosaic { grid-template-columns: 1fr; }
    .opt-reviews__pair { grid-column: 1; grid-row: auto; }
}

/* Белая карточка со скруглением и фирменной синей тенью — тот же вид,
   что у карточек шагов в пятой секции, чтобы страница говорила на одном языке.
   Тень взята в варианте .promo-labels__label: у большой 0 6px 40px 10px разброс
   такой, что соседние карточки сливаются в синюю дымку. */

.opt-reviews__card {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 28px 24px;
    border-radius: 20px;
    background-color: #ffffff;
    box-shadow: 0 3.17647px 21.1765px 5.29412px #C5DBED;
}

@media (max-width: 991px) {
    .opt-reviews__card { padding: 24px 20px; }
}

/* Карточка рейтинга: всё по центру, число крупно. Композиция взята из
   navigation/RatingBadge дизайн-системы — порядок «число, звёзды, источник».
   Плашка-чип, серый фон и эмодзи из компонента не переносятся. */

.opt-reviews__card--rating {
    align-items: center;
    justify-content: center;
    gap: 12px;
    text-align: center;
    overflow: hidden;
}

.opt-reviews__source {
    font-size: 12px;
    line-height: 21px;
    text-transform: uppercase;
    color: #909090;
}

.opt-reviews__score {
    font-size: 44px;
    font-weight: 700;
    line-height: 1;
    color: #0F172A;
    z-index: 1;
}

@media (max-width: 991px) {
    .opt-reviews__score { font-size: 36px; }
}

.opt-reviews__count {
    margin: 0;
    font-size: 14px;
    line-height: 140%;
    color: #9A9CA3;
}

/* Главный отзыв. Тёмное пятно здесь допустимо: секция белая, соседние полосы
   светлые, и это единственный акцент в нижней половине страницы. */

.opt-reviews__card--feature {
    padding: 32px;
    background-color: #102F97;
    box-shadow: none;
}

@media (max-width: 991px) {
    .opt-reviews__card--feature {
        grid-column: 1 / -1;
        grid-row: 2;
        padding: 28px 24px;
    }
}

@media (max-width: 575px) {
    .opt-reviews__card--feature { grid-column: 1; grid-row: auto; }
}

/* Кавычка жёлтым: единственный тёплый акцент на синем, и она заполняет верх
   карточки, который иначе зиял бы пустотой над короткой цитатой. */

.opt-reviews__mark {
    display: block;
    margin-bottom: 8px;
    font-size: 52px;
    font-weight: 700;
    line-height: .8;
    color: #FFCB00;
}

@media (max-width: 991px) {
    .opt-reviews__mark { font-size: 40px; }
}

/* ОТЗЫВ ОБРЕЗАН ДО ЧЕТЫРЁХ СТРОК. Добавлено 04.09.2026.

   Отзывы приходят с сайта и бывают любой длины: сейчас в блоке лежат короткие,
   но стоит появиться развёрнутому — и карточка вытянется, а мозаика из трёх
   карточек развалится, потому что соседние останутся прежними.

   Четыре строки — это столько, сколько человек успевает прочесть, не решая
   заранее, читать ли вообще. Кто хочет целиком, нажимает «Развернуть»
   под отзывом: карточка раскрывается на месте, никуда не уводя.

   КНОПКУ СТАВИТ СКРИПТ, И ТОЛЬКО ТАМ, ГДЕ ТЕКСТ РЕАЛЬНО НЕ ПОМЕСТИЛСЯ.
   Написать её в разметке нельзя: длина отзыва меняется вместе с шириной
   экрана — то, что на компьютере укладывается в три строки, на телефоне
   занимает семь. Скрипт меряет каждый отзыв на месте и пересчитывает,
   когда меняется ширина окна.

   БЕЗ СКРИПТА отзыв остаётся обрезанным, но кнопки нет. Это осознанно:
   лучше ровная мозаика с укороченным текстом, чем разъехавшаяся вёрстка.
   Полный текст всегда доступен по ссылке «Смотреть все отзывы».

   line-clamp с приставкой -webkit- — единственный способ обрезать по строкам,
   который понимают все нынешние браузеры, включая Safari. Старые не поймут
   и покажут отзыв целиком: вёрстка от этого не ломается. */

.opt-reviews__text {
    margin: 0;
    font-size: 15px;
    line-height: 160%;
    color: #4F4F4F;

    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
}

/* Класс ставит скрипт по нажатию. line-clamp снимаем большим числом,
   а не unset: unset в этом свойстве понимают не все браузеры. */

.opt-reviews__text.is-full {
    -webkit-line-clamp: 999;
    overflow: visible;
}

/* Кнопка под отзывом. Не ссылка, а button: она никуда не ведёт, а меняет
   вид того же блока. Подчёркивание вместо рамки — кнопка не должна спорить
   с настоящими кнопками страницы и оттягивать на себя внимание. */

.opt-reviews__more {
    margin-top: 10px;
    padding: 0;
    border: 0;
    background: none;
    color: #102F97;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    line-height: 140%;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.opt-reviews__more:hover,
.opt-reviews__more:focus-visible {
    text-decoration: none;
}

/* В главной карточке подложка синяя, и сайтовый синий на ней не читается. */

.opt-reviews__card--feature .opt-reviews__more {
    color: #ffffff;
    font-size: 16px;
}

.opt-reviews__card--feature .opt-reviews__text {
    font-size: 26px;
    line-height: 140%;
    color: #ffffff;
}

@media (max-width: 991px) {
    .opt-reviews__card--feature .opt-reviews__text { font-size: 20px; }
}

/* Подпись под отзывом: имя, звёзды, дата. Ровно эти три поля есть на сайте,
   города и рода деятельности из прототипа там нет и взять их неоткуда. */

.opt-reviews__foot {
    margin-top: auto;
}

/* В главной карточке подпись идёт сразу за цитатой, а не прижимается к низу.
   Карточка высокая, и прижатая подпись отрывалась от текста — читалось так,
   будто имя относится к чему-то другому. Свободное место внизу забирает
   ссылка на все отзывы. */

.opt-reviews__card--feature .opt-reviews__foot {
    margin-top: 0;
}

.opt-reviews__name {
    margin: 0 0 6px;
    font-size: 16px;
    font-weight: 600;
    line-height: 130%;
    color: #0F172A;
}

.opt-reviews__card--feature .opt-reviews__name {
    color: #ffffff;
}

.opt-reviews__date {
    margin: 4px 0 0;
    font-size: 13px;
    line-height: 140%;
    color: #9A9CA3;
}

.opt-reviews__card--feature .opt-reviews__date {
    color: #C5DBED;
}

/* Звёзды — сайтовый .rating-result. У него глиф ★ 27px, для подписи под
   отзывом это крупно; в карточке рейтинга размер оставляем сайтовый. */

.opt-reviews__foot .rating-result {
    display: flex;
}

.opt-reviews__foot .rating-result span {
    margin: 0 1px 0 0;
    font-size: 16px;
}

.opt-reviews__card--rating .rating-result {
    display: flex;
    justify-content: center;
}

/* Ссылка на все отзывы — в правом нижнем углу главной карточки.

   margin-top: auto забирает всё свободное место карточки себе, поэтому
   ссылка стоит у нижнего края независимо от длины цитаты, а подпись
   остаётся прижатой к тексту.

   Сайтовый .link-btn красит ссылку в #102F97 — ровно цвет подложки, на ней
   она была бы не видна. Перекрашиваем в белое, пунктир оставляем сайтовый,
   только приглушаем.

   Специфичность считана, а не прикинута: сайтовое .link-btn:hover — это
   (0,1,1), одного своего класса с псевдоклассом хватило бы только на (0,1,1)
   и решал бы порядок файлов. Селектор из двух классов даёт (0,2,1)
   и выигрывает наверняка. */

.opt-reviews__all.link-btn {
    align-self: flex-end;
    margin-top: auto;
    color: #ffffff;
    border-bottom-color: rgba(255, 255, 255, .5);
}

.opt-reviews__all.link-btn:hover,
.opt-reviews__all.link-btn:focus {
    color: #ffffff;
    border-bottom-color: transparent;
}

/* Пара узких отзывов справа делит колонку по высоте поровну. */

.opt-reviews__pair {
    display: grid;
    grid-template-rows: 1fr 1fr;
    gap: 24px;
}


/* ============================================================================
   СЕКЦИЯ 7. Вопросы и ответы
   ============================================================================ */

/* Сайтовый .accordion-block--new несёт max-width: 710px, но центрируется
   не сам — на донорских страницах его центрирует родитель. У нас родитель
   .container, поэтому блок прижимался влево под отцентрованным заголовком.
   Добавляем только автоматические поля, ширину не трогаем.

   Правило уже стояло, но было снесено 23.08.2026 при переписывании блока
   шестой секции: замена куска файла захватила и этот. Поймано глазом
   заказчика на собранной странице — значит, отдельная проверка после
   больших замен в css нужна, диффа мне не хватило. */

.opt-faq__list {
    margin-left: auto;
    margin-right: auto;
}

/* Два сайтовых отступа выбивали седьмую секцию из общего ритма страницы.

   Первый: .accordion-block--new несёт margin-top: 80px (style-new.css). На
   донорских страницах аккордеон стоит после текстового блока, там 80px уместны.
   У нас над ним заголовок секции, и от заголовка до содержимого везде 40px —
   восьмидесятка читалась дырой.

   Второй: .accordion-block:last-child даёт margin-bottom: 40px. Он добавлялся
   к собственному нижнему полю секции, и снизу получалось 100px против 60px
   у всех остальных — секция выглядела съехавшей вверх.

   Специфичность считана, а не прикинута: .accordion-block:last-child — это
   (0,1,1), одного своего класса (0,1,0) не хватило бы. Селектор из двух
   классов даёт (0,2,0) и выигрывает у обоих сайтовых правил. */

.opt-faq__list.accordion-block {
    margin-top: 40px;
    margin-bottom: 0;
}

@media (max-width: 991px) {
    .opt-faq__list.accordion-block {
        margin-top: 24px;
    }
}


/* ============================================================================
   СЕКЦИЯ 8. Форма подбора
   ============================================================================
   Двухцветная карточка: левая половина тёмно-синяя, правая белая, скругление
   у внешних углов. Своей разметки модификатор не добавляет — красит те же два
   узла, которые у компонента уже есть: .fabric-search-form__desc и form.

   Это косметика поверх живого компонента, а не новый блок: механика отправки,
   имена полей, ajax и модалка успеха остаются сайтовыми. */

/* Заголовок секции добавлен 25.08.2026: до этого секция была единственной
   из девяти без своего заголовка, начиналась сразу с карточки.

   Своих правил у него нет и не нужно. Сайтовые .title-h2 и .text-center дают
   размер, цвет #0F172A, выравнивание по центру и отступ 40px до содержимого —
   ровно то же, что у заголовков остальных восьми секций.

   Был ещё подзаголовок под ним, .opt-search__lead, — снят по решению
   заказчика вместе со своими правилами: он повторял то, что написано
   в карточке формы ниже. */

.opt-search-card {
    max-width: 1000px;
    margin: 0 auto;
    padding: 0;
    border-radius: 20px;
    overflow: hidden;
    background-color: #ffffff;
    box-shadow: 0 6px 40px 10px #C5DBED;
}

/* Сайтовые .fabric-search-form__desc и form имеют свои max-width и между ними
   остаётся зазор от justify-content: space-between. В двухцветной карточке
   зазор показал бы фон секции насквозь, поэтому половины растягиваются
   по флекс-основе, а ограничения ширины снимаются. */

.opt-search-card .fabric-search-form__desc {
    flex: 0 0 42%;
    max-width: none;
    width: auto;
    padding: 40px;
    background-color: #102F97;
}

@media (max-width: 991px) {
    .opt-search-card .fabric-search-form__desc {
        padding: 30px;
    }
}

@media (max-width: 767px) {
    .opt-search-card .fabric-search-form__desc {
        flex: 1 1 auto;
        width: 100%;
        max-width: none;
        padding: 24px 20px;
    }
}

.opt-search-card form {
    flex: 1 1 auto;
    max-width: none;
    width: auto;
    padding: 40px;
}

@media (max-width: 991px) {
    .opt-search-card form {
        padding: 30px;
    }
}

@media (max-width: 767px) {
    .opt-search-card form {
        width: 100%;
        padding: 24px 20px;
    }
}

/* Текст на тёмной половине. Сайтовые правила красят его в #0F172A —
   на синем он был бы нечитаем. */

.opt-search-card .fabric-search-form__desc h2,
.opt-search-card .fabric-search-form__desc h2 span,
.opt-search-card .fabric-search-form__desc p {
    color: #ffffff;
}

/* Пара «заголовок — подзаголовок» на странице везде 16px: первый экран,
   секция печати, эта карточка. Сайтовый компонент ставит абзац вплотную
   к заголовку — выравниваем. */

.opt-search-card .fabric-search-form__desc h2 {
    margin-bottom: 16px;
}

/* Логотип на тёмной половине.

   Размер намеренно скромный. Начертание знака — плотный гротеск, почти
   совпадающий по весу с заголовком под ним; на одной ширине они слипались
   в две строки одного текста. На 132px знак читается как марка над
   обращением, а заголовок остаётся заголовком. Отступ снизу увеличен
   по той же причине. */

.opt-search-card__logo {
    display: block;
    width: 132px;
    height: auto;
    margin-bottom: 32px;
}

@media (max-width: 991px) {
    .opt-search-card__logo {
        width: 112px;
        margin-bottom: 22px;
    }
}

/* На телефоне знак встаёт по центру.

   Причина смещения влево: тёмная половина — сайтовый флекс-столбец с
   align-items: flex-start (main.min.css:11957), и он на телефоне не
   переключается. Заголовок и абзац там центрует text-align: center
   (main.min.css:12068), а картинка — флекс-элемент, и text-align на неё
   не действует: она осталась прижатой к левому краю, пока текст рядом
   стоял по центру.

   Центруем автоотступами по бокам, а не переключением align-items у
   родителя: у сайтового узла на flex-start держатся и остальные его дети,
   лезть в него ради одной картинки незачем. */

@media (max-width: 767px) {
    .opt-search-card__logo {
        margin-right: auto;
        margin-left: auto;
    }
}


/* Размер заголовка приходится задать явно. У сайтового компонента в h2 два
   span: первый — заголовок, второй — подзаголовок 20px. У нас span один,
   и он подходит под оба правила сразу, поэтому побеждало правило
   span:last-child и заголовок падал с 30px до 20px.
   Селектор (0,2,2) перебивает сайтовый (0,2,1). */

.opt-search-card .fabric-search-form__desc h2 span {
    margin: 0 0 16px;
    font-size: 30px;
    font-weight: 600;
    line-height: 130%;
}

@media (max-width: 991px) {
    .opt-search-card .fabric-search-form__desc h2 span {
        margin: 0 0 12px;
        font-size: 22px;
    }
}

@media (max-width: 575px) {
    .opt-search-card .fabric-search-form__desc h2 span {
        font-size: 20px;
    }
}

/* Абзац на тёмной половине возвращается на телефонах.

   Сайт прячет его: .fabric-search-form__desc>p { display: none } внутри
   @media (max-width: 575px) (style-new.css:4849). На главной там короткий
   рекламный текст, и потерять его не жалко. У нас в этом абзаце инструкция —
   что именно написать в заявке, — и без неё поле «Какую ткань ищете?»
   остаётся без объяснения ровно на том устройстве, с которого заявки и шлют.

   Правило сайта не трогаем, перебиваем своим через .opt-search-card. */

@media (max-width: 575px) {
    .opt-search-card .fabric-search-form__desc > p {
        display: block;
    }
}


/* Подпись под кнопкой. Типографика перенесена из printing.css
   (.file-upload__hint, 13px/#888888/по центру) под свой класс.

   width и max-width — чтобы подпись встала ровно по центру кнопки.
   Сайтовое правило `.fabric-search-form p` в main.min.css держит абзацы формы
   уже кнопки: 450 против 500. Подпись центрировалась по своей ширине
   и оказывалась на 25 пикселей левее середины кнопки — заметно, потому что
   стоит прямо под ней.

   Класс в селекторе повторён дважды. Это не описка: у сайтового правила
   специфичность выше (класс плюс тег), и одного нашего класса не хватало —
   правило просто не применялось. Повтор поднимает вес до двух классов,
   не трогая ни сайтовый файл, ни разметку. Так рекомендует правило изоляции:
   перебивать своим же классом, а не !important. */

.opt-search-card__note.opt-search-card__note {
    width: 100%;
    max-width: none;
    margin: 12px 0 0;
    font-size: 13px;
    line-height: 140%;
    color: #888888;
    text-align: center;
}


/* ============================================================================
   СЛАЙДЕР С ГЛАВНОЙ. Перенесён 24.08.2026
   ============================================================================
   Оформления здесь нет и быть не должно. Блок работает на сайтовом slick
   (js/libs.min.js), инициализируется сайтовым js/main_v2.js, а выглядит
   так, как его описывают main.min.css, style.css и ext/extended.css.
   Все эти файлы страница подключает и так — ровно теми же тегами, что и
   главная. Ни одного правила оформления мы не переносили и не дублировали:
   дублирование как раз и создало бы те конфликты, которых нужно избежать.

   Единственное, что приходится поправить, — внешние отступы самого слайдера.
   Сайт даёт ему margin-top: 30px и margin-bottom: 60px (extended.css), потому
   что на главной он стоит сразу под шапкой и сам разводит себя с соседями.
   У нас он лежит в секции, а секция уже везёт свои 60px сверху и снизу:
   без обнуления вышло бы 90 сверху и 120 снизу вместо ровных 60, и блок
   выпал бы из шкалы отступов страницы.

   Правило заперто внутри .opt-promo-slider и до главной страницы не достаёт:
   там слайдер лежит в .content > .container, нашего класса рядом нет. */

.opt-promo-slider .main-slider {
    margin-top: 0;
    margin-bottom: 0;
}
.opt-promo-slider .main-slider .slick-dots {
    display: none!important;
}

/* ============================================================================
   ФОН СТРАНИЦЫ: ткань. Внедрён 25.08.2026
   ============================================================================
   Вариант «ткань видна полностью», сила проявления «заметно». Оба выбраны
   заказчиком по витрине.

   Исходник image9.jpg весил 2,9 МБ и был почти белым: средняя яркость 235
   из 255, самая тёмная точка 186. На белой странице он был неразличим —
   заказчик так и сказал: «фон просто белый». Картинка проявлена формулой
   out = 255 - (255 - in) * K. Пересобирается командой
   python _tools/make-bg.py image9.jpg

   СИЛА ПРОЯВЛЕНИЯ K ОСЛАБЛЕНА 25.08.2026 ДВАЖДЫ, с 2,0 до 1,28. Заказчик
   посмотрел страницу и два раза подряд попросил светлее процентов на 20:
   сначала ткань перетягивала внимание на себя, потом читалась серой.
   Проценты считаются от того, что видно на экране, а не от исходника,
   поэтому K каждый раз умножался на 0,8: 2,0 -> 1,6 -> 1,28.

   Медиана кадра и самая тёмная его точка по шагам:
     исходник 238 / 186 · K=2,0 — 221 / 117 · K=1,6 — 228 / 133 ·
     K=1,28 — 234 / 157

   Заодно картинка полегчала: 34 КБ вместо 52 в webp.

   ПОТОЛОК. При K = 1 обработки нет вовсе, и картинка возвращается к исходной —
   той, про которую заказчик и сказал «фон просто белый». Светлеть дальше
   можно ещё примерно на четверть от нынешнего, и на этом всё. Если ткань
   и после этого будет казаться серой — дело не в яркости, а в самом кадре:
   шёлк на нём холодного серо-белого тона. Тогда нужен другой исходник
   или тонирование в тёплую сторону, а не осветление.

   Число живёт в одном месте — константа K в начале make-bg.py. Менять фон
   надо там и пересобирать, а не накладывать css-фильтр поверх: фильтр
   браузер считает на каждой прокрутке, а тут это разовая работа.

   Слой лежит первым узлом в контентной зоне и не двигается при прокрутке.
   ============================================================================ */

.opt-bg {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: -1;
    pointer-events: none;

    /* jpg объявлен первым как запасной: браузер, который не понимает
       image-set, оставит его и покажет картинку. Понимающий перебьёт
       следующей строкой и возьмёт webp — 52 КБ вместо 186. */
    background-image: url("../img/opt/bg/fabric-bg.jpg?v=5");
    background-image: image-set(url("../img/opt/bg/fabric-bg.webp?v=5") type("image/webp"),
                                url("../img/opt/bg/fabric-bg.jpg?v=5") type("image/jpeg"));
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
}

/* На телефоне своя нарезка, а не уменьшенный десктопный кадр.

   Экран телефона вертикальный, кадр горизонтальный. При cover горизонтальный
   кадр на вертикальном экране тянется по высоте: чтобы закрыть 844px, нужно
   1477px ширины — почти десктопный файл, да ещё с пустой серединой в кадре.
   Вертикальная нарезка левой части закрывает тот же экран за 21 КБ вместо 52
   и показывает складки. Замер видимой на 375x812 области: разброс яркости
   147..236 против 171..237 у десктопного кадра на том же экране. */

@media (max-width: 767px) {
    .opt-bg {
        background-image: url("../img/opt/bg/fabric-bg-mob.jpg?v=5");
        background-image: image-set(url("../img/opt/bg/fabric-bg-mob.webp?v=5") type("image/webp"),
                                    url("../img/opt/bg/fabric-bg-mob.jpg?v=5") type("image/jpeg"));
    }
}

