/* ============================================================
   Прототип сайта типографии «Прожектор»

   Правило файла: у каждого селектора одно место.
   Правишь компонент — правишь его блок, а не дописываешь в конец.
   Все медиазапросы собраны в разделе «Адаптив» внизу, по убыванию ширины.

   Содержание
     1  Токены
     1-bis  Тонкая тема (класс ui-fine)
     2  База и типографика
     3  Кнопки
     4  Поля и формы
     5  Шапка
     6  Мобильное меню
     6-bis  Поиск
     7  Hero
     8  Портфолио и плейсхолдеры
     9  Преимущества
     9-bis  Решения для бизнеса
     9-tri  С чего начать: входы в сценарии
     9-quad  От промпта до готового изделия
    10  Каталог: табы и карточки
    11  Отзывы и клиенты
    12  Обратный звонок и видео
    13  Подвал
    14  Модалки
    15  Плавающие кнопки, чат, предупреждения
    16  Внутренние страницы
    16-bis  Услуги: карточка с текстом вместо снимка
    16-tri  Страницы решений: welcome pack и мерч
    17  Карточка продукта
    18  Выбор продукта и пути к макету
    19  Параметры заказа
    20  Заявка менеджеру
    21  Препресс-проверка
    22  Редактор макета
    23  Предпросмотр макета
    24  Корзина
    25  Оформление заказа
    26  Личный кабинет
    27  Адаптив
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800&display=swap');

/* Гарнитуры для макетов клиента: лежат рядом файлами, чтобы редактор работал
   без интернета и показывал ровно то, что уйдёт в печать. Интерфейс сайта
   по-прежнему набран Montserrat из строки выше. */
@import url('../fonts/fonts.css');

/* ============================================================
   1  Токены
   ============================================================ */
:root {
  /* Фирменные цвета */
  --orange: #f05d20;
  --orange-dark: #d84c14;
  --orange-light: #ff9747;
  /* Кремовая заливка, две ступени по размеру пятна (28 августа 2026):

       --cream      крупное: полоса раздела, карточка, сводка, плитка под
                    значок, зона загрузки. Поверхность, а не состояние
       --cream-sm   мелкое: выбранный тег, чип, таб, пункт меню под курсором.
                    Всё, что меняет цвет от действия человека

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

     Оранжевый текст на них — только --orange-dark. Обычный #f05d20 даёт на
     #fde4d7 контраст 2,74:1 при нашем пороге 3:1; тёмный держит 3,48. На
     крупной кремовой обычный даёт 2,98 — тоже мимо, поэтому правило одно на
     обе ступени: текст и значки на кремовом набраны тёмным оранжевым. */
  --cream: #ffefe7;
  --cream-sm: #fde4d7;
  --ink: #070707;
  --gray: #6e6e6e;
  --gray-light: #b3b3b3;
  /* Светлые серые поверхности. Ступеней четыре, и делит их размер пятна:

       --bg          полосы разделов и шапка внутренней страницы
       --field       поле ввода
       --fill-lg     крупные плашки: панели, сводки, строки таблиц,
                     заглушки под картинку, зоны загрузки
       --fill        мелкое: теги, чипы, табы, иконочные и серые кнопки
       --fill-hover  наведение на мелкую плашку

     Логика та же, что у кремовой: чем меньше пятно, тем плотнее заливка.
     Тег в 46 px и панель в пол-экрана, залитые одним тоном, весят по-разному —
     панель начинает выглядеть вторым фоном, а тег теряется на карточке.

     Тёплый серый убран 28 августа 2026 по замечанию заказчицы: «кремовый
     серый смотрится плохо». Серый мелких элементов при этом чуть тёплый
     (#eaeae6) — это её выбор, и он не случаен: рядом с ним стоит кремовая
     той же светлоты, а холодный серый рядом с тёплой кремовой проваливается.

     Пары сведены по светлоте: #eaeae6 и #fde4d7 обе ≈ 0.82 по яркости,
     #f2f2f2 и #ffefe7 — обе ≈ 0.888. Невыбранный и выбранный тег весят
     одинаково и различаются только цветом. */
  --bg: #fafafa;
  --field: #f7f7f7;
  --fill-lg: #f2f2f2;
  --fill: #eaeae6;
  --fill-hover: #e0e0dc;
  /* Волосяная линия: рамки карточек, разделители, границы полей в покое.
     Уплотнена 26 августа 2026 с #edf1f4 — на светлых экранах рамку в один
     пиксель того тона приходилось искать глазами, и карточки выглядели не
     очерченными, а размытыми. Толщина при этом одна везде, 1 px: полтора
     пикселя оставались только у части компонентов и читались как «эта рамка
     важнее», хотя ничего такого не значили. */
  --line: #e2e8ee;
  --line-strong: #d8dde2;  /* пунктирные рамки загрузки, границы полей под курсором */
  --white: #fff;

  /* Выделение текста при правке на макете: фирменный оранжевый в четверть
     силы. Плотнее нельзя — под ним должны читаться сами буквы. */
  --select-bg: rgba(240, 93, 32, .26);

  /* Тень листа — макет на холсте и в предпросмотре.

     Четыре слоя вместо одного размытого пятна. Волосяная линия по контуру
     держит край чётким: без неё светлая бумага на светлой подложке теряет
     границу и всё выглядит расфокусированным. Дальше короткая плотная тень
     прижимает лист к поверхности, средняя даёт толщину, длинная и слабая —
     воздух под ним. Так устроены тени окон в macOS, и по той же причине:
     резкость даёт ближний слой, объём — дальний. */
  --shadow-sheet:
    0 0 0 1px rgba(16, 24, 32, .07),
    0 1px 2px rgba(16, 24, 32, .10),
    0 6px 12px -4px rgba(16, 24, 32, .14),
    0 26px 44px -18px rgba(16, 24, 32, .30);

  /* Тень готового изделия в предпросмотре. Устроена как --shadow-sheet, но
     плотнее: край темнее и прижат, а дальнее пятно шире и выходит из-под
     изделия дальше. Холст редактора — рабочая поверхность, там такой объём
     отвлекал бы; в предпросмотре человек смотрит на предмет, и тень делает
     его предметом. Падает строго вниз, без сдвига вбок (16 сентября 2026). */
  --shadow-product:
    0 0 0 1px rgba(16, 24, 32, .08),
    0 1px 2px rgba(16, 24, 32, .18),
    0 5px 10px -3px rgba(16, 24, 32, .16),
    0 20px 34px -12px rgba(16, 24, 32, .28),
    0 44px 64px -26px rgba(16, 24, 32, .30);

  /* Состояния: цвет текста и подложка идут парой */
  --ok: #1f9d55;    --ok-bg: #eafaf1;
  --err: #c0392b;   --err-bg: #fdeceb;
  --warn: #d98218;  --warn-bg: #fdf3e6;
  --info: #2b6cb0;  --info-bg: #eef4fd;

  /* Направляющие макета: вылет — оранжевый, рез — чёрный, безопасное поле —
     зелёное: зелёный читается как «здесь безопасно». Сгиб — синий: это не
     запрет и не край, а линия, по которой изделие сложат */
  --guide-safe: #1f9d55;
  --guide-crease: #2b6cb0;

  /* Радиус кодирует роль: острое — управление, мягкое — контент, круглое — метка */
  --r-control: 10px;  /* кнопки, поля, табы */
  --radius-sm: 10px;  /* мелкие плитки внутри карточек */
  --radius: 16px;     /* карточки и блоки контента */
  --radius-lg: 22px;  /* крупные контейнеры: модалки, сводки */
  --r-pill: 100px;    /* только теги и статусы */

  --shadow: 0 8px 30px rgba(0, 0, 0, .07);
  /* Нейтральная, а не оранжевая: цветное свечение под каждой карточкой
     добавляло оранжевого там, где хватает рамки. С 16 сентября 2026 */
  --shadow-hover: 0 10px 28px rgba(16, 24, 32, .10);
  --container: 1440px;
  --header-h: 152px;
  --font: 'Montserrat', 'Futura', 'Trebuchet MS', system-ui, -apple-system, sans-serif;
  /* Цветные эмодзи в макете: рисунок даёт система, своих контуров у них нет */
  --font-emoji: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
}

/* ============================================================
   1-bis  Тонкая тема
   ============================================================

   Проба от 26 августа 2026. Включается классом на теле страницы
   (`<body class="ui-fine">`) и пока стоит только на карточке продукта —
   `product.html`. Три отличия от базовой темы:

   1. (Уехало в базовую тему 26 августа: полоса под шапкой стала нейтральной
      на всех внутренних страницах, см. раздел 16.)
   2. Заливка выбранного отступает: вместо кремовой плашки — её половина.
      Обводка остаётся оранжевой в полную силу, разбавлять её прозрачностью
      нельзя — линия становится вялой, а цвет перестаёт быть фирменным.
      Толщина рамок отсюда уехала в базовую тему: 26 августа один пиксель
      стал общим правилом, и отдельного правила здесь больше нет.
   3. Выбираемое набрано жирным — и выбранное, и нет. Параметр заказа это
      не подпись, а то, ради чего человек сюда пришёл: тираж, формат,
      материал читаются с расстояния. Выбранное отличает цвет и рамка, а не
      вес. Вес отмечает выбор только там, где выбирают из ряда одинаковых
      строк — в списке и в сайдбаре.

   Понравится — правила разъезжаются по своим разделам, класс снимается.
   Не понравится — удаляется этот раздел целиком и одно слово в `product.html`.
   ============================================================ */
.ui-fine {
  /* Кремовый вполсилы: под волосяной рамкой и жирной строкой плашка нужна
     только чтобы подтвердить выбор, а не чтобы его объявить. С 28 августа
     2026 это ровно крупная кремовая: базовая тема красит выбранный параметр
     плотной --cream-sm, тонкая берёт ступень светлее. Своего значения у
     токена больше нет — он остался именем роли. */
  --cream-soft: var(--cream);
}

/* Параметр заказа набран жирным независимо от выбора: и «50 шт», и «100 шт»
   одинаково крупно читаются, как заголовок «Нужно срочно» у переключателя.
   Выбранное держится на цвете, волосяной рамке и кремовой заливке вполсилы */
.ui-fine .opt-btn { font-weight: 700; }
.ui-fine .dd__val { font-weight: 700; }
.ui-fine .opt-btn.is-active,
.ui-fine .opt-card.is-active,
.ui-fine .opt-toggle.is-active { border-color: var(--orange); background: var(--cream-soft); }

/* Список: вот здесь вес и отмечает выбор — строки одинаковые, и плотность
   ловится раньше оттенка */
.ui-fine .dd__opt { font-weight: 500; }
.ui-fine .dd__opt.is-active { background: var(--cream-soft); font-weight: 700; }
.ui-fine .price-run.is-active { background: var(--cream-soft); }

/* Соседние позиции сбоку: открытая — чёрная и жирная, без плашки.
   Цветной плашкой в узкой колонке отмечено то, что человек уже открыл, —
   ради этого оранжевый тратить не на что */
.ui-fine .sidebar__list a { font-weight: 500; }
.ui-fine .sidebar__list a.is-active { background: none; color: var(--ink); font-weight: 700; }

/* Наведение на карточку: та же волосяная рамка, тень нейтральная */
.ui-fine .item-card:hover,
.ui-fine .way:hover,
.ui-fine .tpl:hover,
.ui-fine .svc:hover,
.ui-fine .pick:hover { border-color: var(--orange); }

/* ============================================================
   2  База и типографика
   ============================================================ */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* Шапка фиксированная, поэтому переход по якорю останавливается так, что
   заголовок раздела оказывается под ней. Отступ равен реальной высоте шапки —
   её считает syncHeaderHeight() в app.js и кладёт в --header-h. */
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h, 120px) + 14px); }

body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--white);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  padding-top: var(--header-h);
}
body.no-scroll { overflow: hidden; }
body.app { padding-top: 0; }  /* редактор занимает весь экран */

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
ul { list-style: none; }

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

h1, h2, h3, h4 { font-weight: 800; line-height: 1.1; letter-spacing: -.02em; }
h1 { font-size: clamp(32px, 4.4vw, 62px); }
h2 { font-size: clamp(28px, 3.4vw, 48px); }
h3 { font-size: clamp(18px, 1.6vw, 24px); }

/* Атрибут `hidden` слабее любого правила с `display`: спрятанный им блок,
   у которого есть `display: flex` или `grid`, остаётся на экране. Ловушка
   сработала дважды — на ленте работ и на строке ассортимента в первом
   экране, — поэтому правило общее, а не по компоненту. */
[hidden] { display: none !important; }

.section { padding: 90px 0; }
.section--gray { background: var(--bg); }
.section--cream { background: var(--cream); }

.section-head { margin-bottom: 46px; }
/* Шапка с ссылкой справа. Раскладка была привязана к `#layout`, а 2 сентября
   2026 тот же приём понадобился отзывам: у обоих разделов лента, и ссылка
   «показать всё» должна стоять у обоих одинаково — в правом верхнем углу,
   а стрелки листания под лентой. */
.section-head--split {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 28px;
}
/* Тихая ссылка «показать всё» в шапке раздела. Оформление то же, что у
   «Подробнее» в каталоге (`.cat-card__link`, раздел 10): это ссылка того же
   рода, и заводить ей собственный вид незачем. Кнопкой она была до
   2 сентября 2026 — и читалась действием рядом с текстом, а не выходом к
   остальному ассортименту. */
.section-head__more {
  flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 700; font-size: 14.5px; color: var(--orange);
}
/* Надзаголовок. Правило было привязано к `.section-head`, и на страницах
   решений кикер первого экрана оставался обычным чёрным текстом — там он
   стоит в `.sol-hero`, а не в шапке раздела. То же ждало блок «От промпта
   до готового изделия». Отвязано 29 августа 2026: это самостоятельный
   элемент, а не деталь одного компонента. */
.kicker {
  display: inline-block;
  font-size: 15px;
  font-weight: 600;
  color: var(--orange);
  margin-bottom: 10px;
}
.section-head p { color: var(--gray); max-width: 720px; margin-top: 14px; }
.section-head__link {
  min-height: 52px;
  padding: 0 18px;
  border: 1px solid rgba(240, 93, 32, .32);
  border-radius: var(--r-control);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--orange);
  background: var(--white);
  font-weight: 700;
  white-space: nowrap;
}
.section-head__link svg {
  width: 18px;
  height: 18px;
  flex: none;
}

.text-orange { color: var(--orange); }

/* Пометка «цена примерная» у расчётной суммы и сноска под сеткой цен —
   карточка товара, редактор (панели «Формат» и «Параметры заказа»),
   корзина, оформление, кабинет. Один класс на всех, текст — константы
   PRICE_APPROX_NOTE и PRICE_APPROX_FOOTNOTE в app.js. Просьба владельца,
   14 октября 2026: цена сайта — прикидка по формуле, окончательную даёт
   менеджер. Снять визуально одной правкой — убрать это правило, текст
   останется неоформленным абзацем; снять совсем — обнулить константы. */
.price-note { display: block; margin-top: 6px; font-size: 13px; color: var(--gray-light); }

/* ============================================================
   3  Кнопки
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 48px;
  padding: 0 24px;
  border-radius: var(--r-control);
  font-weight: 700;
  font-size: 15px;
  transition: .22s ease;
  white-space: nowrap;
}
.btn--primary { background: var(--orange); color: var(--white); }
/* Тени у кнопок нет: оранжевое свечение под оранжевой заливкой было лишним
   оранжевым, а наведение и так видно — кнопка темнеет и приподнимается.
   Убрано 16 сентября 2026. */
.btn--primary:hover { background: var(--orange-dark); transform: translateY(-2px); }
.btn--cream { background: var(--cream-sm); color: var(--orange-dark); }
.btn--cream:hover { background: var(--white); transform: translateY(-2px); }
.btn--ghost { border: 2px solid var(--orange); color: var(--orange); }
.btn--ghost:hover { background: var(--orange); color: var(--white); }
/* Серая кнопка — второе действие рядом с оранжевым: «Отмена», «Назад».
   Серый тот же, что у тегов и плашек, своего у кнопок нет. */
.btn--fill { background: var(--fill); color: var(--ink); }
.btn--fill:hover { background: var(--fill-hover); }

/* Необратимое действие — красный из :root, тот же, что у ошибок макета.
   Оранжевая кнопка читалась бы как «продолжить», а действие обратное. */
.btn--danger { background: var(--err); color: var(--white); }
.btn--danger:hover { transform: translateY(-2px); }

/* Крупная кнопка: чуть больше кегль и радиус, но не парадная */
.btn--lg { height: 56px; padding: 0 32px; font-size: 17px; border-radius: 12px; }
.btn--block { width: 100%; }

/* Вторичная кнопка в hero: фотография слева светлая, поэтому контур тёмный */
.btn--hero-ghost {
  background: transparent;
  border: 2px solid rgba(7, 7, 7, .28);
  color: var(--ink);
}
.btn--hero-ghost:hover {
  background: rgba(7, 7, 7, .06);
  border-color: var(--ink);
  color: var(--ink);
  transform: translateY(-2px);
}

/* ============================================================
   4  Поля и формы
   ============================================================ */
.form { display: grid; gap: 14px; }
.form__row { display: grid; gap: 14px; grid-template-columns: 1fr 1fr; }

.input, .textarea, .select {
  width: 100%;
  height: 58px;
  border-radius: var(--r-control);
  border: 1px solid var(--line);
  background: var(--white);
  padding: 0 20px;
  font-size: 16px;
  /* Набранное человеком — полужирным: в поле рядом с подсказкой того же веса
     не видно, где его собственный ответ. Подсказка остаётся обычной. */
  font-weight: 600;
  transition: .18s;
  color: var(--ink);
}
.input::placeholder, .textarea::placeholder { font-weight: 400; }
.textarea { height: 110px; padding: 16px 20px; resize: vertical; }

/* В модалке и в заявке поле на подложке: серая заливка вместо белой, и
   рамки нет — границу поля рисует сама заливка. Так в образце заказчицы от
   28 августа 2026: пять полей подряд, обведённых по контуру, превращали
   форму в решётку.
   Должно стоять ДО :focus — у правил одинаковая специфичность,
   и фокус обязан перебивать спокойное состояние. */
.modal .input, .modal .textarea, .modal .select,
.rq .input, .rq .textarea, .rq .select, .rq .dd__btn {
  border-color: var(--field);
  background: var(--field);
}
/* Поле в окне крупнее обычного: полей мало, и они — всё, что в окне есть */
.modal .input, .modal .select { height: 54px; }

/* Одинарная обводка: border без второго кольца box-shadow */
.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--orange);
  box-shadow: none;
}
.input.is-error { border-color: var(--err); box-shadow: none; }
/* Поле, которое видно, но не правится, — номер входа в профиле. Без
   отличия оно выглядит сломанным: щёлкаешь, а набрать нельзя. */
.input[readonly] { background: var(--fill-lg); color: var(--gray); }
.input[readonly]:focus { border-color: var(--line); }
/* Оба состояния стоят после :focus намеренно: пока человек печатает, поле
   в фокусе, и оранжевая рамка фокуса иначе съела бы и ошибку, и подтверждение. */

/* Системный select заменён своей стрелкой */
select.input, .select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23f05d20' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  padding-right: 44px;
  cursor: pointer;
}

.form__note { font-size: 12.5px; opacity: .85; display: flex; gap: 9px; align-items: flex-start; margin-bottom: 14px; }
.form__note a { text-decoration: underline; }
.form__note input { margin-top: 3px; accent-color: var(--orange); width: 16px; height: 16px; }
/* Рассылка — единственная галочка формы, и выбор в ней настоящий. Но
   спрашивают её заодно, а не ради неё: серым и мельче полей */
.form__note--quiet { color: var(--gray); margin-bottom: 4px; }
/* Последней строкой формы, под кнопкой и согласием, и набрана так же, как
   согласие: тот же кегль, цвет и выключка по центру. Две служебные строки
   подряд, набранные по-разному, и давали то самое «всё гуляет» */
.form__submit .form__note--quiet {
  justify-content: center; align-items: center; text-align: center;
  margin: 10px 0 0; opacity: 1;
  font-size: 12px; line-height: 1.45; color: var(--gray-light);
}
.form__submit .form__note--quiet input { width: 14px; height: 14px; margin-top: 0; }
.form__submit .form__note--quiet a { color: var(--gray); }

/* Согласие на обработку данных — предупреждение под кнопкой, а не поле.
   Галочкой оно стояло вровень с телефоном и почтой, хотя выбора не
   предлагало: без согласия заявку принять нельзя. См. consentHtml в app.js */
.form__consent {
  margin-top: 12px;
  font-size: 12px; line-height: 1.45; color: var(--gray-light); text-align: center;
}
.form__consent a { color: var(--gray); text-decoration: underline; }

/* Подвал формы: кнопка, согласие, рассылка.

   Галочка рассылки стояла в четырёх пикселях от оранжевой кнопки и читалась
   её подписью — «разлепи текст с кнопкой», 26 августа 2026. 27 августа она
   ушла под кнопку совсем: пришли сюда ради заявки, а рассылка — то, о чём
   спрашивают заодно. Три строки разного назначения (действие, предупреждение,
   выбор) собраны в одну группу, отбитую от полей. */
.form__submit { margin-top: 24px; }
/* В `.form` строки и так разведены сеткой — там отбивке хватает половины */
.form > .form__submit { margin-top: 8px; }

/* Свой выпадающий список: системный select не поддаётся стилизации списка */
.dd { position: relative; }
.dd__btn {
  width: 100%; height: 52px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--white);
  font-size: 15px; text-align: left;
  transition: .16s;
}
.dd__btn:hover { border-color: var(--line-strong); }
.dd.is-open .dd__btn { border-color: var(--orange); }
.dd__btn .chev { color: var(--orange); transition: transform .2s; flex-shrink: 0; }
.dd.is-open .chev { transform: rotate(180deg); }
.dd__val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ничего не выбрано — в поле подсказка, а не первый вариант (C61) */
.dd__val.is-empty { font-weight: 400; color: var(--gray); }

.dd__list {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 40;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .14);
  padding: 6px;
  max-height: 300px; overflow-y: auto;
}
/* Снизу места нет — список раскрывается вверх (`placeDropdownList`) */
.dd--up .dd__list { top: auto; bottom: calc(100% + 6px); }
.dd__opt {
  display: block; width: 100%; text-align: left;
  padding: 11px 14px; border-radius: 8px;
  font-size: 14.5px; transition: .12s;
}
.dd__opt:hover { background: var(--fill); }
.dd__opt.is-active { background: var(--cream-sm); color: var(--orange-dark); font-weight: 600; }

/* Заголовок группы внутри списка: не кнопка, нажимать нечего */
.dd__head {
  padding: 10px 14px 4px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--gray-light);
}
.dd__head:first-child { padding-top: 4px; }

/* ============================================================
   5  Шапка
   ============================================================ */
.topline {
  background: var(--white);
  border-bottom: 1px solid var(--line);
  text-align: center;
  font-size: 13px;
  color: var(--gray);
  /* Боковые поля — как у контейнера на телефоне: в два порога строка на
     узком экране переносится и без них липнет к краям. */
  padding: 9px 24px;
}
/* Короткая строка — только на телефоне, см. адаптив */
.topline__short { display: none; }

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 90;
  background: var(--white);
  transition: box-shadow .25s;
}
.header.is-stuck { box-shadow: 0 4px 24px rgba(0, 0, 0, .08); }
.header.is-stuck .topline { display: none; }

.header__inner {
  display: grid;
  grid-template-columns: 112px 1fr auto;
  gap: 18px;
  align-items: center;
  padding: 12px 0;
}

/* Логотип */
/* Логотип не сжимается: соседи в шапке тянули его ширину, а общее правило
   `img { max-width: 100% }` позволяло картинке уступить — и знак
   сплющивался по горизонтали, а после входа в кабинет пропадал совсем
   (16 сентября 2026). Теперь он меняет только высоту, по ширине экрана,
   и пропорции у него всегда свои. */
.logo { display: inline-flex; align-items: center; flex: none; }
/* В файле есть прозрачные поля по 2,5% — высота задана с их учётом,
   чтобы буквы вышли того же роста, что и раньше */
.logo__img { display: block; flex: none; height: 74px; width: auto; max-width: none; }

/* Меню */
.nav { display: flex; align-items: center; gap: 14px; }
.nav__item { position: relative; }
.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 700;
  font-size: 16px;
  padding: 8px 0;
  transition: color .2s;
}
.nav__link:hover, .nav__item.is-open .nav__link { color: var(--orange); }
.nav__link .chev { transition: transform .25s; color: var(--orange); }
.nav__item.is-open .chev { transform: rotate(180deg); }

/* Правая группа: телефон, корзина, кабинет, кнопка. Отделена линией от меню */
.header__actions {
  display: flex;
  align-items: center;
  gap: 10px;
  position: relative;
  padding-left: 12px;
}
.header__actions::before {
  content: '';
  position: absolute;
  left: 0; top: 50%;
  transform: translateY(-50%);
  width: 1px; height: 30px;
  background: var(--line);
}
.header__actions .btn { white-space: nowrap; }

/* На страницах с собственным hero-CTA кнопка в шапке появляется только при
   скролле — иначе две одинаковые кнопки спорят на первом экране.

   Раньше она пряталась через visibility и держала за собой ширину: на первом
   экране в шапке зияла дыра, и заказчик спросила, что это. Теперь место не
   резервируется. Соседи при появлении сдвигаются, но шапка в этот момент и
   так перестраивается — вместе с кнопкой прячется верхняя строка. */
.has-hero .header:not(.is-stuck) .header__cta { display: none; }
/* На главной кнопки в шапке нет вовсе (27 августа 2026). Первый экран сам
   перечисляет семь действий, включая «Посмотреть всю продукцию», куда эта
   кнопка и вела; общее «Начать заказ» рядом с ними ничего не добавляло.
   Возвращается снятием класса с тела `index.html`. */
.no-header-cta .header__cta { display: none; }

/* Плитки в правой группе шапки: лупа, корзина, кабинет, бургер, а на узком
   экране ещё и контакты.

   Все одинаково серые в покое и светло-оранжевые под курсором. Раньше цвет
   ничего не кодировал: лупа была серой, телефон и корзина — кремовыми, и это
   читалось как «две кнопки главнее третьей», хотя старшинства между ними нет.
   Исключения два, и оба про состояние, а не про кнопку: счётчик на корзине и
   плитка кабинета после входа — они оранжевые всегда. */
.header__search,
.header__cart,
.header__user,
.burger {
  width: 42px; height: 42px;
  border-radius: 12px;
  background: var(--fill);
  color: var(--ink);
  align-items: center; justify-content: center;
  transition: .18s;
}
.header__search,
.header__user { display: flex; }
.header__search:hover,
.header__cart:hover,
.header__user:hover,
.burger:hover { background: var(--cream-sm); color: var(--orange-dark); }

/* Кабинет — только значок, подписи нет ни на какой ширине. Вошёл человек
   или нет, говорит заливка: серая — «Войти», оранжевая — «Личный кабинет».
   Разбор — у `accountHtml` в app.js. */
.header__user.is-authed { background: var(--orange); color: var(--white); }
.header__user.is-authed:hover { background: var(--orange-dark); color: var(--white); }

/* Размер, цвет и ховер — общие с остальными плитками шапки, см. выше */
.header__cart { position: relative; display: flex; }
.header__cart span {
  position: absolute; top: -3px; right: -3px;
  min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: var(--r-pill); background: var(--orange); color: var(--white);
  font-size: 11px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.header__cart:hover span { background: var(--orange-dark); }
/* Позиция легла в корзину — счётчик коротко подпрыгивает, иначе непонятно,
   добавилось ли вообще: со страницы мы больше никуда не уводим */
.header__cart.is-bumped { background: var(--orange); color: var(--white); }
.header__cart.is-bumped span { animation: cart-bump .45s ease 2; }
@keyframes cart-bump {
  0%, 100% { transform: scale(1); }
  40% { transform: scale(1.35); }
}

/* Мегаменю */
.megamenu {
  position: absolute;
  top: calc(100% + 14px);
  left: -24px;
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .14);
  padding: 28px;
  min-width: 940px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: .24s ease;
  z-index: 95;
}
.nav__item.is-open .megamenu { opacity: 1; visibility: visible; transform: translateY(0); }
.megamenu--right { left: auto; right: -24px; min-width: 320px; }

.megamenu__grid { display: grid; grid-template-columns: 260px 1fr; gap: 24px; }
.megamenu__aside { border-right: 1px solid var(--line); padding-right: 20px; }
.megamenu__cat {
  display: block;
  padding: 11px 14px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 15px;
  cursor: pointer;
  transition: .18s;
}
.megamenu__cat:hover, .megamenu__cat.is-active { background: var(--cream-sm); color: var(--orange-dark); }
.megamenu__panel { display: none; }
.megamenu__panel.is-active { display: block; }
.megamenu__title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--gray-light);
  margin-bottom: 14px;
}
.megamenu__list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px 18px;
  max-height: 430px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Подзаголовок внутри списка позиций: занимает всю ширину сетки, поэтому
   кучка под ним начинается с новой строки и читается как кучка */
.megamenu__head {
  grid-column: 1 / -1;
  font-size: 11.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--gray-light);
  padding: 12px 10px 2px;
}
.megamenu__head:first-child { padding-top: 0; }
.megamenu__list a {
  display: block;
  font-size: 14.5px;
  padding: 6px 8px;
  border-radius: 8px;
  transition: .16s;
}
.megamenu__list a:hover { background: var(--cream-sm); color: var(--orange-dark); }
.megamenu__all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  font-weight: 700;
  color: var(--orange);
  font-size: 15px;
}
/* Раздел «Информация» целиком: тринадцать страниц в один столбец — это
   простыня до низа экрана, поэтому две колонки. Порядок читается сверху
   вниз и дальше во второй столбец — как в боковой колонке самого раздела.
   Раскрывается вправо от пункта, как остальные меню: 540 px помещаются
   до правого края и на 1280.

   Колонки — сетка из двух готовых столбцов, а не `columns: 2`: разрез
   считает menuCols в app.js, и считает его по смыслу — слева перечень,
   справа подпись группы и то, что под ней. Колонки от этого разной длины,
   `align-items: start` держит обе прижатыми к верху. */
.megamenu--simple {
  min-width: 540px; padding: 18px; border-radius: var(--radius-lg);
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 8px; align-items: start;
}
/* Кнопка здесь наравне со ссылкой: «Заказать дизайн макета» открывает заявку
   менеджеру, а не страницу, но в списке должна выглядеть такой же строкой */
.megamenu--simple a, .megamenu--simple button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 500;
  transition: .16s;
}
.megamenu--simple a:hover, .megamenu--simple button:hover { background: var(--cream-sm); color: var(--orange-dark); }
/* Меню «Каталог»: три раздела, работы и два решения — шесть строк, которые
   в две колонки читались бы как обрывок таблицы */
.megamenu--one { min-width: 280px; grid-template-columns: 1fr; }
/* Подпись группы внутри простого меню: страницы про деньги стоят отдельно
   от справочных, но заводить ради них второе меню незачем */
.megamenu__label {
  padding: 14px 14px 6px;
  font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--gray-light);
}
/* С подписи начинается правая колонка, и её первая строка должна встать
   вровень с первой ссылкой слева. Отступ меньше обычного, но не равен
   отступу ссылки: строка подписи ниже, и 12px совмещают их середины. */
.megamenu__col > .megamenu__label:first-child { padding-top: 12px; }

/* Телефон со статусом и поповер контактов */
.hcontacts { position: relative; }
.hcontacts__btn {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 10px 5px 4px; border-radius: 12px;
  transition: background .18s;
}
.hcontacts__btn:hover { background: var(--fill); }
.hcontacts__btn .chev { color: var(--gray-light); transition: transform .25s; }
.hcontacts.is-open .chev { transform: rotate(180deg); color: var(--orange); }

/* Иконка вместо номера — включается, когда шапке становится тесно */
.hcontacts__ic { display: none; align-items: center; justify-content: center; }
.hcontacts__main { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.hcontacts__main b { font-size: 16px; font-weight: 700; white-space: nowrap; }
.hcontacts__status {
  font-style: normal; font-size: 12px; color: var(--gray);
  display: flex; align-items: center; gap: 6px; white-space: nowrap;
}
.hcontacts__status::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--gray-light);
}
.hcontacts__status.is-open { color: var(--ok); }
.hcontacts__status.is-open::before { background: var(--ok); }

.hpop {
  position: absolute; top: calc(100% + 12px); right: 0;
  width: 360px; padding: 24px;
  background: var(--white); border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .16);
  opacity: 0; visibility: hidden; transform: translateY(10px);
  transition: .22s ease; z-index: 95;
}
.hcontacts.is-open .hpop { opacity: 1; visibility: visible; transform: translateY(0); }

.hpop__phone { display: block; font-size: 24px; font-weight: 800; letter-spacing: -.02em; }
.hpop__phone:hover { color: var(--orange); }
.hpop__tg { height: 46px; font-size: 15px; margin-top: 12px; }
.hpop__call { height: 44px; font-size: 14.5px; margin-top: 8px; }
.hpop__status { font-size: 13px; color: var(--gray); display: flex; align-items: center; gap: 7px; margin-top: 4px; }
.hpop__status::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--gray-light); }
.hpop__status.is-open { color: var(--ok); }
.hpop__status.is-open::before { background: var(--ok); }

.hpop__title {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--gray-light); margin: 22px 0 10px;
}
.hpop__row { display: flex; align-items: center; gap: 10px; font-size: 14.5px; }
.hpop__row i { color: var(--orange); display: flex; }
.hpop__row:hover { color: var(--orange); }

/* Соцсети значками, как в подвале, только на светлом */
.hpop__soc { display: flex; gap: 8px; margin: 10px 0 16px; }
.hpop__soc a, .hpop__soc__soon {
  width: 40px; height: 40px; border-radius: var(--r-control);
  background: var(--fill); display: flex; align-items: center; justify-content: center; transition: .16s;
}
.hpop__soc a:hover, .hpop__soc__soon:hover { background: var(--cream-sm); color: var(--orange-dark); }
/* Max стоит финальным значком (глиф из вопроса пользователя, не заглушка),
   но остаётся не-ссылкой, пока нет адреса — курсор оставлен обычным, это
   единственная разница с рабочими Telegram и VK рядом. */
.hpop__soc__soon { cursor: default; }

/* Адрес — ссылка на Яндекс.Карты, поэтому ховер: он должен читаться кликабельным */
.hpop__addr { display: flex; gap: 10px; margin-bottom: 14px; border-radius: 10px; transition: .16s; }
.hpop__addr:hover b { color: var(--orange); }
.hpop__addr i { color: var(--orange); display: flex; margin-top: 2px; flex-shrink: 0; }
.hpop__addr b { display: block; font-size: 14px; font-weight: 700; }
.hpop__addr span { display: block; font-size: 12.5px; color: var(--gray); margin-top: 2px; }

.hpop__foot {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  border-top: 1px solid var(--line); margin-top: 18px; padding-top: 16px;
  font-size: 13px; color: var(--gray);
}
.hpop__foot a { color: var(--orange); font-weight: 700; display: inline-flex; align-items: center; gap: 6px; }

/* Бургер. Размер и цвет заданы вместе с остальными плитками шапки выше;
   здесь только то, чем он отличается: до своей ширины он скрыт. */
.burger { display: none; }
/* Полоски бургера красятся currentColor — цвет приходит от плитки и вместе
   с ней меняется на ховере */
.burger span { display: block; width: 20px; height: 2px; background: currentColor; position: relative; }
.burger span::before, .burger span::after { content: ''; position: absolute; left: 0; width: 20px; height: 2px; background: currentColor; }
.burger span::before { top: -6px; }
.burger span::after { top: 6px; }

/* ============================================================
   6  Мобильное меню
   ============================================================ */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: var(--white);
  border-radius: var(--radius-lg);
  transform: translateX(100%);
  transition: transform .3s ease;
  overflow-y: auto;
  padding: 20px 20px 60px;
}
.mobile-menu.is-open { transform: translateX(0); }
.mobile-menu__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
.mobile-menu__close { font-size: 32px; line-height: 1; color: var(--orange); }
.mobile-menu__search {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 14px 16px; margin-bottom: 10px;
  border-radius: var(--r-control);
  background: var(--fill);
  color: var(--gray);
  font-size: 15.5px; font-weight: 600;
}
.mobile-menu__search svg { color: var(--orange); }
.macc__head {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%; padding: 16px 0; font-weight: 700; font-size: 18px;
  border-bottom: 1px solid var(--line);
}
.macc__head .chev { color: var(--orange); transition: transform .2s; }
.macc.is-open .macc__head .chev { transform: rotate(180deg); }
.macc__body { display: none; padding: 8px 0 14px; }
.macc.is-open .macc__body { display: block; }
.macc__body a, .macc__sub a, .macc__body button {
  display: block; width: 100%; text-align: left;
  padding: 9px 12px; font-size: 15px; border-radius: 8px;
}
/* Подзаголовки те же, что в большом меню, но колонок в мобильном списке нет —
   хватает отступа сверху */
.macc__sub .megamenu__head { display: block; padding: 14px 12px 2px; }
.macc__body a:hover, .macc__body button:hover { background: var(--cream-sm); color: var(--orange-dark); }
.macc__group { font-weight: 700; padding: 12px 12px 4px; font-size: 15px; color: var(--orange); }

/* ============================================================
   6-bis  Поиск
   ============================================================
   Панель падает сверху, а не открывается модалкой по центру: поиск —
   продолжение шапки, из которой его позвали. Поле остаётся на месте,
   результаты растут под ним и скроллятся сами, не утягивая страницу. */
.search { position: fixed; inset: 0; z-index: 130; display: none; }
.search.is-open { display: block; }
.search__overlay { position: absolute; inset: 0; background: rgba(7, 7, 7, .45); }
.search__box {
  position: relative;
  max-width: 720px;
  margin: 12vh auto 0;
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: 0 30px 80px rgba(7, 7, 7, .30);
  overflow: hidden;
}
.search__field {
  display: flex; align-items: center; gap: 12px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
}
.search__field > svg { color: var(--orange); flex: none; }
.search__input {
  flex: 1;
  border: none; outline: none; background: none;
  font-family: var(--font); font-size: 18px; color: var(--ink);
}
.search__input::placeholder { color: var(--gray-light); }
.search__close { font-size: 28px; line-height: 1; color: var(--gray-light); flex: none; }
.search__close:hover { color: var(--orange); }

.search__results { max-height: 60vh; overflow-y: auto; padding: 10px 0 14px; }
.search__group + .search__group { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 8px; }
.search__group-title {
  font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--gray-light); padding: 10px 22px 6px;
}
.search__row {
  display: flex; align-items: baseline; gap: 12px;
  width: 100%; padding: 11px 22px; text-align: left;
  transition: background .15s;
}
.search__row:hover { background: var(--cream-sm); }
.search__row-title { font-weight: 600; font-size: 15.5px; }
.search__row:hover .search__row-title { color: var(--orange); }
.search__row-note { font-size: 13px; color: var(--gray-light); margin-left: auto; white-space: nowrap; }

.search__hint { padding: 14px 22px 4px; font-size: 14px; color: var(--gray); }
.search__chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 6px 22px 10px; }
.search__chip {
  padding: 8px 14px;
  border-radius: var(--r-pill);
  background: var(--fill);
  font-size: 14px; font-weight: 600; color: var(--gray);
  transition: .18s;
}
.search__chip:hover { background: var(--cream-sm); color: var(--orange-dark); }

.search__empty { padding: 26px 22px 18px; text-align: center; }
.search__empty p { color: var(--gray); font-size: 15px; margin: 8px 0 18px; }

/* ============================================================
   7  Hero
   Фотография прижата вправо, левая часть высветлена скримом —
   поэтому текст тёмный, а вторичная кнопка с тёмным контуром.
   ============================================================ */
.hero {
  position: relative;
  min-height: 620px;
  display: flex;
  align-items: center;
  background: #f2f2f2;
  overflow: hidden;
  color: var(--ink);
  padding: 70px 0;
}
.hero__photo {
  position: absolute; inset: 0;
  background: url('../img/hero8.jpg') center right / cover no-repeat;
}
/* Скрим отодвинут вправо 27 августа 2026 вместе с подзаголовком: тот стал
   шире середины экрана, а на прежней растяжке его хвост уходил на снимок,
   где серый текст по фотографии уже не читается. Правая четверть кадра
   осталась открытой — снимок всё ещё виден. */
.hero__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(100deg,
    rgba(244, 244, 244, .97) 0%,
    rgba(244, 244, 244, .94) 42%,
    rgba(244, 244, 244, .62) 60%,
    rgba(244, 244, 244, 0) 76%);
}

/* Один доминантный уровень: заголовок против подзаголовка втрое.

   Колонка расширена с 660 до 760 px 27 августа 2026 — ради подзаголовка,
   он единственный из троих просит эту ширину. Метки прижаты обратно к 660:
   ряд по две читается быстрее, чем по три, а заголовок стоит в две строки
   принудительно и от ширины колонки не зависит.

   Ширину держим на 760: подзаголовок разбит на три строки вручную, и самая
   длинная из них на 19 px просит 582 px. Если строки в нём снова станут
   длиннее, ломаться они будут не по своим переносам, а по краю колонки —
   тогда либо править разбивку, либо расширять колонку вместе со скримом. */
.hero__inner { position: relative; z-index: 2; max-width: 760px; }
.hero h1 {
  font-size: clamp(38px, 4.6vw, 64px);
  line-height: 1;
  letter-spacing: -.035em;
  margin-bottom: 22px;
  color: var(--ink);
}
/* Вторая строка того же заголовка. Не подзаголовок: цвет и насыщенность те
   же, что у первой строки, разделяет их только кегль — примерно вдвое
   меньше. Так «Печать и мерч от производителя» читается одной фразой, но
   ударение остаётся на первой строке.

   Насыщенность 700 против 800 у h1 — на глаз одно и то же начертание, но
   мелкий кегль при 800 выглядит жирнее крупного и перетягивает внимание. */
.hero h1 .hero__from {
  display: block;
  font-size: clamp(21px, 2.3vw, 32px);
  font-weight: 700;
  letter-spacing: -.025em;
  margin-top: 10px;
}
.hero__sub {
  font-size: clamp(16px, 1.35vw, 19px);
  font-weight: 500;
  line-height: 1.5;
  color: var(--gray);
  /* Шире прежних 430 px: с 27 августа 2026 подзаголовок держит и число, и
     обещание, и границу «онлайн / менеджер» — в узкую колонку это ложилось
     башней строк. Заканчивается он теперь за серединой экрана, поэтому
     сдвинут и скрим выше; вместе они и держат текст на светлом.

     Ширину задаёт колонка `.hero__inner`, своего ограничения тут нет.

     Отбивка снизу больше, чем сверху (46 против 22): заголовок с текстом —
     одна мысль, метки под ними — другая. Ступенька и делит их. */
  margin-bottom: 46px;
}
/* Середина фразы — обещание, ради которого сюда приходят. Чёрным и жирным,
   остальное серым: это не «важный кусок текста», а единственное, что должно
   прочитаться, если человек читать не собирался. */
.hero__sub b { font-weight: 700; color: var(--ink); }
.hero__actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* Метки действий — главное, что есть в первом экране с 27 августа 2026:
   кнопка «Начать заказ» отсюда убрана, она осталась в шапке.

   Подписи над метками нет: «Можно сразу:» объясняло очевидное, а стопке из
   четырёх рядов добавляло пятый.

   Метка действия и название продукции — разный язык: действие набрано
   плотно, по белому, со значком; название продукции (строка ассортимента
   ниже, сейчас спрятана) — полупрозрачное и без значка. Иначе «Повторить
   заказ» читалось бы как ещё один вид продукции. */
.hero__ways {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: 660px;
}
/* Распорка во всю ширину ряда: следующая метка уходит на новую строку.
   Строки тут смысловые — что есть, комплексный заказ, постоянному клиенту,
   работа с макетом, — и отдавать их на волю переносов нельзя.

   Отрицательное поле гасит лишний просвет: распорка — это ещё одна строка
   сетки, и промежуток между рядами без неё считался бы дважды. */
.hero__ways-br { flex-basis: 100%; height: 0; margin-top: -6px; }
.hero__way {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--white);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 10px 18px;
  border-radius: var(--r-pill);
  font-weight: 700;
  font-size: 14px;
  transition: .18s;
}
.hero__way svg { width: 16px; height: 16px; color: var(--orange); }
.hero__way:hover { border-color: var(--orange); color: var(--orange); }

/* Ассортимент редактора: спокойные метки, не кнопки */
.popular {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-top: 28px;
}
.popular b { font-size: 13px; font-weight: 600; color: var(--gray); letter-spacing: .01em; }
.popular__list { display: flex; flex-wrap: wrap; gap: 10px; }
.popular a {
  background: rgba(255, 255, 255, .55);
  border: 1px solid rgba(7, 7, 7, .18);
  color: #2b2b2b;
  padding: 7px 16px;
  border-radius: var(--r-pill);
  font-weight: 500;
  font-size: 13.5px;
  transition: .18s;
}
.popular a:hover { background: var(--white); border-color: var(--orange); color: var(--orange); }

/* ============================================================
   8  Портфолио и плейсхолдеры
   ============================================================ */
.chip {
  padding: 11px 22px;
  border-radius: var(--r-pill);
  background: var(--fill);
  font-size: 15px;
  font-weight: 600;
  transition: .18s;
}
.chip:hover { background: var(--fill-hover); }
.chip.is-active { background: var(--cream-sm); color: var(--orange-dark); }

.portfolio__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
/* F23, 2 сентября 2026. Карточка была шире, чем выше (4 / 3,4), а затемнение
   начиналось с 62% высоты — подпись в три строки съедала почти половину
   кадра: у «Интервидения» она ложилась ровно на кейсы и пакеты, у ИЭЗ — на
   термостакан. Работа — то, ради чего сюда пришли, и закрывать её подписью
   нельзя.

   Три поправки сразу, поодиночке ни одна не решает:
   1) кадр стал вертикальным — витрина работ не должна выглядеть строкой
      прайса, а вертикаль читается премиальнее сетки товаров;
   2) подпись сократилась до одной строки — это правка `note` в `PORTFOLIO`
      (`content.js`), вёрстка лишь перестала рассчитывать на три;
   3) вместо ровной шторки на полкадра — плотная плашка внизу, которая
      быстро уходит вверх на нет.

   `backdrop-filter` не берём: настоящее матовое стекло на сетке из двенадцати
   снимков заметно грузит страницу и по-разному ведёт себя в браузерах, а
   выигрыш виден только рядом. Если захочется сравнить — это правка одного
   правила ниже. */
.work {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 4 / 4.8;
  cursor: pointer;
  transition: .25s;
}
.work:hover { transform: translateY(-6px); box-shadow: var(--shadow-hover); }
.work__img { position: absolute; inset: 0; }
.work__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Плашка живёт в нижней трети и не трогает остальной кадр. Плотная у самого
   низа, где лежат буквы, дальше растворяется: на светлом снимке белый текст
   всё равно читается, на тёмном плашки почти не видно. */
.work__img::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 38%;
  background: linear-gradient(to top,
              rgba(0, 0, 0, .80) 0%, rgba(0, 0, 0, .74) 34%,
              rgba(0, 0, 0, .32) 68%, rgba(0, 0, 0, 0) 100%);
}
.work__body { position: absolute; left: 0; right: 0; bottom: 0; padding: 22px; color: var(--white); z-index: 2; }
.work__title { font-size: 17px; font-weight: 700; line-height: 1.25; }
/* Строка под названием: что именно сделали. Одна строка по замыслу, но
   заголовок работы бывает длинным и переносится — поэтому не жёсткая высота,
   а ограничение в две строки: третья уже лезет на изделие. */
.work__note {
  font-size: 13.5px; line-height: 1.35; margin-top: 6px;
  color: rgba(255, 255, 255, .82);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Плейсхолдеры изображений: phTone() в app.js раздаёт ph--1…ph--8 по кругу */
.ph { position: absolute; inset: 0; background-size: cover; background-position: center; }
.ph--1 { background: linear-gradient(135deg, #f0641f, #ffb27a); }
.ph--2 { background: linear-gradient(135deg, #2b2b2b, #6d6d6d); }
.ph--3 { background: linear-gradient(135deg, #ffd6bd, #f4a06a); }
.ph--4 { background: linear-gradient(135deg, #3d4a5c, #8fa2b8); }
.ph--5 { background: linear-gradient(135deg, #e0530f, #ff9747); }
.ph--6 { background: linear-gradient(135deg, #4a3b32, #a08d7e); }
.ph--7 { background: linear-gradient(135deg, #ffe8d8, #ffab77); }
.ph--8 { background: linear-gradient(135deg, #1f2933, #55636f); }
.ph::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, .09) 0 14px, transparent 14px 28px);
}

/* ============================================================
   9  Преимущества
   ============================================================ */
.adv { padding: 80px 0; border-bottom: 1px solid var(--line); }
.adv:last-child { border-bottom: none; }
/* Шапка блока намеренно тише остальных на странице. 20 августа 2026 цифры
   под ней выросли до 64 пунктов, и заголовок в 42 спорил с ними: тот же
   чёрный, то же начертание 800, разница только в кегле — глаз не понимал,
   что здесь главное. Теперь главное — числа, а заголовок их представляет:
   кегль вдвое меньше, вес 700.

   Надзаголовок «Печатаем и брендируем с 2014 года» убран в тот же день:
   над крупными числами он был третьей строкой подряд и задерживал взгляд
   перед ними. Та же фраза осталась причиной в списке ниже. */
.adv__head { text-align: center; margin-bottom: 30px; }
.adv__title { font-size: clamp(22px, 2.2vw, 30px); font-weight: 700; }
/* Причины — списком, а не карточками: 17 августа 2026 карточки отсюда убрали,
   до этого места на главной уже идут две сетки (решения и каталог), и третья
   читалась как продолжение каталога. Доверие держит полоса цифр над списком,
   `.stat-row` — общая со страницей «О компании». */
.reasons {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 2px 44px;
  margin-top: 38px;
}
.reason {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 22px 0;
  border-top: 1px solid var(--line);
}
.reason__ic {
  flex: none;
  width: 42px; height: 42px;
  border-radius: 12px;
  background: var(--cream);
  color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
.reason__ic svg { width: 22px; height: 22px; }
.reason b { display: block; font-size: 17px; margin-bottom: 6px; }
.reason p { color: var(--gray); font-size: 15px; line-height: 1.5; }

/* ============================================================
   9-bis  Решения для бизнеса
   ============================================================
   Карточка задачи на главной, до каталога. Внешне это `.cat-card`
   с иконкой: то же белое полотно, та же рамка и тот же ховер — блоки
   стоят подряд и не должны выглядеть из разных наборов. Отличие
   одно: здесь кнопка, а не ссылка, поэтому текст выравниваем сами. */
/* Четыре карточки в ряд, как в каталоге ниже: с 27 августа 2026 их четыре,
   а не шесть, и ряд из трёх оставлял бы четвёртую сиротой на второй строке. */
.solutions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
/* Полоса персональных условий — хвост раздела. Отступ шире, чем шаг сетки:
   это не пятая карточка, а реплика после них. */
.solutions + .cta-band { margin-top: 30px; }
.solution {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: left;
  transition: .22s;
}
.solution:hover { border-color: var(--orange); transform: translateY(-5px); box-shadow: var(--shadow-hover); }
.solution__icon {
  width: 52px; height: 52px;
  border-radius: 12px;
  background: var(--cream);
  color: var(--orange);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 6px;
}
.solution__icon svg { width: 26px; height: 26px; }

/* Карточка со снимком комплекта. Иконку заменил снимок: шесть одинаковых
   оранжевых значков ничего не обещали, а собранный комплект показывает, что
   человек получит. Кадр в край и пропорция 5:4 — как у `.cat-card` в
   каталоге ниже: блоки стоят подряд и должны читаться одним набором. */
.solution--photo { padding: 0; gap: 0; overflow: hidden; }
.solution__body { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 14px 18px 18px; }
.solution__photo {
  aspect-ratio: 5 / 4;
  overflow: hidden;
  display: block;
}
.solution__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.solution__title { font-size: 19px; font-weight: 700; line-height: 1.3; }
.solution__text { font-size: 14.5px; color: var(--gray); line-height: 1.5; flex: 1; }
.solution__link { font-weight: 700; color: var(--orange); font-size: 14.5px; display: inline-flex; gap: 6px; align-items: center; }

/* ============================================================
   9-tri  С чего начать: входы в сценарии
   ============================================================
   Четыре карточки-ссылки сразу под первым экраном. Внешне — та же
   `.cat-card`: белое полотно, волосяная рамка, тот же ховер. Отличие
   одно и намеренное: здесь наверху значок и метка пути, а не снимок.
   Снимка у сценария быть не может — показывать нечего, показывается
   действие.

   Первая карточка серая — так же, как «Весь раздел» в каталоге ниже:
   серая карточка в сетке значит «эта не такая, как остальные». Сплошным
   оранжевым отметить короткий путь нельзя — это цвет действия, а ссылок в
   блоке четыре и все равноправны.

   Кремовой она была до 2 сентября 2026: цвет снят со всех таких карточек
   разом. Заливка `--fill`, а не `--fill-lg`, хотя пятно крупное: половина
   этих карточек стоит на серой полосе раздела (#fafafa), и #f2f2f2 на ней
   не читается вовсе — карточка выглядит дырой в сетке. #eaeae6 виден и на
   белом, и на полосе. Единственное место, где крупное берёт мелкую
   ступень; причина — не размер, а подложка. */
.start-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.start {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: .22s;
}
.start:hover { border-color: var(--orange); transform: translateY(-5px); box-shadow: var(--shadow-hover); }
.start--accent { background: var(--fill); border-color: transparent; }
.start__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.start__ic {
  flex: none;
  width: 46px; height: 46px;
  border-radius: 12px;
  background: var(--fill);
  color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
/* На серой карточке серая плитка значка пропадает — берём белую */
.start--accent .start__ic { background: var(--white); }
.start__ic svg { width: 22px; height: 22px; }
/* Метка пути — крем и оранжевый текст, без рамки. Оранжевый контур здесь
   значил бы кнопку («Обсудить», «Открыть каталог»), а это подпись, нажимать
   её отдельно нельзя. Отдельного правила для выделенной карточки больше нет:
   на кремовой крем пропадал и приходилось брать белый, на серой он виден. */
.start__tag {
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--cream-sm);
  color: var(--orange-dark);
  font-size: 12.5px; font-weight: 700;
  white-space: nowrap;
}
.start h3 { font-size: 19px; }
.start p { font-size: 14.5px; color: var(--gray); line-height: 1.5; flex: 1; }

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

   Сейчас на прототипе не используется: 29 августа 2026 единственная такая
   полоса — «Нет готового макета?» под каталогом — уступила место разделу про
   редактор (пункт F17). Компонент оставлен: следующая реплика между
   разделами соберётся из него, а не заведёт себе новых значений. */
.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px 32px;
}
.cta-band__text { max-width: 780px; }
.cta-band h3 { font-size: 22px; margin-bottom: 8px; }
.cta-band p { color: var(--gray); font-size: 15px; line-height: 1.55; }

/* Врезка «печатаете регулярно». Собрана из значений `.gift-out` — плашки
   «Полный каталог мерча» (раздел 16): та же роль, та же форма, то же место
   в иерархии, поэтому и значения те же, а не свои. Своих здесь два, и оба
   вынужденные — помечены ниже.

   Кнопка контурная по той же причине, что у `.gift-out`: заливку там пробовали
   2 сентября 2026 и в тот же день вернули — на серой плашке оранжевый
   прямоугольник становится самым громким пятном экрана. Здесь он спорил бы с
   «Оформить заказ» и «Повторить заказ», рядом с которыми врезка и стоит. */
.bulk-hint {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 18px 26px;
  background: var(--fill-lg); border-radius: var(--radius);
  padding: 22px 26px; margin-top: 34px;
}
/* Своё: текст занимает остаток строки и переносится сам, кнопка держит
   ширину. У `.gift-out` вместо этого фиксированный `max-width: 620px` —
   ему хватает, он всегда во всю ширину страницы, а врезка стоит и в колонке. */
.bulk-hint > div { flex: 1 1 240px; }
.bulk-hint b { display: block; font-size: 17px; margin-bottom: 6px; }
.bulk-hint p { font-size: 14.5px; color: var(--gray); line-height: 1.55; }
.bulk-hint .btn { flex: none; }

/* Узкий вариант — итоги корзины, как `--sm` у `.gift-out` в выпадашке поиска */
.bulk-hint--sm { padding: 16px 18px; margin-top: 16px; }
.bulk-hint--sm b { font-size: 15px; }
.bulk-hint--sm p { font-size: 13px; }
/* Своё: сводка `.co-side` залита тем же `--fill-lg`, и серая плашка в ней
   пропадает. Внутри сводки врезка белая — единственное место, где так. */
.co-side .bulk-hint { background: var(--white); }

/* ============================================================
   9-quad  От промпта до готового изделия
   ============================================================
   Блок на главной после раздела про редактор: второй путь заказа, где
   макета может не быть совсем. Тексты — `PROMPT` в content.js.

   Форма взята у `.callback` (раздел 12): кремовая карточка в две колонки.
   Своих значений блок не заводит — заливка, радиус и отступы те же, что у
   заявки, а список внутри набран как `.reason` из «Почему заказывают у нас».
   Это не совпадение: и там и там перечисление доводов, и выглядеть они
   должны одинаково.

   Пропорция колонок 1,25 : 1, а не поровну: справа стоит вертикальный кадр
   из ролика, и на равных долях он вырастал выше текста, растягивая карточку
   пустотой. */
.prompt {
  background: var(--fill-lg);
  border-radius: var(--radius-lg);
  padding: 52px;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(360px, .82fr);
  gap: 48px;
  align-items: center;
}
.prompt h2 { margin-bottom: 14px; }
.prompt__lead { max-width: 760px; font-size: 22px; line-height: 1.42; margin-bottom: 0; font-weight: 600; }
.prompt__note { color: var(--gray); font-size: 15.5px; line-height: 1.6; }

/* Список доводов. Маркер — не значок из набора, а номер строки: значков,
   которые честно показывали бы «с чем приходят» и «чем заканчивается», у нас
   нет, а четыре одинаковых оранжевых кружка ничего не добавляют. */
.prompt__list { margin: 24px 0 30px; display: grid; gap: 14px; }
.prompt__list li {
  display: grid;
  gap: 3px;
  padding-left: 18px;
  border-left: 3px solid var(--orange);
}
.prompt__list b { font-size: 17px; }
.prompt__list span { color: var(--gray); font-size: 15px; line-height: 1.55; }
.prompt__actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* Кадр вертикальный, 9:16. Обрезаем до 3:4: на всю высоту ролика карточка
   вытягивалась вдвое выше текста. */
.prompt__shot {
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--ink);
}
.prompt__shot img,
.prompt__shot video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ============================================================
   10  Каталог: табы и карточки
   ============================================================ */
.tabs { display: flex; gap: 12px; margin-bottom: 36px; flex-wrap: wrap; }
/* Таб переключает содержимое на месте — это выбор, а не переход. Поэтому он
   выглядит как выбранный параметр: спокойная плашка, выбранная — кремовая с
   оранжевым текстом, ровно как каналы связи в заявке (`.rq__ch`).

   25 августа 2026 таб успел побывать подчёркнутым, без плашки: я развела его
   с сайдбаром как «раздел». Заказчица поправила — и по делу: сайдбар уводит
   на другую страницу («вы здесь»), а таб меняет панель под собой, никуда не
   уводя. Различает языки не форма элемента, а то, переход это или выбор. */
.tab {
  padding: 15px 34px;
  border-radius: var(--r-control);
  background: var(--fill);
  font-weight: 700;
  font-size: 18px;
  transition: .2s;
}
.tab:hover { background: var(--fill-hover); }
.tab.is-active { background: var(--cream-sm); color: var(--orange-dark); }
.tabpanel { display: none; }
.tabpanel.is-active { display: block; animation: fade .3s ease; }
@keyframes fade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.cat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
/* Сетка на странице раздела: там уже стоит боковая навигация, и в четыре
   колонки карточка получилась бы мельче, чем те же группы на главной.
   Три, а не две: с кадром 5:4 карточка в половину ширины даёт снимок на
   пол-экрана, и шесть групп уезжают в три прокрутки. Ниже 1280 адаптив
   перехватывает — он объявлен позже. */
.cat-grid--wide { grid-template-columns: repeat(3, 1fr); }
/* Карточка группы: снимок ведёт, подпись объясняет. Кадр идёт в край
   карточки, а не плиткой внутри полей: `overflow: hidden` отдаёт ему
   скругление самой карточки. Так собран `.pick` на выборе продукта, и он
   оказался лучше — плитка в полях давала второй контур внутри первого, а в
   узкой колонке кадр ещё и терял 28 px ширины.

   Пропорция 5:4 — общая для всех сеток со снимком (`.item-card`,
   `.solution--photo`, `.pick`). Пропорция, а не фиксированная высота:
   картинка растёт вместе с колонкой. Ближе к квадрату, чем прежние 4:3, —
   съёмки типографии почти все квадратные, и от кадра остаётся 80 % высоты
   вместо 75 %. Шире не берём: у вертикальных сюжетов вроде термоса или
   бутылки срезается горлышко. */
.cat-card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: .22s;
  min-height: 210px;
}
/* Подпись под кадром: поля живут здесь, у карточки их больше нет */
.cat-card__body { flex: 1; display: flex; flex-direction: column; gap: 10px; padding: 14px 16px 18px; }
/* Карточка «весь раздел» без снимка: поля и промежутки — у неё самой */
.cat-card--plain { padding: 24px; gap: 10px; }
.cat-card:hover { border-color: var(--orange); transform: translateY(-5px); box-shadow: var(--shadow-hover); }
.cat-card__img {
  aspect-ratio: 5 / 4;
  position: relative;
  overflow: hidden;
}
.cat-card__img img { width: 100%; height: 100%; object-fit: cover; }
.cat-card h3 { font-size: 18px; }
.cat-card p { font-size: 14px; color: var(--gray); flex: 1; }
.cat-card__link { font-weight: 700; color: var(--orange); font-size: 14.5px; display: inline-flex; gap: 6px; align-items: center; }
/* «Весь раздел» — карточка «эта не такая, как остальные»: серая заливка
   задана в index.html по месту, оранжевый на ней только тёмный (порог 3:1,
   обычный даёт на #eaeae6 те же 2,74, что и на кремовой). */
.cat-card--plain .cat-card__link { color: var(--orange-dark); }

/* ============================================================
   11  Отзывы и клиенты
   ============================================================ */
/* Строка с рейтингом над каруселью. Отзывы настоящие, и ссылка на карточку
   в Яндекс.Картах — единственное, что это доказывает: без неё пять звёзд
   ничем не отличаются от пяти нарисованных. */
.reviews__source { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 26px; }
.reviews__rating { font-size: 38px; font-weight: 800; line-height: 1; }
.reviews__stars { color: var(--orange); letter-spacing: 3px; margin-right: 8px; }
.reviews__source-text { font-size: 14.5px; color: var(--gray); }

.reviews__wrap { position: relative; }

/* Лента режет всё, что вышло за её рамку, а тень карточки — это 30 пикселей
   размытия при сдвиге на 8 вниз. Поэтому поле под тень даём внутри ленты, а
   наружу возвращаем отрицательным полем: карточки стоят на той же вертикали,
   что заголовок, отступ до стрелок прежний, а тень нигде не обрывается.
   Боковое поле равно полю `.container` — лента доходит ровно до края страницы
   и за него не вылезает; на узких экранах поле другое, см. «Адаптив».

   `scroll-padding` обязателен: началом ленты прилипание считает край поля, и
   без поправки карточка после прокрутки встаёт на 40 пикселей левее заголовка. */
.reviews__track {
  display: flex;
  gap: 22px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 40px;
  margin: -24px -40px -26px;
  padding: 24px 40px 38px;
  scrollbar-width: none;

  /* Карточка, которая не поместилась, гаснет к краю, а не рубится ножом.
     Ширину гашения ставит JS классами `has-prev` / `has-next`: только там,
     где есть что прокручивать. Иначе крайние карточки выцветали бы у
     собственного края ленты, где за ними ничего нет. */
  --fade-left: 0px;
  --fade-right: 0px;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-left),
                                      #000 calc(100% - var(--fade-right)), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, #000 var(--fade-left),
                                      #000 calc(100% - var(--fade-right)), transparent 100%);
}
/* 80 пикселей. Невлезающий край карточки на разных ширинах занимает от 40 до
   90 — гашение накрывает его целиком или почти целиком, но не дотягивается до
   текста соседней карточки: у неё поле в 32 пикселя, и в него гашение упирается
   раньше, чем в буквы. */
.reviews__track.has-prev { --fade-left: 80px; }
.reviews__track.has-next { --fade-right: 80px; }
.reviews__track::-webkit-scrollbar { display: none; }
.review {
  flex: 0 0 clamp(280px, 31%, 420px);
  scroll-snap-align: start;
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: 32px;
  box-shadow: var(--shadow);
}
.review__stars { color: var(--orange); font-size: 17px; letter-spacing: 3px; margin-bottom: 14px; }
.review__text { font-size: 15.5px; color: #333; margin-bottom: 22px; }
.review__author { display: flex; align-items: center; gap: 12px; }
.review__ava {
  /* flex: none обязателен: без него кружок сжимается под длинным именем
     («ТРЕЛУЧЬЕ, клуб стрельбы из лука») и из круга становится овалом. */
  flex: none;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--orange); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 18px;
}
.review__name { font-weight: 700; }
.review__role { font-size: 13.5px; color: var(--gray); }

.slider-nav { display: flex; gap: 10px; margin-top: 26px; }
.slider-nav button {
  width: 52px; height: 52px; border-radius: 12px;
  background: var(--white); box-shadow: var(--shadow);
  display: flex; align-items: center; justify-content: center;
  color: var(--orange); transition: .2s;
}
.slider-nav button:hover { background: var(--orange); color: var(--white); }
/* Стрелка, которой некуда вести, гаснет и не нажимается: в ленте изделий
   на главной листать бывает нечего, и живая кнопка без действия читается
   поломкой. У отзывов состояние не наступает — карточек всегда больше экрана. */
.slider-nav button[disabled] { opacity: .35; box-shadow: none; }
.slider-nav button[disabled]:hover { background: var(--white); color: var(--orange); }

/* Лента клиентов шла без подписи — было непонятно, что это вообще за плитки.
   Подпись по центру: над ней теперь центрированная строка цифр. Чёрным и
   в 18 пунктов — серой пометой в 15 она читалась не подписью к ленте, а
   служебной строкой. Вес 700, как у заголовка блока: ниже его по кеглю,
   но того же рода — это подпись, а не второй голос. */
.clients-head { margin: 10px 0 18px; text-align: center; }
.clients-head h3 { font-size: 18px; font-weight: 700; }

/* Бегущая строка. 20 августа 2026 знаки вышли из белых кружков: кружок
   задавал всем общий размер, но в одну строку вставал тяжёлой плиткой и
   съедал высоту. Теперь логотип идёт как есть, а ритм держит шаг ячейки —
   знаки разной формы стоят через равные промежутки и вписываются по своей
   стороне (`contain`), поэтому не обрезаются.

   Края растворяются маской, а не белой полосой поверх: маска не знает про
   фон и переживёт переезд блока в другую секцию. */
.clients {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.clients__track {
  display: flex;
  width: max-content;
  animation: clients-run 75s linear infinite;
}
/* Под курсором лента замирает: знак хочется рассмотреть, а он уезжает */
.clients:hover .clients__track { animation-play-state: paused; }
/* Половина ленты — это ровно один список, дальше идёт его копия. Поэтому
   на -50% первый знак встаёт на своё же место и шва не видно. */
@keyframes clients-run { to { transform: translateX(-50%); } }

.client {
  flex: none;
  width: 200px; height: 96px;
  padding: 0 20px;
  display: flex; align-items: center; justify-content: center;
}
/* Размер знака ставит скрипт: он равняет логотипы по площади, а не по
   высоте — пропорции слишком разные (см. отрисовку ленты в index.html).
   Здесь только запас на случай, если скрипт не отработал: без него
   картинка развернулась бы в свою натуральную величину. */
.client img { max-width: 100%; max-height: 56px; width: auto; object-fit: contain; }
/* Ховера у знака нет намеренно: он никуда не ведёт, подсветка обещала бы клик */

/* ============================================================
   12  Обратный звонок и видео
   ============================================================ */
/* Заливка светлая, а не оранжевая во весь блок. Сплошной оранжевый на такой
   площади читается как одна огромная кнопка: белые поля выглядят дырами в
   ней, серый текст согласия на оранжевом не читается вовсе, а настоящую
   кнопку «Отправить» приходится делать белой — то есть отбирать у действия
   его единственный цвет. Замечание заказчицы 25 августа 2026. */
.callback {
  background: var(--cream);
  border-radius: var(--radius-lg);
  padding: 56px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 50px;
  align-items: center;
}
.callback h2 { margin-bottom: 12px; }
.callback p { color: var(--gray); font-size: 17px; }
.callback .input, .callback .textarea { background: var(--white); }

/* Блок живёт в тексте «О компании» (переехал с главной 17 августа 2026),
   поэтому отступы свои, а не от секции */
.video__frame {
  position: relative;
  margin: 22px 0 30px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 16 / 7.4;
  background: linear-gradient(135deg, #1c1c1c, #4a4a4a);
  display: flex; align-items: center; justify-content: center;
}
.video__frame::before {
  content: '';
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, .05) 0 20px, transparent 20px 40px);
}
.video__play {
  width: 106px; height: 106px;
  border-radius: 50%;
  background: var(--orange);
  color: var(--white);
  display: flex; align-items: center; justify-content: center;
  z-index: 2;
  transition: .25s;
}
.video__play:hover { transform: scale(1.08); }

/* ============================================================
   13  Подвал
   ============================================================ */
.footer { background: var(--ink); color: var(--white); padding: 66px 0 32px; }
.footer a { color: rgba(255, 255, 255, .74); transition: .18s; }
.footer a:hover { color: var(--orange-light); }

.footer__grid { display: grid; grid-template-columns: 1.35fr 1fr 1fr 1fr; gap: 40px; padding-bottom: 44px; border-bottom: 1px solid rgba(255, 255, 255, .12); }
.footer__title { font-size: 15px; font-weight: 700; margin-bottom: 18px; text-transform: uppercase; letter-spacing: .06em; }
/* Второй заголовок в той же колонке: отделяется воздухом, а не линией */
.footer__title--sub { margin-top: 26px; }
/* Заголовок колонки — кнопка, но свёртка есть только на телефоне (см.
   адаптив). Здесь он выглядит и ведёт себя как обычный заголовок. */
.footer__toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left; pointer-events: none;
}
.footer__toggle .chev { display: none; color: rgba(255, 255, 255, .45); transition: transform .25s; }
.footer__list li { margin-bottom: 11px; font-size: 14.5px; }
/* Действия под списком продукции: та же колонка, но это входы в сценарий */
.footer__list--act { margin-top: 16px; padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, .12); }
.footer__about { margin-top: 18px; font-size: 14.5px; color: rgba(255, 255, 255, .7); max-width: 300px; }
.footer__contact { font-size: 26px; font-weight: 800; margin: 22px 0 16px; display: inline-block; }
/* Всё про связь одним списком: значок слева, содержимое строкой справа */
.footer__contacts li { display: flex; gap: 10px; font-size: 14.5px; color: rgba(255, 255, 255, .74); margin-bottom: 12px; }
.footer__contacts svg { flex: none; margin-top: 3px; color: rgba(255, 255, 255, .45); }
.footer__contacts a { display: inline-block; margin-bottom: 2px; }
.footer__metro { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.footer__metro span { font-size: 12.5px; padding: 5px 12px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .1); }
.footer__socials { display: flex; gap: 10px; margin-top: 18px; }
.footer__socials a, .footer__socials__soon {
  width: 44px; height: 44px; border-radius: 12px;
  background: rgba(255, 255, 255, .1);
  display: flex; align-items: center; justify-content: center;
}
.footer__socials a:hover, .footer__socials__soon:hover { background: var(--orange); color: var(--white); }
/* Max в финальном виде — курсор обычный, это единственное, чем он
   отличается от рабочих Telegram и VK, пока для него нет ссылки. */
.footer__socials__soon { cursor: default; }
.footer__bottom { padding-top: 26px; display: flex; justify-content: space-between; gap: 24px; font-size: 12.5px; color: rgba(255, 255, 255, .5); }
.footer__bottom p { max-width: 780px; }
/* Реквизиты строкой вместо колонки: на сайте нужны только для узнавания
   юрлица, полный набор — таблицей на «О компании» */
.footer__req { color: rgba(255, 255, 255, .62); margin-bottom: 6px; }
.footer__req a { font-size: 12.5px; text-decoration: underline; text-underline-offset: 2px; }
/* Согласия и политики — только здесь: в списке «Информация» они дублировались */
.footer__legal-links { display: flex; flex-direction: column; gap: 6px; text-align: right; }
/* На тёмном подвале знак выбеливается — как и текстовый логотип до него */
.footer__logo .logo__img { filter: brightness(0) invert(1); }

/* ============================================================
   14  Модалки
   ============================================================ */
.modal {
  position: fixed; inset: 0; z-index: 130;
  display: none;
  align-items: center; justify-content: center;
  padding: 20px;
}
.modal.is-open { display: flex; }
.modal__overlay { position: absolute; inset: 0; background: rgba(0, 0, 0, .55); backdrop-filter: blur(3px); }
.modal__box {
  position: relative;
  background: var(--white);
  border-radius: var(--radius-lg);
  /* Поля окна равны со всех сторон и чуть уже прежних боковых: содержимое
     стоит одной колонкой, и её край — единственная вертикаль в окне.
     Крестик и заголовок выровнены по этой же линии (образец заказчицы,
     28 августа 2026). */
  padding: 42px;
  width: 100%;
  max-width: 620px;
  max-height: 92vh;
  overflow-y: auto;
  animation: pop .26s ease;
}
/* Окно шаблонов шире формы: в 620 px три превью визитки становятся с ноготь */
.modal__box--wide { max-width: 940px; }
@keyframes pop { from { opacity: 0; transform: translateY(24px) scale(.97); } to { opacity: 1; transform: none; } }
/* Крестик стоит в строке заголовка и правым краем — на краю колонки:
   в углу он читался отдельной деталью, не связанной ни с чем на экране */
.modal__close {
  position: absolute; top: 38px; right: 42px;
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--fill);
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--gray);
  transition: .18s;
}
.modal__close:hover { background: var(--orange); color: var(--white); }
/* Заголовок окна крупный: в образце заказчицы он вдвое выше подписи к полю
   и сразу говорит, куда человек попал. Выше не надо — «Заказ у менеджера»
   не должен ломаться на три строки. */
.modal h2 { font-size: clamp(26px, 3vw, 34px); line-height: 1.05; margin-bottom: 8px; padding-right: 56px; }
.modal__lead { font-size: 15px; color: var(--gray); margin-bottom: 26px; }
/* Окно-вопрос: заголовок, одна строка объяснения, две кнопки поровну. Уже и
   тише обычной модалки — спрашивать «точно?» большим окном не о чем.
   Крестика здесь нет: «Отмена» и есть отказ, а второй способ отказаться
   заставляет выбирать там, где выбора нет. Образец — системное окно браузера
   при уходе со страницы (образец заказчицы, 10 сентября 2026). */
.modal__box--ask { max-width: 460px; padding: 36px; text-align: center; }
.modal__box--ask h2 { font-size: 26px; padding-right: 0; margin-bottom: 10px; }
.modal__box--ask .modal__lead { margin-bottom: 28px; }
/* Поля внутри модалки оформлены в разделе «Поля и формы» — рядом с :focus */

.success { text-align: center; padding: 20px 0; }
.success__icon {
  width: 92px; height: 92px; border-radius: 50%;
  background: var(--cream); color: var(--orange);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 22px;
}
/* Экран «отправлено» набран по центру — место под крестик ему не нужно */
.success h2 { margin-bottom: 10px; padding-right: 0; }
.success p { color: var(--gray); }
/* Номер заявки и дорога в кабинет (C71) — отдельным абзацем под ответом:
   сначала «когда ответим», потом «где потом найти» */
.success__saved { margin: 18px auto 0; max-width: 440px; font-size: 14px; }
.success__saved b { color: var(--ink); }
.success__saved a { color: var(--orange-dark); text-decoration: underline; text-underline-offset: 2px; }

/* ============================================================
   15  Плавающие кнопки, чат, предупреждения
   ============================================================ */
.fab { position: fixed; right: 26px; bottom: 26px; z-index: 80; display: flex; flex-direction: column; gap: 12px; }
.fab button {
  width: 60px; height: 60px; border-radius: 14px;
  background: var(--orange); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  transition: .22s;
}
.fab button:hover { transform: translateY(-3px) scale(1.05); }
/* Оранжевым кнопкам связи тень не нужна, белой «Наверх» нужна: без неё она
   теряется на белом фоне. Та же, что у белых стрелок слайдера. */
.fab .to-top { background: var(--white); color: var(--orange); box-shadow: var(--shadow); opacity: 0; pointer-events: none; }
.fab .to-top.is-visible { opacity: 1; pointer-events: auto; }
/* Кнопка связи: пока открыто меню или окно, на ней крестик — закрыть там же,
   где открыл */
.fab__chat .fab__x { display: none; font-size: 30px; line-height: 1; }
.fab__chat.is-on .fab__open { display: none; }
.fab__chat.is-on .fab__x { display: block; }
.fab__chat.is-on { background: var(--ink); }

/* Меню способов связи — столбик над кнопкой, подпись слева от значка.
   Без общей подложки: пункты стоят поверх страницы, как у ПМГ, и каждый —
   отдельная кнопка. */
.fabmenu {
  position: fixed; right: 26px; bottom: 100px; z-index: 85;
  display: flex; flex-direction: column; align-items: flex-end; gap: 12px;
  opacity: 0; visibility: hidden; transform: translateY(12px);
  transition: opacity .2s, transform .2s, visibility .2s;
}
.fabmenu.is-open { opacity: 1; visibility: visible; transform: none; }
.fabmenu__item { display: flex; align-items: center; gap: 12px; text-align: right; }
.fabmenu__label {
  background: var(--white); border-radius: var(--r-control); box-shadow: var(--shadow);
  padding: 8px 14px; line-height: 1.25; transition: .16s;
}
.fabmenu__label b { display: block; font-size: 14.5px; font-weight: 700; }
.fabmenu__label small { display: block; font-size: 12px; color: var(--gray); }
.fabmenu__item:hover .fabmenu__label { color: var(--orange-dark); }
/* Размер как у кнопки связи и «Наверх» — 60 px: в 52 столбик значков был
   уже самой кнопки, и правый край ряда ломался (23 сентября 2026) */
.fabmenu__ic {
  width: 60px; height: 60px; flex: none; border-radius: 14px;
  background: var(--orange); color: var(--white);
  display: flex; align-items: center; justify-content: center; transition: .22s;
}
.fabmenu__ic svg { width: 24px; height: 24px; }
.fabmenu__ic--ink { background: var(--ink); }
.fabmenu__item:hover .fabmenu__ic { transform: scale(1.05); }

/* Панель собранного набора идёт во всю ширину и накрыла бы кнопки связи —
   точнее, они накрыли бы её кнопку «Отправить менеджеру». Пока панель
   на экране, кнопки и чат поднимаются над ней. */
body.has-pick-bar .fab { bottom: 114px; }
body.has-pick-bar .chat,
body.has-pick-bar .fabmenu { bottom: 188px; }
/* Плашки в левом углу поднимаются по той же причине. Про cookie это было
   упущено с самого начала — она уезжала под панель набора; замечено
   5 сентября 2026, когда рядом с ней встало окно с персональными ценами. */
body.has-pick-bar .cookie,
body.has-pick-bar .offer-pop { bottom: 114px; }

.chat {
  position: fixed; right: 26px; bottom: 100px; z-index: 85;
  width: 340px;
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .22);
  overflow: hidden;
  display: none;
}
.chat.is-open { display: block; animation: pop .24s ease; }
.chat__head { background: var(--orange); color: var(--white); padding: 16px 18px; display: flex; align-items: center; gap: 12px; }
.chat__ava { width: 42px; height: 42px; border-radius: 50%; background: rgba(255, 255, 255, .25); display: flex; align-items: center; justify-content: center; font-weight: 800; }
.chat__name { font-weight: 700; }
.chat__status { font-size: 12px; opacity: .9; }
.chat__close { margin-left: auto; color: var(--white); font-size: 20px; }
.chat__body { padding: 18px; background: var(--fill-lg); height: 240px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
/* Пузырь — сообщение, а не метка: скругление контента. Пилюлей он был до
   18 сентября 2026, и на ответе в две строки текст прижимался к краям. */
.msg { max-width: 84%; padding: 11px 15px; border-radius: var(--radius); font-size: 14px; line-height: 1.45; }
.msg--in { background: var(--white); align-self: flex-start; box-shadow: var(--shadow); }
.msg--out { background: var(--orange); color: var(--white); align-self: flex-end; }
/* Выход к человеку прямо под ответом помощника */
.msg__acts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.msg__acts button, .msg__acts a {
  font-size: 13px; font-weight: 600; padding: 7px 12px;
  border-radius: var(--r-control); background: var(--fill); transition: .16s;
}
.msg__acts button:hover, .msg__acts a:hover { background: var(--cream-sm); color: var(--orange-dark); }
.chat__foot { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }
.chat__foot input { flex: 1; height: 44px; border: 1px solid var(--line); border-radius: var(--r-control); padding: 0 16px; font-size: 14px; }
.chat__foot button { width: 44px; height: 44px; border-radius: 50%; background: var(--orange); color: var(--white); display: flex; align-items: center; justify-content: center; }

/* Плашка про cookie: угол экрана, а не окно поперёк сайта. Слева, чтобы не
   спорить с кнопками связи справа; ниже них по z-index — если что-то и
   перекроется, то уведомление, а не кнопка. */
.cookie {
  position: fixed; left: 20px; bottom: 20px; z-index: 70;
  /* 440, а не 400: с L10 две кнопки встают в одну строку */
  max-width: 440px; padding: 16px 18px;
  background: var(--white); border-radius: var(--radius);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .14);
  animation: pop .22s ease;
}
.cookie p { font-size: 13px; line-height: 1.5; color: var(--gray); }
/* Короткая фраза — только на телефоне, см. адаптив */
.cookie__short { display: none; }
.cookie a { color: var(--orange); font-weight: 600; }
/* Две кнопки равного веса (L10): обе серые, ни одна не выделена */
.cookie__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.cookie button {
  white-space: nowrap; padding: 9px 18px;
  border-radius: var(--r-control); background: var(--fill);
  font-size: 13.5px; font-weight: 600; transition: .16s;
}
.cookie button:hover { background: var(--cream-sm); color: var(--orange-dark); }
.cookie b { font-weight: 600; color: var(--ink); }
/* «Настройки cookie» в подвале — выглядит как соседние ссылки */
.footer__cookie { color: inherit; font: inherit; text-align: inherit; padding: 0; background: none; opacity: inherit; }
.footer__cookie:hover { color: var(--orange); }

/* Окно «печатаете регулярно». Та же форма и тот же угол, что у cookie, и это
   намеренно: приём один — уведомление, которое можно не заметить. Оба сразу
   на экране не встречаются, очередь держит renderRegularOffer в app.js.

   z-index на единицу ниже cookie: если очередь когда-нибудь собьётся,
   перекрыто будет предложение, а не обязательное согласие. */
.offer-pop {
  position: fixed; left: 20px; bottom: 20px; z-index: 69;
  max-width: 400px; padding: 18px 20px;
  background: var(--white); border-radius: var(--radius);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .14);
  animation: pop .22s ease;
}
.offer-pop b { display: block; font-size: 17px; margin-bottom: 6px; }
.offer-pop p { font-size: 13.5px; line-height: 1.5; color: var(--gray); }
.offer-pop__act { display: flex; align-items: center; gap: 16px; margin-top: 14px; }
.offer-pop__act .btn { height: 42px; padding: 0 20px; font-size: 14px; }
.offer-pop__no { font-size: 13.5px; color: var(--gray); }
.offer-pop__no:hover { color: var(--ink); }

/* Хранилище переполнено — макеты перестают сохраняться */
.storage-warn {
  position: fixed; left: 20px; bottom: 20px; z-index: 140;
  max-width: 380px; padding: 18px 20px;
  background: var(--err-bg); border-radius: var(--radius);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .18);
}
.storage-warn b { display: block; color: var(--err); margin-bottom: 6px; }
.storage-warn span { display: block; font-size: 13.5px; color: var(--gray); margin-bottom: 12px; }
/* Два действия в ряд: первое ведёт в кабинет разбирать макеты, второе —
   стирает всё и потому одето тише, простой строкой (DESIGN.md, «Кнопки»). */
.storage-warn__act { display: flex; align-items: center; gap: 14px; }
.storage-warn__act .btn { height: 38px; padding: 0 16px; font-size: 13.5px; }
.storage-warn__act button:not(.btn) {
  font-size: 13.5px; font-weight: 600; color: var(--gray);
}
.storage-warn__act button:not(.btn):hover { color: var(--err); }

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

   Плашка светлая, а не цвета --ink: тёмной она пропадала на подвале, и
   в кабинете «добавлено в корзину» читалось как часть подвала. Светлая
   карточка с рамкой и тенью видна на любом фоне сайта.

   Правило у всплывающих сообщений одно (18 сентября 2026, DESIGN.md,
   «Скругления»): сообщение — контент, скругление `--radius`; кнопка в нём —
   управление, `--r-control`. Пилюлей они были раньше, и в две строки текст
   прижимался к краям. */
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 150;
  display: flex; align-items: center; gap: 16px;
  max-width: 460px; padding: 12px 12px 12px 20px;
  background: var(--white); color: var(--ink); font-size: 14px; line-height: 1.5;
  border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 18px 46px rgba(0, 0, 0, .22);
  animation: pop .22s ease;
}
.toast a, .toast button {
  flex-shrink: 0;
  background: var(--orange); color: var(--white);
  padding: 8px 16px; border-radius: var(--r-control);
  font-size: 13.5px; font-weight: 600;
}
.toast a:hover, .toast button:hover { background: var(--ink); color: var(--white); }
/* В редакторе — в правом нижнем углу холста, рядом с его собственными
   сообщениями; почему там, сказано у `placeOnCanvas` (app.js). Класс двойной,
   чтобы узкий экран в «Адаптиве» не вернул положение от окна.

   И цвет там редакторский, тёмный, как у `.ed-toast`: оба сообщения стоят в
   одном углу, и светлое рядом с тёмным читалось как две разные системы.
   Довод про подвал к холсту не относится. */
.toast.toast--canvas {
  position: absolute; left: auto; right: 16px; bottom: 16px; transform: none; z-index: 4;
  max-width: min(460px, calc(100% - 32px));
  background: var(--ink); color: var(--white); border-color: transparent;
  font-size: 13px; box-shadow: 0 10px 30px rgba(0, 0, 0, .25);
}
.toast.toast--canvas a:hover, .toast.toast--canvas button:hover { background: var(--orange-light); }

/* ============================================================
   16  Внутренние страницы
   ============================================================ */
/* Полоса под шапкой: нейтральная, с волосяной линией снизу. Кремовой она
   была до 26 августа 2026 — сплошная оранжевая заливка во всю ширину читалась
   как рекламный баннер, а не как крошки с заголовком, и забирала внимание у
   того, ради чего человек пришёл. Обкатано на карточке продукта, оттуда
   разошлось на все внутренние страницы. */
.page-head { background: var(--bg); border-bottom: 1px solid var(--line); padding: 22px 0 26px; }
.crumbs { display: flex; flex-wrap: wrap; gap: 8px; font-size: 13.5px; color: var(--gray); margin-bottom: 10px; }
.crumbs a:hover { color: var(--orange); }
.crumbs span { color: var(--gray-light); }
/* Заголовок раздела мельче витринного: шапка не должна отодвигать контент. */
.page-head h1 { font-size: clamp(26px, 3vw, 38px); margin-bottom: 6px; }
.page-head p { max-width: 720px; color: #4a4a4a; font-size: 16px; line-height: 1.45; }

.steps-line { display: flex; gap: 8px; align-items: center; margin-bottom: 30px; flex-wrap: wrap; }
.steps-line span { font-size: 13.5px; color: var(--gray-light); font-weight: 600; }
.steps-line span.is-active { color: var(--orange); }
.steps-line span.is-done { color: var(--ink); }
.steps-line i { color: var(--gray-light); font-style: normal; }

.layout { display: grid; grid-template-columns: 290px 1fr; gap: 42px; padding: 38px 0 60px; }
/* Колонка текста ужимается по сетке, а не по самому широкому блоку внутри:
   у элемента сетки min-width: auto, и на 360 px «Как это работает» раздела
   каталога распирал её на 2 px вбок (C84) */
.layout > main { min-width: 0; }
.sidebar { position: sticky; top: 180px; align-self: start; }
.sidebar__title { font-size: 13px; text-transform: uppercase; letter-spacing: .07em; color: var(--gray-light); font-weight: 700; margin-bottom: 14px; }
.sidebar__list a { position: relative; display: block; padding: 11px 16px; border-radius: var(--r-control); font-size: 15px; font-weight: 500; transition: .16s; }
/* Открытый раздел — кремовая плашка с оранжевым текстом, ровно как в
   мегаменю и на табах.

   Наведение красит только слово. Серую плашку под курсором заказчица
   забраковала сразу: рядом с кремовой она читается как второй выбранный
   пункт, два прямоугольника подряд. Общее правило отсюда: где в покое плашки
   нет — наведение меняет цвет текста; где плашка есть (таб, фильтр, канал
   связи) — она просто темнеет. */
.sidebar__list a:hover { color: var(--orange); }
.sidebar__list a.is-active { background: var(--cream-sm); color: var(--orange-dark); font-weight: 700; }
/* «Другие разделы» под списком раздела каталога (category.html) */
.sidebar__other .sidebar__title { margin: 22px 0 12px; }
.sidebar__cta { margin-top: 24px; background: var(--cream); border-radius: var(--radius); padding: 24px; }
.sidebar__cta h4 { margin-bottom: 8px; font-size: 17px; }
.sidebar__cta p { font-size: 14px; color: var(--gray); margin-bottom: 16px; }

/* Блок «Не нашли нужный предмет?» (подбор сувениров с менеджером). Один вид на все четыре места, где он
   встречается, — разметку собирает `giftOut` в app.js, там же и почему.
   До 2 сентября 2026 вид был разный: кремовая плашка с оранжевой кнопкой в
   разделе, строка под волосяной линией в группе, мелкая приписка на странице
   решения. Заказчица попросила один, и выбрала этот: серая плашка, текст,
   кнопка.

   Плашка серая, а не кремовая: кремовая — главный призыв (`.sidebar__cta`),
   а это запасной путь под витриной. По той же причине кнопка контурная. Тон `--fill-lg`: панель
   в половину ширины, залитая тоном мелких плашек, начинает читаться вторым
   фоном — см. разбор заливок в шапке файла.

   Текст: вопрос и объяснение (до 14.10.2026 была ещё мелкая приписка про
   чужой сайт, `small` оставлен на случай примечаний). Ширина текста ограничена, иначе на широком экране строка
   уезжает под самую кнопку и читается тяжело. */
.gift-out {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 18px 26px;
  background: var(--fill-lg); border-radius: var(--radius);
  padding: 22px 26px; margin-top: 34px;
  text-align: left;
}
.gift-out__text { max-width: 620px; }
.gift-out b { display: block; font-size: 17px; margin-bottom: 6px; }
.gift-out p { font-size: 14.5px; color: var(--gray); line-height: 1.55; }
/* Мелкая строка серая обычная, не светлая: `--gray-light` на `--fill-lg` даёт
   контраст 1,9:1 при норме 4,5 — мелкая строка
   просто не читалась. Ступень важности держит размер и то, что выше набрано
   жирным, а не осветление до нечитаемости. */
.gift-out small { display: block; font-size: 13px; color: var(--gray); margin-top: 8px; }
/* «Подобрать сувениры с менеджером» на телефоне шире плашки: в одну строку
   кнопка вылезала за экран (14.10.2026), поэтому ей разрешён перенос. */
.gift-out .btn {
  flex: none; max-width: 100%;
  white-space: normal; text-align: center; line-height: 1.25;
  height: auto; min-height: 48px; padding-block: 10px;
}
/* В выпадашке поиска — теснее и мельче: она узкая, и главным действием там
   остаётся «Спросить менеджера». */
.gift-out--sm { margin-top: 28px; padding: 14px 16px; gap: 10px 18px; }
.gift-out--sm b { font-size: 15px; }
.gift-out--sm p, .gift-out--sm small { font-size: 13px; }

.item-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
/* Подзаголовок внутри сетки карточек: во всю ширину, поэтому кучка под ним
   начинается с новой строки. Первый — без верхнего отступа, он и так первый */
.item-grid__head {
  grid-column: 1 / -1;
  font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--gray-light);
  margin-top: 22px;
}
.item-grid__head:first-child { margin-top: 0; }
/* Картинка — главное в карточке, поэтому она идёт в край и в той же
   пропорции 5:4, что у `.cat-card`: сорок позиций подряд не должны
   выглядеть набором из разных мест. Подпись держим короткой: название
   и цена, срок и тираж сорок раз подряд не читают */
.item-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: .2s;
  background: var(--white);
}
.item-card__body { flex: 1; display: flex; flex-direction: column; gap: 10px; padding: 14px 16px 16px; }
.item-card:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.item-card__img { aspect-ratio: 5 / 4; position: relative; overflow: hidden; }
.item-card__img img { width: 100%; height: 100%; object-fit: cover; }
.item-card h3 { font-size: 16.5px; }
/* Подпись остаётся для карточек оборудования на инфо-странице */
.item-card__meta { font-size: 13px; color: var(--gray); margin-top: auto; }
/* Подпись под названием — только у позиций самообслуживания, где заказ правда
   идёт без менеджера. Их 10 из 187, и именно поэтому подпись что-то значит.

   Цена тут была до 2 сентября 2026 и была выдумана: `900 + номер позиции в
   списке × 130`, отчего тапочки выходили дороже бейсболок. Заменять её на
   «Считает менеджер» тоже не вышло: подпись встала на 177 плитках из 187,
   то есть почти на всех, и перестала что-либо сообщать — заказчица убрала её
   в тот же день. Отсутствие подписи и означает «считает менеджер»: это
   обычный порядок, а помечают исключения. Разбор — docs/ARCHIVE.md, раздел V. */
.item-card__note { font-size: 13.5px; color: var(--gray); margin-top: auto; }

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

   Внутри три текста с разной ролью, и они не должны слипнуться в один
   абзац: серым — что это такое, на кремовой подложке — что это даёт
   компании (ради него раздел и переделан), списком — материалы и
   результат. */
.svc-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
/* Список услуг внутри группы идёт в одну колонку: рядом с текстом стоит
   снимок изделия, и в половину ширины они вдвоём не помещаются. */
.svc-list--wide { grid-template-columns: 1fr; }
.svc {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--white);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: .2s;
}
/* Поля живут у текста, а не у карточки: снимок должен доходить до края, и
   скругление ему даёт `overflow: hidden` самой карточки. До 2 сентября 2026
   кадр лежал плиткой со своим скруглением внутри полей — второй контур внутри
   рамки, ровно то, от чего отказались в остальном прототипе. */
.svc__body {
  flex: 1; min-width: 0;
  padding: 26px 26px 22px;
  display: flex; flex-direction: column; gap: 14px;
}
/* Карточка раздела услуг: кадр сверху во всю ширину карточки. Полосу
   держим широкой (16:9), а не квадратом, — под ней ещё три блока текста,
   и квадрат уводил бы описание за первый экран. Заглушки на месте
   отсутствующего кадра нет: разделы сняты все, а полосатый прямоугольник
   в этой вёрстке выглядит ошибкой.

   `overflow: hidden` и `flex: none` держат пропорцию: без них вертикальный
   кадр распирал обложку по своей высоте, и в одном ряду карточки выходили
   разной длины (21 сентября 2026) — как у `.item-card__img`. */
.svc__cover { flex: none; aspect-ratio: 16 / 9; overflow: hidden; background: var(--fill-lg); }
.svc__cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Карточка со снимком: текст слева, изделие справа. Ширину текста держим —
   строка во всю колонку читается тяжело, а картинка не должна занимать
   больше трети: главное тут всё-таки объяснение. */
.svc--photo { flex-direction: row; align-items: stretch; }
/* Предела ширины у текста тут нет намеренно. Он был — 720 px, — и из-за него
   справа оставался зазор в 39 px: остаток свободного места в строке флексбокса
   ложился за картинкой, а не под неё, и снимок не доходил до края. Растянуть
   вместо этого снимок тоже не годится: он забирал половину карточки, а главное
   здесь объяснение. Поэтому остаток забирает текст, а снимок держит свои
   300 px. Строка выходит около 750 px — на тридцать пикселей длиннее прежнего
   предела, читаемости это не рушит. */
/* Снимок в край и во всю высоту карточки: высоту задаёт текст рядом, поэтому
   своей пропорции у него нет — она бы спорила с длиной описания.

   Про зазор справа и предел ширины текста — в правиле `.svc--photo` выше. */
.svc__media { flex: none; width: 300px; align-self: stretch; background: var(--fill-lg); }
.svc__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.svc:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.svc__head { display: flex; align-items: center; gap: 13px; }
.svc__icon {
  flex: none; width: 46px; height: 46px;
  border-radius: var(--radius-sm);
  background: var(--cream); color: var(--orange);
  display: grid; place-items: center;
}
.svc__icon svg { width: 24px; height: 24px; }
.svc h3 { font-size: 19px; line-height: 1.25; }
.svc__text { font-size: 15px; line-height: 1.6; color: var(--gray); }
/* Плашка серая, а не кремовая. Кремовая была до 2 сентября 2026, и на списке
   услуг такие плашки складывались в оранжевую полосу во всю страницу: в каждой
   карточке значок, плашка, точки списка и ссылка — четыре тёплых пятна, и так
   семь раз подряд. Правило — в docs/DESIGN.md, «Сколько оранжевого на экране».
   Значок остался кремовым: 46 пикселей и панель в треть карточки весят
   по-разному, см. разбор заливок в шапке файла. */
.svc__gain {
  background: var(--fill-lg);
  border-radius: var(--radius-sm);
  padding: 15px 17px;
  font-size: 15px; line-height: 1.55;
}
.svc__facts { display: grid; gap: 8px; font-size: 14px; color: var(--gray); }
.svc__facts li { position: relative; padding-left: 18px; line-height: 1.45; }
.svc__facts li::before {
  content: ''; position: absolute; left: 3px; top: 7px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--orange);
}
.svc__link {
  margin-top: auto; padding-top: 4px;
  font-weight: 700; color: var(--orange); font-size: 14.5px;
  display: inline-flex; gap: 6px; align-items: center;
}

/* ============================================================
   16-tri  Страницы решений: welcome pack и корпоративный мерч
   ============================================================

   Композиция выбрана заказчиком 19 августа 2026 из двух черновиков:
   центральная — обещание по центру, под ним полоса снимков, дальше готовые
   наборы тремя колонками. Второй вариант (текст слева, наборы широкими
   карточками) отклонён вместе со своим файлом.

   Порядок блоков задаётся в данных (`SOLUTION_PAGES` в content.js), а не
   в разметке: страницы отличаются содержимым, а не вёрсткой. */

.sol-hero { text-align: center; padding: 58px 0 40px; }
.sol-hero h1 { font-size: 52px; line-height: 1.06; letter-spacing: -.02em; max-width: 900px; margin: 12px auto 0; }
.sol-hero__lead { color: var(--gray); font-size: 17.5px; line-height: 1.6; max-width: 680px; margin: 20px auto 0; }
.sol-hero__actions { display: flex; gap: 12px; justify-content: center; margin-top: 28px; }

.sol-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.sol-strip figure { margin: 0; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden; background: var(--fill-lg); }
.sol-strip img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Готовый набор. Сборной съёмки комплекта у типографии нет, поэтому набор
   собирается из трёх кадров: крупный сверху, два мелких под ним — вместе
   они читаются как одна витринная выкладка. */
.packs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; align-items: stretch; }
/* Кликабельна вся карточка, а не только кнопка внизу: набор — это один
   выбор, и человек тыкает в фотографию раньше, чем доскроллит до кнопки. */
.pack {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 18px 18px 22px; display: flex; flex-direction: column; transition: .2s;
  cursor: pointer;
}
.pack:hover { border-color: var(--orange); box-shadow: var(--shadow-hover); transform: translateY(-4px); }
.pack__shots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 18px; }
.pack__shots figure { margin: 0; border-radius: var(--radius-sm); overflow: hidden; background: var(--fill-lg); aspect-ratio: 1 / 1; }
.pack__shots figure:first-child { grid-column: 1 / 3; aspect-ratio: 16 / 10; }
.pack__shots img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pack__when { font-size: 12.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--gray-light); }
.pack h3 { font-size: 24px; margin: 6px 0 4px; }
.pack__size { font-size: 17px; font-weight: 700; color: var(--orange); margin-bottom: 14px; }
.pack__text { color: var(--gray); font-size: 14.5px; line-height: 1.55; margin-bottom: 16px; }
.pack__list { display: grid; gap: 8px; margin-bottom: 20px; }
.pack__list li { position: relative; padding-left: 20px; font-size: 14.5px; line-height: 1.4; }
.pack__list li::before { content: ''; position: absolute; left: 0; top: 10px; width: 11px; height: 2px; background: var(--orange); }
/* Состав из настоящего заказа. Строка отбита волосяной линией и набрана
   мельче состава: это подпись к нему, а не ещё один пункт. Цифры
   моноширинные — в трёх карточках рядом тиражи читаются столбиком. */
.pack__from {
  border-top: 1px solid var(--line); padding-top: 12px; margin: -4px 0 16px;
  color: var(--gray); font-size: 13.5px; line-height: 1.5;
  font-variant-numeric: tabular-nums;
}

/* Цену набора ставит типография: поле `price` у набора. Пока его нет,
   на месте суммы стоит строка про расчёт — выдуманных цифр тут не будет. */
.pack__price { font-size: 26px; font-weight: 800; letter-spacing: -.02em; margin-top: auto; margin-bottom: 14px; }
.pack__price--none { font-size: 16px; font-weight: 600; color: var(--gray); }

/* ————— Подарки по поводу —————

   Пять входов по дате, а не по изделию. Ряд стоит сразу под наборами, и
   ритм у него нарочно другой: карточка набора высокая, со списком и ценой,
   плитка повода низкая — снимок, название, строка примера и ссылка. Иначе
   два ряда карточек подряд читаются как один длинный список.

   Плитка бывает двух видов: ссылка на свою страницу (сейчас такая одна —
   welcome pack) и кнопка, открывающая заявку. Заливкой их не разводим:
   кремовая плитка стояла тут до 3 сентября 2026 и в ряду одинаковых карточек
   читалась как выделенная реклама, а не как переход. Разница видна по
   подписи внизу — «Открыть страницу» против «Собрать к дате».

   `overflow: hidden` на снимке обязателен: плитка — колонка флексбокса, и
   без него картинка своим натуральным размером задаёт минимальную высоту
   элементу, а `aspect-ratio` перестаёт работать. Кадры у нас разной
   пропорции, поэтому первая плитка оказывалась выше остальных. */
.occasions { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }
.occasion {
  display: flex; flex-direction: column; text-align: left; padding: 0;
  font: inherit; color: inherit; cursor: pointer;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius-lg); overflow: hidden; transition: .2s;
}
.occasion:hover { border-color: var(--orange); box-shadow: var(--shadow-hover); transform: translateY(-4px); }
.occasion__img { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: var(--fill-lg); }
.occasion__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.occasion__body { display: flex; flex-direction: column; flex: 1; gap: 6px; padding: 16px 16px 18px; }
.occasion__when { font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--gray-light); line-height: 1.3; }
.occasion h3 { font-size: 18px; line-height: 1.2; }
.occasion p { color: var(--gray); font-size: 14px; line-height: 1.5; }
/* Пример состава — не список, а одна строка через точку: это подсказка,
   что бывает внутри, а не то, что человек выбирает. */
.occasion__list { color: var(--gray-light); font-size: 13px; line-height: 1.5; }
.occasion__cta { margin-top: auto; padding-top: 12px; font-weight: 700; color: var(--orange); font-size: 14px; display: inline-flex; gap: 6px; align-items: center; }

/* Основы: готовый состав отмечает свои предметы, дальше человек добавляет
   своё. Кнопки не залипают активными — это не фильтр, а разовое действие:
   после первого же клика по предмету состав уже не равен основе. */
.pick-base { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 22px; }
.pick-base__label { font-size: 14.5px; font-weight: 600; color: var(--gray); margin-right: 4px; }
.pick-base__clear { color: var(--gray); }

/* Плитка предмета. Раньше это была ссылка в каталог, теперь — переключатель,
   поэтому у неё есть отмеченное состояние: рамка, галочка на снимке и другая
   подпись внизу. Кнопке нужно вернуть выключку по левому краю. */
.pick-card { text-align: left; width: 100%; }
.pick-card.is-picked { border-color: var(--orange); background: var(--cream); }
.pick-card__mark {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
  border-radius: var(--r-pill); background: var(--orange); color: var(--white);
  display: grid; place-items: center; opacity: 0; transform: scale(.6); transition: .18s;
}
.pick-card__mark svg { width: 15px; height: 15px; }
.pick-card.is-picked .pick-card__mark { opacity: 1; transform: none; }
.pick-card__add { font-weight: 700; color: var(--orange); font-size: 14.5px; }
.pick-card:not(.is-picked) .pick-card__add { color: var(--gray-light); }

/* «Что-то своё» — последняя плитка сетки. Пунктир и плюс вместо снимка:
   это не предмет из списка, а приглашение назвать то, чего в списке нет,
   и выглядеть как остальные восемь она не должна. Галочка ей не нужна —
   плитка не отмечается, а открывает заявку. */
.pick-card--more {
  border-style: dashed; border-color: var(--line-strong); background: var(--fill-lg);
  justify-content: center; gap: 8px;
  padding: 14px 16px 18px;
}
.pick-card--more:hover { border-style: solid; }
.pick-card__plus {
  width: 40px; height: 40px; border-radius: var(--r-pill);
  background: var(--cream); color: var(--orange);
  display: grid; place-items: center; font-size: 24px; font-weight: 700;
  margin-bottom: 4px;
}
.pick-card--more p { flex: none; }
.pick-card--more:not(.is-picked) .pick-card__add { color: var(--orange); }

/* Панель состава. Прилипает к низу окна, а не стоит блоком в потоке: предметы
   отмечают, прокручивая длинную сетку, и итог должен быть виден всё это время.
   Пока не выбрано ничего — панели нет вовсе. */
.pick-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--white); border-top: 1px solid var(--line);
  box-shadow: 0 -8px 30px rgba(0, 0, 0, .07);
  padding: 14px 0;
}
.pick-bar__in { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.pick-bar__list { min-width: 0; }
.pick-bar__list b { display: block; font-size: 16px; }
.pick-bar__list span {
  display: block; color: var(--gray); font-size: 14px; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pick-bar .btn { flex: none; }
/* Чтобы панель не накрыла подвал и кнопку брифа */
body.has-pick-bar { padding-bottom: 88px; }

/* Зачем это компании. Крупные номера вместо иконок: значки уже работают
   в каталоге и в услугах, а здесь нужен другой ритм — это не список
   возможностей, а четыре довода. */
.sol-why { display: grid; grid-template-columns: repeat(2, 1fr); gap: 40px 56px; }
.sol-why__item { border-top: 2px solid var(--ink); padding-top: 18px; }
.sol-why__num { font-size: 13px; font-weight: 800; color: var(--orange); letter-spacing: .1em; margin-bottom: 10px; }
.sol-why__item h3 { font-size: 22px; line-height: 1.25; margin-bottom: 10px; }
.sol-why__item p { color: var(--gray); font-size: 15.5px; line-height: 1.6; }

/* Способы нанесения: тексты берутся из SERVICES, второй раз не пишутся */
.sol-methods { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.sol-method {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 24px; display: flex; flex-direction: column; gap: 12px; transition: .2s;
}
.sol-method:hover { border-color: var(--orange); box-shadow: var(--shadow-hover); transform: translateY(-4px); }
.sol-method__ic { width: 44px; height: 44px; border-radius: var(--radius-sm); background: var(--cream); color: var(--orange); display: grid; place-items: center; }
.sol-method__ic svg { width: 24px; height: 24px; }
.sol-method h3 { font-size: 18px; }
.sol-method p { color: var(--gray); font-size: 14.5px; line-height: 1.55; }
.sol-method__link { margin-top: auto; font-weight: 700; color: var(--orange); font-size: 14.5px; display: inline-flex; gap: 6px; align-items: center; }

/* Шаги на одной линии. Линия принадлежит ряду, а не шагу: иначе между
   колонками остаются разрывы и процесс распадается на четыре отдельных
   отрезка вместо одного пути. */
.sol-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 28px; position: relative; padding-top: 26px; }
.sol-steps::before { content: ''; position: absolute; top: 5px; left: 0; right: 0; height: 2px; background: var(--line); }
.sol-step { position: relative; }
.sol-step::before {
  content: ''; position: absolute; top: -26px; left: 0;
  width: 12px; height: 12px; border-radius: 50%; background: var(--orange);
}
.sol-step b { display: block; font-size: 17px; margin-bottom: 8px; }
.sol-step p { color: var(--gray); font-size: 14.5px; line-height: 1.55; }

/* Отзыв: одна цитата крупно, без карусели — здесь она доказательство,
   а не раздел «отзывы» */
.sol-quote {
  background: var(--cream); border-radius: var(--radius-lg);
  padding: 40px 44px; display: grid; grid-template-columns: auto 1fr; gap: 22px; align-items: start;
}
.sol-quote__ava {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--orange); color: var(--white);
  display: grid; place-items: center; font-size: 22px; font-weight: 800;
}
.sol-quote p { font-size: 20px; line-height: 1.55; margin-bottom: 14px; }
.sol-quote span { color: var(--gray); font-size: 14.5px; }


/* Карточка станка. От карточки изделия отличается тем, что читают тут
   название, а не картинку: «Цифровая печатная машина Ricoh Pro C7100»
   говорит заказчику больше, чем снимок серого ящика. Поэтому снимок
   уходит в угол фиксированной ширины, а название набрано крупнее. */
.eq-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.eq-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; align-items: stretch;
  transition: .2s;
  background: var(--white);
}
.eq-card:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
/* Снимок станка — в край карточки и во всю её высоту. Плитка со своим
   скруглением внутри полей была здесь до 2 сентября 2026 и заводила в вёрстку
   третью пропорцию (4:3 против 5:4 и 16:9) на ровном месте. */
.eq-card__img { flex: none; width: 132px; background: var(--fill-lg); }
.eq-card__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.eq-card__body { min-width: 0; align-self: center; padding: 14px 16px; }
.eq-card h3 { font-size: 19px; line-height: 1.2; }
.eq-card__meta { font-size: 13.5px; color: var(--gray); margin-top: 7px; }

/* Строка характеристик на самой странице станка: она тут вместо лида,
   поэтому крупнее обычного текста, но спокойнее заголовка. */
.eq-spec { font-size: 18px; color: var(--gray); line-height: 1.45; }

.prose h2 { font-size: 30px; margin: 84px 0 18px; }
.prose h3 { font-size: 21px; margin: 26px 0 10px; }
.prose p, .prose li { color: #3d3d3d; font-size: 16px; margin-bottom: 12px; }
/* Меры строки у текста нет — абзацы идут во всю колонку. С 10 по 11 сентября
   2026 прямые абзацы и списки были ограничены 720 px, но рядом с ними стоят
   карточки, таблицы и схемы во всю ширину, и текст обрывался на полдороге:
   заказчица приняла это за сломанную вёрстку. Колонку задаёт раскладка
   страницы, а не сам текст. */
.prose ul { padding-left: 4px; }
.prose ul li { position: relative; padding-left: 26px; }
.prose ul li::before { content: ''; position: absolute; left: 6px; top: 9px; width: 8px; height: 8px; border-radius: 50%; background: var(--orange); }
.prose a { color: var(--orange); text-decoration: underline; }

.table { width: 100%; border-collapse: collapse; margin: 20px 0 26px; font-size: 15px; }
.table th, .table td { text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line); }
.table th { background: var(--fill-lg); font-weight: 700; font-size: 14px; }
.table tr:hover td { background: var(--fill-lg); }
.table td:last-child, .table th:last-child { text-align: right; }
/* Маленькая справочная таблица внутри текста: три-четыре строки, которые
   поясняют схему над ними, — вылеты по видам продукции. Кегль и поля
   поменьше, ширина — вся колонка, как у схемы с текстом над ней: до
   11 сентября 2026 таблица стояла по центру шириной 760 px и под
   полноширинной схемой читалась куцей. Оговорка к таблице идёт подписью под
   ней, а не лишней строкой. */
.table--sm { width: 100%; min-width: 0; font-size: 14.5px; margin: 28px 0 22px; }
.table--sm th, .table--sm td { padding: 10px 16px; }
.table--sm caption { caption-side: bottom; text-align: left; font-size: 14px; color: var(--gray); padding-top: 10px; }

.accordion__item { border-bottom: 1px solid var(--line); }
.accordion__head {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 20px;
  padding: 22px 0; text-align: left; font-weight: 700; font-size: 18px;
}
.accordion__head .plus { color: var(--orange); font-size: 26px; transition: transform .25s; flex-shrink: 0; }
.accordion__item.is-open .plus { transform: rotate(45deg); }
.accordion__body { display: none; padding-bottom: 22px; color: var(--gray); max-width: 900px; }
.accordion__item.is-open .accordion__body { display: block; }

/* Облако ссылок «что здесь есть». Завелось как оглавление длинной
   инфо-страницы: «Требования к макетам» — это два десятка разделов подряд,
   и человеку, которому нужно одно тиснение, приходилось листать всё
   (замечание заказчика 31 августа 2026). 2 сентября 2026 тем же компонентом
   стала оглавляться большая группа каталога — там сорок карточек, и по ним
   не видно, что в «Одежде» есть зонты. Плитки — общий `.chip`, здесь только
   их раскладка: строка мельче обычной, потому что это навигация, а не
   содержание.

   Плашки под облаком нет намеренно. Она была до 2 сентября 2026: серая
   панель `--fill-lg`, а плитки внутри перекрашены в белый, чтобы не
   слиться, — и читались дырками в панели, а не ссылками. Теперь узор тот
   же, что был у мессенджеров в поповере шапки до 22 сентября 2026: мелкий заголовок
   капсом и ряд серых пилюль прямо на фоне страницы. Обратно панель не
   заводим. */
.toc { margin-bottom: 30px; }
.toc__title {
  font-size: 13px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--gray-light); font-weight: 700; margin-bottom: 12px;
}
.toc__group + .toc__group { margin-top: 20px; }
.toc__list { display: flex; flex-wrap: wrap; gap: 8px; }
.toc .chip { padding: 8px 16px; font-size: 13.5px; }
.toc .chip:hover { background: var(--cream-sm); color: var(--orange-dark); }

.info-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; margin: 26px 0; }
/* Две колонки вместо трёх. Раньше это писалось инлайновым стилем прямо в
   тексте страницы, и он перебивал «Адаптив»: на телефоне сетка оставалась
   в две колонки и растягивала страницу на 33 px вправо. */
.info-grid--2 { grid-template-columns: repeat(2, 1fr); }
.info-card { background: var(--fill-lg); border-radius: var(--radius); padding: 26px; }
/* Верхний отступ обнулён явно: внутри `.prose` заголовок получал ещё 26 px
   от `.prose h3`, и над ним в карточке стояло вдвое больше воздуха, чем по
   бокам. Последний элемент карточки тоже без нижнего отступа — поля даёт
   сама карточка. */
.info-card h3 { font-size: 18px; margin: 0 0 10px; }
.info-card p { font-size: 14.5px; color: var(--gray); }
.info-card > :last-child { margin-bottom: 0; }
/* Карточка с действием: описание и кнопка под ним. Кнопки соседних карточек
   встают на одну линию, даже если описания разной длины. */
.info-card--act { display: flex; flex-direction: column; align-items: flex-start; }
.info-card--act p { margin-bottom: 18px; }
.info-card--act .btn { margin-top: auto; }
/* Призыв в последней ячейке сетки: тот же кремовый фон, что у врезки
   `.sidebar__cta`. Встаёт на место недостающей карточки, и ряд не
   обрывается пустотой. */
.info-card--cta { background: var(--cream); }
/* Список внутри карточки: тем же кеглем, что и абзац в ней. Без этого
   `.prose li` даёт 16 px, и карточка со списком весит больше соседней
   с текстом, хотя роль у них одна. */
.info-card li { font-size: 14.5px; margin-bottom: 8px; }
.info-card li:last-child { margin-bottom: 0; }

/* Страница требований к макетам: белые карточки вместо серых плашек.
   Это всё ещё обычная info-card, но с более читаемой поверхностью и
   фирменной оранжевой рамкой для технических правил. */
.info-grid--req { align-items: stretch; }
.info-card--req {
  background: var(--white);
  border: 2px solid var(--orange);
}
.info-card--req p + p { margin-top: 12px; }
.req-lines { display: grid; gap: 0; }
.req-lines p {
  display: grid; gap: 4px;
  margin: 0; padding: 13px 0;
  border-top: 1px solid var(--line);
}
.req-lines p:first-child { padding-top: 2px; border-top: 0; }
.req-lines p:last-child { padding-bottom: 0; }
.req-lines b { color: var(--ink); }
.req-lines span { color: var(--gray); }
.req-lines code {
  display: inline-block; justify-self: start;
  padding: 4px 9px; margin: 2px 0;
  border-radius: 7px;
  background: var(--cream-sm);
  color: var(--orange-dark);
  font: 700 13px/1.25 var(--font);
  white-space: nowrap;
}

/* Основные требования — шесть карточек, все открыты: это то, что человек
   должен увидеть, не нажимая. Номер слева, заголовок и текст — во второй
   колонке, так абзацы стоят ровным краем под заголовком. Колонок столько,
   сколько влезает по 260px: три на широком экране, одна на телефоне.
   Карточки в тонкой рамке и одной высоты — как «Руководство и шаблоны» ниже:
   без рамок шесть разделов сливались в один текст. */
.req-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  grid-auto-rows: 1fr;
  gap: 16px;
  margin: 30px 0 18px;
}
.req-card {
  display: grid;
  grid-template-columns: 28px 1fr;
  align-items: baseline;
  align-content: start;
  padding: 22px 24px 24px 20px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.req-card__num {
  color: var(--gray-light);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .08em;
}
.prose .req-card__title {
  margin: 0 0 14px;
  font-size: 20px;
  line-height: 1.25;
}
.req-card__body {
  grid-column: 2;
  display: grid;
  gap: 10px;
  justify-items: start;
}
.prose .req-card__body p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--gray);
}
/* Выделение внутри текста полужирное, а не жирное: иначе оно спорит с
   заголовком карточки */
.req-card__body b { font-weight: 600; color: var(--ink); }
/* Плашка «!» внутри карточки — та же .note, только плотнее и во всю ширину
   колонки: сетка тела карточки прижимает элементы к левому краю */
.req-card__body .note {
  justify-self: stretch;
  gap: 10px;
  margin: 2px 0;
  padding: 11px 14px;
}
.req-card__body .note__ic { width: 20px; height: 20px; font-size: 12px; }
.prose .req-card__body .note p { font-size: 14px; line-height: 1.5; color: var(--ink); }
/* Оранжевый на странице — только у ссылок, и ссылка всегда подчёркнута:
   смысловое выделение идёт чёрным жирным. Иначе «не считаются макетами»
   и «ниже ↓» выглядели одинаково, и было непонятно, что нажимается.
   Стрелку не подчёркиваем — линия под ней читается как опечатка. Ссылка
   наружу, в PDF, — обычная <a>, её подчёркивает .prose a целиком. */
.req-card__more {
  padding: 0;
  border: 0;
  background: none;
  color: var(--orange);
  font: 700 14px/1.4 var(--font);
  cursor: pointer;
}
.req-card__more span {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.req-card__more:hover { color: var(--orange-dark); }

.req-alert {
  padding: 12px 14px;
  border-radius: var(--r-control);
  background: var(--cream);
  color: var(--orange-dark) !important;
}

/* Руководство и шаблоны: две карточки, у каждой содержание под раскрытием.
   Пока обе закрыты, карточки одной высоты и кнопки стоят на одной линии;
   когда одна раскрыта, вторая не тянется за ней пустым низом. */
.guide-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 72px;
}
.guide-actions:has(.guide-toc[open]) { align-items: start; }
.guide-action {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 22px 24px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.guide-action h3 { font-size: 18px; margin: 0 0 10px; }
.guide-action p { font-size: 14.5px; color: var(--gray); }
.guide-action .btn { margin-top: auto; }
.guide-toc {
  align-self: stretch;
  margin-top: 22px;
  border-top: 1px solid var(--line);
}
.guide-toc summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 16px 0 0;
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.guide-toc summary::-webkit-details-marker { display: none; }
.guide-toc__plus {
  color: var(--orange);
  font-size: 24px;
  line-height: 1;
  transition: transform .16s;
}
.guide-toc[open] .guide-toc__plus { transform: rotate(45deg); }
/* Содержание руководства — как в самом PDF: группа, под ней пункты со
   страницами справа. Список лежит внутри .prose, у той свои маркеры и
   отступы у ul и li, поэтому селекторы здесь на ступень сильнее. */
.guide-toc__group { margin-top: 18px; }
.guide-toc__group > b {
  display: block;
  margin-bottom: 4px;
  font-size: 15px;
  color: var(--ink);
}
.guide-toc .guide-toc__list {
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}
.guide-toc__group .guide-toc__list { margin-top: 0; }
.guide-toc .guide-toc__list li {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 0;
  padding: 8px 0;
  border-top: 1px solid var(--line);
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--gray);
}
.guide-toc .guide-toc__list li::before { content: none; }
.guide-toc__list li > span {
  flex: none;
  color: var(--ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.guide-toc__group:last-child .guide-toc__list li:last-child { padding-bottom: 0; }
/* Названия шаблонов короткие — двумя колонками без описаний */
.guide-toc .guide-toc__list--short {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 24px;
}
.guide-toc .guide-toc__list--short li {
  display: block;
  padding: 9px 0;
  font-size: 15px;
  color: var(--ink);
}
.guide-toc .guide-toc__list--short li:nth-child(-n+2) { border-top: 0; padding-top: 0; }
.guide-toc .guide-toc__list--short li:nth-last-child(-n+2) { padding-bottom: 0; }

/* Схема вылетов рядом с объяснением: сначала человек видит линию реза,
   потом сразу читает, зачем она нужна. */
.bleed-layout {
  display: grid;
  grid-template-columns: minmax(340px, 1.08fr) minmax(260px, .92fr);
  gap: 34px;
  align-items: center;
  margin: 30px 0 30px;
}
.bleed-layout .info-fig { margin: 0; }
.bleed-copy {
  display: grid;
  gap: 14px;
}
.bleed-copy p {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--gray);
}
.bleed-copy b { color: var(--ink); }
/* Схемы на инфо-страницах: рисуем вектором в разметке, отдельных файлов нет */
.info-fig { margin: 26px 0; max-width: 560px; }
.info-fig--wide { max-width: 700px; }
.src {
  margin: 18px 0 64px !important;
  text-align: center;
}
/* Таблица размеров слева, схема вложенности справа. 10 сентября 2026 схему
   ставили над таблицей во всю ширину — в паре ей доставалась половина
   колонки, и подписи A7 и A8 не читались. 11 сентября пара вернулась по
   просьбе заказчицы, но таблица теперь узкая, по содержимому, и схема
   получает почти три четверти колонки: A8 внутри своего прямоугольника
   выходит около 12 px. На телефоне — одна под другой, см. «Адаптив». */
.fmt { display: grid; grid-template-columns: minmax(220px, 280px) 1fr; gap: 36px; align-items: start; margin: 22px 0; }
.fmt svg { display: block; width: 100%; height: auto; }
.fmt .table { margin: 0; }
.info-fig svg { display: block; width: 100%; height: auto; }
.info-fig figcaption { font-size: 14px; color: var(--gray); margin-top: 10px; }

/* Пара «так / не так» на инфо-странице. Взята с руководства типографии: там
   имя файла и два чёрных показаны именно парой примеров, и это единственные
   страницы документа, которые понятны с одного взгляда, без чтения.

   Состояние несёт подложка и метка, цветной полосы сбоку нет — как везде в
   системе. Цвета — пары состояний из токенов, свои сюда не заводим. */
.demo { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 22px 0 26px; }
.demo__item { border-radius: var(--radius); padding: 18px 20px; }
.demo__item--ok { background: var(--ok-bg); }
.demo__item--no { background: var(--err-bg); }
.demo__mark {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  margin-bottom: 10px;
}
.demo__item--ok .demo__mark { color: var(--ok); }
.demo__item--no .demo__mark { color: var(--err); }
.demo__sample { font-size: 16px; font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.demo__note { font-size: 14px; color: var(--gray); margin-top: 8px; line-height: 1.45; }

/* Вступление длинной инфо-страницы: стоит до оглавления и набрано крупнее
   основного текста — иерархия размером, как и везде. Идёт во всю колонку,
   как и остальной текст: мера в 720 px снята 11 сентября 2026 вместе с мерой
   у `.prose`, см. выше. */
/* Отступ между абзацами — примерно строка (26 px при интерлиньяже 28,7 px).
   Было 14 px, вдвое меньше строки: абзацы слипались в одну плиту текста, и
   вступление читалось скомканным. Граница абзаца должна быть виднее границы
   строки, иначе её нет. */
.intro { margin-bottom: 38px; }
.intro p { font-size: 18.5px; line-height: 1.55; color: #3d3d3d; margin-bottom: 26px; }
.intro p:last-child { margin-bottom: 0; }
.intro a { color: var(--orange); text-decoration: underline; }

/* Отсылка к странице руководства типографии — по одной на раздел требований.
   Строка служебная: мельче текста и серым, чтобы читалась как сноска, а не
   как продолжение раздела. Селектор из двух классов — иначе `.prose p`
   перебивает кегль и цвет. */
.prose .src {
  max-width: 620px;
  font-size: 14px;
  color: var(--gray);
  margin: 10px 0 56px;
  text-align: left;
}

/* Чек-лист «перед отправкой»: строки, которые человек сверяет глазами.
   Галочки зелёные и одинаковые — это маркер пункта, а не состояние: ничего
   ещё не проверено, отмечать нечего. Разделители волосяные, рамка одна на
   весь список: восемь отдельных карточек читались бы восемью задачами. */
.check {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px 24px; margin: 22px 0 26px;
}
.check__row { display: flex; align-items: flex-start; gap: 12px; padding: 15px 0; font-size: 16px; color: #3d3d3d; }
.check__row + .check__row { border-top: 1px solid var(--line); }
.check__row svg { margin-top: 4px; color: var(--ok); }

/* Ряд кнопок внутри текста инфо-страницы: скачать руководство, открыть
   шаблоны, написать. Переносится, а не сжимает кнопки: на узкой колонке
   вторая уходит на следующую строку целиком. */
.btn-row { display: flex; flex-wrap: wrap; gap: 14px; margin: 22px 0 20px; }
.btn-row--center { justify-content: center; }

/* Оговорка в тексте: то, что стоит знать, но что не отменяет сказанного
   рядом, — «макет не по требованиям возьмём, но результат не предскажем».
   Тихая: подложка предупреждения и кружок с «!», обычный кегль, без
   жирного и без полосы сбоку. Пара цветов — из токенов состояний. */
.note { display: flex; align-items: flex-start; gap: 12px; padding: 14px 18px; margin: 18px 0 26px; background: var(--warn-bg); border-radius: var(--r-control); }
.note__ic {
  width: 22px; height: 22px; flex-shrink: 0; margin-top: 1px; border-radius: 50%;
  background: var(--warn); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 13px;
}
.prose .note p { font-size: 15px; margin: 0; }
/* `.prose a` красит любую ссылку внутри текста оранжевым и подчёркивает — по
   специфичности он сильнее модификаторов кнопки, и «Скачать руководство»
   выходило оранжевым текстом на оранжевом фоне. Возвращаем кнопке её вид. */
.prose a.btn { text-decoration: none; }
.prose a.btn--primary { color: var(--white); }
.prose a.btn--ghost { color: var(--orange); }
.prose a.btn--ghost:hover { color: var(--white); }
/* Метро на «Контактах»: строка между карточками связи и адресами */
.info-metro { font-size: 14.5px; color: var(--gray); margin: -6px 0 26px; }

/* Настоящие Яндекс.Карты вместо нарисованной схемы (17 августа 2026).
   Виджету не нужен ключ API, но нужен интернет: без сети рамка останется
   пустой, и это честно — рисованная схема делала вид, что карта есть.

   Адрес и карта — одна пара на место (3 сентября 2026, когда офис на Зорге
   убран и адрес остался один). Карточка слева, карта справа, обе тянутся на
   высоту строки. */
.contacts-place {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 20px; margin: 26px 0;
}
.contacts-place + .contacts-place { margin-top: 20px; }
.map-embed {
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--fill-lg);
}
.map-embed iframe { display: block; width: 100%; height: 320px; border: 0; }
.map-embed__stub {
  height: 320px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 24px; text-align: center;
  background: var(--fill-lg);
}
.map-embed__addr { font-weight: 600; max-width: 340px; }
.map-embed__note { font-size: 13px; color: var(--gray); }
.map-embed figcaption {
  padding: 14px 18px;
  font-size: 14.5px; font-weight: 600;
  background: var(--cream);
}

.blog-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.post { border-radius: var(--radius); overflow: hidden; background: var(--white); box-shadow: var(--shadow); transition: .22s; }
.post:hover { transform: translateY(-5px); box-shadow: var(--shadow-hover); }
.post__img { height: 180px; position: relative; overflow: hidden; }
.post__body { padding: 22px; }
.post__meta { display: flex; gap: 10px; font-size: 12.5px; color: var(--gray); margin-bottom: 10px; }
.post__meta span:first-child { color: var(--orange); font-weight: 700; }
.post h3 { font-size: 18px; line-height: 1.3; }

.empty-state { text-align: center; padding: 60px 20px; }
.empty-state h3 { margin-bottom: 10px; }
.empty-state p { color: var(--gray); margin-bottom: 22px; }
.empty-state__acts { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.designs-top { display: flex; justify-content: flex-end; margin-bottom: 16px; }

/* ============================================================
   17  Карточка продукта
   ============================================================ */
.product-hero { display: grid; grid-template-columns: 1.05fr 1fr; gap: 46px; align-items: start; }
/* Изделие едет рядом с параметрами: колонка параметров длинная, галерея
   короткая, и без этого слева половину экрана оставалась пустота.
   Отступ сверху — высота липкой шапки плюс воздух. */
.product-hero__media { position: sticky; top: 92px; }
.gallery__main { border-radius: var(--radius-lg); overflow: hidden; aspect-ratio: 4 / 3; position: relative; background: var(--fill-lg); }
.gallery__thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 12px; }
.gallery__thumb {
  border-radius: var(--radius-sm); overflow: hidden; aspect-ratio: 1;
  position: relative; cursor: pointer; border: 2px solid transparent; background: var(--fill-lg);
}
.gallery__thumb.is-active { border-color: var(--orange); }
.gallery__main img, .gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }

.product__price { font-size: 34px; font-weight: 800; color: var(--orange); margin: 6px 0 22px; }
.product__price small { display: block; margin-top: 4px; font-size: 15px; color: var(--gray); font-weight: 600; }
.product__price.is-wait { color: var(--gray-light); }

/* Сводка расчёта: цена, три главных числа и сравнение ступеней тиража.
   Собрана в одну карточку рядом с параметрами — до 26 августа 2026 ступени
   лежали таблицей внизу страницы, и человек уходил за ними от кнопок.
   Рамка волосяная, заливки нет: это не плашка-акцент, а итог колонки. */
.price-box {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 22px 22px 16px;
  margin: 6px 0 22px;
}
.price-box .product__price { margin: 0 0 16px; }

.price-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.price-fact { background: var(--fill-lg); border-radius: var(--radius-sm); padding: 12px 14px; }
.price-fact span { display: block; font-size: 12.5px; color: var(--gray); margin-bottom: 3px; }
.price-fact b { font-size: 15.5px; }

/* Минимальная сумма заказа. Тихая подпись под ступенями: она объясняет,
   почему маленький тираж стоит одинаково, и в остальное время не мешает.
   Кегль и цвет — те же, что у подписи в `.price-fact`. */
.price-min { margin-top: 12px; font-size: 12.5px; color: var(--gray); }
.price-min:empty { display: none; }

/* Ступени тиража. Строка нажимается и ставит свой тираж — то же действие,
   что у кнопок наверху колонки, поэтому выбранная отмечена так же: кремом.
   Итог набран тёмным, а не оранжевым: единственный акцент колонки — цена
   сверху, четыре оранжевых числа под ней её же и съедают. */
.price-runs { margin-top: 6px; }
.price-run {
  width: 100%; text-align: left;
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: baseline; gap: 14px;
  padding: 11px 12px;
  border-radius: var(--r-control);
  transition: .16s;
}
.price-run b { font-size: 14.5px; }
.price-run em { font-style: normal; font-size: 13px; color: var(--gray); }
.price-run i { font-style: normal; font-size: 14.5px; font-weight: 700; }
.price-run:hover { background: var(--fill-lg); }
.price-run.is-active { background: var(--cream-sm); }
.price-run.is-active i { color: var(--orange); }

/* Хвост карточки: описание (только у позиций без расчёта) и вопросы.
   Скрытые разделы выпадают вместе со своим отступом — пробела не остаётся.

   Отступ сверху такой же, как над развилкой: блок способов отделён с обеих
   сторон одинаково, иначе он липнет к вопросам снизу. Полями, а не padding —
   причина та же, что у .fork выше.

   `auto` по бокам обязательно. Этот блок ещё и `.container`, а тому задано
   `margin: 0 auto` — сокращённая запись отсюда обнуляет его, и на экране
   шире 1440 хвост перестаёт центроваться и липнет к левому краю, пока
   развилка над ним стоит по центру. Ровно это и случилось 26 августа: на
   моём окне в 1400 расхождения не было, потому что там контейнер и так уже
   уже своей предельной ширины. */
.product-tail { display: grid; gap: 48px; margin: 54px auto 60px; }
/* Описание товара стоит во всю ширину контейнера, без сайдбара, — это 1392 px
   на экране 1440, строка в сто семьдесят знаков. Поэтому здесь мера строки
   остаётся, хотя у остального `.prose` она снята 11 сентября 2026: там
   колонку сужает сайдбар, здесь нет. */
.product-tail .prose > p, .product-tail .prose > ul, .product-tail .prose > ol { max-width: 720px; }
.product__opts { display: grid; gap: 16px; margin: 26px 0; }
.product__opts label { font-size: 13.5px; font-weight: 700; display: block; margin-bottom: 7px; }
.product__actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* Бейджи сняты с экрана 25 августа 2026 по просьбе заказчицы: «и так инфы
   много, куда ещё это». На карточке они стояли над параметрами и повторяли
   то, что страница и так говорит подробнее, — срок есть в таблице «Стоимость
   и сроки», проверка макета расписана в развилке, «считает менеджер» видно по
   самой форме заявки.

   Разметка оставлена во всех шаблонах: понадобятся снова — снимается одна
   строка ниже, и они вернутся везде разом. Стиль самой плашки тоже оставлен,
   на нём же держится вид бейджа, если блок включат. */
.badges { display: none; }
.badge { background: var(--fill); color: var(--gray); font-size: 13px; font-weight: 600; padding: 8px 16px; border-radius: var(--r-pill); }

.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.steps--manager { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.step { background: var(--white); border-radius: var(--radius); padding: 26px; border: 1px solid var(--line); }
.step__num { font-size: 30px; font-weight: 800; color: var(--orange); line-height: 1; margin-bottom: 12px; letter-spacing: -.02em; }
.step h3 { font-size: 17px; margin-bottom: 8px; }
.step p { font-size: 14px; color: var(--gray); }

/* Развилка внутри единого блока процесса. Заливка серая, а не кремовая:
   2 сентября 2026 цвет снят со всех карточек «эта не такая, как
   остальные» разом. Номер шага перекрашен в тёмный оранжевый — на
   #eaeae6 обычный даёт 2,74 при пороге 3:1, ровно как на кремовой. */
.step--fork { background: var(--fill); border-color: transparent; }
.step--fork .step__num { color: var(--orange-dark); }
.step__fork { margin-top: 4px; }
.step__fork li {
  position: relative; padding-left: 18px; font-size: 14px;
  color: var(--gray); margin-bottom: 4px;
}
.step__fork li::before {
  content: ''; position: absolute; left: 4px; top: 8px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--orange);
}

/* Колонок столько, сколько чисел в `SITE.stats`. Жёсткие три стояли до
   2 сентября 2026, когда «5000 заказов в год» убрали по ответу заказчика и
   третья колонка осталась пустой дырой. Числа задаёт контент, сетка под них
   подстраивается. */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 30px 0; }
.stat { background: var(--cream); border-radius: var(--radius); padding: 26px; }
/* Кегль ужат с 38 до 30: в плитках теперь не только числа, но и короткие
   фразы («1–2 дня», «Цена сразу»), и на 38 они переносились по слогам */
.stat b { display: block; font-size: 30px; color: var(--orange); line-height: 1.1; margin-bottom: 8px; }
.stat span { font-size: 14px; color: var(--gray); }

/* Главная: те же цифры без плиток — число тёмным и крупно, строка сжата
   к середине полосы. Плитки там читались как третья сетка карточек подряд
   после решений и каталога. На «О компании» они остаются: цифры идут одни
   вверху страницы, и полотно под ними держит блок. */
.stat-row--plain {
  max-width: 760px;
  margin: 8px auto 40px;
  gap: 24px;
}
.stat-row--plain .stat { background: none; padding: 0; text-align: center; }
.stat-row--plain .stat b {
  font-size: clamp(38px, 5vw, 64px);
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--ink);
  margin-bottom: 2px;
}
.stat-row--plain .stat span { font-size: 15px; }

/* ============================================================
   18  Выбор продукта и пути к макету
   ============================================================ */
/* Шаг сетки тот же, что в каталоге на главной: страницы стоят рядом в одном
   маршруте, и ритм плиток не должен отличаться на два пикселя */
.pick-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.layout-ribbon {
  position: relative;
  margin-inline: calc((100vw - min(var(--container), 100vw)) / -2 - 40px);
  padding-left: calc((100vw - min(var(--container), 100vw)) / 2 + 40px);
  overflow: hidden;
  /* Лента режет всё, что вышло за её рамку, а карточка на наведении
     приподнимается на 4 px и отбрасывает тень в 44 px размытия — сверху ей
     нужно около 12 px, снизу около 32. Без запаса тень обрубалась ровной
     линией по краю ленты (замечено 2 сентября 2026).

     Запас даёт не эта рамка, а поля самой прокручиваемой полосы ниже: у неё
     `overflow-x: auto`, а значит по вертикали она тоже режет, и поля должны
     быть именно у неё. Здесь остаётся снять лишнюю высоту отрицательными
     полями — иначе раздел разъедет на 60 px. Тот же приём у ленты отзывов
     (`.reviews__track`, раздел 11).

     Снизу снимаем не всё: 14 px из 40 остаются под тень. Отрицательное поле
     в -40 px возвращало стрелки листания вплотную к нижнему краю карточки,
     и оранжевая тень наведения ложилась прямо на них — особенно заметно на
     погашенной стрелке, она полупрозрачная и тень просвечивает насквозь
     (замечено 2 сентября 2026). Теперь до стрелок 14 + 26 = 40 px, а тень
     достаёт на 32 (подъём 4 + сдвиг 14 + половина размытия 44). У отзывов
     этот же зазор 38 px. */
  margin-block: -20px -26px;
}
.layout-ribbon::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(15vw, 220px);
  pointer-events: none;
  background: linear-gradient(90deg, rgba(247, 247, 247, 0), var(--bg) 72%);
  transition: opacity .2s;
}
/* Кромка гаснет только там, где за ней ещё что-то есть. Класс ставит JS
   главной, как у отзывов: докрутили ленту до конца — размывать нечего, и
   градиент над последней карточкой читается грязью. */
.layout-ribbon:not(.has-next)::after { opacity: 0; }

/* Стрелки листания стоят под лентой слева — там же, где у отзывов
   (F27, 2 сентября 2026). Отступ и вид берёт общий `.slider-nav`,
   раздел 11. */
.pick-grid--ribbon {
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* Поля кругом — это место под тень поднятой карточки, а не отступ:
     полоса режет по вертикали (`overflow-x: auto` включает и вертикальное
     обрезание), и без запаса тень обрубается ровной линией. Слева запас
     возвращается отрицательным полем, чтобы первая карточка по-прежнему
     стояла ровно по краю контейнера, а `scroll-padding-left` держит на этой
     же линии снап: без него лента прилипала бы на 20 px левее. */
  padding: 20px max(48px, calc((100vw - min(var(--container), 100vw)) / 2 + 136px)) 40px 20px;
  margin-left: -20px;
  scroll-padding-left: 20px;
  scrollbar-width: none;
}
.pick-grid--ribbon::-webkit-scrollbar { display: none; }
/* Карточка ленты уже, чем в каталоге, и в ней одно название (F31,
   2 сентября 2026): лента — приглашение, а не выбор, и десять позиций должны
   читаться лентой, а не таблицей. Ориентир — пять карточек в контейнере
   1440 при зазоре 20 px, шестая выглядывает краем и сама говорит, что список
   не кончился. Снимок при этом не трогаем: пропорция 5:4 и заливка в край —
   весь приём, ради которого лента выглядит лентой. */
.pick-grid--ribbon .pick {
  flex: 0 0 clamp(220px, 18vw, 260px);
  scroll-snap-align: start;
}
/* Подпись в одну-две строки, поэтому поля меньше каталожных, а название
   выключено по центру: у «Бирок» строка одна, у «Листовок, флаеров,
   сертификатов» две, а высоту карточки в ряду держит самая высокая. */
.pick-grid--ribbon .pick__body {
  padding: 14px 16px 16px;
  min-height: 66px;
  display: flex; align-items: center;
}
.pick {
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--white); transition: .2s;
}
.pick:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
/* Гнездо под фотографию изделия: пропорция 5:4 и кадр в край, как во всех
   сетках каталога. Подложка и выключка по центру остаются для второго
   случая — когда снимка нет и показывается плоский макет шаблона. */
.pick__img { background: var(--fill-lg); display: flex; align-items: center; justify-content: center; aspect-ratio: 5 / 4; }
.pick__img img { max-width: 100%; max-height: 100%; box-shadow: var(--shadow); }
.pick__img img.photo { width: 100%; height: 100%; object-fit: cover; }
.pick__body { padding: 16px 18px 18px; }
.pick__body b { display: block; font-size: 16px; margin-bottom: 4px; }
.pick__body span { display: block; font-size: 13px; color: var(--gray); }
.pick__body em { display: block; font-style: normal; font-size: 13.5px; font-weight: 700; color: var(--orange); margin-top: 8px; }
/* Три пути к макету: загрузить, собрать онлайн, отдать дизайнеру.

   Собраны по центру и одинаковыми: это три равных выбора, и любая разница в
   оформлении читается как подсказка «бери вот этот». По той же причине
   у карточки дизайнера больше нет серого значка — он делал третий путь
   отключённым на вид, хотя для клиента без макета он как раз главный.
   Высота набрана полями, а не минимальной высотой: описания разной длины,
   и жёсткая высота оставила бы у короткого дыру снизу. */
.ways { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.way {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 36px 26px 32px;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  text-align: center; transition: .2s; background: var(--white);
}
.way:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.way__ic {
  width: 58px; height: 58px; border-radius: 16px; background: var(--cream); color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
.way__ic svg { width: 26px; height: 26px; }
/* Текст растягивается, ссылка прижимается к низу: описания разной длины,
   и без этого «Проверить макет» и «Выбрать шаблон» стояли бы на разной
   высоте — три равных пути перестали бы выглядеть равными. */
.way__body { flex: 1; display: flex; flex-direction: column; gap: 8px; }
.way h3 { font-size: 17.5px; }
.way p { font-size: 14px; color: var(--gray); max-width: 330px; }
.way__go { font-weight: 700; color: var(--orange); font-size: 14.5px; display: flex; gap: 6px; align-items: center; }

/* Развилка на карточке продукта: три способа во всю ширину под первым
   экраном. Это равнозначный выбор, а не хвост колонки параметров, — в узкой
   колонке он читался как список второстепенных ссылок. */
/* Отступ полями, а не padding: этот блок одновременно `.container`, а в
   адаптиве контейнеру задан `padding: 0 24px` сокращённой записью — она
   обнуляет любой вертикальный padding отсюда. Старые 6px сверху по этой же
   причине не работали ни на одном экране уже, вероятно, месяц. */
.fork { margin-top: 54px; }
/* Заголовок раздела на карточке продукта. Один класс на оба — «Способ
   подготовки макета» и «Частые вопросы»: два соседних заголовка, набранных
   по разным правилам, читаются как сбитая вёрстка даже когда левые края
   совпадают до пикселя. Совпадали: заказчица 26 августа приняла их за
   съехавшие, потому что текст в карточках по центру, а заголовок под ними
   был слева. */
.block-title { font-size: 30px; text-align: center; margin-bottom: 26px; }

/* Вертикальная раскладка в узкой колонке продукта */
.ways--stack { grid-template-columns: 1fr; gap: 12px; }
.ways--stack .way {
  display: grid; grid-template-columns: 46px 1fr; gap: 16px;
  align-items: start; padding: 18px; width: 100%;
}
.ways--stack .way h3 { margin-bottom: 4px; }
.ways--stack .way__go { grid-column: 2; margin-top: 4px; }

.tpl-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }

/* Шаблоны выбираются в отдельном окне: на странице сетка занимала больше
   места, чем весь заказ выше, а половине людей она не нужна вовсе — те
   пришли с готовым файлом. Колонок здесь три, как на странице, но окно ниже
   экрана, поэтому список прокручивается внутри себя. */
.tpl-grid--modal { margin-top: 20px; }
/* Граница между шаблонами своего листа и свёрстанными под другой (A14):
   заголовок с линией через всю сетку, а не отдельное окно — открыть можно
   и те и другие */
.tpl-group {
  grid-column: 1 / -1; display: grid; gap: 4px;
  margin-top: 8px; padding-top: 20px; border-top: 1px solid var(--line);
}
.tpl-group b { font-size: 15px; }
.tpl-group span { font-size: 13.5px; color: var(--gray); }
.tpl {
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  transition: .2s; background: var(--white); text-align: left;
}
.tpl:hover { border-color: var(--orange); transform: translateY(-4px); box-shadow: var(--shadow-hover); }
.tpl__img { aspect-ratio: 90 / 50; position: relative; background: var(--fill-lg); display: flex; align-items: center; justify-content: center; }
.tpl__img img { width: 100%; height: 100%; object-fit: contain; }
.tpl__body { padding: 14px 16px; display: flex; justify-content: space-between; align-items: center; }
.tpl__body b { font-size: 14.5px; }
.tpl__body span { font-size: 13px; color: var(--orange); font-weight: 700; }
/* Вторая часть названия — уточнение варианта, см. tplTitleHtml (data.js) */
.tpl__body .tpl-variant { display: block; font-size: 13px; font-weight: 400; color: var(--gray); }

/* Лента работ: свой блок на главной, перед отзывами.
   Переход в портфолио выравнивается по нижнему краю заголовка: слева две
   строки (надзаголовок и заголовок), и по базовой линии ссылка вставала бы
   вровень с надзаголовком, то есть выше. Сама ссылка — общая
   `.section-head__more`, раздел 2: три ленты на одной странице открывают
   «всё остальное» одинаково. */
.works-head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 20px; margin: 54px 0 20px;
}
.works-head h3 { font-size: 22px; }
.works-ribbon { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
/* На главной кадр квадратный, а не вертикальный, как в портфолио: там сетка
   работ — сам смысл страницы, здесь это один блок среди семи, и колонка
   в полторы высоты подмяла бы под себя всю главную. Подпись тут одна строка
   с названием, без второй. */
.works-ribbon .work { aspect-ratio: 1 / 1; }

/* Две двери раздела «Работа с макетом онлайн»: закрывают его под лентой
   карточек. «Все изделия» вынесены в шапку раздела, чтобы не выглядеть
   третьим способом работы с макетом. */
.layout-doors { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 28px; }

/* ============================================================
   19  Параметры заказа
   ============================================================ */
.opt-group { margin-bottom: 20px; }
.opt-label { font-size: 13px; font-weight: 700; color: var(--gray); margin-bottom: 9px; }
.opt-hint { font-size: 12.5px; color: var(--gray-light); margin-top: 7px; }
.opt-hint.is-error { color: var(--err); }

.opt-btns { display: flex; flex-wrap: wrap; gap: 8px; }
.opt-btn {
  padding: 12px 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--white);
  font-size: 15px; font-weight: 600;
  transition: .16s;
}
.opt-btn:hover { border-color: var(--line-strong); }
.opt-btn.is-active { border-color: var(--orange); background: var(--cream-sm); color: var(--orange-dark); }

.opt-custom { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.opt-custom__field { position: relative; display: flex; }
.opt-custom .input { width: 160px; height: 46px; padding-right: 40px; }

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

   Зелёный отсюда убран 26 августа 2026. Зелёная обводка среди оранжевых
   кнопок выбора выглядела чужой: рядом с «100 шт» в кремовой плашке поле
   вдруг становилось цветом из другой системы. Принятый ввод — тот же выбор,
   что и нажатая ступень, и отмечается он так же.

   Галочка выровнена растяжкой, а не сдвигом на половину высоты: 17 пикселей
   внутри поля в 46 давали дробную координату, и значок размывался. */
.opt-custom__ok {
  position: absolute; right: 13px; top: 0; bottom: 0;
  width: 18px; color: var(--orange);
  display: flex; align-items: center;
  transform: scale(.6);
  opacity: 0; transition: .16s; pointer-events: none;
}
.opt-custom__ok svg { width: 100%; height: auto; }
.input.is-ok { border-color: var(--orange); }
.input.is-ok ~ .opt-custom__ok { opacity: 1; transform: none; }
/* Только подпись «шт» рядом с полем. Раньше селектор был без `>` и цеплял
   заодно галочку внутри поля: она красилась серым и мельчала, поэтому
   подтверждение ввода выглядело блёклым знаком непонятно чего. */
.opt-custom > span { font-size: 13.5px; color: var(--gray); }
/* Ручной тираж — без системных стрелок */
.opt-custom input::-webkit-outer-spin-button,
.opt-custom input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.opt-custom input { -moz-appearance: textfield; }

.opt-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.opt-card {
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--white);
  text-align: left;
  transition: .16s;
}
.opt-card b { display: block; font-size: 15.5px; font-weight: 700; }
.opt-card span { display: block; font-size: 13px; color: var(--gray); margin-top: 2px; }
.opt-card:hover { border-color: var(--line-strong); }

/* Карточка с силуэтом: фигура сверху, подписи под ней, всё по центру.
   Место под фигуру фиксировано, иначе карточки прыгают по высоте — у A4 и A6
   силуэты разной величины, и это как раз то, что нужно показать. */
.opt-card--shape { text-align: center; padding: 14px 16px 13px; }
.opt-card__fig {
  display: flex; align-items: flex-end; justify-content: center;
  height: 64px; margin-bottom: 10px;
}
.opt-shape { fill: var(--gray-light); transition: fill .16s; }
.opt-card:hover .opt-shape { fill: var(--gray); }
.opt-card.is-active .opt-shape { fill: var(--orange); }
.opt-card.is-active { border-color: var(--orange); background: var(--cream-sm); }
.opt-card.is-active b { color: var(--orange); }

/* Срочный заказ */
.opt-toggle {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 18px; margin-bottom: 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  cursor: pointer; transition: .16s;
}
.opt-toggle:hover { border-color: var(--line-strong); }
.opt-toggle.is-active { border-color: var(--orange); background: var(--cream-sm); }
.opt-toggle input { display: none; }
.opt-toggle__box {
  width: 24px; height: 24px; flex-shrink: 0;
  border: 1px solid var(--line-strong); border-radius: 6px;
  background: var(--white);
  display: flex; align-items: center; justify-content: center;
  color: transparent; transition: .16s;
}
.opt-toggle__box svg { width: 15px; height: 15px; }
.opt-toggle.is-active .opt-toggle__box { background: var(--orange); border-color: var(--orange); color: var(--white); }
.opt-toggle__txt b { display: block; font-size: 15px; }
.opt-toggle__txt em { font-style: normal; font-size: 13px; color: var(--gray); }

/* Детали — визуально тише основных полей */
.opt-more {
  margin-top: 26px; padding: 22px;
  background: var(--fill-lg); border-radius: var(--radius);
}
.opt-more__head {
  font-size: 13px; font-weight: 700; color: var(--gray-light);
  text-transform: uppercase; letter-spacing: .06em; margin-bottom: 18px;
}
.opt-more .opt-group:last-of-type { margin-bottom: 0; }
.opt-more .input { background-color: var(--white); }
.opt-more__total {
  margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 14.5px; color: var(--gray);
}
.opt-more__total b { color: var(--ink); font-size: 16px; }

/* Несочетаемые параметры */
.opt-warn {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 18px; margin: 4px 0 20px;
  background: var(--warn-bg); border-radius: var(--r-control);
}
.opt-warn__ic {
  width: 26px; height: 26px; flex-shrink: 0; border-radius: 50%;
  background: var(--warn); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 15px;
}
/* Текст забирает всё свободное место, кнопка прижата к правому краю */
.opt-warn > div { flex: 1; min-width: 0; }
.opt-warn b { display: block; font-size: 14.5px; }
.opt-warn em { font-style: normal; font-size: 13px; color: var(--gray); }
.opt-warn .btn { flex-shrink: 0; height: 40px; padding: 0 16px; font-size: 13.5px; }

/* Обязательное не выбрано, а человек уже пошёл дальше (C61): рамка поля
   тем же цветом, что и плашка под путями, — видно, куда смотреть */
.opt-group.is-need .dd__btn,
.opt-group.is-need .opt-card { border-color: var(--warn); }
.ways-need { margin: 18px 0 0; }

/* «Что печатаем» над кнопкой «В корзину» — окно заказа в редакторе и
   страница проверки файла (C92). Одна строка мелким шрифтом, не замечание:
   параметры перед глазами там, куда смотрят перед нажатием. Невыбранное —
   цветом плашки выше, и поле для него стоит под строкой. */
.order-line {
  display: flex; align-items: baseline; gap: 16px;
  margin-top: 24px; font-size: 13.5px; line-height: 1.6; color: var(--gray);
}
.order-line p { flex: 1; min-width: 0; margin: 0; }
.order-line b { color: var(--ink); font-weight: 700; margin-right: 8px; }
.order-line em { font-style: normal; font-weight: 600; color: var(--warn); }
.order-line__sum { color: var(--ink); font-weight: 700; white-space: nowrap; }
.order-line__opt-sum { float: right; margin-left: 16px; color: var(--gray); white-space: nowrap; }
.order-line__need { margin: 16px 0 0; }
.order-line__edit {
  flex-shrink: 0; font-size: 13px; font-weight: 600; color: var(--orange-dark);
  text-decoration: underline; text-underline-offset: 2px;
}
.order-line__edit:hover { color: var(--ink); }
.order-line__pick { max-width: 440px; margin: 14px 0 0; }

#primaryOpts { margin-top: 4px; }

/* ============================================================
   20  Заявка менеджеру
   ============================================================ */
/* С чем пришли: название позиции, тираж со сроком и параметры печати.

   До 26 августа 2026 это была одна строка оранжевым через точку — восемь
   значений подряд, которые никто не дочитывал. Уровни разведены не цветом,
   а весом и кеглем: название держит вес, тираж и срок идут строкой ниже,
   параметры — мелким серым. Оранжевый отсюда убран совсем: это не действие
   и не выбор, а справка о том, что человек уже выбрал. */
/* Выход из заявки: строка под полем «Что нужно» — человек мог нажать
   «Заказать дизайн у нас», ещё не зная, что нам вообще заказывают, и без
   неё из окна ведёт только крестик. Не кнопка — действие в окне одно, и это
   «Отправить заявку»; поэтому и кегль мелкий, и цвет серый.
   Почему именно под полем, а не наверху, — в комментарии у MODAL_ESCAPE. */
.rq-escape {
  /* Подтянута к полю «Что нужно»: это подпись к нему, а не отдельная строка
     формы. Отрицательный отступ съедает воздух, который `.rq .ed-field`
     ставит после каждой группы. */
  margin: -13px 0 22px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--gray-light);
}
/* Вопрос и переход — одной строкой и мельче полей: это запасной выход, а не
   второе действие окна. Оранжевым в кегле 14,5 со стрелкой (как ссылки
   каталога) он спорил с «Отправить заявку» — заказчица 27 августа 2026:
   «слишком много на себя берёт, это доп-опция». Стрелка убрана там же. */
.rq-escape .cat-card__link { font-size: 13px; font-weight: 600; margin-left: 5px; }

.rq__context {
  background: var(--cream); padding: 14px 18px;
  border-radius: var(--r-control); margin-bottom: 22px;
}
.rq__context b { display: block; font-size: 16px; }
.rq__context span { display: block; font-size: 14px; font-weight: 600; margin-top: 2px; }
.rq__context em {
  display: block; font-style: normal;
  font-size: 13px; color: var(--gray); line-height: 1.45;
}
/* Между «что заказываем» и «как печатаем» — воздух, а не ещё одна строка */
.rq__context em:first-of-type { margin-top: 10px; }
/* Заголовок блока формы. С 9 сентября 2026 их два — «Как с вами связаться»
   и «О заказе», — и между ними волосяная линия: до этого имя, телефон и
   вопросы по заказу шли одним столбцом и читались одним требованием.

   Линия одна на всю форму. Больше линий дробят её на полоски и делают
   длиннее на вид — ровно то, от чего уходили. */
.rq__legend {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--gray-light); margin-bottom: 14px;
}
.rq__legend--part {
  border-top: 1px solid var(--line);
  padding-top: 24px; margin-top: 4px;
}
/* «Заполните, что знаете» — разрешение не знать ответа, а не вторая подпись:
   обычным регистром и весом, тем же серым, что подсказка под плашкой файла.
   С заглавной с 11 сентября 2026: это отдельная фраза, а не продолжение
   заголовка, — со строчной она читалась опечаткой.

   Второй строкой, а не справа от заголовка: справа она помещается в окне
   заявки (620 px) и не помещается в колонке карточки (320), а ширина здесь
   зависит от места, а не от ширины экрана — медиазапросом это не лечится. */
.rq__legend--part em {
  display: block; margin-top: 6px;
  font-style: normal; font-weight: 500; font-size: 12.5px; line-height: 1.5;
  text-transform: none; letter-spacing: 0;
  color: var(--gray);
}
/* Крупность и ритм — по образцу заказчицы от 28 августа 2026.

   Поля заявки брали размер у редактора: класс `.ed-field` задаёт подпись в
   12 px жирным и поле высотой 38. В панели редактора это правильно, там два
   десятка полей на экран. В окне заявки полей пять, и они — всё, ради чего
   окно открыли: подпись набрана обычным весом и читается подписью, поле выше
   в полтора раза, между группами воздух вдвое против прежнего. Правила
   scoped на `.rq`, редактора не касаются. */
.rq .ed-field { margin-bottom: 22px; }
.rq .ed-field > label {
  font-size: 14px; font-weight: 500; color: var(--gray); margin-bottom: 9px;
}
.rq .ed-field .input,
.rq .ed-field select.input,
.rq .ed-field .dd__btn { height: 54px; font-size: 15px; padding: 0 18px; }
.rq .ed-field .textarea { height: 150px; font-size: 15px; padding: 16px 18px; }
/* Две колонки имени и телефона отбиты так же, как строки формы */
.rq .ed-grid2 { gap: 16px; }

/* Каналы встают в одну строку: перенос делит их на группы, которых в списке
   нет. Поэтому кнопки узкие, а текст в них не переносится. С 29 августа
   2026 их четыре, а не пять — Viber убран, — и строка стала свободнее. */
.rq__channels { display: flex; flex-wrap: wrap; gap: 8px; }
/* Заливка без обводки — как в поповере телефона: выбор канала не должен
   спорить за внимание с кнопкой отправки. Ростом тег чуть ниже поля: рядом
   с ним видно, что это выбор из готового, а не строка для ввода. */
.rq__ch {
  display: inline-flex; align-items: center;
  height: 46px; padding: 0 18px;
  border-radius: var(--r-pill);
  background: var(--fill);
  font-size: 14.5px; font-weight: 600;
  white-space: nowrap;
  transition: .16s;
}
.rq__ch:hover { background: var(--fill-hover); }
.rq__ch.is-active { background: var(--cream-sm); color: var(--orange-dark); }
/* Max выглядит как рабочий канал (финальный вид), но без data-ch — клик по
   нему не выбирает канал, ниже это только курсор и подтверждает. */
.rq__ch--soon { cursor: default; }

/* Вопросы о заказе с готовыми ответами — 11 сентября 2026, разметка в
   `briefFieldsHtml` (`app.js`).

   Выпадающий список — общий `.dd`, но в заявке он выглядит полем: та же
   серая заливка (правило `.rq .input` в разделе форм), выбранное полужирным,
   как набранный текст, а пока ничего не выбрано — подсказка обычным весом. */
.rq .dd__val { font-weight: 600; color: var(--ink); }
.rq .dd__val.is-empty { font-weight: 400; color: var(--gray); }
/* Фокус — оранжевой рамкой, как у строки ввода, а не синим кольцом браузера */
.rq .dd__btn:focus { outline: none; border-color: var(--orange); }
/* Выбранный пункт — серой заливкой, как наведение, а не кремовой с
   оранжевым: заказчица 11 сентября 2026 увидела в одном окне кремовый
   выбранный пункт, в другом серый наведённый и прочла это как два разных
   списка. Оранжевый в форме остаётся за кнопкой отправки и фокусом. */
.rq .dd__opt.is-active { background: var(--fill); color: var(--ink); }
/* «Свой размер» открывает строку прямо под списком — продолжение ответа */
.rq .rq-own { margin-top: 8px; }
/* «можно несколько» у ряда кнопок: без неё кнопки читаются как каналы
   связи выше, где выбирают один */
.rq .ed-field > label i { font-weight: 400; color: var(--gray-light); }

/* Поле даты: строка с подсказкой и значком, календарь всплывает под ней.
   Прижат вправо, к значку: в строке с тиражом поле даты стоит правой
   колонкой, и календарь, отложенный от левого края, вылез бы за окно. */
.rq-date { position: relative; }
.rq .rq-date .input { padding-right: 48px; }
.rq-date__ic {
  position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
  display: flex; color: var(--orange); pointer-events: none;
}
.rq-date__ic svg { width: 18px; height: 18px; }

/* Слой — как у списка `.dd__list`: та же рамка, скругление и тень */
.cal {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
  width: 300px; max-width: 100%;
  padding: 12px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 18px 44px rgba(0, 0, 0, .14);
}
.cal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.cal__head b { font-size: 14.5px; font-weight: 600; }
.cal__nav {
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 8px; color: var(--ink); transition: .12s;
}
.cal__nav svg { width: 16px; height: 16px; }
.cal__nav:hover { background: var(--fill); }
.cal__nav:disabled { color: var(--gray-light); background: none; cursor: default; }
.cal__week, .cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
/* Дни недели набраны как заголовок группы в `.dd__head` */
.cal__week span {
  padding: 6px 0; text-align: center;
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--gray-light);
}
/* Состояния дня — как у пункта списка `.dd__opt` */
.cal__day { height: 36px; border-radius: 8px; font-size: 14px; transition: .12s; }
.cal__day:hover { background: var(--fill); }
.cal__day.is-today { color: var(--orange-dark); font-weight: 700; }
.cal__day.is-active { background: var(--cream-sm); color: var(--orange-dark); font-weight: 600; }
.cal__day:disabled { color: var(--gray-light); background: none; cursor: default; }

/* «Прикрепить макет или образец» — одна плашка во всю ширину.

   Пунктир означает «сюда кладут файл», ширина ставит плашку в общий ритм
   формы: те же края, что у полей и у кнопки отправки. По весу с «Отправить
   заявку» она не спорит — рамка волосяная, заливки нет, и прикладывать файл
   необязательно, так и написано в самой строке.

   Плашек тут было две: строка-переключатель и такая же пунктирная зона
   загрузки, раскрывавшаяся под ней. Сведены в одну 9 сентября 2026, разбор —
   в комментарии к разметке (`requestFormHtml`, app.js). */
.rq__attach { position: relative; margin: 0 0 22px; }
.rq__file {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  text-align: left;
  padding: 18px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-control);
  cursor: pointer; transition: .16s;
}
/* Наведение и файл над плашкой — одно состояние: «отпустите здесь» */
.rq__file:hover, .rq__file.is-over { border-color: var(--orange); background: var(--cream); }
.rq__file.is-over { border-style: solid; }
/* Файл принят с оговоркой или не принят совсем — причина стоит второй
   строкой в самой плашке, цвет берём из состояний дизайн-системы */
.rq__file.is-warn { border-color: var(--warn); background: var(--warn-bg); }
.rq__file.is-warn .rq__file-txt em { color: var(--warn); }
.rq__file.is-error { border-color: var(--err); background: var(--err-bg); }
.rq__file.is-error .rq__file-txt em { color: var(--err); }
.rq__file-ic {
  width: 42px; height: 42px; flex-shrink: 0;
  border-radius: 10px; background: var(--cream); color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
.rq__file-txt b { display: block; font-size: 14.5px; }
/* «необязательно» — тихая приписка к заголовку зоны, не вторая подпись */
.rq__file-txt b i {
  font-style: normal; font-weight: 500; font-size: 13.5px; color: var(--gray-light);
}
.rq__file-txt em { font-style: normal; font-size: 12.5px; color: var(--gray); }
/* «можно перетащить сюда» — только там, где есть мышь: на телефоне это
   лишняя строка о невозможном действии */
.rq__file-txt em i { font-style: normal; }
/* «Убрать» появляется вместе с приложенным файлом и живёт в углу плашки:
   клик по ней самой открывает выбор файла заново, а убрать — отдельное
   действие, и путать их нельзя */
.rq__file-del {
  position: absolute; top: 9px; right: 10px;
  padding: 4px 8px; border-radius: 8px;
  font-size: 12.5px; font-weight: 600; color: var(--gray);
  transition: .16s;
}
.rq__file-del:hover { color: var(--orange); background: var(--white); }
/* Ссылка на требования к макетам под плашкой: видна только тому,
   кто файл и правда приложил. */
.rq__hint { margin-top: 10px; font-size: 12.5px; line-height: 1.6; color: var(--gray); }
.rq__hint a { color: var(--orange); font-weight: 700; }

/* Ловушка для ботов: убрана из потока и с экрана, но не display:none и не
   hidden — скрипты такие поля пропускают, а это должны заполнить. */
.rq__trap {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}

.rq__err {
  margin: 10px 0; padding: 11px 15px;
  border-radius: var(--r-control);
  background: var(--err-bg); color: var(--err); font-size: 14px;
}

/* Шапка панели заявки — одна на модалку и на карточку товара.

   Раньше их было три: в модалке заголовок отбивался от полей восемью
   пикселями и при этом висел под сорока шестью пустыми сверху, на карточке
   у него была своя пара классов, а длинное название в модалке заезжало под
   крестик. Теперь правило одно: заголовок, под ним пояснение, ниже — воздух
   до первого поля, справа — место под крестик. */
/* Между заголовком и первым полем воздуха больше, чем между полями: так
   видно, что заголовок — не подпись к первому из них */
.rq-head { margin-bottom: 30px; }
.rq-head h2, .rq-head h3 { margin: 0; }
.rq-head h3 { font-size: 22px; }
.rq-head p { margin-top: 8px; font-size: 14.5px; line-height: 1.5; color: var(--gray); }

/* Отправка — самое крупное в окне: кнопка выше поля, и после плашки с
   файлом отбита ровно так же, как отбиты друг от друга группы полей */
.rq .form__submit { margin-top: 10px; }
.rq .form__submit .btn { height: 58px; font-size: 16px; }

/* Форма прямо на карточке продукта */
.rq-inline {
  display: block;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 30px;
  background: var(--white);
}

/* ============================================================
   21  Препресс-проверка
   ============================================================ */
.pf-drop {
  border: 2px dashed var(--line-strong); border-radius: var(--radius-lg);
  padding: 56px 30px; text-align: center; background: var(--fill-lg); transition: .2s;
  cursor: pointer;
}
.pf-drop.is-over { border-color: var(--orange); background: var(--cream); }
.pf-drop h3 { margin-bottom: 8px; }
.pf-drop p { color: var(--gray); font-size: 14.5px; }
.pf-drop__ic {
  width: 72px; height: 72px; border-radius: 12px; background: var(--cream); color: var(--orange);
  display: flex; align-items: center; justify-content: center; margin: 0 auto 18px;
}
.pf-drop__formats { font-size: 14.5px; line-height: 1.6; }
.pf-drop__formats b { color: var(--ink); }
.pf-drop__no { margin-top: 14px; font-size: 12.5px; color: var(--gray-light); }
.pf-alt { text-align: center; margin-top: 30px; color: var(--gray); font-size: 14.5px; }
.pf-alt a { color: var(--orange); font-weight: 700; }
/* Граница автопроверки: что меряем мы, что остаётся на стороне макета.
   Прижата к сетке карточек, потому что читается как их продолжение. */
.pf-note { margin-top: 16px; color: var(--gray); font-size: 13.5px; line-height: 1.6; }
.pf-note a { color: var(--orange); font-weight: 700; }

.pf-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 26px; }
.pf-stat { border-radius: var(--radius); padding: 20px; background: var(--fill-lg); }
.pf-stat b { display: block; font-size: 30px; line-height: 1; margin-bottom: 6px; }
.pf-stat span { font-size: 13.5px; color: var(--gray); }
.pf-stat--err b { color: var(--err); }
.pf-stat--warn b { color: var(--warn); }
.pf-stat--ok b { color: var(--ok); }

.pf-list { display: grid; gap: 12px; }
.pf-issue {
  display: grid; grid-template-columns: 40px 1fr auto; gap: 14px; align-items: start;
  padding: 18px; border-radius: var(--radius); border: 1px solid var(--line); background: var(--white);
}
.pf-issue__ic {
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 17px;
}
.pf-issue--error .pf-issue__ic { background: var(--err-bg); color: var(--err); }
.pf-issue--warn .pf-issue__ic { background: var(--warn-bg); color: var(--warn); }
.pf-issue--info .pf-issue__ic { background: var(--info-bg); color: var(--info); }
.pf-issue--ok .pf-issue__ic { background: var(--ok-bg); color: var(--ok); }
.pf-issue h4 { font-size: 16px; margin-bottom: 5px; }
.pf-issue p { font-size: 14px; color: var(--gray); }
/* Какой объект и на какой стороне — между заголовком и объяснением */
.pf-issue__obj { display: block; font-size: 12.5px; font-weight: 600; color: var(--ink); margin: -1px 0 5px; }
.pf-issue__fix { white-space: nowrap; height: 42px; padding: 0 20px; font-size: 14px; }
/* Два выхода у одной строки («Дорисовать вылеты» / «Растянуть на вылет») —
   столбиком одной ширины, первый главный */
.pf-issue__fixes { display: grid; gap: 8px; }
.pf-issue__fix--alt { border-color: transparent; color: var(--gray); }
.pf-issue.is-fixed { opacity: .55; }

/* Без заливки: внутри лежит своя серая подложка изделия (`.pv__sides`), и
   серое на сером сливалось в одно пятно. Рамка оставлена — она держит блок
   целым вместе с легендой (14 сентября 2026). */
.pf-preview { border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line); background: var(--white); padding: 20px; }
/* Правила для картинки внутри не пиши: здесь живёт разметка `Preview`, и она
   сама кладёт страницу файла в лист изделия. Прежнее `.pf-preview img` с
   max-height и width:auto доставало до `.pv__img` и сминало страницу внутри
   листа — файл выглядел меньше изделия и со своей тенью. */
.pf-preview-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; margin: 34px 0 16px;
}
.pf-preview-head h3 { font-size: 20px; }
.pf-file { display: flex; align-items: center; gap: 14px; padding: 16px; background: var(--fill-lg); border-radius: var(--radius); margin-bottom: 20px; }
.pf-file__ic {
  width: 44px; height: 44px; border-radius: 12px; background: var(--orange); color: var(--white);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 12px;
}
.pf-file b { display: block; font-size: 15px; }
.pf-file span { font-size: 13px; color: var(--gray); }

/* ============================================================
   22  Редактор макета

   Раскладка: верхняя панель, узкая навигация, выдвижная панель,
   холст с плавающими элементами управления, правая панель.
   Левая сторона добавляет контент, правая — структура и свойства.
   ============================================================ */
.ed { display: grid; grid-template-rows: auto 1fr; height: 100vh; overflow: hidden; }

/* ————— Верхняя панель ————— */
.ed-top {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding: 10px 18px; border-bottom: 1px solid var(--line); background: var(--white);
  /* Строка сетки `.ed` без этого не уже своего содержимого: шапка тянула
     редактор за край планшета вместе с «Заказать печать» (C88) */
  min-width: 0;
}
.ed-top__left { display: flex; align-items: center; gap: 16px; min-width: 0; }
/* Логотип с названием изделия — одна группа: на телефоне шапка
   раскладывается в ряды, и эта группа занимает первый целиком. */
.ed-top__id { display: flex; align-items: center; gap: 16px; min-width: 0; }
.ed-top .logo { transform: scale(.72); transform-origin: left center; margin-right: -14px; }
.ed-top__doc { min-width: 0; }
/* Название сжимается до многоточия, а не вылезает на соседей: у узкой
   шапки места ему достаётся ровно столько, сколько осталось от кнопок. */
.ed-top__name {
  font-size: 16px; font-weight: 800; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ed-top__spec {
  font-size: 12px; color: var(--gray);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.ed-top__right { display: flex; align-items: center; gap: 10px; }
.ed-top__order { display: flex; align-items: center; gap: 10px; }
.ed-chip {
  display: flex; align-items: center; gap: 6px; height: 38px; padding: 0 12px;
  border-radius: var(--r-control); background: var(--fill); color: var(--ink);
  font-size: 13px; font-weight: 600; transition: .16s;
}
.ed-chip:hover, .ed-chip.is-open { background: var(--cream-sm); color: var(--orange-dark); }
.ed-chip.is-open .ic { transform: rotate(180deg); }
.ed-chip .ic { transition: transform .16s; }
/* Служебная кнопка режима сборки шаблонов: стоит у названия макета и одета
   тише соседей — она не про заказ, а про нашу кухню, и уедет вместе с
   режимом. Пунктир говорит «временное» без единого лишнего слова. */
.ed-chip--dev {
  height: 30px; padding: 0 10px; font-size: 12px; font-weight: 600;
  background: transparent; color: var(--gray); border: 1px dashed var(--line);
}
.ed-chip--dev:hover { background: var(--fill); color: var(--ink); }
.ed-top__btn { height: 40px; padding: 0 18px; font-size: 14px; }
/* Гостю у «Сохранить проект»: тихая строка, а не третья кнопка — она
   напоминает о входе и не спорит с заказом */
.ed-top__hint {
  max-width: 190px; font-size: 12px; line-height: 1.35; font-weight: 600;
  color: var(--gray); text-align: right; transition: color .16s;
}
.ed-top__hint:hover { color: var(--orange-dark); }

/* ————— Тело ————— */
.ed-body { display: grid; grid-template-columns: 76px auto 1fr 340px; overflow: hidden; }
/* Колонки закреплены за панелями: закрытая выдвижная панель убирается из потока,
   и без этого холст с правой панелью съезжали на её место. */
.ed-nav { grid-column: 1; }
.ed-drawer { grid-column: 2; }
.ed-canvas { grid-column: 3; }
.ed-right { grid-column: 4; }

/* ————— Узкая навигация ————— */
.ed-nav {
  display: flex; flex-direction: column; justify-content: space-between;
  border-right: 1px solid var(--line); background: var(--white); padding: 8px 0; overflow-y: auto;
}
.ed-nav__main, .ed-nav__foot { display: grid; gap: 2px; padding: 0 6px; }
.ed-nav__foot { border-top: 1px solid var(--line); padding-top: 8px; margin-top: 8px; }
.ed-nav__btn {
  display: grid; justify-items: center; gap: 4px; padding: 9px 2px;
  border-radius: 12px; color: var(--gray); transition: .16s; width: 100%;
}
.ed-nav__btn span { font-size: 10.5px; font-weight: 600; line-height: 1.15; text-align: center; }
.ed-nav__btn:hover { background: var(--fill); color: var(--ink); }
.ed-nav__btn.is-active { background: var(--cream-sm); color: var(--orange-dark); }

/* ————— Выдвижная панель: часть раскладки, а не модалка ————— */
.ed-drawer {
  /* position нужен выбору страницы PDF: он ложится поверх панели, а не рядом */
  position: relative;
  width: 340px; display: flex; flex-direction: column; overflow: hidden;
  border-right: 1px solid var(--line); background: var(--white);
}
/* display:flex перебивает [hidden] — закрытая панель должна схлопывать колонку */
.ed-drawer[hidden] { display: none; }
.ed-drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 10px; flex-shrink: 0;
}
.ed-drawer__head h3 { font-size: 17px; font-weight: 800; }
.ed-icobtn {
  width: 30px; height: 30px; border-radius: 9px; color: var(--gray);
  display: flex; align-items: center; justify-content: center; transition: .16s;
}
.ed-icobtn:hover { background: var(--fill); color: var(--ink); }
.ed-drawer__body { overflow-y: auto; padding: 0 16px 20px; }
.ed-drawer__tools { display: grid; gap: 8px; margin-bottom: 14px; }

/* ————— Холст ————— */
.ed-canvas { position: relative; overflow: hidden; background: #eceff2; }
/* Центрируем макет полями, а не `justify-content: center`.

   С центрированием флексбокса лист, который больше окна, вылезает за
   контейнер в обе стороны, но прокрутка добирается только вправо и вниз:
   левый край и верх становятся недостижимы. На 200% половину макета
   посмотреть было нельзя. `margin: auto` центрирует так же, пока лист
   помещается, и честно отдаёт прокрутку, когда перестал. */
.ed-stagewrap {
  position: absolute; inset: 0; overflow: auto;
  display: flex;
  /* Поля держат макет в стороне от плавающих панелей: сверху панель
     управления, снизу карточки сторон и легенда. Иначе на обычном масштабе
     панель срезает угол листа. */
  padding: 74px 36px 150px;
  /* Одним пальцем — прокрутка, как было. Щипок браузеру не отдаём: он
     масштабировал бы всю страницу целиком, а нам нужен масштаб макета,
     его считает Editor.bindZoom. */
  touch-action: pan-x pan-y;
  overscroll-behavior: contain;
}
/* overflow скрывает всё, что вышло за вылет: на реальном листе это уходит
   в обрез. Побочный эффект — у объекта вплотную к краю обрезаются и ручки
   растягивания; такой объект двигают перетаскиванием и правят числами
   в панели свойств. Решено мириться, см. C6 в BACKLOG.md. */
/* `relative` — для слоя кадрирования: он ложится поверх листа и не
   срезается его вылетом (`.ed-crop`). */
.ed-sheet { flex: 0 0 auto; margin: auto; position: relative; }
.ed-stage {
  /* `z-index: 0` здесь не про порядок, а про границу: он делает лист
     контекстом наложения, и большие числа внутри — номера слоёв объектов,
     `9999` у технических линий — остаются его внутренним делом. Без этого
     линии всплывали над плавающей панелью масштаба и над выпадающими
     списками в шапке. Рядом с соседями по `.ed-canvas` ноль ничего не
     меняет: у легенды, карточек сторон и панели свойств свои тройки. */
  position: relative; z-index: 0; overflow: hidden;
  box-shadow: var(--shadow-sheet);
  user-select: none; touch-action: none;
  outline: 1px dashed rgba(240, 93, 32, .75); outline-offset: -1px;
}
.ed-stage.is-clean { outline: none; }
.ed-stage__bg, .ed-stage__bgimg { position: absolute; inset: 0; width: 100%; height: 100%; }
.ed-stage__bgimg { object-fit: cover; }

.ed-obj { position: absolute; cursor: move; }
.ed-obj.is-locked { cursor: default; }
/* Рамка выделения — одна и та же коробка у текста, фигуры, картинки и значка.
   Волосяная линия, без отступа наружу: рамка потолще уводила глаз на себя и
   закрывала край макета, по которому и надо судить о размере.

   Линия рисуется `outline`, а не `border`, и от этого лежит вплотную снаружи
   объекта, а не поверх его края. Разница не косметическая: поверх края
   оранжевая рамка на оранжевой заливке пропадала совсем — выглядело как
   «выделение не работает». Снаружи она всегда на бумаге и видна на любой
   краске. Скругление коробка повторяет — его задаёт разметка. */
.ed-sel__box {
  position: absolute; inset: 0; pointer-events: none;
  outline: 1px solid var(--orange);
}
/* Рамка выделения на пустом месте холста. Держится на `position: fixed` и
   экранных координатах: холст прокручивается и масштабируется, а рамка
   живёт поверх страницы и от этого не зависит. */
.ed-marquee {
  position: fixed; z-index: 200; pointer-events: none;
  border: 1px solid var(--orange);
  background: var(--select-bg);
  border-radius: 2px;
}
/* Перенос строк считает движок (`Editor.textLines`), сюда приходят готовые
   строки — отсюда `pre`. Пока текст правят, рвёт браузер: в поле лежит
   исходный текст, и наши строки к нему неприменимы. */
.ed-text { width: 100%; height: 100%; overflow: visible; white-space: pre; word-break: break-word; }
.ed-text.is-editing { white-space: pre-wrap; }
/* Правка текста прямо на макете. Подложки нет намеренно: макет должен
   выглядеть так же, как напечатается, а белая заливка меняла вид фона.
   Выделение — фирменное оранжевое вместо системного синего: синий на макете
   читается как часть картинки.

   Своей рамки у поля правки нет: узел текста поднят на `textShift`, и обводка
   по нему вставала выше ручек — при входе в правку рамка будто съезжала.
   Остаётся обычная рамка выделения, та же, что до двойного клика. */
.ed-text.is-editing { outline: none; cursor: text; }
.ed-text.is-editing::selection { background: var(--select-bg); }
.ed-text.is-editing ::selection { background: var(--select-bg); }
.ed-rect, .ed-img, .ed-shape, .ed-icon { width: 100%; height: 100%; display: block; }
/* Картинка с кадром: весь файл внутри обёртки, лишнее срезается. Размер и
   сдвиг ставит разметка (`imageHtml`) процентами от коробки. */
.ed-imgclip { position: absolute; inset: 0; overflow: hidden; }
.ed-img--cut { position: absolute; max-width: none; }
/* Выкройка фигуры доходит до краёв коробки, а обводка рисуется по контуру —
   её внешняя половина оказывается за краем. Показываем её целиком: canvas
   предпросмотра и PDF так рисовали всегда, и без этой строки холст остался
   бы единственным местом, где обводка срезана. */
.ed-shape { overflow: visible; }
/* Цветной эмодзи: картинка из `emojiCanvas`, та же, что уходит в PDF.
   Рисунок в ней уже занимает коробку по длинной стороне, поэтому рамка,
   за которую его тянут, идёт по самому смайлику. */
.ed-emoji { width: 100%; height: 100%; user-select: none; }
.ed-emoji img { display: block; width: 100%; height: 100%; pointer-events: none; }

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

   Тени нет намеренно: она утолщает ручку вдвое и ложится пятном на макет
   под ней. Белая заливка с волосяной обводкой видна и на тёмном. */
.ed-h {
  position: absolute; width: 7px; height: 7px; background: var(--white);
  border: 1px solid var(--orange); border-radius: 2px;
  transform: translate(-50%, -50%);
}
/* Ручка мелкая глазу, но не пальцу: невидимый запас вокруг ловит промах */
.ed-h::after { content: ''; position: absolute; inset: -4px; }
.ed-h--nw { left: 0; top: 0; cursor: nwse-resize; }
.ed-h--ne { left: 100%; top: 0; cursor: nesw-resize; }
.ed-h--se { left: 100%; top: 100%; cursor: nwse-resize; }
.ed-h--sw { left: 0; top: 100%; cursor: nesw-resize; }
.ed-h--n { left: 50%; top: 0; cursor: ns-resize; }
.ed-h--s { left: 50%; top: 100%; cursor: ns-resize; }
.ed-h--w { left: 0; top: 50%; cursor: ew-resize; }
.ed-h--e { left: 100%; top: 50%; cursor: ew-resize; }
/* Боковые — короткие полоски вдоль своего края: по форме видно, что тянут
   только вширь или только ввысь, и угол с серединой уже не спутать. */
.ed-h--n, .ed-h--s { width: 13px; height: 5px; border-radius: 2.5px; }
.ed-h--w, .ed-h--e { width: 5px; height: 13px; border-radius: 2.5px; }
/* Ручка поворота — над верхним краем, на ножке: так её не путают с угловой
   ручкой размера, а объект не приходится хватать за угол. Круглая, потому
   что тянут её не по прямой, а по дуге. */
.ed-h--rot { left: 50%; top: -19px; width: 8px; height: 8px; border-radius: 50%; }
.ed-h--rot::before {
  content: ''; position: absolute; left: 50%; top: 100%;
  width: 1px; height: 15px; margin-left: -.5px;
  background: var(--orange);
}
/* Курсор — сами стрелки поворота, а не рука: рука в редакторе значит
   «двигаю», а тут вращают. Точка отсчёта — середина картинки, 14 14.
   Второе объявление даёт чёткую версию на плотных экранах и молча
   пропускается там, где `image-set` в курсоре не понимают. */
.ed-h--rot,
body.is-rotating,
body.is-rotating .ed-canvas,
body.is-rotating .ed-obj,
body.is-rotating .ed-h {
  cursor: url("../img/ui/cursor-rotate.png") 14 14, grab;
  cursor: image-set(url("../img/ui/cursor-rotate.png") 1x,
                    url("../img/ui/cursor-rotate@2x.png") 2x) 14 14, grab;
}

/* Кадрирование. Слой стоит на месте всего файла и повёрнут вместе с
   картинкой. Серое — тень прорези: она заливает всё вокруг рамки, а
   обрезает её сам слой, так что гаснет только файл, соседний макет виден
   как есть. Затемнение того же тона, что под модальным окном. */
.ed-crop { position: absolute; z-index: 1; touch-action: none; }
.ed-crop__img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; pointer-events: none; }
.ed-crop__shade { position: absolute; inset: 0; overflow: hidden; cursor: move; }
.ed-crop__hole { position: absolute; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .55); pointer-events: none; }
/* Пунктир белый с тёмной подложкой — читается и на светлом снимке, и на сером */
.ed-crop__frame {
  position: absolute; cursor: move;
  outline: 1px dashed var(--white); box-shadow: 0 0 0 1px rgba(0, 0, 0, .35);
}

/* Технические линии всегда поверх макета. В разметке они и так идут
   последними, но объекты получают свой номер слоя в `z-index`, а `auto`
   проигрывает любому числу — из-за этого подложка «в край» закрывала и рез,
   и сгиб, и безопасное поле. Число заведомо больше числа слоёв. */
.ed-guides { position: absolute; inset: 0; pointer-events: none; z-index: 9999; }
.ed-guide { position: absolute; }
.ed-guide--trim { outline: 1px solid rgba(0, 0, 0, .8); }
.ed-guide--safe { outline: 1px dashed color-mix(in srgb, var(--guide-safe) 85%, transparent); }

/* Направляющие прилипания — только пока объект тащат. Волосок в один
   физический пиксель на любом увеличении: слой не масштабируется, размеры
   в него приходят готовыми из движка. Номер слоя на единицу меньше
   технических линий: рез и безопасное поле важнее совпадения краёв. */
.ed-snap { position: absolute; inset: 0; pointer-events: none; z-index: 9998; }
.ed-snap__l { position: absolute; background: var(--orange); }

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

   Лист режется по форме через clip-path, поэтому тень из box-shadow ушла бы
   вместе с углами: она рисуется по прямоугольнику. Берём drop-shadow — он
   повторяет силуэт. Слои те же, что в --shadow-sheet, но их два вместо
   четырёх: фильтр считается на каждый кадр перетаскивания. */
.ed-stage--shaped {
  box-shadow: none; outline: none;   /* прямоугольная рамка вылета не годится */
}
/* Тень фигурного листа — на обёртке: `clip-path` применяется после фильтров
   и на самом листе срезал бы её вместе с полями. Класс вешает редактор при
   отрисовке, а не селектор `:has` — чтобы не зависеть от его поддержки. */
.ed-sheet--shaped {
  filter: drop-shadow(0 1px 1px rgba(16, 24, 32, .16))
          drop-shadow(0 14px 22px rgba(16, 24, 32, .18));
}
.ed-cut { position: absolute; left: 0; top: 0; overflow: visible; }
.ed-cut path { fill: none; }
.ed-cut__bleed { stroke: rgba(240, 93, 32, .75); stroke-width: 2; stroke-dasharray: 5 4; }
.ed-cut__trim { stroke: rgba(0, 0, 0, .8); stroke-width: 1; }
.ed-cut__safe {
  stroke: color-mix(in srgb, var(--guide-safe) 85%, transparent);
  stroke-width: 1; stroke-dasharray: 4 3;
}

/* Линия сгиба: синий пунктир из точек — так её не спутать ни с резом
   (чёрная сплошная), ни с безопасным полем (зелёный штрих). Точки редкие:
   сгиб проходит по макету, и плотная линия читалась бы как часть рисунка. */
.ed-guide--crease-v { border-left: 1px dotted var(--guide-crease); }
.ed-guide--crease-h { border-top: 1px dotted var(--guide-crease); }

/* ————— Плавающая легенда технических линий —————

   Стоит столбиком, а не строкой: строка тянулась через полхолста и упиралась
   в карточки сторон. Столбик занимает угол и растёт вниз, где пусто. */
/* Панель прижата к низу холста и растёт вверх, поэтому нижняя строка — она же
   выключатель линий — стоит на месте, сколько бы обозначений над ней ни было.
   Значка-решётки у неё нет: он не добавлял к словам ничего, а выглядел вторым
   управлением рядом с первым. Обозначения появляются и исчезают вместе с
   линиями, отдельного «свернуть» нет. */
.ed-legend {
  position: absolute; left: 16px; bottom: 16px; z-index: 3;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  background: rgba(255, 255, 255, .94); border-radius: var(--radius);
  padding: 6px; box-shadow: 0 4px 18px rgba(0, 0, 0, .1);
}
.ed-legend__body {
  display: flex; flex-direction: column; gap: 8px;
  padding: 4px 8px 0; font-size: 12px; color: #55606b;
}
.ed-legend__body span { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.ed-legend i { width: 15px; height: 0; border-top: 1px dashed currentColor; display: inline-block; flex: none; }
.ed-legend .l-bleed { color: var(--orange); }
.ed-legend .l-trim { color: #111; }
.ed-legend .l-safe { color: var(--guide-safe); }
.ed-legend .l-crease { color: var(--guide-crease); }
.ed-legend .l-crease i { border-top-style: dotted; }
.ed-legend .l-trim i { border-top-style: solid; }
/* Выключатель линий: нижняя строка панели. Волосяная линия отделяет её от
   обозначений и появляется только вместе с ними — когда линии выключены,
   отделять нечего. */
.ed-legend__switch {
  align-self: stretch; text-align: left; padding: 4px 8px;
  font-size: 12px; font-weight: 600; color: var(--orange-dark);
  transition: color .14s;
}
.ed-legend__body + .ed-legend__switch {
  margin-top: 4px; padding-top: 9px; border-top: 1px solid var(--line);
}
.ed-legend__switch:hover { color: var(--ink); }
/* Плашка cookie стоит в том же левом нижнем углу и ложилась прямо на
   выключатель линий — пока её не закроют, нажать его было нельзя.
   Поднимаем на её высоту с зазором; на телефоне плашка ниже холста, и
   правило там не нужно, но и не мешает. */
body.has-cookie .ed-legend { bottom: 212px; }  /* с двумя кнопками плашка выше (L10) */

/* ————— Карточки сторон ————— */
.ed-sides {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 3;
  display: flex; gap: 10px; padding: 8px; border-radius: var(--radius);
  background: rgba(255, 255, 255, .94); box-shadow: 0 4px 18px rgba(0, 0, 0, .1);
}
.ed-sidecard { display: grid; gap: 5px; justify-items: center; padding: 4px; border-radius: 10px; transition: .16s; }
.ed-sidecard__thumb {
  width: 74px; height: 46px; border-radius: 7px; overflow: hidden;
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--line);
  display: flex; align-items: center; justify-content: center;
}
.ed-sidecard__thumb img { width: 100%; height: 100%; object-fit: contain; }
.ed-sidecard__thumb em { font-size: 10.5px; color: var(--gray-light); font-style: normal; }
.ed-sidecard__cap { font-size: 11.5px; font-weight: 600; color: var(--gray); }
.ed-sidecard:hover .ed-sidecard__thumb { border-color: var(--line-strong); }
.ed-sidecard.is-active .ed-sidecard__thumb { border-color: var(--orange); }
.ed-sidecard.is-active .ed-sidecard__cap { color: var(--orange); }

/* Кнопка «поменять стороны местами» стоит в разрыве между карточками.
   Прижата к верху ряда, а не к его середине: ряд выше карточек на подпись,
   и по центру кнопка уезжала бы ниже миниатюр, к которым относится. */
.ed-swap {
  align-self: start; margin-top: 12px;
  width: 30px; height: 30px; border-radius: 50%; color: var(--gray-light);
  display: flex; align-items: center; justify-content: center; transition: .16s;
}
.ed-swap:hover { background: var(--cream-sm); color: var(--orange-dark); }

/* ————— Панель управления канвасом —————

   Стоит сверху, а не внизу (17 августа 2026). Внизу она делила ряд с
   карточками сторон и легендой — три плавающие панели в одной полосе.

   С 15 сентября 2026 это два острова. Слева — отмена и масштаб, справа —
   предпросмотр и состояние макета. Оба прибиты к `.ed-canvas`, а не к окну:
   выдвижная панель — своя колонка сетки, и левый остров едет вместе с краем
   холста, а не прячется под неё. */
.ed-canvasbar {
  position: absolute; top: 16px; z-index: 3;
  display: flex; align-items: center; gap: 2px; padding: 5px;
  background: rgba(255, 255, 255, .94); border-radius: var(--r-pill);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .1);
}
.ed-canvasbar--view { left: 16px; }
.ed-canvasbar--check { right: 16px; }
.ed-barbtn {
  height: 32px; min-width: 32px; padding: 0 6px; border-radius: 9px; color: var(--gray);
  display: flex; align-items: center; justify-content: center; gap: 6px; transition: .16s;
}
.ed-barbtn:hover:not(:disabled) { background: var(--fill); color: var(--ink); }
.ed-barbtn:disabled { opacity: .35; cursor: not-allowed; }
/* Нажатое состояние кнопки-переключателя: сейчас так живёт лупа «1:1» */
.ed-barbtn.is-active { background: var(--cream-sm); color: var(--orange-dark); }
.ed-barbtn--val { font-size: 12.5px; font-weight: 700; color: var(--ink); min-width: 52px; }
.ed-barbtn--val.is-open { background: var(--cream-sm); color: var(--orange-dark); }
.ed-barbtn--wide { font-size: 12.5px; font-weight: 600; padding: 0 10px; }
.ed-bar__sep { width: 1px; height: 20px; background: var(--line); margin: 0 4px; }

/* Состояние макета у холста: сколько замечаний нашёл препресс прямо сейчас.
   Цвета те же, что в окне проверки, — одно замечание не должно выглядеть
   в двух местах двумя разными бедами. */
.ed-barbtn--status { font-size: 12.5px; font-weight: 600; padding: 0 10px 0 8px; }
.ed-status__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: currentColor; }
.ed-barbtn--status b { font-weight: 700; }
.ed-barbtn--status.is-ok { color: var(--ok); }
.ed-barbtn--status.is-ok:hover { background: var(--ok-bg); color: var(--ok); }
.ed-barbtn--status.is-warn { color: var(--warn); }
.ed-barbtn--status.is-warn:hover { background: var(--warn-bg); color: var(--warn); }
.ed-barbtn--status.is-err { color: var(--err); }
.ed-barbtn--status.is-err:hover { background: var(--err-bg); color: var(--err); }

/* Узкая рабочая область: три плавающих блока внизу расходятся по местам */
.ed-canvas.is-tight .ed-barbtn--wide span { display: none; }
/* В тесноте от состояния остаётся число: слово «замечания» уходит, цвет и
   цифра остаются — этого хватает, чтобы заметить и нажать. */
.ed-canvas.is-tight .ed-barbtn--status { padding: 0 8px; }
.ed-canvas.is-tight .ed-barbtn--status span { display: none; }
/* Совсем узкий холст — телефон или открытая панель на планшете: два острова
   в одну строку не помещаются, правый встаёт под левый, а не наезжает на него. */
.ed-canvas.is-cramped .ed-canvasbar--check { top: 62px; }
.ed-canvas.is-tight .ed-sidecard__thumb { width: 58px; height: 36px; }
.ed-canvas.is-tight .ed-sides { padding: 6px; gap: 6px; }
.ed-canvas.is-tight .ed-swap { margin-top: 7px; }

/* ————— Лупа 1:1 —————
   Слева сверху: правый верх занят панелью холста, левый низ — легендой.
   Окно внутри не масштабируется вместе с холстом — в этом весь смысл: его
   размеры считает `Loupe` в настоящих миллиметрах. */
.ed-loupe {
  position: absolute; left: 16px; top: 16px; z-index: 4;
  background: rgba(255, 255, 255, .96); border-radius: var(--radius);
  padding: 10px; box-shadow: 0 4px 18px rgba(0, 0, 0, .12);
  display: flex; flex-direction: column; gap: 8px; max-width: calc(100% - 32px);
}
.ed-loupe__head { display: flex; align-items: center; gap: 10px; font-size: 12.5px; }
.ed-loupe__head b { font-size: 12.5px; }
.ed-loupe__x { margin-left: auto; }
/* Фон окна — цвет рабочей области: то, что вышло за край листа, читается
   как «здесь бумаги уже нет», а не как белое поле макета. */
.ed-loupe__win {
  position: relative;
  background: #eceff2; border: 1px solid var(--line); border-radius: 4px;
  overflow: hidden; max-width: 100%;
}
/* Рука. Курсор говорит, что картинку можно тянуть; жест забираем целиком —
   иначе палец на планшете прокручивал бы страницу, а не кусок. */
.ed-loupe__win.is-movable { cursor: grab; touch-action: none; }
.ed-loupe__win.is-grabbing { cursor: grabbing; }
/* Кусок нарисован с запасом вокруг окна и ездит сдвигом — см. `Loupe.draw`.
   Размер ему задаёт `Loupe`, и он окончательный: ужатый холст показывал бы
   не натуральную величину. */
.ed-loupe__win canvas { position: absolute; left: 0; top: 0; display: block; max-width: none; }
.ed-loupe__foot { font-size: 11.5px; color: var(--gray-light); line-height: 1.4; max-width: 340px; }
.ed-loupe__link { color: var(--orange); font-size: 11.5px; font-weight: 600; }
.ed-loupe__link:hover { color: var(--orange-dark); }
/* Рамка карты — не картинка, а размер: её ширину задаёт та самая величина,
   которую подстраивают. */
.ed-loupe__card {
  border: 1px dashed var(--orange); border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; color: var(--gray-light);
}
.ed-loupe__range { width: 100%; }
.ed-loupe__row { display: flex; gap: 8px; justify-content: flex-end; }
/* Рамка на холсте — куда смотрит окно 1:1. Цвет выделения, но с заливкой и
   ярлыком: без них её легко принять за выделенный объект. Поверх технических
   линий, мышь пропускает насквозь — править макет под ней можно как обычно. */
.ed-loupe-mark {
  position: absolute; z-index: 9999; pointer-events: none;
  box-shadow: inset 0 0 0 1.5px var(--orange);
  background: rgba(240, 93, 32, .06);
}
.ed-loupe-mark::before {
  content: '1:1'; position: absolute; left: 0; top: 0;
  background: var(--orange); color: #fff;
  font-size: 11px; font-weight: 600; line-height: 1; padding: 3px 5px;
  border-radius: 0 0 4px 0;
}

/* ————— Пипетка: режим взятия цвета с макета —————

   Весь знак режима — курсор. Плашка с надписью «ткните в цвет» и кнопкой
   «взять с экрана» стояла над холстом до 7 сентября 2026; вместе с системной
   пипеткой она убрана, потому что объясняла то, что курсор и так говорит. */
/* Курсор — сама пипетка, а не крестик: крестик в редакторе значит «сейчас
   что-то нарисую». Картинка лежит в `assets/img/ui`, точка отсчёта — её
   кончик. Второе объявление даёт чёткую версию на плотных экранах и молча
   пропускается там, где `image-set` в курсоре не понимают. */
body.is-picking .ed-canvas,
body.is-picking .ed-obj,
body.is-picking .ed-h {
  cursor: url("../img/ui/cursor-pipette.png") 4 24, crosshair;
  cursor: image-set(url("../img/ui/cursor-pipette.png") 1x,
                    url("../img/ui/cursor-pipette@2x.png") 2x) 4 24, crosshair;
}

/* ————— Правая панель: свойства сверху, слои закреплены снизу —————
   Свойства забирают всю свободную высоту и прокручиваются сами. Общим
   скроллом на колонку простыня свойств текста (под тысячу пикселей у
   абзаца) уносила список слоёв под нижний край, а слои ещё и ездили вверх-
   вниз от каждой смены выделения — при том что тянут мышью именно их. */
.ed-right {
  border-left: 1px solid var(--line); background: var(--white);
  overflow: hidden; display: flex; flex-direction: column;
}
.ed-block { padding: 14px 16px; }
.ed-block--props { flex: 1; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }
/* Полоса прокрутки видна всегда, а не только под курсором: в macOS она
   скрыта по умолчанию, и о том, что панель листается, никто не догадывался */
.ed-block--props::-webkit-scrollbar { width: 11px; }
.ed-block--props::-webkit-scrollbar-track { background: transparent; }
.ed-block--props::-webkit-scrollbar-thumb {
  background: var(--line-strong); border-radius: 6px;
  border: 3px solid var(--white); background-clip: padding-box;
}
.ed-block--props::-webkit-scrollbar-thumb:hover { background: var(--gray-light); background-clip: padding-box; }
#edLayersBlock { flex: none; border-top: 1px solid var(--line); transition: box-shadow .18s; }
/* Пока ниже есть ещё поля, край панели подсвечен тенью. Рисует её блок
   слоёв: он стоит на месте, а прокручивается то, что над ним */
.ed-block--props.has-more + #edLayersBlock { box-shadow: 0 -12px 16px -10px rgba(17, 17, 17, .18); }
/* Заголовок свойств остаётся над полями при прокрутке: без него в длинной
   простыне непонятно, что листаешь */
/* Липнет к самому верхнему краю: `top` равен отступу блока. При меньшем
   значении между шапкой колонки и заголовком оставалась щель, и в неё
   просвечивали прокрученные поля. Тень того же белого закрывает щель,
   если браузер посчитает отступ иначе */
.ed-block--props .ed-block__head {
  position: sticky; top: -14px; z-index: 2;
  background: var(--white); padding: 8px 0 4px; margin-top: -14px;
  box-shadow: 0 -14px 0 var(--white);
}
.ed-block__head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--gray-light); margin-bottom: 12px;
}
.ed-block__head span { flex: 1; text-align: left; }
.ed-block__head .ic:last-child { transition: transform .18s; }
.ed-block__head--static { cursor: default; }
.ed-block.is-collapsed .ed-layers,
.ed-block.is-collapsed .ed-layers__foot { display: none; }
.ed-block.is-collapsed .ed-block__head { margin-bottom: 0; }
.ed-block.is-collapsed .ed-block__head .ic:last-child { transform: rotate(-90deg); }

/* ————— Слои ————— */
/* minmax(0,1fr): без него колонка растёт под длинное имя слоя и меню уезжает за край */
.ed-layers {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr);
  /* Три с половиной строки: половинка следующей говорит, что список
     прокручивается, а слои больше не занимают полпанели */
  gap: 2px; max-height: 125px; overflow-y: auto;
}
.ed-layer {
  display: flex; align-items: center; gap: 4px; padding: 5px 4px 5px 0;
  border-radius: 9px; font-size: 13px; transition: background .14s; background: var(--white);
}
.ed-layer:hover { background: var(--fill); }
.ed-layer.is-active { background: var(--cream-sm); color: var(--orange-dark); }
.ed-layer.is-hidden { opacity: .5; }
.ed-layer.is-dragging {
  position: relative; z-index: 5; background: var(--white);
  box-shadow: 0 8px 22px rgba(0, 0, 0, .16); opacity: .96;
}
.ed-layer__grip { display: flex; color: var(--gray-light); cursor: grab; padding: 2px; flex-shrink: 0; }
.ed-layer__grip:active { cursor: grabbing; }
.ed-layer__ic {
  width: 24px; height: 24px; border-radius: 7px; background: var(--fill); color: var(--gray);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.ed-layer.is-active .ed-layer__ic { background: var(--white); color: var(--orange); }
.ed-layer__emoji { width: 15px; font-size: 13px; line-height: 1; text-align: center; font-family: var(--font-emoji); }
.ed-layer__name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: left; }
/* Метка отделки: элемент уйдёт в отдельный файл для фольги или лака */
.ed-layer__finish {
  flex: none; max-width: 84px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  padding: 2px 6px; border-radius: var(--r-pill); font-size: 10.5px; line-height: 1.3;
  background: #f4e3c3; color: #7a5a12;
}
.ed-layer__act {
  width: 24px; height: 24px; border-radius: 7px; color: var(--gray-light);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: .14s;
}
.ed-layer__act:hover { background: var(--white); color: var(--ink); }
.ed-layer__act--del:hover { background: var(--err-bg); color: var(--err); }
.ed-layer__drop {
  position: absolute; left: 0; right: 0; height: 2px; border-radius: 2px;
  background: var(--orange); pointer-events: none;
}
/* «Очистить сторону» — под списком слоёв, отделена воздухом от самих слоёв.
   Лежит вне прокрутки списка, иначе прячется под его нижним краем */
.ed-layers__foot:empty { display: none; }
/* Отступ побольше: кнопка стоит сразу под списком, а по списку тянут слои
   мышью — промахнуться по «Очистить сторону» было слишком легко */
.ed-layers__clear { width: 100%; justify-content: center; margin-top: 18px; }

/* ————— Скачивание ————— */
.ed-export { display: grid; gap: 8px; padding: 6px 14px 18px; }
.ed-export__btn { width: 100%; justify-content: center; }

/* ————— Свойства ————— */
.ed-props__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 14px; }
.ed-props__kind { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; }
.ed-props__acts { display: flex; gap: 4px; }
.ed-props__acts button {
  width: 30px; height: 30px; border-radius: 9px; background: var(--fill); color: var(--gray);
  display: flex; align-items: center; justify-content: center; transition: .14s;
}
.ed-props__acts button:hover { background: var(--orange); color: var(--white); }
.ed-props__sep { height: 1px; background: var(--line); margin: 16px 0 14px; }

.ed-field { margin-bottom: 12px; }
.ed-field.is-off { opacity: .55; }
.ed-field > label { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; color: var(--gray); margin-bottom: 6px; }
/* Сброс рядом с подписью поля — «в центр» у кадрирования фона */
.ed-field__act { margin-left: auto; font-size: 11.5px; font-weight: 600; color: var(--gray-light); transition: color .14s; }
.ed-field__act:hover { color: var(--orange); }
/* Поле описания в AI-студии: отступ снизу у поля даёт сетка панели */
.ed-field--ai { margin-bottom: 0; }
.ed-field--ai > label, .ed-field--ai .ed-field__act { white-space: nowrap; }
.ed-field--ai .textarea { line-height: 1.45; }
.ed-field .input, .ed-field .textarea, .ed-field select.input { height: 38px; border-radius: var(--r-control); font-size: 13.5px; padding: 0 11px; }

/* ————— Плотная раскладка панели свойств —————
   Подпись стоит слева от контрола, а не над ним. Сверху она тратила по 24 px
   на каждом поле, и свойства текста разворачивались на 914 px — до половины
   полей человек добирался прокруткой. Ничего не убрано и не спрятано: поля
   просто стоят рядами. Длинная подпись переносится на две строки и всё равно
   умещается в высоту контрола. */
.ed-props .ed-field {
  display: grid; grid-template-columns: 88px minmax(0, 1fr);
  align-items: center; gap: 4px 14px; margin-bottom: 8px;
}
/* Подпись переносится по словам, если не влезла: строка поля 34 px, две
   строки подписи по 15 в неё помещаются и ряд не растёт */
.ed-props .ed-field > label { margin-bottom: 0; line-height: 1.25; flex-wrap: wrap; }
.ed-props .ed-field > *:not(label) { grid-column: 2; }
/* Пояснения и предупреждения под полем — во всю ширину: подпись им не нужна */
.ed-props .ed-field > .ed-note,
.ed-props .ed-field > .ed-status,
.ed-props .ed-field > .ed-mini { grid-column: 1 / -1; }
.ed-props .ed-field .input,
.ed-props .ed-field .textarea,
.ed-props .ed-field .dd__btn { height: 34px; }
/* В парных рядах подпись остаётся сверху: на половине колонки слева её не
   разместить */
.ed-props .ed-grid2 .ed-field,
.ed-props .ed-size .ed-field { display: block; margin-bottom: 0; }
.ed-props .ed-grid2 .ed-field > label,
.ed-props .ed-size .ed-field > label { margin-bottom: 3px; font-size: 11.5px; }
.ed-props .ed-grid2 { margin-bottom: 8px; }
/* Два числа под одной подписью: X и Y, ширина и высота. Какое из них какое,
   говорит светлая метка внутри поля — подпись над каждым стоила бы строки */
.ed-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.ed-nudge[data-tag]::after {
  content: attr(data-tag); position: absolute; left: 11px; top: 50%;
  transform: translateY(-50%); pointer-events: none;
  font-size: 10.5px; font-weight: 700; color: var(--gray-light);
}
/* Отступ под метку с запасом: у «Ш» и «В» буква шире латинских, и число
   в неё упиралось */
.ed-nudge[data-tag] .input { padding-left: 30px; }
/* Ряды, которым подпись слева не подходит: шесть кнопок выравнивания и
   ползунки фильтров занимают всю ширину панели, подпись остаётся над ними */
.ed-props .ed-field--wide { display: block; }
.ed-props .ed-field--wide > label { margin-bottom: 6px; }
.ed-props .ed-field--wide > .ed-seg { margin-top: 6px; }
/* Значение фильтра — у правого края строки, отдельно от названия: между
   словом и знаковым числом тире читалось как минус */
.ed-props .ed-field--slider > label { justify-content: space-between; }
.ed-props .ed-field--slider > label > i {
  font-style: normal; font-size: 13px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
/* Кегль и начертание: кеглю — ровно столько, сколько нужно числу со
   стрелками, остальное списку. На 96 px список сжимался до «О…» */
.ed-pair--kegl { grid-template-columns: 74px minmax(0, 1fr); }
/* Скрепка пропорций стоит вровень с полями, а не выше их: подписи у ширины
   и высоты нет, выравнивать ряд по низу больше не от чего */
.ed-props .ed-size { align-items: center; }
.ed-props .ed-ratio { height: 34px; margin-bottom: 0; }
/* Образец цвета — во всю ширину поля, как выпадающий список рядом. Половина
   колонки оставалась от старой раскладки с подписями сверху */
.ed-props .ed-color { max-width: none; height: 34px; }
/* «Сгруппировать» не впритык к соседям: кнопка действия, а не поле */
.ed-props .ed-group-btn { margin: 4px 0 14px; }
.ed-props .ed-size { grid-column: 2; margin: 0; align-items: center; }
/* Выпадающий список в панели редактора — той же высоты, что поля рядом */
.ed-field .dd__btn { height: 38px; font-size: 13.5px; padding: 0 11px; }
.ed-field .dd__opt { padding: 8px 10px; font-size: 13px; }
.ed-field .dd__head { padding: 9px 10px 3px; }
/* Имя гарнитуры набрано ею самой, поэтому строке нужен воздух: у Lobster и
   Pacifico выносные элементы выше, чем у гротесков. */
.ed-field .dd__opt span { font-size: 14.5px; line-height: 1.3; display: block; }
.ed-field .textarea { height: auto; padding: 9px 11px; }
.ed-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* Ширина, скрепка пропорций, высота. Скрепка стоит на уровне полей, а не
   подписей, поэтому ряд выравнивается по низу. */
.ed-size { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: end; }
.ed-ratio {
  width: 32px; height: 38px; margin-bottom: 12px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-strong); border-radius: var(--r-control);
  background: var(--white); color: var(--gray-light); cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.ed-ratio:hover { color: var(--gray); border-color: var(--gray-light); }
.ed-ratio.is-on { color: var(--orange-dark); border-color: var(--orange); background: var(--cream-sm); }
.ed-mini { font-size: 11.5px; color: var(--gray-light); line-height: 1.4; }
/* Подписи на концах ползунка: вместо процентов — что стоит в начале и в конце */
.ed-ends { display: flex; justify-content: space-between; gap: 8px; margin-top: 2px; }
.ed-ends + .range { margin-top: 10px; }

/* Образец перехода в панели «Фон». Пока градиент не кладётся на макет, это
   единственное место, где его видно, поэтому полоса крупная. */
.ed-gradsample { height: 76px; border-radius: var(--r-control); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); }
/* Число в подписи набрано не курсивом — <i> здесь только держатель, чтобы
   обновлять значение, не переписывая подпись с кнопкой внутри. */
.ed-field > label i { font-style: normal; }

.ed-seg { display: flex; gap: 4px; }
.ed-seg button {
  flex: 1; height: 36px; border-radius: 9px; background: var(--fill); color: var(--gray);
  font-size: 13px; font-weight: 600; display: flex; align-items: center; justify-content: center; transition: .14s;
}
.ed-seg button.is-active { background: var(--cream-sm); color: var(--orange-dark); }
.ed-seg--wide button { height: 38px; }
/* Подсегмент внутри вкладки — «Сплошной / Переход» в цвете фона.
   Ниже и легче основного ряда, чтобы читался как уточнение, а не как
   второй ряд вкладок. */
.ed-seg--sub { margin-bottom: 14px; }
.ed-seg--sub button { height: 30px; font-size: 12.5px; border-radius: 8px; }

/* Выравнивание объекта: шесть направлений плюс выбор ориентира */
.ed-align { display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; }
.ed-align button {
  height: 34px; border-radius: 9px; background: var(--fill); color: var(--gray);
  display: flex; align-items: center; justify-content: center; transition: .14s;
}
.ed-align button:hover { background: var(--cream-sm); color: var(--orange-dark); }
.ed-align__ref { margin-top: 6px; }
/* Выравнивание между собой — под линией и своим заголовком, чтобы два ряда
   по шесть кнопок не читались одним на двенадцать (B9-bis) */
.ed-field--between { border-top: 1px solid var(--line); padding-top: 12px; }
.ed-align--dist { grid-template-columns: 1fr 1fr; margin: 4px 0 8px; }
.ed-align--dist button { gap: 6px; font-size: 11.5px; font-weight: 600; }
.ed-align button:disabled { opacity: .45; cursor: not-allowed; }
.ed-align button:disabled:hover { background: var(--fill); color: var(--gray); }
.ed-field--between .ed-status--soon { margin-bottom: 0; }
.ed-align__ref button { height: 30px; font-size: 11.5px; font-weight: 600; }

.range { width: 100%; accent-color: var(--orange); }
/* Ширина образца — ровно половина колонки панели: так одиночное поле цвета
   («Цвет» у текста, фон стороны) выглядит той же плашкой, что заливка с
   обводкой в паре, и не растягивается в широкую полосу краски. */
.ed-color {
  display: flex; width: 100%; max-width: 132px; height: 38px; padding: 3px;
  border: 1px solid var(--line-strong); border-radius: var(--r-control); background: var(--white);
  transition: .14s;
}
.ed-color:hover { border-color: var(--orange); }
.ed-color i {
  flex: 1; border-radius: 5px;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
/* «Цвета нет» — тонкая черта через весь образец. Толщину задаём в пикселях
   по оси градиента, а не долей: доля на широкой кнопке дала бы жирную полосу
   вместо черты. */
.ed-color i.is-none {
  background: linear-gradient(to bottom right,
    transparent calc(50% - 1px), var(--err) calc(50% - 1px),
    var(--err) calc(50% + 1px), transparent calc(50% + 1px));
}

/* Действия с картинкой и то, что под ними раскрывается */
.ed-imgacts, .ed-imgacts__stub { display: grid; gap: 8px; margin-bottom: 12px; }
/* Отступ от строки разрешения над кнопками: у `.ed-dpi` своих полей нет */
.ed-dpi + .ed-imgacts { margin-top: 12px; }
/* Подсказка режима темнее обычной мелкой: без неё непонятно, что делать с рамкой */
.ed-imgacts__note { margin: -4px 0 12px; color: var(--gray); }
.ed-imgacts__stub .ed-status--soon { margin-bottom: 0; }
/* «Фильтры» в свойствах картинки — та же гармошка, что в «Помощи», но с
   линией сверху: над ней кнопки, а не другой раздел */
.ed-imgfilters { border-top: 1px solid var(--line); margin-bottom: 12px; }
.ed-imgfilters .ed-status--soon { margin-bottom: 0; }
.ed-file { font-size: 12.5px; color: var(--gray); background: var(--fill-lg); padding: 9px 11px; border-radius: var(--r-control); word-break: break-all; }
.ed-dpi { font-size: 12px; color: var(--ok); background: var(--ok-bg); padding: 9px 11px; border-radius: var(--r-control); line-height: 1.4; }
.ed-dpi.is-warn { color: var(--warn); background: var(--warn-bg); }
.ed-dpi.is-bad { color: var(--err); background: var(--err-bg); }
/* Число в поле ушло за порог печати (C64). Цвет предупреждения — тот же, что
   у замечания в проверке и у счётчика над холстом: одно замечание не должно
   выглядеть в трёх местах тремя разными бедами. Под полем — строка причины. */
.ed-field .input.is-warn { border-color: var(--warn); background: var(--warn-bg); }
/* Стрелки числовых полей редактора (`EdNumber`). Родной счётчик спрятан: он
   виден только под курсором, в каждом браузере свой, а у Y двигал объект
   наоборот (C68). На его месте две кнопки, видные сразу. */
.ed-nudge { position: relative; display: block; }
.ed-nudge .input { padding-right: 26px; -moz-appearance: textfield; }
.ed-nudge .input::-webkit-outer-spin-button,
.ed-nudge .input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ed-nudge__btns {
  position: absolute; top: 3px; right: 3px; bottom: 3px; width: 20px;
  display: grid; grid-template-rows: 1fr 1fr;
}
.ed-nudge__btns button {
  display: flex; align-items: center; justify-content: center;
  color: var(--gray-light); border-radius: 4px; transition: .14s;
}
.ed-nudge__btns button:hover { color: var(--orange); background: var(--fill-lg); }
.ed-nudge__btns button:first-child svg { transform: rotate(180deg); }
.ed-nudge .input:disabled + .ed-nudge__btns { opacity: .4; pointer-events: none; }
.ed-limit { font-size: 12px; line-height: 1.45; color: var(--warn); margin: -4px 0 12px; }
.ed-status {
  display: flex; align-items: flex-start; gap: 8px; font-size: 12px; line-height: 1.4;
  padding: 9px 11px; border-radius: var(--r-control); color: var(--ok); background: var(--ok-bg);
}
.ed-status .ic { flex-shrink: 0; margin-top: 1px; }
.ed-status--warn { color: var(--warn); background: var(--warn-bg); }
/* Временное: функция в прототипе не доведена, и надпись уйдёт вместе с
   доработкой. Синим, чтобы не путалась с предупреждениями о макете — те
   остаются на сайте навсегда (13 сентября 2026, решение заказчицы). */
.ed-status--soon { color: var(--info); background: var(--info-bg); margin-bottom: 12px; }
/* Та же пометка в самом низу панели, под результатами: отступ сверху, а не снизу */
.ed-status--soon.ed-status--last { margin: 10px 0 0; }
.ed-status--err { color: var(--err); background: var(--err-bg); }
/* Замечания в блоке «Скачать» — кнопка: открывают окно проверки. Рамка на
   наведении своего же цвета, чтобы у трёх состояний плашки не заводить три
   правила подсветки. */
.ed-status--act { width: 100%; text-align: left; cursor: pointer; font: inherit; font-size: 12px; transition: .14s; }
.ed-status--act span { flex: 1; }
.ed-status--act:hover { box-shadow: inset 0 0 0 1px currentColor; }
.ed-note { font-size: 12px; color: var(--gray); line-height: 1.5; background: var(--fill-lg); padding: 10px 12px; border-radius: var(--radius); margin-top: 10px; }
/* Ссылка внутри заметки была одного цвета с текстом и не читалась как ссылка.
   Уводящая со страницы — отдельной строкой со стрелкой из рамки: это привычный
   знак «откроется в новой вкладке», и подписывать это словами не нужно. */
.ed-note a { color: var(--orange-dark); text-decoration: underline; text-underline-offset: 2px; }
.ed-note__link {
  display: flex; align-items: center; gap: 5px; width: fit-content;
  margin-top: 8px; font-weight: 600; text-decoration: none;
}
.ed-note__link:hover { text-decoration: underline; text-underline-offset: 2px; }
.ed-note__link .ic { flex-shrink: 0; }
.ed-empty p { font-size: 13px; color: var(--gray); margin-bottom: 8px; }
.ed-hint { font-size: 12px; color: var(--gray-light); line-height: 1.45; }
/* Ссылка внутри подсказки: отправляет в «Помощь», где лежит полный список
   клавиш. Кнопка, а не ссылка, — открывается панель, а не страница. */
.ed-hint button { font: inherit; color: var(--gray); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; transition: .14s; }
.ed-hint button:hover { color: var(--orange); }

/* ————— Общие элементы выдвижных панелей ————— */
.ed-sub {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--gray-light); margin: 16px 0 8px;
}
.ed-search { position: relative; display: flex; align-items: center; }
.ed-search .ic { position: absolute; left: 11px; color: var(--gray-light); pointer-events: none; }
.ed-search input {
  width: 100%; height: 38px; padding: 0 12px 0 34px; font-size: 13.5px;
  border: 1px solid var(--line-strong); border-radius: var(--r-control); background: var(--white);
}
.ed-search input:focus { outline: none; border-color: var(--orange); }

.ed-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ed-chip-sm {
  height: 30px; padding: 0 12px; border-radius: var(--r-pill); background: var(--fill);
  font-size: 12.5px; font-weight: 600; color: var(--gray); transition: .14s;
}
.ed-chip-sm:hover { color: var(--ink); }
.ed-chip-sm.is-active { background: var(--cream-sm); color: var(--orange-dark); }

.ed-bigbtn {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  height: 42px; border-radius: var(--r-control); background: var(--fill);
  font-size: 13.5px; font-weight: 600; transition: .16s;
}
.ed-bigbtn:hover { background: var(--cream-sm); color: var(--orange-dark); }
.ed-bigbtn--primary { background: var(--orange); color: var(--white); }
.ed-bigbtn--primary:hover { background: var(--orange-dark); color: var(--white); }
.ed-bigbtn:disabled { opacity: .45; cursor: not-allowed; }
.ed-bigbtn--primary:disabled:hover { background: var(--orange); }
.ed-btn-ghost {
  display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 12px;
  border: 1px solid var(--line-strong); border-radius: var(--r-control);
  font-size: 12.5px; font-weight: 600; color: var(--gray); background: var(--white); transition: .14s;
}
.ed-btn-ghost:hover { border-color: var(--orange); color: var(--orange); }
.ed-btn-ghost.is-on { border-color: var(--orange); color: var(--orange); background: var(--cream-sm); }
.ed-btn-ghost:disabled { opacity: .45; cursor: not-allowed; border-color: var(--line-strong); color: var(--gray); }
/* Кнопка действия во всю ширину колонки: «Кадрировать», «Убрать фон» */
.ed-btn-ghost--wide { width: 100%; height: 38px; justify-content: center; }
/* Нейросеть думает (`aiRun`): кнопка нажата и показывает, что идёт.
   Неактивной её не гасим — это не «нельзя», а «уже делаем» */
.ed-btn-ghost.is-busy, .ed-btn-ghost.is-busy:disabled {
  opacity: 1; cursor: progress; border-color: var(--orange); color: var(--orange); background: var(--cream-sm);
}
.ed-spin {
  width: 14px; height: 14px; flex-shrink: 0; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent; animation: ed-spin .8s linear infinite;
}
@keyframes ed-spin { to { transform: rotate(360deg); } }
/* Бейдж «AI» на кнопках, которые ходят в нейросеть типографии (`AI_API`):
   «Повысить разрешение», «Убрать фон», «Дорисовать вылеты» в свойствах
   фото, обе кнопки AI-студии (макет и фото по описанию) и ссылка на пустой
   стороне. Добавлено 14 октября 2026 по просьбе владельца — явно показать,
   где подключён внешний сервис, а не угадывать по иконке. Высота меньше
   строки текста кнопки, поэтому в ряд (`display:flex` у самой кнопки) он
   встаёт как обычное слово и высоту кнопки не меняет.
   Цвет — кремовая плашка с тёмно-оранжевым текстом (та же пара, что у
   «нажатой» кнопки `.ed-btn-ghost.is-on`), а не фирменный оранжевый на
   белом: кнопка генерации в AI-студии (`.ed-bigbtn--primary`) сама залита
   оранжевым, и бейдж тем же цветом на ней сливался бы с фоном. */
.ed-ai-badge {
  display: inline-flex; align-items: center; flex-shrink: 0;
  height: 14px; padding: 0 5px; border-radius: var(--r-pill);
  background: var(--cream-sm); color: var(--orange-dark);
  font-size: 9.5px; font-weight: 800; letter-spacing: .03em; line-height: 14px;
}
/* Строка-вход: слева образец, справа — что на стороне сейчас лежит.
   Не орган управления, а указатель на раздел «Фон» в левой панели. */
.ed-btn-ghost--row { width: 100%; height: 38px; text-align: left; }
.ed-btn-ghost--row em { margin-left: auto; font-style: normal; font-weight: 500; color: var(--gray-light); }
.ed-dot { width: 20px; height: 20px; flex-shrink: 0; border-radius: 5px; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); }
.ed-dot.is-none {
  background: linear-gradient(to bottom right,
    transparent calc(50% - 1px), var(--err) calc(50% - 1px),
    var(--err) calc(50% + 1px), transparent calc(50% + 1px));
}

.ed-list { display: grid; gap: 4px; }
.ed-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px; width: 100%;
  padding: 9px 11px; border-radius: var(--r-control); background: var(--fill); transition: .14s; text-align: left;
}
.ed-row:hover { background: var(--cream-sm); }
.ed-row__main { font-size: 13.5px; font-weight: 600; }
.ed-row__note { font-size: 11.5px; color: var(--gray-light); flex-shrink: 0; }

/* Разделы «Помощи» гармошкой — родной `details`. Заголовок строкой во всю
   ширину, шеврон справа, как у блока «Слои»: закрытый смотрит вправо,
   открытый — вниз. Разделы отбиты волосяной линией. */
.ed-fold { border-bottom: 1px solid var(--line); }
.ed-fold__head {
  display: flex; align-items: center; gap: 8px; padding: 13px 0;
  font-size: 13.5px; font-weight: 600; color: var(--ink); cursor: pointer; list-style: none;
  transition: color .14s;
}
.ed-fold__head::-webkit-details-marker { display: none; }
.ed-fold__head span { flex: 1; }
.ed-fold__head .ic { color: var(--gray-light); transform: rotate(-90deg); transition: transform .18s; }
.ed-fold__head:hover { color: var(--orange-dark); }
.ed-fold[open] .ed-fold__head .ic { transform: none; }
.ed-fold__body { padding: 0 0 16px; }
.ed-fold__text { font-size: 12.5px; line-height: 1.5; color: var(--gray); }
.ed-fold__text a { color: var(--orange-dark); text-decoration: underline; text-underline-offset: 2px; }
.ed-fold__body .ed-note__link { font-size: 12.5px; color: var(--orange-dark); }
.ed-fold__btn { height: 36px; padding: 0 16px; font-size: 13px; margin-top: 10px; }

/* Горячие клавиши (C54). Группа — подпись капителью и пары под ней; группы
   отбиты линией, чтобы подпись группы не сливалась с парами. Пара — клавиша
   и под ней пояснение: на узкой панели сетка в две колонки съедала ширину
   пояснений. Внутри пары зазор 1 px, между парами 9 — список читается
   парами, а не столбцами. Клавиша не переносится никогда. */
.ed-keys { display: grid; gap: 9px; }
.ed-keys + .ed-keys { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.ed-keys__title {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--gray-light);
}
.ed-keys__pair { display: grid; gap: 1px; }
.ed-keys__key { font: inherit; font-size: 13px; font-weight: 600; color: var(--ink); white-space: nowrap; }
.ed-keys__what { font-size: 12px; line-height: 1.4; color: var(--gray); }

/* Без подложки: светло-серое пояснение на сером блоке не читалось
   (15 сентября 2026). Пункты делит линия, пояснение — тем же --gray,
   что у подписей клавиш в «Помощи». */
.ed-switch { display: flex; align-items: flex-start; gap: 10px; padding: 12px 0 8px; cursor: pointer; }  /* снизу 8: ещё 4 добавляет зазор .ed-list, линия встаёт посередине */
.ed-switch + .ed-switch { border-top: 1px solid var(--line); }
.ed-switch input { accent-color: var(--orange); margin-top: 3px; }
.ed-switch b { display: block; font-size: 13px; }
.ed-switch em { display: block; font-size: 12px; color: var(--gray); font-style: normal; line-height: 1.4; margin-top: 3px; }

.ed-hintbox {
  display: flex; gap: 10px; padding: 12px; border-radius: var(--radius);
  background: var(--info-bg); color: var(--info);
}
.ed-hintbox .ic { flex-shrink: 0; margin-top: 1px; }
.ed-hintbox b { font-size: 13px; }
.ed-hintbox p { font-size: 12px; line-height: 1.5; margin-top: 4px; }

/* ————— Сетки панелей ————— */
.ed-tplgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* Та же граница, что `.tpl-group` на карточке, в масштабе панели */
.ed-tplgroup {
  grid-column: 1 / -1; display: grid; gap: 3px;
  margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--line);
}
.ed-tplgroup b { font-size: 12.5px; }
.ed-tplgroup span { font-size: 12px; line-height: 1.5; color: var(--gray); }
.ed-tpl { display: grid; gap: 6px; border-radius: var(--radius); padding: 6px; transition: .16s; }
.ed-tpl__img {
  display: block; border-radius: var(--radius-sm); overflow: hidden;
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--line); aspect-ratio: 9 / 5;
}
.ed-tpl__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ed-tpl__cap { font-size: 12.5px; font-weight: 600; color: var(--gray); }
.ed-tpl:hover .ed-tpl__img { border-color: var(--line-strong); }
.ed-tpl.is-active .ed-tpl__img { border-color: var(--orange); }
.ed-tpl.is-active .ed-tpl__cap { color: var(--orange); }
.ed-tpl__cap .tpl-variant { display: block; font-weight: 400; color: var(--gray); }

.ed-filegrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.ed-filecard { display: grid; gap: 5px; border-radius: var(--radius); transition: .16s; }
.ed-filecard__img {
  display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3;
  border-radius: var(--radius-sm); overflow: hidden; background: var(--fill-lg); color: var(--gray-light);
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--line);
}
.ed-filecard__img img { width: 100%; height: 100%; object-fit: cover; }
.ed-filecard__cap { font-size: 11.5px; color: var(--gray); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ed-filecard:hover .ed-filecard__img { border-color: var(--orange); }

/* Выбор страницы PDF — поверх выдвижной панели, там же, где стоял файл */
.ed-pdfpick {
  position: absolute; inset: 0; z-index: 6; overflow: auto;
  padding: 16px; background: var(--white);
  display: flex; flex-direction: column; gap: 10px;
}
.ed-pdfpages { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.ed-pdfpage { display: grid; gap: 5px; border-radius: var(--radius); transition: .16s; }
.ed-pdfpage span {
  display: block; aspect-ratio: 4 / 3; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--fill-lg);
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--line);
}
.ed-pdfpage img { width: 100%; height: 100%; object-fit: contain; }
.ed-pdfpage em { font-style: normal; font-size: 11.5px; color: var(--gray); }
.ed-pdfpage:hover span { border-color: var(--orange); }

.ed-elgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ed-el {
  display: grid; justify-items: center; gap: 6px; padding: 12px 4px;
  border-radius: var(--radius-sm); background: var(--fill); color: var(--gray); transition: .16s;
}
.ed-el span { font-size: 10.5px; line-height: 1.15; text-align: center; }
.ed-el .ed-elemoji { font-size: 24px; line-height: 1; font-family: var(--font-emoji); }
.ed-el:hover { background: var(--cream-sm); color: var(--orange-dark); }

/* Семь столбцов — по числу цветов радуги в базовой палитре фона */
.ed-swatches { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.ed-swatch {
  aspect-ratio: 1; border-radius: 9px; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); transition: .14s;
}
.ed-swatch:hover { transform: scale(1.08); }
.ed-swatch.is-active { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12), 0 0 0 2px var(--orange); }
/* Кнопка цвета стоит первой строкой вкладки, поэтому отступ у неё снизу:
   сверху его уже дал предыдущий блок — вкладки или переключатель. */
.ed-bgacts { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 14px; }

.ed-patterns { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.ed-pattern { display: grid; gap: 5px; border-radius: var(--radius-sm); transition: .16s; }
.ed-pattern span {
  display: block; aspect-ratio: 1; border-radius: var(--radius-sm); background-color: var(--white);
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--line);
}
.ed-pattern em { font-size: 10.5px; color: var(--gray); font-style: normal; }
.ed-pattern:hover span { border-color: var(--line-strong); }
.ed-pattern.is-active span { border-color: var(--orange); }

/* ————— Всплывающие панели ————— */
.ed-pop {
  position: fixed; z-index: 60; background: var(--white); border-radius: var(--radius);
  box-shadow: 0 14px 44px rgba(0, 0, 0, .18); border: 1px solid var(--line);
  padding: 6px; min-width: 180px;
}
.ed-pop--menu { padding: 5px; }
.ed-menu__item {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 8px 10px;
  border-radius: 9px; font-size: 13px; color: var(--ink); transition: .14s; text-align: left;
}
.ed-menu__item:hover { background: var(--fill); }
.ed-menu__item--danger { color: var(--err); }
.ed-menu__item--danger:hover { background: var(--err-bg); }
.ed-menu__check { width: 14px; display: flex; color: var(--orange); flex-shrink: 0; }
/* Подсказка под меню: то же самое жестом */
.ed-menu__hint {
  padding: 8px 10px 4px; margin-top: 4px; border-top: 1px solid var(--line);
  font-size: 11.5px; line-height: 1.4; color: var(--gray-light);
}

.ed-pop--order { width: 300px; padding: 14px; }
.ed-order__list { display: grid; gap: 7px; margin-bottom: 12px; }
.ed-order__list > div { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; }
.ed-order__list dt { color: var(--gray); flex-shrink: 0; }
.ed-order__list dd { font-weight: 600; text-align: right; }
/* Невыбранное на карточке (C92) — тем же цветом, что строка в окне заказа */
.ed-order__list dd em { font-style: normal; color: var(--warn); }
.ed-order__total {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 10px 0; border-top: 1px solid var(--line); margin-bottom: 12px;
}
.ed-order__total span { font-size: 12.5px; color: var(--gray); }
.ed-order__total b { font-size: 19px; font-weight: 800; color: var(--orange); }
.ed-order__fields .ed-field { margin-bottom: 10px; }
.ed-order__toggle {
  display: flex; align-items: center; gap: 9px; font-size: 12.5px;
  padding: 9px 11px; border-radius: var(--r-control); background: var(--fill); cursor: pointer; margin-bottom: 10px;
}
.ed-order__toggle.is-active { background: var(--cream-sm); color: var(--orange-dark); font-weight: 600; }
.ed-order__toggle input { accent-color: var(--orange); }

/* Вопрос «убрать оборот?» показывается вместо полей — плашка та же, что у
   предупреждений препресса, своих цветов на один случай не заводим. */
.ed-order__warn {
  font-size: 12px; line-height: 1.5; color: var(--warn); background: var(--warn-bg);
  padding: 11px 12px; border-radius: var(--radius);
}
.ed-order__warn b { display: block; margin-bottom: 5px; font-size: 13px; }
.ed-order__ask { display: grid; gap: 7px; margin-top: 12px; }

/* ————— Форма и размер: панель геометрии —————
   Форму и формат выбирают глазами, поэтому в списке не названия, а силуэты:
   у наклейки и бирки — тот контур, что уедет на холст, у остальных изделий —
   пропорция формата и контур штампа, если он есть. Ширина панели рассчитана
   на три силуэта в ряд: восемь форм бирки складываются в три ровных ряда. */
.ed-pop--die { width: 316px; padding: 14px; max-height: 82vh; overflow-y: auto; }
/* Список внутри панели раскрывается в потоке, а не слоем: панель сама
   прокручивается и обрезала слой по нижнему краю — из пяти сложений было
   видно два (замечание 21 сентября). Теперь список раздвигает панель, а
   `placeDropdownList` докручивает её до последнего пункта. */
.ed-pop--die .dd__list { position: static; margin-top: 6px; max-height: none; box-shadow: none; }
/* Колонки считает auto-fit, а не жёсткая тройка: восемь форм бирки и шесть
   штампов дорхенгера ложатся по три в ряд, а два формата визитки занимают
   всю ширину вдвоём, вместо того чтобы жаться слева от пустого места.
   minmax с числом, а не с `1fr`: минимум колонки с `1fr` равен ширине самого
   длинного слова, и «Прямоугольник» растягивал свою колонку за счёт соседних. */
.ed-die__forms { display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: 6px; margin-bottom: 12px; }
.ed-die__form {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 9px 4px 7px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--white); transition: .14s; text-align: center;
}
.ed-die__form:hover { border-color: var(--line-strong); }
.ed-die__form.is-active { border-color: var(--orange); background: var(--cream-sm); }
.ed-die__form.is-active .ed-die__name { color: var(--orange); font-weight: 600; }
.ed-die__fig { display: flex; align-items: center; justify-content: center; height: 32px; color: var(--gray-light); }
.ed-die__form:hover .opt-shape { fill: var(--gray); }
.ed-die__form.is-active .opt-shape { fill: var(--orange); }
.ed-die__name { font-size: 10.5px; line-height: 1.25; color: var(--gray); }
/* Второй строкой у форматов идут миллиметры: название отвечает на «какой»,
   размер — на «сколько это». Оттенком тише, чтобы не спорили. */
.ed-die__name em { display: block; margin-top: 2px; font-size: 9.5px; font-style: normal; color: var(--gray-light); }

.ed-die .ed-field { margin-bottom: 12px; }
/* Книжная / альбомная — тот же сегмент, что и переключатели заливки, но с
   маленьким силуэтом листа перед подписью: на двух словах контраст между
   кнопками не всегда читается с первого взгляда, силуэт его усиливает. */
.ed-die__orient .ed-seg button { display: flex; align-items: center; justify-content: center; gap: 6px; }
.ed-die__orient-fig { flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 1.3; opacity: .7; }
/* Ширина и высота — две подписанные колонки: знак умножения между ними
   встаёт по центру полей, а не по центру всей пары с подписями. */
.ed-die__pair { display: flex; align-items: flex-end; gap: 8px; }
.ed-die__cell { flex: 1; min-width: 0; }
.ed-die__cell > span { display: block; font-size: 12px; font-weight: 700; color: var(--gray); margin-bottom: 6px; }
.ed-die__x { color: var(--gray-light); padding-bottom: 7px; }
.ed-die__pair .input { width: 100%; min-width: 0; }
.ed-die__size em { display: block; margin-top: 5px; }
.ed-die__slider .ed-nudge { width: 76px; flex-shrink: 0; }
.ed-die__slider .input { width: 100%; }

/* Ползунок: тот же приём, что у полосы оттенка в палитре — своя дорожка и
   своя ручка, потому что системный вид не поддаётся оформлению. */
.ed-range {
  flex: 1; height: 4px; -webkit-appearance: none; appearance: none;
  border-radius: var(--r-pill); background: var(--line-strong); cursor: pointer;
}
.ed-range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--orange); border: 2px solid var(--white);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .25); cursor: pointer;
}
.ed-range::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--white);
  background: var(--orange); box-shadow: 0 1px 4px rgba(0, 0, 0, .25); cursor: pointer;
}

.ed-die__hole { border-top: 1px solid var(--line); padding-top: 12px; }
.ed-die__image { margin-bottom: 12px; }
.ed-die__file { display: block; margin-bottom: 8px; }
.ed-die__file span {
  display: flex; align-items: center; justify-content: center; gap: 7px; height: 34px;
  border: 1px dashed var(--line-strong); border-radius: var(--r-control);
  font-size: 12.5px; font-weight: 600; color: var(--gray); cursor: pointer; transition: .14s;
}
.ed-die__file:hover span { border-color: var(--orange); color: var(--orange); }
.ed-die__image .ed-btn-ghost { width: 100%; margin-bottom: 8px; }

/* ————— Выбор цвета ————— */
.ed-pop--color { width: 276px; padding: 12px; }
/* Поле ловит нажатие рамкой на 8 px шире себя: за скруглением и у самого
   края нажатие иначе проходило мимо, и в угол с чистым белым было не
   попасть. Скругление у поля маленькое по той же причине. */
.edc__svhit { margin: -8px; padding: 8px; cursor: crosshair; touch-action: none; }
.edc__sv { position: relative; height: 132px; border-radius: 4px; }
.edc__sv:focus { outline: none; }
.edc__sv:focus-visible { box-shadow: 0 0 0 2px var(--orange); }
.edc__dot {
  position: absolute; width: 13px; height: 13px; border-radius: 50%; margin: -6.5px 0 0 -6.5px;
  border: 2px solid var(--white); box-shadow: 0 0 0 1px rgba(0, 0, 0, .3); pointer-events: none;
}
.edc__hue {
  width: 100%; height: 12px; margin: 12px 0; -webkit-appearance: none; appearance: none;
  border-radius: var(--r-pill); background: linear-gradient(90deg,
    #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
.edc__hue::-webkit-slider-thumb {
  -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--white); border: 2px solid var(--white); box-shadow: 0 0 0 1px rgba(0, 0, 0, .3); cursor: pointer;
}
.edc__btn {
  width: 32px; height: 32px; border-radius: 9px; background: var(--fill); color: var(--gray);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: .14s;
}
.edc__btn:hover { background: var(--cream-sm); color: var(--orange-dark); }
/* Пипетка включена и ждёт тычка в макет */
.edc__btn.is-on { background: var(--cream-sm); color: var(--orange-dark); }

/* Шапка палитры: вкладки способа ввода и пипетка. Вкладки — тот же
   сегмент, что «Цвет / Паттерн / Картинка» у фона, только ниже: в палитре
   шириной 276 они не должны перетягивать внимание с самого цвета. */
.edc__head { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
.edc__tabs { flex: 1; min-width: 0; }
.edc__tabs button { height: 32px; font-size: 12px; }
.edc__pane[hidden] { display: none; }

/* Ячейки кодов: подпись канала над полем, над подписью — полоска цвета
   канала: у красок — цвет самой краски, у RGB — цвет луча экрана. Так C, M,
   Y, K и R, G, B читаются без знания букв, и обе вкладки свёрстаны
   одинаково. */
.edc__fields { display: grid; gap: 6px; }
.edc__fields--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.edc__fields--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.edc__cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.edc__cell > span { font-size: 11px; font-weight: 600; color: var(--gray); }
.edc__cell--wide { margin-top: 8px; }
/* Код целиком и кнопка копирования рядом: HEX во вкладке RGB и код красок
   во вкладке CMYK устроены одинаково — вставить сюда, скопировать отсюда. */
.edc__row { display: flex; align-items: flex-end; gap: 6px; margin-top: 8px; }
.edc__row .edc__cell { flex: 1; }
.edc__row .edc__btn--sm { width: 32px; height: 32px; border-radius: 9px; }
.edc__bar { display: block; height: 4px; border-radius: 2px; }
.edc__num {
  width: 100%; min-width: 0; height: 32px; padding: 0 8px;
  font-size: 12.5px; font-family: 'JetBrains Mono', monospace; letter-spacing: .02em;
  border: 1px solid var(--line-strong); border-radius: 9px; background: var(--white);
}
.edc__num:focus { outline: none; border-color: var(--orange); }
.edc__num::placeholder { font-family: var(--font); font-size: 11.5px; color: var(--gray-light); }
/* Сумма красок — число, за которым следят: по центру под ячейками, крупнее
   подписей полей (23 сентября 2026, замечание заказчицы). Перебор —
   цветом предупреждения. */
.edc__sum {
  margin-top: 10px; text-align: center;
  font-size: 12.5px; color: var(--gray);
}
.edc__sum b { font-weight: 600; color: var(--ink); }
.edc__sum[hidden] { display: none; }
.edc__sum.is-over, .edc__sum.is-over b { color: var(--warn); }
/* Номер Pantone без своих красок: цвет элемента не изменился — поле и
   подсказка под ним цветом предупреждения, пока не введут CMYK */
.edc__spot.is-pending .edc__num { border-color: var(--warn); background: var(--warn-bg); }
.edc__spothint { margin-top: 5px; font-size: 11px; line-height: 1.4; color: var(--warn); }
/* Pantone — внизу вкладки CMYK, за строкой «Есть номер Pantone?»: случай
   редкий, и рядом с ним — дорога к менеджеру для тех, у кого нет CMYK */
.edc__spotwrap { margin-top: 12px; border-top: 1px solid var(--line); border-bottom: 0; }
.edc__spotwrap .ed-fold__head { padding: 10px 0; font-size: 12.5px; }
.edc__spotwrap .ed-fold__body { padding-bottom: 4px; }
.edc__spotwrap[hidden] { display: none; }
.edc__spotnote { margin-top: 6px; font-size: 11px; line-height: 1.45; color: var(--gray); }
.edc__spotnote a, .edc__spotnote button { color: var(--gray); text-decoration: underline; white-space: nowrap; font: inherit; }
.edc__spotnote a:hover, .edc__spotnote button:hover { color: var(--orange-dark); }
.edc__spothint[hidden] { display: none; }

/* Экран и бумага — одна плашка из двух половин вплотную: разницу видно
   сразу, как на карточках Pantone «Solid / CMYK». На вкладке CMYK экранной
   половины нет — у красок, введённых числами, экранного оригинала нет, —
   и бумага занимает всю ширину. */
.edc__pair { display: flex; gap: 2px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
/* Подпись над плашкой, как у всех полей палитры: сначала что это, потом
   сам цвет (23 сентября 2026, замечание заказчицы) */
.edc__half { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.edc__half[hidden] { display: none; }
.edc__half i { display: block; height: 34px; border: 1px solid var(--line); }
.edc__half:first-child i { border-radius: 8px 0 0 8px; border-right: 0; }
.edc__half:last-child i { border-radius: 0 8px 8px 0; border-left: 0; }
.edc__half[hidden] + .edc__half i { border-radius: 8px; border-left: 1px solid var(--line); }
.edc__half span { font-size: 11px; font-weight: 600; color: var(--gray); }
.edc__half:last-child span { text-align: right; }
.edc__half[hidden] + .edc__half span { text-align: left; }

/* Для печати — отдельным блоком под линией: заголовок и копирование одной
   строкой, краски под ними ровными колонками во всю ширину. */
.edc__print { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.edc__print[hidden] { display: none; }
.edc__printhead { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.edc__lbl { font-size: 11px; font-weight: 600; color: var(--gray); }
.edc__inks { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.edc__ink { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.edc__ink i { display: block; width: 100%; height: 4px; border-radius: 2px; }
.edc__ink b { font-size: 12.5px; font-weight: 600; font-family: 'JetBrains Mono', monospace; }
.edc__btn--sm { width: 28px; height: 28px; border-radius: 8px; }

/* Недавние и «Без цвета» — под своей линией: это уже не про текущий цвет */
.edc__foot { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.edc__foot .edc__none { margin-top: 0; }
.edc__foot .edc__recent + .edc__none { margin-top: 10px; }

.edc__none {
  display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; height: 32px; border-radius: 9px; background: var(--fill);
  font-size: 12px; font-weight: 600; color: var(--gray); transition: .14s;
}
.edc__none:hover { background: var(--err-bg); color: var(--err); }

/* Предупреждение о непечатном цвете: две фразы, вторая мельче первой — её
   дочитывает тот, у кого цвет фирменный. Появляется только когда расхождение
   перешло порог, поэтому палитра обычно без него. Стоит последним, под
   «Без цвета» (C57), и цвета предупреждения — как строка под полем. */
/* Предупреждение идёт сразу за плашками «Экран / На бумаге» и читается с
   ними как одно целое, поэтому линии между ними нет (23 сентября 2026). */
.edc__gamut { margin-top: 10px; }
.edc__gamut:empty { display: none; }
.edc__gamut p { font-size: 11.5px; line-height: 1.45; color: var(--warn); }
.edc__gamut p + p { margin-top: 6px; font-size: 11px; }
/* На вкладке CMYK подсказка не предупреждает, а подтверждает: краски уйдут
   как введены. Поэтому спокойным серым, а ссылка на менеджера — ещё мельче:
   это для редкого случая, отдельной краски или цветопробы. */
.edc__gamut--quiet p { color: var(--gray); }
.edc__go {
  display: block; width: 100%;
  margin-top: 8px; height: 30px; padding: 0 12px; border-radius: 9px;
  background: var(--fill); color: var(--ink); font-size: 12px; font-weight: 600; transition: .14s;
}
.edc__go:hover { background: var(--cream-sm); color: var(--orange-dark); }

/* Недавние цвета — своя зона под линией: квадраты одного размера, ряд от
   левого края (23 сентября 2026). Сеткой на десять колонок они
   растягивались по ширине палитры, и три цвета выглядели как три полосы;
   по центру ряд из двух-трёх квадратов висел в воздухе. */
.edc__recentbox { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.edc .ed-sub { margin: 0 0 7px; }
.edc__recent { display: flex; flex-wrap: wrap; gap: 5px; }
.edc__recent .ed-swatch { width: 24px; height: 24px; border-radius: 7px; }

/* ————— Короткое сообщение поверх редактора —————
   Живёт в правом нижнем углу холста (15 сентября 2026). По центру снизу оно
   ложилось на карточки сторон — ровно туда, куда смотрят после «оборот
   вернули». Угол холста свободен: слева легенда, по центру стороны, справа
   ничего. Прибито к `.ed-canvas`, а не к окну: у окна в этом углу панель
   свойств. Подъём над карточками сторон на узком холсте и над соседним
   сообщением считает `placeOnCanvas` (app.js).

   Скругление карточное, а не пилюлей (18 сентября 2026): пилюля — для
   меток, и на сообщении в две строки она поджимала текст к краям. */
.ed-toast {
  position: absolute; right: 16px; bottom: 16px; z-index: 4;
  background: var(--ink); color: var(--white); font-size: 13px; line-height: 1.5;
  padding: 12px 18px; border-radius: var(--radius); box-shadow: 0 10px 30px rgba(0, 0, 0, .25);
  max-width: min(460px, calc(100% - 32px));
}
/* С кнопкой сообщение становится строкой «текст — действие»: кнопка не
   переносится под текст и не растягивает пилюлю в блок. */
.ed-toast--act { display: flex; align-items: center; gap: 14px; padding-right: 8px; }
.ed-toast__act {
  flex: none; padding: 6px 14px; border-radius: var(--r-control);
  background: var(--orange); color: var(--white); font-size: 13px; font-weight: 700;
  transition: background .16s;
}
.ed-toast__act:hover { background: var(--orange-light); }
/* Действие по желанию — ссылкой в строке, цветом текста: предлагает, а не
   зовёт нажать */
.ed-toast__link {
  display: inline; padding: 0; font: inherit; font-weight: 600; color: inherit;
  text-decoration: underline; text-underline-offset: 2px;
}
.ed-toast__link:hover { color: var(--orange-light); }

/* ============================================================
   23  Предпросмотр макета
   Два режима: с линиями — холст с вылетом; без линий — готовое изделие.
   ============================================================ */
/* Окно облегает изделие: у плаката оно узкое и высокое, у визитки широкое.
   Раньше коробка всегда была во всю ширину, и вокруг вертикального плаката
   оставались пустые поля в пол-экрана. */
.pv__box { width: fit-content; min-width: 340px; max-width: min(1300px, 94vw); }


/* Подложка под изделием того же серого, что холст редактора. Белый макет на
   белом фоне не читается как предмет: контраст даёт подложка, а не тень. */
/* Поля подложки заметно шире промежутка между сторонами: так две стороны
   читаются как пара, а не как два отдельных предмета, прижатых к краям.
   Числа связаны с расчётом в preview.js — правишь здесь, правь и там. */
.pv__sides {
  display: flex; gap: 22px; justify-content: center; flex-wrap: nowrap;
  padding: 54px; margin-top: 4px;
  border-radius: var(--radius);
  /* Свет сверху: на ровном сером тень внизу читается нарисованной, а с
     перепадом светлоты — падающей. Бумажной фактуры нет нарочно: мелкое
     зерно читалось как испорченное сжатие картинки, крупное пятнами тоже не
     прижилось — сняты 16 сентября 2026 по решению заказчицы. */
  background-color: #eceff2;
  background-image:
    radial-gradient(120% 90% at 50% 0%, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0) 65%);
}
.pv__side { text-align: center; }
/* Стороны друг под другом — раскладку выбирает `Preview.layout`, когда в
   столбик изделие выходит крупнее, чем в ряд: на телефоне визитка рядом со
   своим оборотом была шириной 119 px при месте под 280 (C90) */
.pv__sides--stack { flex-direction: column; align-items: center; }

/* Тень из нескольких слоёв, см. --shadow-product: короткая и плотная прижимает
   край к подложке, длинная и слабая даёт объём. Одна большая размытая тень на
   светлом фоне выглядит грязным пятном — отсюда и ощущение мутности. */
.pv__stage {
  position: relative;
  background: var(--white);
  box-shadow: var(--shadow-product);
  overflow: hidden;
}
/* Превью внутри окна проверки: макет под списком замечаний. Порядок тот же,
   что на странице проверки файла, — сначала ответ «что не так», потом
   картинка. Полюбоваться макетом можно и без проверки, кнопкой «Превью». */
/* Нижняя строка окна: волосяная линия отделяет действия от отчёта, иначе
   кнопки читаются продолжением картинки. Стоят по центру — как картинка
   макета над ними и как действия в остальных окнах. */
.check-actions {
  display: flex; justify-content: center; gap: 12px; flex-wrap: wrap;
  margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--line);
}
.check-pv__wait { padding: 30px 0; text-align: center; font-size: 13.5px; color: var(--gray-light); }
/* Замечание, у которого есть место на макете, отзывается на наведение */
.pf-issue.is-locatable { cursor: default; transition: background .15s; }
.pf-issue.is-locatable:hover { background: var(--fill-lg); }
/* Список стоит выше картинки, и в окно они попадают вместе не всегда —
   поэтому у замечания есть и щелчок: прокручивает к макету и зажигает рамку. */
.pf-issue__where {
  margin-top: 8px; font-size: 13px; font-weight: 600; color: var(--orange-dark);
  text-decoration: underline; text-underline-offset: 2px;
}
.pf-issue__where:hover { color: var(--ink); }

/* Подсветка объекта, к которому относится замечание */
.pv__mark {
  position: absolute; pointer-events: none; border-radius: 2px;
  opacity: 0; transition: opacity .15s;
}
.pv__mark.is-on { opacity: 1; }
.pv__mark--error { outline: 2px solid var(--err); background: rgba(192, 57, 43, .16); color: var(--err); }
.pv__mark--warn { outline: 2px solid var(--warn); background: rgba(217, 130, 24, .16); color: var(--warn); }
.pv__mark--info { outline: 2px solid var(--info); background: rgba(43, 108, 176, .16); color: var(--info); }
/* Кольцо у тонкого объекта: длинную плоскую рамку глаз принимает за линию
   макета, а кольцо вокруг середины читается как указатель на место. Белый
   ободок держит его видным на любом фоне. */
.pv__ring {
  position: absolute; left: 50%; top: 50%; width: 28px; height: 28px; margin: -14px 0 0 -14px;
  border-radius: 50%; border: 2px solid currentColor; box-shadow: 0 0 0 2px var(--white);
}
/* max-width: none обязателен: после резки картинка шире листа на вылет с
   обеих сторон, а общее `img { max-width: 100% }` ужимало её до листа —
   правый край не доходил на вылет, и штамп срезал изделие по прямой
   (13 сентября 2026, «Стадион»). */
.pv__img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; }
.pv__empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--gray-light); background: var(--fill-lg);
}
/* Фигурное изделие в предпросмотре: белого прямоугольника под ним нет —
   картинка уже обрезана по штампу, и тень должна идти по силуэту.

   Тень висит на обёртке, а не на самом листе: `clip-path` применяется после
   фильтров, поэтому тень на том же элементе он срезал бы вместе с полями —
   изделие оставалось без тени вовсе. На родителе фильтр видит уже обрезанный
   силуэт, и тень повторяет форму. */
.pv__sheet {
  /* Те же слои, что в --shadow-product, только без волосяной линии: у
     drop-shadow нет разлёта, и отрицательный spread не записать. */
  filter: drop-shadow(0 1px 1px rgba(16, 24, 32, .22))
          drop-shadow(0 4px 6px rgba(16, 24, 32, .12))
          drop-shadow(0 18px 26px rgba(16, 24, 32, .24));
}
.pv__stage--shaped { background: none; box-shadow: none; }
.pv__cut { position: absolute; left: 0; top: 0; overflow: visible; }
.pv__cut path { fill: none; }
/* Двойная толщина: лист обрезан по этой же линии, половину обводки срежет
   clip-path — на экране остаётся ровно одна линия по краю. */
.pv__cut--bleed { stroke: rgba(240, 93, 32, .75); stroke-width: 2; stroke-dasharray: 5 4; }
.pv__cut--trim { stroke: rgba(0, 0, 0, .8); stroke-width: 1; }
.pv__cut--safe {
  stroke: color-mix(in srgb, var(--guide-safe) 80%, transparent);
  stroke-width: 1; stroke-dasharray: 4 3;
}

.pv__guides { position: absolute; inset: 0; pointer-events: none; }
.pv__bleed, .pv__trim, .pv__safe { position: absolute; }
.pv__bleed { inset: 0; outline: 1px dashed rgba(240, 93, 32, .75); outline-offset: -1px; }
.pv__trim  { outline: 1px solid rgba(0, 0, 0, .8); }
.pv__safe  { outline: 1px dashed color-mix(in srgb, var(--guide-safe) 80%, transparent); }

.pv__cap { margin-top: 10px; font-size: 13.5px; font-weight: 600; color: var(--gray); }

/* Обозначения линий: строка-кнопка под подложкой и список под ней. Поверх
   подложки панель стоять не может — она закрывает то самое изделие, ради
   которого окно открыли; тремя строками, как было до 10 сентября 2026, она
   занимала больше места, чем сам макет. Управление одно: строка гасит линии на
   изделии, объяснения уходят вместе с ними. Отдельного «свернуть» нет нарочно
   — оно двигало всё, что ниже, не меняя ничего на картинке. */
.pv__legend {
  margin-top: 16px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 13px;
  font-size: 13px; color: var(--gray);
}
.pv__legend-switch {
  font-size: 13px; font-weight: 600; color: var(--orange-dark);
  transition: color .14s;
}
.pv__legend-switch:hover { color: var(--ink); }
.pv__legend-body { display: flex; flex-direction: column; gap: 9px; }
/* Строка обозначения: пунктир, промежуток, текст. Без промежутка отрезок
   линии прилипает к слову и читается частью буквы. */
.pv__legend-body span { display: flex; align-items: center; gap: 10px; }
/* Линии убраны: гаснут только они. Изделие остаётся на месте и того же
   размера — перерисовки нет, иначе картинка прыгала бы на каждое нажатие. */
.pv.is-clean .pv__guides,
.pv.is-clean .pv__cut { display: none; }
/* Объяснения прячем, но место за ними оставляем: при `display: none` панель
   становилась ниже, и кнопки под ней вместе с подвалом прыгали вверх на
   каждое нажатие (14 сентября 2026, замечание заказчицы). */
.pv.is-clean .pv__legend-body { visibility: hidden; }

.pv__k { width: 22px; height: 0; display: inline-block; flex-shrink: 0; }
.pv__k--bleed { border-top: 1px dashed var(--orange); }
.pv__k--trim { border-top: 1px solid #000; }
.pv__k--safe { border-top: 1px dashed var(--guide-safe); }

/* ============================================================
   24  Корзина
   ============================================================ */
.guest-note {
  display: flex; align-items: center; gap: 18px;
  background: var(--cream); border-radius: var(--radius);
  padding: 20px 24px;
}
.guest-note__ic {
  width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0;
  background: var(--white); color: var(--orange);
  display: flex; align-items: center; justify-content: center;
}
.guest-note__ic svg { width: 22px; height: 22px; }
.guest-note b { display: block; font-size: 15.5px; margin-bottom: 3px; }
.guest-note span { display: block; font-size: 13.5px; color: var(--gray); }
.guest-note .btn { flex-shrink: 0; height: 46px; padding: 0 24px; font-size: 14.5px; }
/* После оплаты: значок, текст, под ним кнопка — всё по центру. В строку
   кнопка с номером телефона забирала половину ширины, и текст рядом
   складывался в узкую колонку на семь строк (14 сентября 2026). */
.guest-note--stack { flex-direction: column; text-align: center; padding: 24px; }
.guest-note--stack span { max-width: 440px; margin: 0 auto; }

.cart-list { display: grid; gap: 14px; }
/* Миниатюра позиции — корзина, оформление, кабинет (21 сентября 2026).
   Слот фиксированного размера держит вёрстку, а внутри лежит само изделие
   в своих пропорциях: визитка — узкой полосой, А6 — стоячим листом. Подложки
   у слота нет: белый прямоугольник вокруг макета читался частью изделия, и
   визитка с листовкой выглядели одинаковыми рамками. Край изделию даёт
   волосяная линия по контуру, без тени (22 сентября 2026): тень делала
   значок в строке заказа предметом из предпросмотра и удешевляла интерфейс.
   На цветном макете линия растворяется, на белом и сером держит край листа.
   drop-shadow, а не outline, потому что у фигурной вырубки миниатюра
   прозрачная и линия должна идти по контуру. Тень изделия остаётся только в
   предпросмотре, см. --shadow-product.
   Снимок продукции (позиция с чужим файлом) — не изделие, а фотография: он
   заливает слот целиком. position: relative обязателен: заглушка .ph внутри
   абсолютная и без него отмеряет размеры от ближайшего позиционированного
   предка — на оформлении это липкая сводка .co-side, и заглушка заливала её
   целиком. */
.cart-item__img, .co-item__img, .order__img {
  position: relative; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.cart-item__img > img, .co-item__img > img, .order__img > img {
  display: block; width: auto; height: auto; max-width: 100%; max-height: 100%;
  filter: drop-shadow(0 0 .5px rgba(16, 24, 32, .30));
}
.cart-item__img > img.is-photo, .co-item__img > img.is-photo, .order__img > img.is-photo {
  width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-sm); filter: none;
}
.cart-item__img > .ph, .co-item__img > .ph, .order__img > .ph { border-radius: var(--radius-sm); }
/* Позиция — как карточка заказа в кабинете (14 сентября 2026): превью слева,
   справа сверху название и цена, под ними таблица параметров, внизу через
   линию тираж и действия. Раньше в строке было четыре колонки — батарея
   текста, тираж, цена и две подчёркнутые ссылки, — и глаз не понимал, что
   к чему относится. */
.cart-item {
  display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 20px;
  align-items: start; padding: 20px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--white);
}
.cart-item__img { width: 110px; height: 82px; }
/* Название переносится, цена — нет: она держит правый край */
.cart-item__head { display: flex; align-items: flex-start; gap: 16px; }
.cart-item__head > div:first-child { min-width: 0; }
.cart-item__head b { display: block; font-size: 17px; margin-bottom: 4px; }
.cart-item__head span { display: block; font-size: 13.5px; color: var(--gray); }
.cart-item__repeat {
  display: inline-block !important; margin-top: 6px;
  font-size: 12px !important; font-weight: 700; color: var(--orange-dark) !important;
  background: var(--cream-sm); padding: 3px 10px; border-radius: var(--r-pill);
}
.cart-item__price { margin-left: auto; flex-shrink: 0; text-align: right; }
.cart-item__sum { font-size: 19px; font-weight: 800; white-space: nowrap; }
.cart-item__unit { font-size: 12.5px; color: var(--gray); margin-top: 2px; }
/* Подвал позиции: тираж слева, действия справа. Удаление — значком корзины,
   тем же `.design__del`, что в «Моих макетах» (раздел 26). */
.cart-item__foot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
}
.cart-item__qty { display: flex; align-items: center; gap: 10px; }
.cart-item__qty label { font-size: 12px; font-weight: 700; color: var(--gray); }
.cart-item__qty .dd { width: 150px; }
.cart-item__qty .dd__btn { height: 40px; font-size: 14px; padding: 0 12px; }
.cart-item__acts { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.cart-item__acts .btn { height: 40px; padding: 0 16px; font-size: 13.5px; }

.cart-add {
  display: flex; align-items: center; justify-content: center;
  padding: 20px; border: 1.5px dashed var(--line-strong); border-radius: var(--radius);
  font-weight: 600; color: var(--gray); transition: .18s;
}
.cart-add:hover { border-color: var(--orange); color: var(--orange-dark); background: var(--cream-sm); }

/* ============================================================
   25  Оформление заказа
   ============================================================ */

/* Вернуть адрес по умолчанию — ссылка под полем, а не кнопка: действие
   служебное и появляется, только когда адрес поменяли руками */
.co-addr-reset {
  margin-top: 8px; font-size: 13.5px; font-weight: 600;
  color: var(--orange); background: none; text-decoration: underline;
}
.co-addr-reset:hover { color: var(--ink); }
.co { display: grid; grid-template-columns: 1fr 380px; gap: 34px; align-items: start; }
/* Две равные колонки — профиль в кабинете. Классом, а не инлайном: инлайн
   не даёт «Адаптиву» свернуть их в одну на узком экране. */
.co--half { grid-template-columns: 1fr 1fr; }
.co-block { border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 28px; margin-bottom: 18px; }
.co-block h2 { font-size: 22px; margin-bottom: 18px; }
.co-opts { display: grid; gap: 10px; }
.co-opt {
  display: flex; gap: 14px; align-items: flex-start; padding: 16px 18px;
  border: 1px solid var(--line); border-radius: var(--radius); cursor: pointer; transition: .16s;
}
.co-opt:hover { border-color: var(--orange); }
.co-opt.is-active { border-color: var(--orange); background: var(--cream-sm); }
.co-opt input { margin-top: 3px; accent-color: var(--orange); }
.co-opt b { display: block; font-size: 15px; }
.co-opt span { font-size: 13.5px; color: var(--gray); }
.co-opt em { font-style: normal; margin-left: auto; font-weight: 700; white-space: nowrap; }

/* Реквизиты для счёта: подблок внутри «Оплаты», видимый только когда выбран
   счёт юрлицу. Отделён линией сверху, а не плашкой — это продолжение выбора
   способа оплаты, а не отдельная карточка. */
.co-invoice { margin-top: 22px; padding-top: 22px; border-top: 1px solid var(--line); }
.co-invoice h3 { font-size: 17px; margin-bottom: 8px; }
.co-invoice__lead { font-size: 14px; color: var(--gray); margin-bottom: 16px; }
.co-invoice__note { margin-top: 14px; font-size: 13.5px; color: var(--gray); }

.co-side { position: sticky; top: 20px; border-radius: var(--radius-lg); background: var(--fill-lg); padding: 28px; }
.co-side h3 { font-size: 19px; margin-bottom: 18px; }
.co-row { display: flex; justify-content: space-between; gap: 16px; font-size: 14.5px; padding: 9px 0; }
/* Название позиции переносится, сумма — нет: она держит правый край колонки
   и не разваливается на «500» и «₽». min-width снимает минимум флекса,
   иначе длинное название распирает строку и толкает сумму за край. */
.co-row span:first-child { color: var(--gray); min-width: 0; }
.co-row > :last-child { flex-shrink: 0; text-align: right; white-space: nowrap; }
.co-row--total { border-top: 1px solid #e2e2e2; margin-top: 10px; padding-top: 16px; font-size: 20px; font-weight: 800; }
.co-row--total b { color: var(--orange); }

/* Финальная сверка: все параметры видно построчно.

   Позиция набрана столбиком: превью, под ним название и цена одной строкой,
   ниже параметры таблицей во всю ширину сводки (C70). До 13 сентября 2026 это
   были три колонки — превью, текст, цена, — и на параметры оставалась узкая
   середина: короткое значение вставало напротив подписи, длинное
   переносилось под неё вправо, выходила лесенка. */
.co-item { padding-bottom: 18px; margin-bottom: 14px; border-bottom: 1px solid #e6e6e6; }
/* Миниатюра слева от названия с ценой, как в корзине и кабинете; таблица
   параметров под ними во всю ширину сводки. До 21 сентября 2026 превью
   стояло над позицией на всю ширину — белой плашкой высотой 132 px, и в
   заказе из трёх позиций сводка вырастала на три таких плашки. */
.co-item__top { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 16px; align-items: center; }
.co-item__img { width: 92px; height: 66px; }
/* Название переносится, цена — нет: она держит правый край */
.co-item__head { display: flex; align-items: baseline; gap: 12px; }
.co-item__head b { font-size: 15px; min-width: 0; }
.co-item__sum { margin-left: auto; font-style: normal; font-weight: 700; white-space: nowrap; }
/* Две колонки, общие для всех строк: подпись слева, значение напротив, оба
   по левому краю. Длинное значение переносится внутри своей колонки, имя
   файла — по любому символу, чтобы не распирать колонку. */
.co-specs { margin-top: 10px; display: grid; gap: 5px; }
.co-specs div { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 12px; font-size: 12.5px; }
.co-specs dt { color: var(--gray-light); }
.co-specs dd { color: var(--gray); overflow-wrap: anywhere; }
/* Широкая таблица — карточки кабинета и позиции корзины. Та же `.co-specs`,
   что в сводке выше, только шире. Колонка подписей одной ширины во всех
   таблицах: в карточке заказа их несколько — по позиции и доставка, — и
   колонка «по самой длинной подписи» ставила значения каждой таблицы на свою
   линию. Подпись длиннее колонки переносится внутри неё. На телефоне колонка
   в долях ширины — «Адаптив». Кегль — как у служебных строк карточки. */
.co-specs--wide { grid-template-columns: minmax(0, 12em) minmax(0, 1fr); column-gap: 12px; row-gap: 5px; }
.co-specs--wide div { display: contents; font-size: 13.5px; }
.co-specs--wide a { color: var(--orange-dark); text-decoration: underline; text-underline-offset: 2px; }

.co-error {
  margin-top: 14px; padding: 12px 16px; border-radius: var(--radius);
  background: var(--err-bg); color: var(--err); font-size: 14px;
}

/* ============================================================
   26  Личный кабинет
   ============================================================ */
/* Подтверждение после переключения согласия на рассылку: галочка сама по
   себе не показывает, что состояние сохранилось. */
.acc-note {
  margin-top: 10px; padding: 12px 16px; border-radius: var(--radius);
  background: var(--ok-bg); color: var(--ok); font-size: 14px;
}
.acc-head { display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap; margin-bottom: 26px; }
/* Длинная почта вместо имени не должна распирать страницу на телефоне */
.acc-user { display: flex; align-items: center; gap: 14px; min-width: 0; max-width: 100%; }
.acc-user > div { min-width: 0; }
.acc-ava {
  flex: none; width: 56px; height: 56px; border-radius: 50%; background: var(--orange); color: var(--white);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 21px;
}
.acc-user b { font-size: 18px; display: block; overflow-wrap: anywhere; }
.acc-user span { display: block; font-size: 14px; color: var(--gray); overflow-wrap: anywhere; }

/* Карточка по верхнему краю: у заказа параметры идут таблицей по позициям,
   и превью, выровненное по центру высокой карточки, висело бы посередине */
.order {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; margin-bottom: 16px;
  display: grid; grid-template-columns: 92px 1fr auto; gap: 22px; align-items: start;
}
/* Позиция заказа своим блоком: название с тиражом и цена — `.co-item__head`
   с оформления, под ними таблица параметров. Позиции делит волосяная линия,
   и той же линией от них отделены доставка и оплата (C74). */
.order__item + .order__item,
.order__foot { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
/* Заказ с картинкой у каждой позиции: общей картинки слева нет, заголовок
   заказа во всю ширину, у позиции миниатюра и таблица рядом. Подвал с
   доставкой встаёт под таблицы, а не под миниатюры. */
.order--items { grid-template-columns: minmax(0, 1fr) auto; }
.order--items .order__title { font-size: 22px; margin-bottom: 14px; }
.order--items .order__item { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 22px; align-items: start; }
.order--items .order__item .co-specs { margin-top: 6px; }
.order--items .order__item > div:last-child > .co-specs:first-child { margin-top: 0; }
.order--items .order__foot { margin-left: 114px; }
.order__foot .co-specs { margin-top: 0; }
/* Над подвалом ничего нет — сообщение с «Контактов» без параметров и
   текста: линия под самым заголовком отделяла бы пустоту */
.order__title + .order__foot { margin-top: 0; padding-top: 0; border-top: 0; }

.order__img { width: 92px; height: 66px; }
.order__no { font-size: 13px; color: var(--gray); margin-bottom: 4px; }
.order__title { font-size: 18px; font-weight: 700; margin-bottom: 6px; }
.order__opts { font-size: 13.5px; color: var(--gray); }
.order__side { text-align: right; display: grid; gap: 10px; justify-items: end; }
/* Кнопки в столбце — одной ширины: «Повторить заказ» и «Вопрос по заказу»
   разной длины смотрелись двумя разными по важности элементами (23 сентября
   2026). Ширину задаёт самая длинная надпись. */
.order__side .btn { width: 100%; max-width: 280px; justify-content: center; }
.order__sum { font-size: 20px; font-weight: 800; }
/* Заявка: картинки и суммы нет, поэтому две колонки, а текст задачи —
   абзацем под параметрами, не серой строкой параметров (C71) */
.order--request { grid-template-columns: 1fr auto; align-items: start; }
.order__text { margin-top: 10px; font-size: 14.5px; color: var(--ink); white-space: pre-line; }

.status { font-size: 12.5px; font-weight: 700; padding: 5px 13px; border-radius: var(--r-pill); display: inline-block; }
.status--done { background: var(--ok-bg); color: var(--ok); }
.status--new { background: var(--cream-sm); color: var(--orange-dark); }

.design-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.design {
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--white); transition: .2s;
}
.design:hover { border-color: var(--orange); box-shadow: var(--shadow-hover); }
.design__img { aspect-ratio: 90 / 50; border-radius: var(--radius-sm); background: var(--fill-lg); display: flex; align-items: center; justify-content: center; padding: 12px; }
.design__img img { max-width: 100%; max-height: 100%; box-shadow: var(--shadow); }
.design__body { padding: 16px; }
.design__body b { font-size: 15px; display: block; margin-bottom: 4px; }
.design__body span { font-size: 12.5px; color: var(--gray); }
.design__acts { display: flex; gap: 8px; padding: 0 16px 16px; }
.design__acts .btn { height: 40px; padding: 0 16px; font-size: 13.5px; flex: 1; }
/* Удаление — иконка, а не третья кнопка в ряд: действие редкое и обратного
   хода не имеет, соседям по весу оно не ровня. Красным становится только под
   курсором, чтобы карточка не выглядела предупреждением. */
.design__del {
  flex: none; width: 40px; height: 40px; display: grid; place-items: center;
  border-radius: var(--r-control); color: var(--gray); transition: .16s;
}
.design__del:hover { background: var(--err-bg); color: var(--err); }

/* Окно входа: ссылки-переходы между шагами (вход, регистрация, «Забыли
   пароль?»). Кнопки, а не ссылки: никуда не ведут, только меняют шаг.
   До 14 октября 2026 здесь были поля кода из SMS. */
.auth-links { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.auth-link {
  padding: 6px 0; font-size: 14.5px; color: var(--orange-dark);
  text-decoration: underline; text-underline-offset: 3px; background: none; border: 0; cursor: pointer;
}
.auth-link:hover { color: var(--orange); }

/* ============================================================
   27  Адаптив
   Порядок — по убыванию ширины. Внутри блока правило побеждает
   любое из блока выше, поэтому новые правки добавляем в свой блок.

   Шапка сжимается ступенями:
     1440+       логотип · меню · телефон со статусом · корзина · кабинет · кнопка
     1240–1439   телефон сворачивается в иконку, меню и кнопка остаются
     до 1240     меню уезжает в бургер
   ============================================================ */

/* Шапка не помещается в 1440 — отдаём ей поля контейнера */
@media (max-width: 1520px) {
  .container { padding: 0 24px; }
  /* Лента отзывов вылезает в поле страницы ровно на его ширину — здесь она
     стала 24, значит и вылет с прилипанием тоже. */
  .reviews__track { margin-inline: -24px; padding-inline: 24px; scroll-padding-inline: 24px; }
  /* То же самое для ленты продуктов на главной. Без этой строки она
     продолжала вылезать на 40 при поле в 24, то есть на 16 px за правый край
     окна, и вся страница получала горизонтальную прокрутку на ноутбучных
     ширинах 1240–1520. */
  .layout-ribbon {
    margin-inline: calc((100vw - min(var(--container), 100vw)) / -2 - 24px);
    padding-left: calc((100vw - min(var(--container), 100vw)) / 2 + 24px);
  }
}

@media (max-width: 1439px) {
  /* Номер не помещается — сворачиваем в иконку, но поповер с контактами
     остаётся: раньше здесь стояла голая ссылка «позвонить» и данные пропадали.
     Значок — телеграм, а не трубка (16 сентября 2026): звонить менеджер
     компании не станет, а написать в бот — да. Поэтому и в панели первой
     встаёт «Написать в Telegram», а номер идёт под ней. */
  .hcontacts__main, .hcontacts__btn .chev { display: none; }
  .hcontacts__ic { display: flex; }
  /* Свёрнутый телефон становится такой же плиткой, как лупа и корзина:
     серой в покое, светло-оранжевой под курсором и пока панель открыта */
  .hcontacts__btn {
    width: 42px; height: 42px; padding: 0; gap: 0; border-radius: 12px;
    justify-content: center; background: var(--fill); color: var(--ink);
    transition: .18s;
  }
  .hcontacts__btn:hover,
  .hcontacts.is-open .hcontacts__btn { background: var(--cream-sm); color: var(--orange-dark); }
  .hpop { display: flex; flex-direction: column; }
  .hpop__tg { order: -1; margin-top: 0; }
  .hpop__phone { margin-top: 18px; }
  .header__actions { padding-left: 4px; }
  .header__actions::before { display: none; }
  .nav { gap: 16px; }
}

@media (max-width: 1280px) {
  /* Пять плиток повода в ряд перестают читаться раньше остальных сеток:
     в колонку уходит уже не строка примера, а само название. */
  .occasions { grid-template-columns: repeat(3, 1fr); }
  .megamenu { min-width: 720px; }
  .megamenu__list { grid-template-columns: repeat(2, 1fr); }
  .portfolio__grid, .cat-grid { grid-template-columns: repeat(3, 1fr); }

  /* Редактор ужимает боковые панели раньше, чем ломает раскладку */
  .ed-body { grid-template-columns: 68px auto 1fr 304px; }
  .ed-drawer { width: 300px; }
  .ed-top__spec { display: none; }
}

/* Ниже этой ширины строка шапки не собирается — меню в бургер */
@media (max-width: 1240px) {
  /* Прячем именно «Начать заказ», а не все `.btn` в правой группе: кнопки
     панели контактов тоже `.btn`, и с телефона она открывалась без
     «Написать в Telegram» и «Заказать звонок» (16 сентября 2026) */
  .header__center, .header__cta { display: none; }
  /* Контакты остаются плиткой со значком телеграма (см. 1439 px выше).
     До 16 сентября 2026 здесь они прятались, а вместо них стояла трубка со
     ссылкой `tel:` — на телефоне она сразу набирала номер, на компьютере
     открывала FaceTime, и написать в бот с первого экрана было нельзя. */
  /* Плитки крупнее: здесь по ним попадают пальцем, а не курсором */
  .header__search, .header__cart, .header__user, .hcontacts__btn, .burger { width: 46px; height: 46px; }
  .burger { display: flex; }
  .header__inner { grid-template-columns: 1fr auto; }
  .logo__img { height: 56px; }
}

@media (max-width: 1100px) {
  :root { --header-h: 86px; }
  .topline { font-size: 12px; }

  .layout { grid-template-columns: 1fr; row-gap: 0; }
  /* В одну колонку боковая врезка «Нужна консультация?» уезжает под текст
     страницы: над ним она стояла в самом верху, за списком разделов, и на
     телефоне её никто не находил (заказчица, 11 сентября 2026). Сайдбар
     распускается в сетку раскладки, и врезка встаёт последней. */
  .sidebar { display: contents; }
  .sidebar__list { margin-bottom: 30px; }
  .sidebar__cta { order: 1; margin-top: 30px; }
  /* Раздел каталога и «Информация»: вместо списка во всю высоту — ряд
     плиток, который листают вбок, как на маркетплейсах. Открытая страница
     подсвечена и подкручена в поле зрения (category.html, info.html).
     Заголовок над рядом не нужен: он повторяет заголовок страницы.
     «Информации» ряд дан 17 сентября 2026 (C86): тринадцать страниц
     списком занимали 600 px, и текст начинался за первым экраном. */
  .sidebar--tiles > .sidebar__title { display: none; }
  .sidebar--tiles .sidebar__list:not(.sidebar__other) {
    display: flex; gap: 8px;
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    margin: 0 -24px 26px; padding: 0 24px; scroll-padding-inline: 24px;
  }
  .sidebar--tiles .sidebar__list:not(.sidebar__other)::-webkit-scrollbar { display: none; }
  /* Плитка не шире экрана за вычетом полей: «Политика обработки
     персональных данных» в 381 px на 360-пиксельном телефоне уходила за
     край. Полное название стоит заголовком открытой страницы. */
  .sidebar--tiles .sidebar__list:not(.sidebar__other) a {
    flex: none; white-space: nowrap;
    max-width: calc(100vw - 48px); overflow: hidden; text-overflow: ellipsis;
    padding: 10px 16px; border-radius: var(--r-pill);
    background: var(--fill); font-size: 14.5px; font-weight: 600;
  }
  .sidebar--tiles .sidebar__list:not(.sidebar__other) a.is-active { background: var(--cream-sm); font-weight: 700; }
  /* У каталога «Другие разделы» уходят под товары, перед врезкой */
  .sidebar--catalog .sidebar__other { order: 1; margin: 30px 0 0; }
  .sidebar--catalog .sidebar__other .sidebar__title { margin-top: 0; }
  /* Четыре колонки подвала в две: контакты остаются широкой первой */
  .footer__grid { grid-template-columns: 1fr 1fr; gap: 34px 40px; }
  .solutions, .start-grid { grid-template-columns: 1fr 1fr; }
  .contacts-place { grid-template-columns: 1fr; }
  .callback { grid-template-columns: 1fr; padding: 36px; gap: 28px; }
  /* Кадр из ролика в одну колонку разворачивается во весь экран и съедает
     блок: держим его в разумной ширине и ставим по центру под текстом */
  .prompt { grid-template-columns: 1fr; padding: 36px; gap: 28px; }
  .prompt__shot { max-width: 320px; margin: 0 auto; width: 100%; }
  /* В одну колонку прилипать некуда: галерея просто идёт первой */
  .product-hero { grid-template-columns: 1fr; }
  .product-hero__media { position: static; }
  .block-title { font-size: 24px; }
  .steps { grid-template-columns: repeat(2, 1fr); }
  .item-grid, .blog-grid, .info-grid { grid-template-columns: repeat(2, 1fr); }
  .sol-hero h1 { font-size: 38px; }
  .packs { grid-template-columns: 1fr; }
  .occasions { grid-template-columns: repeat(2, 1fr); }
  .sol-methods { grid-template-columns: repeat(2, 1fr); }
  .sol-steps { grid-template-columns: repeat(2, 1fr); gap: 24px 28px; }
  /* Узкая колонка: снимок встаёт над текстом, иначе тексту остаётся треть */
  .svc--photo { flex-direction: column; }
  .svc__media { width: 100%; aspect-ratio: 16 / 9; overflow: hidden; }
  .eq-grid { grid-template-columns: 1fr; }
  .pick-grid, .works-ribbon { grid-template-columns: repeat(2, 1fr); }
  .pick-grid--ribbon { display: flex; }
  .pick-grid--ribbon .pick { flex-basis: min(380px, 42vw); }
  .ways, .tpl-grid, .design-grid, .pf-summary { grid-template-columns: 1fr; }

  /* Правая панель уходит под холст: узкая навигация и выдвижная остаются слева.
     `minmax(0, 1fr)`, а не `1fr`: колонку холста распирало содержимое, и на
     768 px редактор выходил шириной 975 (C88, 17 сентября 2026) */
  .ed-body { grid-template-columns: 64px auto minmax(0, 1fr); grid-template-rows: 1fr 236px; }
  /* Шапке редактора нужно около 900 px: на планшете название изделия
     сжималось в ноль, а «Параметры заказа» уходили под «Выйти». Не
     помещается — кнопки заказа переносятся второй строкой и держатся вправо */
  .ed-top { flex-wrap: wrap; row-gap: 10px; }
  .ed-top__right { margin-left: auto; }
  .ed-nav { grid-column: 1; grid-row: 1 / 3; }
  .ed-drawer { grid-column: 2; grid-row: 1 / 3; width: 280px; }
  .ed-canvas { grid-column: 3; grid-row: 1; }
  .ed-right { grid-column: 3; grid-row: 2; border-left: none; border-top: 1px solid var(--line); }
  /* Полоса под холстом — две колонки: слева слои и под ними скачивание,
     справа свойства. Одной лентой свойства текста занимали 980 px, и
     «Скачать PDF» лежал на четыре прокрутки ниже края полосы (C88). Трём
     колонкам на планшете тесно: у слоёв пропадали названия. Свойствам —
     ширина правой панели на 1280 px */
  .ed-right {
    display: grid; align-content: start; overflow-y: auto;
    grid-template-columns: minmax(0, 1fr) minmax(288px, 1fr);
    /* Лишнюю высоту длинных свойств забирает строка скачивания, а не слоёв:
       иначе между слоями и «Скачать» вырастала пустота в триста пикселей */
    grid-template-rows: auto 1fr;
  }
  /* В полосе колонки стоят рядом, и свои скроллы блокам не нужны: полоса
     прокручивается целиком. `min-height` обратно в `auto`: в прокручиваемой
     ленте телефона нулевой минимум сжимал свойства в одну строку заголовка */
  .ed-block--props { overflow: visible; flex: 0 0 auto; min-height: auto; }
  /* Здесь прокручивается вся полоса, а не блок свойств, отступа сверху у неё
     нет — заголовок липнет к нулю, иначе уезжает за край */
  .ed-block--props .ed-block__head { top: 0; }
  #edLayersBlock { grid-column: 1; grid-row: 1; border-top: none; }
  .ed-block--export { grid-column: 1; grid-row: 2; border-top: 1px solid var(--line); }
  .ed-block--props { grid-column: 2; grid-row: 1 / 3; border-left: 1px solid var(--line); }
  .ed-layers { max-height: 125px; }
  .ed-stagewrap { padding: 24px 24px 110px; }

  /* `minmax(0, 1fr)`, а не `1fr`: у `1fr` нижняя граница — самое широкое
     содержимое, и одна неразрывная подпись распирала всю страницу за экран
     (C87, 17 сентября 2026) */
  .co { grid-template-columns: minmax(0, 1fr); }
  .co-side { position: static; }
  .order { grid-template-columns: 1fr; }
  .order__side { text-align: left; justify-items: start; }
  /* Рядом с миниатюрой таблице на телефоне остаётся полторы сотни пикселей —
     миниатюра встаёт над позицией, таблица получает всю ширину */
  .order--items .order__item { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .order--items .order__item .order__img { width: 64px; height: 46px; }
  .order--items .order__foot { margin-left: 0; }

  .cart-item { grid-template-columns: 90px minmax(0, 1fr); gap: 14px; }
  .cart-item__img { width: 90px; height: 68px; }
  .guest-note { flex-direction: column; align-items: flex-start; }
}

/* Фотография в hero уходит вниз, текст получает чистый фон */
@media (max-width: 900px) {
  .hero__photo { background-position: 72% center; }
  .hero__scrim {
    background: linear-gradient(180deg,
      rgba(244, 244, 244, .96) 0%,
      rgba(244, 244, 244, .9) 55%,
      rgba(244, 244, 244, .35) 100%);
  }
  .hero__inner { max-width: 100%; }
  .hero__sub { max-width: 100%; }
  .hero__ways { max-width: 100%; }
  /* Узкая колонка ломает строки сама, и заданная разбивка только рвёт ряды */
  .hero__ways-br { display: none; }
  /* На узком экране стороны рядом уже не помещаются — только тогда переносим.
     Поле 20 px повторено в preview.js (`PAD_NARROW`) — правишь здесь, правь и там */
  .pv__sides { flex-wrap: wrap; padding: 20px; }
  /* Обозначения линий на узком холсте лягут на сам макет — оставляем только
     строку «Убрать технические линии», она короткая. */
  .ed-legend__body { display: none; }
  .ed-legend__body + .ed-legend__switch { margin-top: 0; padding-top: 4px; border-top: none; }
}

@media (max-width: 760px) {
  /* На телефоне плашка про cookie растягивается по ширине и встаёт над
     кнопкой звонка — иначе она её закрывает */
  .cookie, .offer-pop { left: 12px; right: 12px; bottom: 96px; max-width: none; }
  /* C75: плашка в одну строку — короткая фраза и кнопка справа. В три строки
     с кнопкой под ними она была высотой 160 px и лежала на метках первого
     экрана. Кнопки — в своей группе: выдержит и вторую, если её заведут (L10). */
  /* C86, 17 сентября 2026: у нижнего края во всю ширину, а кнопка связи на
     это время поднимается над ней (`has-cookie`, ставит renderCookieNotice).
     Слева от кнопки на 360 px оставалось 252 px, и даже «Мы используем
     cookie» ломалась на две строки. Первый экран плашка больше не закрывает:
     она выходит после первой прокрутки (afterFirstScroll в app.js). */
  /* С 8 октября 2026 (L10) кнопок две: фраза строкой, под ней кнопки
     поровну. В одну строку с фразой две кнопки на 360 px не встают. */
  .cookie {
    display: flex; flex-direction: column; align-items: stretch; gap: 8px;
    padding: 10px 10px 10px 14px; bottom: 12px;
  }
  /* Высота плашки ~100 px плюс зазор */
  body.has-cookie .fab { bottom: 124px; }
  body.has-cookie .chat,
  body.has-cookie .fabmenu { bottom: 198px; }
  body.has-cookie.has-pick-bar .fab { bottom: 212px; }
  body.has-cookie.has-pick-bar .chat,
  body.has-cookie.has-pick-bar .fabmenu { bottom: 286px; }
  /* Кнопки связи на телефоне мельче и ближе к краю: в 60 px и с полем 26
     они накрывали правый край карточки корзины — «наверх» ложилась на
     «Добавить ещё позицию», а чат на тираж позиции */
  .fab { right: 14px; bottom: 14px; gap: 10px; }
  .fab button { width: 52px; height: 52px; }
  .fabmenu { right: 14px; bottom: 80px; gap: 10px; }
  /* Кнопка в замечании проверки — под текстом, а не третьей колонкой:
     на 360 px она сжимала объяснение до слова в строке */
  .pf-issue__fix, .pf-issue__fixes { grid-column: 2; justify-self: start; }
  .fabmenu__ic { width: 52px; height: 52px; }
  /* Плашка о переполнении — во всю ширину, как cookie, и над ней:
     в углу шириной 380 px она вылезала за экран и ложилась на подвал */
  .storage-warn { left: 12px; right: 12px; bottom: 12px; max-width: none; padding: 16px; }
  body.has-cookie .storage-warn { bottom: 122px; }
  .cookie__long { display: none; }
  .cookie__short { display: inline; }
  .cookie__actions { margin-top: 0; flex-wrap: nowrap; }
  .cookie button { flex: 1 1 0; min-width: 0; white-space: normal; padding: 9px 6px; font-size: 13px; line-height: 1.25; }
  .topline { padding-inline: 16px; }
  .topline__long { display: none; }
  .topline__short { display: inline; }
  /* Логотип мельчает вместе с экраном, а не сплющивается: 56 px от 400 px
     и шире, на самом узком телефоне — 44 */
  .logo__img { height: clamp(44px, 14vw, 56px); }
  /* Панель контактов — во всю ширину под шапкой: от плитки посередине
     шапки 360 px вправо-влево не помещаются */
  .hpop {
    position: fixed; top: calc(var(--header-h) + 4px); left: 12px; right: 12px;
    width: auto; max-height: calc(100dvh - var(--header-h) - 20px); overflow-y: auto;
  }

  .section { padding: 56px 0; }
  .adv { padding: 46px 0; }

  /* Сводка расчёта на телефоне: плитки уже, а в ступени срок и цена за штуку
     переезжают на вторую строку — в одну строку с итогом они не встают */
  .price-box { padding: 18px 16px 12px; }
  .price-fact { padding: 10px 11px; }
  .price-fact b { font-size: 14.5px; }
  .price-run { grid-template-columns: 1fr auto; row-gap: 2px; padding: 10px; }
  .price-run em { grid-column: 1 / -1; grid-row: 2; }
  /* Поиск занимает экран целиком: половинчатая панель на телефоне только мешает */
  .search__box { margin: 0; max-width: none; height: 100%; border-radius: 0; }
  .search__results { max-height: calc(100% - 74px); }
  .search__input { font-size: 16px; }  /* меньше 16px — Safari зумит страницу при фокусе */
  /* Таблица в карточке кабинета: 12em на телефоне — половина карточки, и
     значениям остаётся узкая полоса. Подписи в долях, длинная переносится. */
  .co-specs--wide { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); }
  /* Цена способа доставки — под описанием, а не справа. «По тарифу
     перевозчика» не переносится и справа отбирала у названия и адреса почти
     всю ширину, а до правки колонки ещё и выталкивала страницу за экран (C87) */
  .co-opt { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 14px; row-gap: 6px; }
  .co-opt em { grid-column: 2; margin-left: 0; }
  /* Пять плиток в шапке — поиск, связь, корзина, кабинет, меню — на 46 px не
     помещались в 360 px: меню уходило за край. Корзина появляется, когда в
     ней что-то есть, и плитки не должны менять размер от этого, поэтому на
     телефоне они всегда 42 px, как на компьютере (C91, 17 сентября 2026) */
  .header__search, .header__cart, .header__user, .hcontacts__btn, .burger { width: 42px; height: 42px; }
  .header__actions { gap: 6px; }
  /* Позиция корзины: превью над текстом, а не сбоку — рядом с превью
     оставалось 180 px, и «Изменить макет» со значком удаления не влезали */
  .cart-item { grid-template-columns: minmax(0, 1fr); }
  .hero { min-height: 480px; }
  /* «Рассчитать комплексный заказ» в 32-пиксельные поля не помещается —
     на телефоне кнопке нужны поля поуже и кегль поменьше */
  .hero__actions .btn { flex: 1; padding: 0 18px; font-size: 15.5px; }
  /* Шесть меток — сетка 2 × 3 одинаковых плиток. Таблетками по ширине
     текста они вставали в столбик: «Готовые решения бизнесу» не оставляла
     соседке места, и шесть строк съедали 300 px первого экрана
     (16 сентября 2026). В плитке длинная подпись переносится на вторую
     строку, и ряд остаётся ровным. */
  .hero__ways { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: 1fr; gap: 8px; }
  .hero__way {
    min-height: 54px; padding: 7px 10px; gap: 8px;
    border-radius: var(--r-control); font-size: 13.5px; line-height: 1.2;
  }
  .hero__way svg { flex: none; }
  /* C75: заданные переносы подзаголовка — только для широкой колонки. На
     телефоне строки ломаются сами, и жёсткий перенос оставлял висеть
     «шаблоны в редакторе,» отдельным обрывком. */
  .hero__sub br { display: none; }
  /* То же у строки форматов на проверке файла (C86): «Также принимаем»
     оставался висеть отдельной строкой */
  .pf-drop__formats br { display: none; }

  .portfolio__grid, .cat-grid, .item-grid, .blog-grid, .info-grid, .demo, .fmt, .guide-actions, .bleed-layout,
  .reasons, .svc-list, .start-grid { grid-template-columns: 1fr; }
  /* Разделы каталога — в две колонки: в одну семь карточек со снимком на
     весь экран растягивали «Что мы печатаем» на три с лишним тысячи
     пикселей (16 сентября 2026). Показываем все, но мельче. Описание группы
     в колонку шириной 160 px вставало в пять строк — остаются снимок,
     название и число позиций, описание есть на странице раздела. */
  .cat-grid--groups, .cat-grid--wide.cat-grid--groups { grid-template-columns: 1fr 1fr; gap: 12px; }
  .cat-grid--groups .cat-card { min-height: 0; }
  /* Вкладки мельче: в полный размер «Услуги» уезжала одна на вторую строку
     и забирала под себя ещё 70 px. Перенос не запрещён — в кабинете
     вкладок четыре, там он нужен. */
  .tabs { gap: 8px; margin-bottom: 24px; }
  .tab { padding: 12px 14px; font-size: 15px; }
  .cat-grid--groups .cat-card__body { gap: 6px; padding: 10px 12px 12px; }
  .cat-grid--groups .cat-card h3 { font-size: 15px; line-height: 1.25; flex: 1; }
  .cat-grid--groups .cat-card p { display: none; }
  .cat-grid--groups .cat-card__link { font-size: 13px; }
  .cat-grid--groups .cat-card--plain { padding: 14px 12px; }
  /* Решения — лентой, как отзывы: карточка на 82 % ширины, край следующей
     виден и подсказывает, что ленту листают. В столбик четыре карточки со
     снимком занимали 2 600 px. */
  .solutions {
    display: flex; gap: 12px;
    overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
    margin: -4px -24px -12px; padding: 4px 24px 12px; scroll-padding-inline: 24px;
    scrollbar-width: none;
  }
  .solutions::-webkit-scrollbar { display: none; }
  .solution { flex: 0 0 82%; scroll-snap-align: start; }
  .req-cards { grid-auto-rows: auto; }
  .fmt { gap: 20px; }
  .sol-hero h1 { font-size: 30px; }
  .sol-strip, .sol-why, .sol-methods, .sol-steps, .occasions { grid-template-columns: 1fr; }
  .sol-hero__actions { flex-direction: column; }
  /* В одну колонку общая линия шагов теряет смысл — остаются только точки */
  .sol-steps { padding-top: 0; }
  .sol-steps::before { display: none; }
  .sol-step { padding-left: 24px; }
  .sol-step::before { top: 5px; }
  .sol-quote { grid-template-columns: 1fr; padding: 28px; }
  .sol-quote p { font-size: 17px; }
  /* Панель состава на телефоне: список предметов уступает место кнопке —
     остаётся счётчик, а перечисление всё равно не влезало в строку */
  .pick-bar__in { gap: 14px; }
  .pick-bar__list span { display: none; }
  .pick-bar .btn { padding: 0 18px; }
  /* На телефоне снимок станка ужимается ещё, чтобы название получило строку */
  .eq-card__img { width: 96px; }
  .eq-card h3 { font-size: 17px; }
  /* Лента: шаг ячейки мельче, иначе в кадр попадают полтора логотипа */
  .client { width: 132px; height: 72px; padding: 0 12px; }
  .client img { max-height: 40px; }
  .steps { grid-template-columns: 1fr; }
  /* Три числа в столбик: в два столбца третье осталось бы сиротой */
  .stat-row { grid-template-columns: 1fr; }
  .pick-grid { grid-template-columns: 1fr; }
  /* C82: работы на главной — 2 × 2, а не столбиком. Четыре квадрата во всю
     ширину занимали около 1 550 px, самый длинный блок главной после того,
     как каталог и решения стали короче (16 сентября 2026). В плитке шириной
     160 px название работы встаёт в три строки — кегль мельче, поля уже, а
     затемнение выше, чтобы все три строки лежали на нём, а не на снимке. */
  .works-ribbon { grid-template-columns: 1fr 1fr; gap: 12px; }
  .works-ribbon .work__body { padding: 12px 10px; }
  .works-ribbon .work__title { font-size: 13px; }
  .works-ribbon .work__img::after { height: 62%; }
  .section-head--split { flex-direction: column; align-items: stretch; gap: 18px; }
  /* Ссылка остаётся ссылкой: растянутая во всю ширину, она делает кликабельной
     всю строку и начинает читаться кнопкой — ровно тем, чем быть перестала. */
  .section-head__more { align-self: flex-start; }
  .section-head__link { width: 100%; }
  .layout-ribbon {
    margin-inline: -20px;
    padding-left: 20px;
  }
  .layout-ribbon::after { width: 74px; }
  .pick-grid--ribbon {
    display: flex;
    padding-right: 78px;
  }
  .pick-grid--ribbon .pick { flex-basis: 82vw; }
  /* «Все работы» встают под заголовком: рядом с ним ссылка на этой ширине
     уже не помещается. Во всю ширину её не растягиваем — правило выше
     (`.section-head__more`) оставляет её ссылкой, а не полосой во весь экран. */
  .works-head { flex-direction: column; align-items: stretch; gap: 14px; }
  /* Двери встают друг под друга во всю ширину: рядом они на этой ширине
     ужимаются и обрывают названия. */
  .layout-doors { flex-direction: column; }
  .layout-doors .btn { width: 100%; }

  .footer__grid { grid-template-columns: 1fr; gap: 0; }
  .footer__grid > div:first-child { padding-bottom: 30px; }
  /* Колонки ссылок сворачиваются под свои заголовки: контакты остаются
     открытыми, остальное раскрывается нажатием */
  .footer__col { border-top: 1px solid rgba(255, 255, 255, .12); }
  .footer__toggle { pointer-events: auto; margin-bottom: 0; padding: 16px 0; }
  .footer__toggle .chev { display: block; }
  .footer__col.is-open .footer__toggle .chev { transform: rotate(180deg); }
  .footer__col:not(.is-open) .footer__col-body { display: none; }
  .footer__col-body { padding-bottom: 18px; }
  .footer__bottom { flex-direction: column; }
  .footer__legal-links { text-align: left; }
  /* Кнопка и ссылка под текстом: рядом они уже не помещаются */
  .form__row { grid-template-columns: 1fr; }
  .modal__box { padding: 30px 22px; }
  /* Крестик уходит к краю вместе с полями окна */
  .modal__close { top: 20px; right: 20px; width: 40px; height: 40px; }
  /* Заголовок окна мельче, и места под крестик ему нужно меньше */
  .modal h2 { padding-right: 48px; }
  /* Имя и телефон в столбик: в две колонки подпись «Как к вам обращаться»
     ломается на две строки, и поля перестают стоять вровень */
  .rq .ed-grid2 { grid-template-columns: 1fr; }
  /* Пять каналов в один ряд на телефоне не встают — отпускаем перенос */
  .rq__ch { height: 42px; padding: 0 15px; font-size: 14px; }
  /* Значок над текстом: в строку с ним заголовок зоны загрузки на телефоне
     ломается на три строки и плашка вырастает вдвое */
  .rq__file { flex-direction: column; gap: 10px; text-align: center; padding: 16px 14px; }
  .rq__file-txt b { font-size: 14px; }
  .rq__file-txt em i { display: none; }
  .rq__file-del { top: 7px; right: 7px; }
  /* Заголовки текстовых страниц: «Конфиденциальность» кеглем 30 шире
     колонки на 360 px и распирала «Политику» вбок на 20 px (17 сентября
     2026). Кегль — как у заголовка окна; слово, которое не влезает и так,
     переносится по слогам, а не уходит за край. */
  .prose h2 { font-size: 26px; hyphens: auto; -webkit-hyphens: auto; overflow-wrap: break-word; }
  .callback, .prompt { padding: 28px 22px; }
  .prompt { display: block; }
  /* Блок плотнее (16 сентября 2026): крупный вводный абзац вставал в шесть
     строк, а кадр 4:5 во всю ширину — ещё в треть экрана. Текст тот же,
     кадр квадратный: у бутылки на снимке ничего не срезается. */
  .prompt__lead { font-size: 18px; }
  .prompt__note { font-size: 14.5px; line-height: 1.55; margin-top: 12px; }
  .prompt__list { margin: 18px 0 22px; gap: 10px; }
  .prompt__list b { font-size: 15.5px; }
  .prompt__list span { font-size: 14px; line-height: 1.45; }
  .prompt__actions { gap: 10px; }
  .prompt__shot { width: 100%; max-width: none; margin: 22px 0 0; aspect-ratio: 1 / 1; }
  /* Поля и кегль — как у кнопок первого экрана: «Посмотреть, что уже
     сделали» в 32-пиксельные поля на 360 px не помещалась (C84) */
  .prompt__actions .btn { width: 100%; padding: 0 18px; font-size: 15.5px; }
  .chat { width: calc(100vw - 40px); right: 20px; }
  /* На узком экране текст с кнопкой разъезжается в четыре строки —
     переносим кнопку под текст */
  .toast {
    left: 16px; right: 16px; transform: none; max-width: none;
    flex-direction: column; align-items: stretch; gap: 10px;
    padding: 16px; text-align: center;
  }
  .reviews__source { gap: 10px; }
  .reviews__track { gap: 14px; }
  .review { flex: 0 0 84%; }

  /* ————— Редактор на телефоне (C89, 20 сентября 2026) —————

     Шапка — сетка из трёх рядов, а не строка с переносом. Строкой она не
     помещается никогда: «Сохранить проект» с «Заказать печать» просят
     300 px из 390, и название изделия сжималось в ноль, а «Заказать
     печать» уходила за правый край. Перенос не годится потому, что
     расставляет элементы в порядке разметки, а на телефоне первым должно
     читаться изделие, последним — действие заказа.

     Ряды: изделие и выход · лента параметров · сохранить и заказать.
     Колонки общие для первого и третьего ряда, поэтому правая колонка
     равна ширине «Заказать печать», а «Выйти» прижат к её правому краю. */
  .ed-top {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: center; gap: 8px 10px; padding: 8px 12px;
  }
  /* Группы шапки раскрываются в ту же сетку: свои ряды у них есть,
     собственные рамки не нужны */
  .ed-top__left, .ed-top__right { display: contents; }
  .ed-top__id { grid-column: 1; grid-row: 1; gap: 8px; }
  .ed-top .logo { transform: scale(.6); margin-right: -24px; }
  #edExit { grid-column: 2; grid-row: 1; justify-self: end; }
  /* Лента параметров: вместе с «Формой и размером» и служебной кнопкой
     шаблона она шире экрана — листается вбок, как ряды разделов каталога */
  .ed-top__order {
    grid-column: 1 / -1; grid-row: 2;
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    margin-inline: -12px; padding-inline: 12px;
  }
  .ed-top__order::-webkit-scrollbar { display: none; }
  .ed-top__order > * { flex: 0 0 auto; }
  .ed-chip { height: 34px; }
  /* На телефоне для строки нет ряда: о входе скажет плашка после сохранения */
  .ed-top__hint { display: none; }
  #edSave { grid-column: 1; grid-row: 3; }
  #edCheck { grid-column: 2; grid-row: 3; }
  .ed-top__btn { height: 38px; padding: 0 14px; font-size: 13px; }

  .ed-body { grid-template-columns: 56px auto minmax(0, 1fr); grid-template-rows: 1fr 200px; }
  /* На телефоне двум колонкам места нет — полоса снова одна лента (C89).
     Порядок «свойства, слои, скачивание» здесь тот же, что на десктопе, и
     берётся из разметки. Заголовки блоков липкие — в ленте высотой 200 px
     без них не понять, что листаешь. */
  .ed-right { display: flex; }
  .ed-block--props { border-left: none; }
  #edLayersBlock { border-top: 1px solid var(--line); }
  .ed-block--export { border-top: 1px solid var(--line); }
  .ed-block__head {
    position: sticky; top: -14px; z-index: 1;
    background: var(--white); padding: 4px 0; margin-top: -4px;
  }
  /* Выдвижная панель накрывает холст, а не делит с ним ширину: своей
     колонкой она оставляла холсту 94 px из 390 — от листа оставалась
     полоска, и человек не видел, куда кладёт текст или картинку.
     Закрывается тем же крестиком в её шапке. */
  .ed-body { position: relative; }
  .ed-drawer {
    /* Область в сетке — вся ширина: абсолютный элемент в гриде считает
       края от своей колонки, а её ширина здесь ноль, и панель уезжала
       на 56 px правее, чем просили. */
    grid-column: 1 / -1; grid-row: 1 / -1;
    position: absolute; inset: 0 0 0 56px; width: auto; z-index: 20;
    box-shadow: 0 0 0 100vmax rgba(16, 24, 32, .18);
  }
  .ed-nav__btn span { display: none; }
  .ed-nav__btn { padding: 11px 2px; }
  /* Плашка cookie стоит у нижнего края и закрывала нижнюю кнопку узкой
     навигации — «Справка» переставала нажиматься, пока её не закроют */
  body.has-cookie .ed-nav { padding-bottom: 76px; }
  /* По той же причине — нижняя часть полосы свойств: кнопки «Скачать PDF»
     и низ длинных свойств оказывались под плашкой */
  body.has-cookie .ed-right { padding-bottom: 70px; }

  /* Плавающие панели холста: на 390 px рядом они не помещаются — легенда
     линий и переключатель сторон лежали друг на друге. Теперь столбиком:
     выключатель линий у нижнего края, стороны над ним. Высота легенды
     здесь постоянная — обозначения линий скрыты с 900 px, остаётся одна
     строка, поэтому стороны можно поднять на фиксированные 58. */
  .ed-legend, body.has-cookie .ed-legend { left: 12px; bottom: 12px; padding: 4px; }
  /* «Убрать линии» вместо «Убрать технические линии»: в нижнем ряду рядом
     с островом состояния полная строка не помещается, а слово «линии» с
     цветными обозначениями над ним объясняет себя само */
  .ed-legend__word { display: none; }
  .ed-sides { bottom: 58px; padding: 6px; gap: 4px; }
  /* Миниатюры сторон уменьшать дальше некуда — на 54 × 34 макет уже не
     читается, а место занимает. Остаются подписи: это переключатель, и
     работает он как переключатель. Выбранная сторона — заливкой, потому
     что рамку миниатюры, которой она подсвечивалась, мы убрали. */
  .ed-sidecard__thumb { display: none; }
  .ed-sidecard { padding: 5px 12px; }
  .ed-sidecard__cap { font-size: 13px; }
  .ed-sidecard.is-active { background: var(--cream-sm); }
  .ed-swap { align-self: center; margin-top: 0; }
  /* Остров состояния уходит вниз, к правому краю: над холстом он вставал
     второй строкой под островом масштаба и вместе с ним закрывал верхнюю
     треть макета. Внизу справа пусто — легенда стоит слева, стороны над
     ней. Сверху остаётся одна полоса, и листу нужно поле только под неё. */
  .ed-canvas.is-cramped .ed-canvasbar--check { top: auto; bottom: 12px; right: 12px; }
  .ed-canvasbar { top: 12px; }
  .ed-canvasbar--view { left: 12px; }
  /* Поля холста: сверху под остров масштаба, снизу под легенду со сторонами */
  .ed-stagewrap { padding: 62px 12px 112px; }

  /* Списки форм и параметров: попапу отдана вся высота экрана, кроме
     шапки редактора, а когда внизу стоит плашка cookie — ещё и её
     полоса. Иначе «Итого» и «Изменить параметры» оказывались под ней. */
  .ed-pop--die { max-height: 74vh; }
  body.has-cookie .ed-pop--die { max-height: 64vh; }
  body.has-cookie .ed-pop--order { max-height: 64vh; overflow-y: auto; }

  .ed-tplgrid, .ed-filegrid { grid-template-columns: 1fr; }
}

/* Медиазапросы не про ширину — их два.

   Человек попросил систему не двигать картинку — бегущая строка первый
   кандидат: останавливаем её и отдаём ленту на прокрутку пальцем или колесом. */
@media (prefers-reduced-motion: reduce) {
  .ed-spin { animation-duration: 2.4s; }
  .clients { overflow-x: auto; }
  .clients__track { animation: none; }
}

/* Экран без мыши. После касания телефон держит `:hover` на пункте, пока не
   нажмут что-то другое, — и в разделах каталога один пункт горел оранжевым,
   а другой был выбран (заказчица, 16 сентября 2026). Наведение, которое
   красит только текст, здесь отменяем; выбранный пункт не трогаем. */
@media (hover: none) {
  .sidebar__list a:hover:not(.is-active) { color: inherit; }

  /* Ручки выделения под палец: видимая чуть крупнее, запас вокруг — до
     44 px. Ручка поворота поднята выше, иначе её запас ложится на запас
     верхней боковой, и палец попадает не в ту (C88) */
  .ed-h { width: 11px; height: 11px; }
  .ed-h::after { inset: -16px; }
  .ed-h--n, .ed-h--s { width: 19px; height: 7px; }
  .ed-h--w, .ed-h--e { width: 7px; height: 19px; }
  .ed-h--rot { top: -42px; width: 12px; height: 12px; }
  .ed-h--rot::before { height: 36px; }
}

/* ————— AI-студия: «Макет» и «Картинка» (12 октября 2026) ————— */
.ed-aimode { margin-bottom: 10px; }
.ed-ailead { margin: 0 0 12px; font-size: 12.5px; line-height: 1.45; color: var(--gray); }
.ed-genimg { margin-top: 10px; }
/* Нейросеть думает: кнопка остаётся оранжевой и показывает, что идёт */
.ed-bigbtn.is-busy, .ed-bigbtn.is-busy:disabled { opacity: 1; cursor: progress; }
.ed-bigbtn.is-busy .ed-spin { border-color: var(--white); border-right-color: transparent; }
/* Мобильные браузеры увеличивают страницу при фокусе на поле мельче 16 px */
@media (max-width: 1024px), (pointer: coarse) {
  .ed-field--ai .textarea { font-size: 16px; }
}
