/* ══════════════════════════════════════════════════════════════
   СЛОЙ САЙТА. Всё рисуется только переменными --w-*.
   Значения приходят из темы (renderer/theme.ts), здесь их нет.

   Перенос из vitrio-builder-v0.7.html + адаптив и поля форм.
   ══════════════════════════════════════════════════════════════ */

.site {
  font-family: var(--w-fb);
  color: var(--w-tx);
  background: var(--w-bg);
  font-size: var(--w-body);
  line-height: var(--w-lead);
}
/* Ширина считается по рамке, а не по содержимому. Без этого любой
   элемент с внутренним отступом и заданной шириной вылезал за край:
   так первый экран «по центру на фоне» на телефоне давал прокрутку
   вбок (`tools/adaptive.py` находил 376 внутри 344). */
.site *, .site *::before, .site *::after { box-sizing: border-box }
.site h1, .site h2, .site h3, .site h4 {
  font-family: var(--w-fh);
  font-weight: var(--w-hw);
  letter-spacing: var(--w-track);
  line-height: 1.14;
  margin: 0;
  /* Длинное слово в крупном заголовке шире экрана телефона:
     «переживает» при 82 px — это 400 px. Переносим по слогам, а не
     режем страницу. */
  overflow-wrap: break-word;
  hyphens: auto;
}
.site h1 { font-size: var(--w-h1) }
.site h2 { font-size: var(--w-h2) }
.site h3 { font-size: var(--w-h3) }
.site h4 { font-size: var(--w-h4) }
.site p { margin: 0 }
.site a { color: inherit; text-decoration: none }
/* Кнопка-ссылка остаётся кнопкой. `.site a` специфичнее, чем `.w-btn`,
   и перекрашивал её текст в цвет страницы: на тёмном акценте это было
   чёрным по чёрному, то есть кнопка без подписи. Видно только у кнопок,
   ведущих на страницу (`btn(..., to=...)` рисует `<a>`, без `to` —
   `<span>`), поэтому и жило незамеченным. Виды кнопок из темы
   (`bs-*`, `blk-bs-*`) специфичнее и по-прежнему главнее. */
.site a.w-btn { color: var(--w-accent-tx) }
.site a.w-btn.ghost { color: var(--w-tx) }
.site img { max-width: 100% }

.wrap {
  max-width: var(--w-container);
  margin: 0 auto;
  padding-left: var(--w-pad);
  padding-right: var(--w-pad);
}
.sec { padding-top: var(--w-secy); padding-bottom: var(--w-secy) }

.bg-surface { background: var(--w-surface) }
.bg-soft    { background: var(--w-soft) }
.bg-accent  { background: var(--w-accent); color: var(--w-accent-tx) }
.bg-dark    { background: var(--w-dark);   color: var(--w-dark-tx) }
.bg-accent h1, .bg-accent h2, .bg-accent h3,
.bg-dark h1, .bg-dark h2, .bg-dark h3 { color: inherit }
.bg-accent .w-soft, .bg-dark .w-soft { color: currentColor; opacity: .75 }

.w-soft { color: var(--w-soft-tx) }

.w-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--w-btn-h); padding: 0 var(--w-btn-x);
  border-radius: var(--w-btn-r); font-size: var(--w-btn-fs, var(--w-body));
  font-weight: var(--w-btn-w); background: var(--w-accent);
  color: var(--w-accent-tx); border: var(--w-bw) solid var(--w-accent);
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.w-btn.ghost { background: transparent; color: var(--w-tx); border-color: var(--w-border) }

.w-card {
  background: var(--w-surface);
  border: var(--w-bw) solid var(--w-border);
  border-radius: var(--w-r); box-shadow: var(--w-shadow);
  overflow: hidden; display: flex; flex-direction: column; min-width: 0;
}
/* Анатомия карточки (U-03): одна на все темы, чтобы карточки в ряду были
   одной высоты. Ссылка-обёртка растягивается по ячейке сетки, тело —
   колонкой, подпись прижата к низу. */
.w-grid > a { display: flex; min-width: 0 }
.w-grid > a > .w-card { flex: 1 }
.w-card-body {
  padding: var(--w-cardpad, var(--w-gap)); display: flex; flex-direction: column; flex: 1;
  gap: var(--w-cardgap, calc(var(--w-gap) * 0.5)); min-width: 0;
}
.w-chips { display: flex; gap: calc(var(--w-gap) * 0.25); white-space: nowrap; overflow: hidden; min-height: 1.6em }
.w-chips .w-chip { flex: 0 0 auto }
.w-name { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  line-height: 1.25; min-height: calc(2 * 1.25em); overflow-wrap: anywhere; hyphens: auto }
.w-price { display: flex; align-items: baseline; gap: calc(var(--w-gap) * 0.4); flex-wrap: wrap; font-variant-numeric: tabular-nums }
/* Значок скидки внутри цены не поднимает строку. У `.w-chip` свои поля
   по вертикали, и карточка со скидкой была на семь пикселей выше
   соседей — цены в ряду переставали стоять на одной линии (правило 22).
   Поля остаются по горизонтали, по вертикали значок живёт в строке. */
.w-price .w-chip { padding-block: 0; line-height: 1.45 }
.w-meta { font-size: var(--w-small); color: var(--w-soft-tx); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: auto }
.w-meta > span + span::before { content: ' · ' }
.w-meta:empty { display: none }

.w-img {
  background: var(--w-img-bg); border-radius: var(--w-rimg);
  display: flex; align-items: center; justify-content: center;
  color: var(--w-soft-tx); font-size: var(--w-small);
  position: relative; overflow: hidden;
  /* Ширина картинки с пропорцией считается от высоты и на телефоне
     легко перерастает колонку — предел ставится здесь, один раз. */
  max-width: 100%;
}
.w-img-el { width: 100%; height: 100%; object-fit: cover; display: block }

/* Кегль меню — своя роль размеров (контракт §3): «меню 16, текст 14» задаётся одним набором. */
.w-nav { font-size: var(--w-nav, var(--w-small)) }
.w-grid { display: grid; gap: var(--w-gap); min-width: 0 }
.w-grid > * { min-width: 0 }

.w-num {
  width: 32px; height: 32px; flex: 0 0 auto; border-radius: 999px;
  background: var(--w-accent); color: var(--w-accent-tx);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--w-fh); font-weight: var(--w-hw);
  font-size: var(--w-small);
}
.w-dot {
  width: 12px; height: 12px; flex: 0 0 auto; border-radius: 4px;
  background: var(--w-accent);
}

/* Формы */
.w-form { display: flex; flex-direction: column; gap: var(--w-gap); padding: var(--w-gap) }
.w-input {
  /* Рамка и поля внутрь высоты: без этого поле выше кнопки на два
     пикселя рамки, и в строке «почта + подписаться» это видно. */
  box-sizing: border-box;
  height: var(--w-btn-h); padding: 0 14px; width: 100%;
  border: var(--w-bw) solid var(--w-border); border-radius: var(--w-r);
  background: var(--w-bg); color: var(--w-tx);
  font-family: var(--w-fb); font-size: var(--w-body);
}
.w-input::placeholder { color: var(--w-soft-tx) }

/* Первый экран поверх фона */
.w-over { position: relative }
.hero-over {
  position: absolute; inset: 0; display: flex; align-items: center;
  z-index: 2; pointer-events: none;
}
.hero-over .w-btn { pointer-events: auto }

/* Число колонок задаётся полем блока — рендерер вешает класс */
.w-cols-1 { grid-template-columns: minmax(0, 1fr) }
.w-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)) }
.w-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)) }
.w-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)) }
.w-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)) }
.w-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)) }

.w-ratio-1-1 { grid-template-columns: repeat(2, minmax(0, 1fr)) }
.w-ratio-2-1 { grid-template-columns: 2fr 1fr }
.w-ratio-1-2 { grid-template-columns: 1fr 2fr }

.w-slot-empty {
  border: 1px dashed var(--w-border); border-radius: var(--w-r);
  padding: var(--w-gap); text-align: center; color: var(--w-soft-tx);
  font-size: var(--w-small);
}

/* ── Адаптив: раскладка схлопывается по правилам темы, а не руками ── */
@media (max-width: 900px) {
  .w-cols-4, .w-cols-5, .w-cols-6 { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .w-cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)) }
}
@media (max-width: 640px) {
  .w-grid { grid-template-columns: minmax(0, 1fr) !important }
  .w-ratio-1-1, .w-ratio-2-1, .w-ratio-1-2 { grid-template-columns: minmax(0, 1fr) }
}

/* Шрифтовой масштаб на телефоне. Характер темы живёт в крупных
   заголовках (в разобранных шаблонах h1 доходит до 140 px), но на
   экране в 360 px такой заголовок — это одно слово в строку и прокрутка
   вбок. Поэтому кегль не задаётся заново, а ограничивается долей
   ширины экрана: на компьютере тема как есть, на телефоне — читаемо.
   Проверяется `tools/adaptive.py` на всех блоках каталога. */
@media (max-width: 720px) {
  .site h1 { font-size: min(var(--w-h1), 9.5vw) }
  .site h2 { font-size: min(var(--w-h2), 7.6vw) }
  .site h3 { font-size: min(var(--w-h3), 6.2vw) }
  .site h4 { font-size: min(var(--w-h4), 5.4vw) }
}

/* Плавающая кнопка мессенджера — в углу, поверх содержимого. */
.w-float { position: fixed; right: var(--w-gap); bottom: var(--w-gap); z-index: 20;
           box-shadow: 0 6px 20px rgb(0 0 0 / .18) }

/* Плашка о cookie: закрывается флажком, без скрипта. */
.w-cookie-cb { display: none }
.w-cookie {
  position: fixed; left: var(--w-gap); right: var(--w-gap); bottom: var(--w-gap); z-index: 30;
  display: flex; gap: var(--w-gap); align-items: center; flex-wrap: wrap;
  padding: var(--w-gap); background: var(--w-surface); color: var(--w-tx);
  border: var(--w-bw) solid var(--w-border); border-radius: var(--w-r);
  box-shadow: 0 6px 20px rgb(0 0 0 / .14); max-width: 720px; margin: 0 auto;
}
.w-cookie p { flex: 1; min-width: 200px }
.w-cookie-cb:checked ~ .w-cookie { display: none }

/* Тарифы: выделенная карточка — рамка акцентом. */
.w-card[data-featured="true"] { border-color: var(--w-accent); box-shadow: 0 0 0 1px var(--w-accent) }

/* Меню шапки на телефоне: флажок вместо скрипта. На компьютере флажок
   и кнопка «Меню» скрыты, меню видно всегда; на телефоне меню раскрывается
   на всю ширину под строкой шапки, пока флажок отмечен. */
.w-menu-cb { display: none }
.w-burger { display: none }
@media (max-width: 720px) {
  .w-burger { display: inline-flex; order: 10; margin-left: auto }
  .w-nav-sp { display: none }
  .w-nav { display: none !important; order: 20; flex-basis: 100%; flex-direction: column; gap: calc(var(--w-gap) * 0.5) }
  .w-menu-cb:checked ~ .w-nav { display: flex !important }
  .w-nav a { padding: calc(var(--w-gap) * 0.3) 0; border-bottom: var(--w-bw) solid var(--w-border) }
}

/* ══════════════════════════════════════════════════════════════
   ЭФФЕКТЫ
   ══════════════════════════════════════════════════════════════ */
.fx-img-soft     .w-img { filter: saturate(.82) brightness(1.03) }
.fx-img-mono     .w-img { filter: grayscale(1) contrast(1.06) }
.fx-img-duo      .w-img { filter: grayscale(1) contrast(1.15) }
.fx-img-duo      .w-img::after {
  content: ''; position: absolute; inset: 0;
  background: var(--w-accent); mix-blend-mode: color; opacity: .62;
}
.fx-img-warm     .w-img { filter: sepia(.26) saturate(1.12) brightness(1.02) }
.fx-img-contrast .w-img { filter: contrast(1.16) saturate(1.06) }

.fx-ov-dark .w-img::before {
  content: ''; position: absolute; inset: 0; background: rgb(0 0 0/.28); z-index: 1;
}
.fx-ov-grad .w-img::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, transparent 35%, rgb(0 0 0/.45));
}
.fx-ov-tint .w-img::before {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: color-mix(in srgb, var(--w-accent) 22%, transparent);
}
.fx-grain .w-img::after {
  content: ''; position: absolute; inset: 0; z-index: 2; opacity: .22;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

.fx-lift .w-card { transition: transform 220ms cubic-bezier(.2,.7,.3,1), box-shadow 220ms }
.fx-lift .w-card:hover { transform: translateY(-4px); box-shadow: 0 14px 34px rgb(0 0 0/.12) }
.fx-gradbtn .w-btn:not(.ghost) {
  background: linear-gradient(135deg, var(--w-accent),
    color-mix(in srgb, var(--w-accent) 70%, #fff));
}
.fx-glass .blk-header {
  position: sticky; top: 0; z-index: 20;
  backdrop-filter: blur(10px);
  background: color-mix(in srgb, var(--w-bg) 78%, transparent);
}
.fx-div-line     .blk + .blk { border-top: var(--w-bw) solid var(--w-border) }
.fx-div-diagonal .blk + .blk { border-top: calc(var(--w-bw) * 2) solid var(--w-border) }
.fx-div-wave     .blk + .blk { border-top: var(--w-bw) solid var(--w-border) }

.fx-ratio-16x9 .w-card .w-img { aspect-ratio: 16/9; height: auto }
.fx-ratio-4x3  .w-card .w-img { aspect-ratio: 4/3;  height: auto }
.fx-ratio-1x1  .w-card .w-img { aspect-ratio: 1/1;  height: auto }
.fx-ratio-3x4  .w-card .w-img { aspect-ratio: 3/4;  height: auto }

/* Появление при прокрутке — только CSS: сайты без JavaScript по
   построению (правило 18). Где view() не поддерживается, блоки просто
   видны. Уважает системную настройку: это поведение рендерера,
   а не опция темы. */
@supports (animation-timeline: view()) {
  .fx-reveal .blk:not(.blk-header) {
    animation: w-reveal linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 28%;
  }
}
@keyframes w-reveal { from { opacity: .15; transform: translateY(18px) } to { opacity: 1; transform: none } }

/* Блоки-акценты (U-12). Бегущая строка: две одинаковые ленты едут влево
   на половину ширины — стык незаметен. Скорость и кегль — атрибутами
   данных, чтобы в документе блока не было ни секунд, ни кеглей. */
.w-marquee { display: flex; overflow: hidden; white-space: nowrap; gap: 0; font-family: var(--w-fh); font-weight: var(--w-hw); text-transform: uppercase; letter-spacing: var(--w-track) }
.w-marquee-track { display: flex; flex: 0 0 auto; min-width: 100%; justify-content: space-around; gap: calc(var(--w-gap) * 2); padding-right: calc(var(--w-gap) * 2); animation: w-marquee 28s linear infinite; will-change: transform }
.w-marquee[data-speed="slow"] .w-marquee-track { animation-duration: 48s }
.w-marquee[data-speed="fast"] .w-marquee-track { animation-duration: 14s }
.w-marquee[data-big="true"] { font-size: var(--w-h2) }
.w-marquee-item::before { content: '•'; color: var(--w-accent); margin-right: calc(var(--w-gap) * 0.75) }
@keyframes w-marquee { to { transform: translateX(-100%) } }
/* Стикер: наклон — свойство стиля сайта, а не документа блока. */
.w-sticker { display: inline-block; padding: calc(var(--w-gap) * 0.6) calc(var(--w-gap) * 1.2); background: var(--w-accent); color: var(--w-accent-tx); font-family: var(--w-fh); font-weight: var(--w-hw); font-size: var(--w-h3); border-radius: var(--w-r); box-shadow: var(--w-shadow); white-space: nowrap }
.w-sticker[data-tilt="left"] { transform: rotate(-6deg) }
.w-sticker[data-tilt="right"] { transform: rotate(6deg) }
.w-report td:first-child { width: 30% }
.w-report[data-narrow="true"] { max-width: calc(var(--w-container) * 0.6) }
/* Без движения строка — обычный ряд фраз с переносом; копия ленты не нужна. */
@media (prefers-reduced-motion: reduce) {
  .w-marquee-track { animation: none; min-width: 0; flex-wrap: wrap; justify-content: center; padding-right: 0; row-gap: calc(var(--w-gap) * 0.5) }
  .w-marquee { white-space: normal }
  .w-marquee-track[aria-hidden="true"] { display: none }
}
@media (prefers-reduced-motion: reduce) {
  .fx-lift .w-card { transition: none }
  /* Селектор повторяет тот, что включает появление, вместе с `:not`:
     без этого правило менее специфично, анимация не отключалась, и
     человек с системной настройкой «меньше движения» видел блоки
     полупрозрачными — состояние `from` держится `animation-fill-mode`.
     Тем же чинятся снимки: playwright просит reduced motion. */
  .fx-reveal .blk:not(.blk-header) { animation: none }
}

/* ══════════════════════════════════════════════════════════════
   СТИЛИСТИКА
   ══════════════════════════════════════════════════════════════ */
.cs-border .w-card { background: var(--w-surface); border: var(--w-bw) solid var(--w-border); box-shadow: none }
.cs-shadow .w-card { background: var(--w-surface); border: 0; box-shadow: 0 6px 24px rgb(0 0 0/.09) }
.cs-plain  .w-card { background: transparent; border: 0; box-shadow: none }
.cs-fill   .w-card { background: var(--w-soft); border: 0; box-shadow: none }

.bs-outline .w-btn:not(.ghost) { background: transparent; color: var(--w-accent); border-color: var(--w-accent) }
.bs-soft    .w-btn:not(.ghost) {
  background: color-mix(in srgb, var(--w-accent) 14%, transparent);
  color: var(--w-accent); border-color: transparent;
}
.bs-link    .w-btn:not(.ghost) {
  background: none; border: 0; padding: 0; height: auto; color: var(--w-accent);
  text-decoration: underline; text-underline-offset: 4px;
}

.is-round  .w-img { border-radius: calc(var(--w-rimg) * 2.2) }
.is-circle .w-img { border-radius: 999px; aspect-ratio: 1/1; height: auto }
.is-arch   .w-img { border-radius: 999px 999px var(--w-rimg) var(--w-rimg) }

.hs-caps h1, .hs-caps h2, .hs-caps h3 { text-transform: uppercase; letter-spacing: .02em }
.hs-underline h2 { padding-bottom: 10px; border-bottom: 2px solid var(--w-accent); display: inline-block }
.hs-accent h1::after, .hs-accent h2::after {
  content: ''; display: block; width: 44px; height: 3px;
  background: var(--w-accent); margin-top: 12px; border-radius: 2px;
}

.al-center .wrap > h1, .al-center .wrap > h2 { text-align: center }
.al-center .w-grid { text-align: center }
/* Центр — это и текст, и то, что стоит над ним: маркер, номер, иконка.
   Квадратик-маркер оставался слева при центрированном тексте под ним
   (`docs/visual-diagnosis-2026-09-19.md`, §1.2). */
.al-center .w-grid .w-btn, .al-center .w-num, .al-center .w-dot,
.al-center .w-grid .w-icon,
.blk-al-center .w-grid .w-btn, .blk-al-center .w-num, .blk-al-center .w-dot,
.blk-al-center .w-grid .w-icon { margin-left: auto; margin-right: auto }
/* Карточка товара, услуги, статьи читается слева при любой центровке
   темы — так во всех разобранных витринах. Центр внутри карточки
   разводил метку, название, цену и подпись по разным осям. Центр
   остаётся у презентационных сеток без карточек: преимущества,
   цифры, этапы. */
.al-center .w-card, .blk-al-center .w-card { text-align: left }
.al-center .w-card .w-btn, .blk-al-center .w-card .w-btn { margin-left: 0; margin-right: 0 }

/* Центровка темы — про заголовки и презентационные блоки, но не про
   данные. `.w-grid` — примитив раскладки, он же держит таблицу
   характеристик, форму и строку корзины; центр в них разваливает пару
   «подпись — значение» и ставит кнопки столбиком по середине. Товар,
   корзина и заказ читаются слева при любой теме. */
.al-center .w-specs,
.al-center .w-specs td,
.al-center .w-form,
.al-center .w-cart-row,
.al-center .w-prod-info,
.al-center .w-prod-info h1,
.blk-al-center .w-specs,
.blk-al-center .w-specs td,
.blk-al-center .w-form,
.blk-al-center .w-cart-row,
.blk-al-center .w-prod-info,
.blk-al-center .w-prod-info h1 { text-align: left }
/* Колонка товара выстраивается по левому краю целиком: кнопки в ней
   тоже, иначе «В корзину» уезжает на середину, а надпись над ней — нет. */
.al-center .w-prod-info .w-btn,
.blk-al-center .w-prod-info .w-btn { margin-left: 0; margin-right: 0 }
.al-center .w-specs td:last-child,
.blk-al-center .w-specs td:last-child { text-align: right }
/* Кнопка внутри формы не тянется к центру: в строке «поле + кнопка»
   это разрывало пару на две центрированные половины. */
.al-center .w-form .w-btn,
.blk-al-center .w-form .w-btn { margin-left: 0; margin-right: 0 }

.pt-grid {
  background-image:
    linear-gradient(color-mix(in srgb, var(--w-tx) 5%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--w-tx) 5%, transparent) 1px, transparent 1px);
  background-size: 48px 48px;
}
.pt-dots {
  background-image: radial-gradient(color-mix(in srgb, var(--w-tx) 9%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
}
.pt-noise {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.045'/%3E%3C/svg%3E");
}
.pt-glow {
  background-image: radial-gradient(60% 42% at 50% 0%,
    color-mix(in srgb, var(--w-accent) 16%, transparent), transparent 70%);
}

/* Насыщенные подложки. Строятся из токенов темы, поэтому одинаково
   уместны и на светлой, и на тёмной палитре. */
.pt-mesh {
  background-image:
    radial-gradient(42% 38% at 12% 8%,  color-mix(in srgb, var(--w-accent) 26%, transparent), transparent 70%),
    radial-gradient(38% 34% at 88% 14%, color-mix(in srgb, var(--w-accent) 16%, transparent), transparent 70%),
    radial-gradient(46% 40% at 70% 92%, color-mix(in srgb, var(--w-tx) 8%, transparent), transparent 72%);
}
.pt-aurora {
  background-image:
    radial-gradient(58% 42% at 20% 0%,  color-mix(in srgb, var(--w-accent) 34%, transparent), transparent 68%),
    radial-gradient(48% 38% at 82% 12%, color-mix(in srgb, var(--w-soft-tx) 26%, transparent), transparent 70%),
    radial-gradient(70% 50% at 50% 108%, color-mix(in srgb, var(--w-accent) 20%, transparent), transparent 72%);
}
.pt-stripes {
  background-image: repeating-linear-gradient(
    -45deg,
    color-mix(in srgb, var(--w-accent) 7%, transparent) 0 12px,
    transparent 12px 34px);
}

/* Первый экран поверх узора читается плохо, если узор яркий:
   подложка под текстом обязательна. */
.pt-aurora .hero-over .wrap, .pt-mesh .hero-over .wrap { position: relative; z-index: 2 }

/* ══════════════════════════════════════════════════════════════
   ЛОКАЛЬНЫЕ НАСТРОЙКИ БЛОКА

   Множители токенов, а не литералы: блок с плотными отступами
   останется плотным и в просторной теме, но отступ всё равно
   вычисляется из --w-secy. Поэтому смену темы он переживает.
   ══════════════════════════════════════════════════════════════ */

.blk-pad-none .sec { padding-block: 0 }
.blk-pad-s    .sec { padding-block: calc(var(--w-secy) * 0.45) }
.blk-pad-l    .sec { padding-block: calc(var(--w-secy) * 1.5) }

/* «Сетка и ритм» (U-04): отступ под заголовком секции — токен темы, а не
   inline-margin блока. !important нужен, потому что блоки задавали
   margin-bottom: var(--w-gap) в документе; теперь это расстояние крутится
   отдельным ползунком. Только заголовки-дети .wrap: заголовки в стеках
   (первый экран) живут по промежутку стека. */
.sec > .wrap > h1, .sec > .wrap > h2, .sec > .wrap > h3 { margin-bottom: var(--w-headgap) !important }

/* ── Шапка секции (A-138, `build.sec_head`) ──────────────────────
   Надзаголовок, заголовок, подводка — колонкой на шкале расстояний;
   действие («все товары», сортировка) — справа по нижней линии.
   Ширина текста ограничена: подводка на всю ширину контейнера читается
   как абзац, а не как подводка. Выравнивание — от характера. */
.w-sec-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--w-s3); flex-wrap: wrap; min-width: 0;
}
.w-sec-text { display: flex; flex-direction: column; gap: var(--w-s2); min-width: 0; max-width: 42em }
.w-sec-text > h1 { max-width: none }
.w-sec-head .w-eyebrow { margin-bottom: 0 }
.w-sec-action { display: flex; align-items: center; gap: var(--w-s2); flex-wrap: wrap }
.w-lead { font-size: var(--w-lead-fs, calc(var(--w-body) * 1.15)); max-width: 36em }
.sec > .wrap > .w-sec-head { margin-bottom: var(--w-headgap) }
.al-center .sec > .wrap > .w-sec-head, .blk-al-center .sec > .wrap > .w-sec-head {
  justify-content: center; text-align: center;
}
.al-center .sec > .wrap > .w-sec-head .w-sec-text,
.blk-al-center .sec > .wrap > .w-sec-head .w-sec-text { align-items: center; margin-inline: auto }
.al-center .sec > .wrap > .w-sec-head .w-sec-action,
.blk-al-center .sec > .wrap > .w-sec-head .w-sec-action { flex-basis: 100%; justify-content: center }

/* Варианты раскладки (U-13): роль `variant` меняет вид тех же полей
   правилами по общим классам блока — документ блока не знает о варианте.
   wide: сетка «текст | фото» становится столбиком, фото первым и во всю
   ширину; tilt: фото и карточки чуть наклонены, чётные — в другую сторону;
   kpi: каждая ячейка сетки — плитка на подложке. */
/* !important: статическая сетка блока задаёт колонки inline-стилем (build.grid). */
.blk-v-wide .w-grid { grid-template-columns: minmax(0, 1fr) !important }
.blk-v-wide .w-grid > .w-img { order: -1; height: var(--w-hero-h); width: 100% }
.blk-v-wide .w-grid > .w-img .w-img-el { height: 100% }
.blk-v-tilt .w-img:not(.w-card .w-img), .blk-v-tilt .w-card { transform: rotate(-2deg); box-shadow: var(--w-shadow) }
.blk-v-tilt .w-grid > :nth-child(even) > .w-img:not(.w-card .w-img), .blk-v-tilt .w-grid > :nth-child(even) .w-card,
.blk-v-tilt .w-grid > .w-img:nth-child(even) { transform: rotate(2deg) }
.blk-v-tilt .w-grid { padding-block: calc(var(--w-gap) * 0.5) }
.blk-v-kpi .w-grid > * { background: var(--w-surface); color: var(--w-tx); border: var(--w-bw) solid var(--w-border); border-radius: var(--w-r); padding: var(--w-gap) }
.blk-v-kpi .w-grid > .w-img { padding: 0; overflow: hidden }
.blk-v-kpi .w-grid > a > .w-card { border: 0; box-shadow: none }
@media (prefers-reduced-motion: reduce) { .blk-v-tilt .w-img, .blk-v-tilt .w-card { transition: none } }

/* Промежуток в сетке блока (U-02): множитель от --w-gap темы, не значение. */
.blk-gap-tight .w-grid { gap: calc(var(--w-gap) * 0.5) }
.blk-gap-loose .w-grid { gap: calc(var(--w-gap) * 1.5) }

.blk-w-narrow .wrap { max-width: calc(var(--w-container) * 0.7) }
.blk-w-wide   .wrap { max-width: calc(var(--w-container) * 1.18) }
.blk-w-full   .wrap { max-width: none }

.blk-al-center .wrap > h1, .blk-al-center .wrap > h2,
.blk-al-center .wrap > h3 { text-align: center }
.blk-al-center .w-grid { text-align: center }
.blk-al-center .w-grid .w-btn { margin-left: auto; margin-right: auto }
.blk-al-left .wrap > h1, .blk-al-left .wrap > h2,
.blk-al-left .wrap > h3 { text-align: left }
.blk-al-left .w-grid { text-align: left }

.blk-div-top    { border-top: var(--w-bw) solid var(--w-border) }
.blk-div-bottom { border-bottom: var(--w-bw) solid var(--w-border) }
.blk-div-both   { border-block: var(--w-bw) solid var(--w-border) }

@media (max-width: 640px) { .blk-hide-mobile { display: none } }
@media (min-width: 641px) { .blk-hide-desktop { display: none } }

/* ── Поиск и характеристики ─────────────────────────────────── */
.w-search { display: flex; gap: calc(var(--w-gap) * 0.5); flex-wrap: wrap }
.w-search .w-input { flex: 1; min-width: 220px }

.w-specs { width: 100%; border-collapse: collapse; font-size: var(--w-small) }
.w-specs td { padding: calc(var(--w-gap) * 0.4) 0;
  border-bottom: var(--w-bw) solid var(--w-border); vertical-align: top }
.w-specs td:first-child { color: var(--w-soft-tx); width: 45% }
.w-specs tr:last-child td { border-bottom: 0 }

.w-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px; border-radius: var(--w-btn-r);
  border: var(--w-bw) solid var(--w-border); font-size: var(--w-small);
  color: var(--w-soft-tx); text-decoration: none;
}
.w-chip:hover { border-color: var(--w-accent); color: var(--w-accent) }

/* Выбранное значение подбора. Без пометки человек не видит, что
   фильтр уже применён, и жмёт его второй раз — снимая. */
.w-chip[data-on] {
  background: var(--w-accent);
  color: var(--w-accent-tx);
  border-color: var(--w-accent);
}
.w-chip[data-on]:hover { color: var(--w-accent-tx) }

/* ── Сообщения форм покупателя: ошибка и подтверждение ─────── */
/* Ссылка «сразу к содержимому»: уводится за экран, возвращается по
   фокусу с клавиатуры. Скрывать её через display:none нельзя — так её
   не найдёт и клавиатура. */
.w-skip { position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--w-accent); color: var(--w-accent-tx);
  padding: calc(var(--w-gap) * .5) var(--w-gap); border-radius: var(--w-r) }
.w-skip:focus { left: var(--w-gap); top: var(--w-gap) }

.w-notice { padding: calc(var(--w-gap) * .5) var(--w-gap); border-radius: var(--w-r); font-size: var(--w-small); margin: 0 }
.w-notice-bad { background: color-mix(in srgb, var(--w-accent) 12%, var(--w-surface)); color: var(--w-tx); border: var(--w-bw) solid var(--w-accent) }
.w-notice-ok { background: var(--w-soft); color: var(--w-tx); border: var(--w-bw) solid var(--w-border) }

/* ── Форматированный текст статьи (узел rich, контракт v2) ─── */
.w-rich { line-height: var(--w-lead); color: var(--w-tx) }
.w-rich .w-rich-p { margin: 0 0 calc(var(--w-gap) * 0.75) }
.w-rich .w-rich-h2 { font-family: var(--w-fh); font-size: var(--w-h3); font-weight: var(--w-hw); margin: calc(var(--w-gap) * 1.25) 0 calc(var(--w-gap) * 0.5) }
.w-rich .w-rich-h3 { font-family: var(--w-fh); font-size: var(--w-h4); font-weight: var(--w-hw); margin: var(--w-gap) 0 calc(var(--w-gap) * 0.4) }
.w-rich .w-rich-list { margin: 0 0 calc(var(--w-gap) * 0.75); padding-left: calc(var(--w-gap) * 1.2) }
.w-rich .w-rich-list li { margin-bottom: calc(var(--w-gap) * 0.25) }
.w-rich .w-rich-quote { margin: var(--w-gap) 0; padding: calc(var(--w-gap) * 0.5) var(--w-gap); border-left: calc(var(--w-bw) * 3) solid var(--w-accent); background: var(--w-soft); border-radius: var(--w-r); color: var(--w-soft-tx) }
.w-rich .w-rich-figure { margin: var(--w-gap) 0 }
.w-rich .w-rich-figure img { display: block; width: 100%; height: auto; border-radius: var(--w-rimg) }
.w-rich .w-rich-figure figcaption { margin-top: calc(var(--w-gap) * 0.3); font-size: var(--w-small); color: var(--w-soft-tx) }
.w-rich a { color: var(--w-accent); text-decoration: underline; text-underline-offset: 3px }

/* ══════════════════════════════════════════════════════════════
   РЕЖИМЫ ТЕМЫ (T-03) — новые значения реестра renderer/theme-modes.json.
   Каждое значение реестра обязано иметь правило здесь: проверяет
   tests/unit.py. Добавили режим — добавьте правило.
   ══════════════════════════════════════════════════════════════ */
.cs-outline .w-card { background: var(--w-surface); border: var(--w-bw) solid var(--w-accent); box-shadow: none }
.bs-shadow  .w-btn:not(.ghost) { box-shadow: 0 8px 22px color-mix(in srgb, var(--w-accent) 35%, transparent) }

.fx-div-dotted .blk + .blk { border-top: calc(var(--w-bw) * 2) dotted var(--w-border) }
.fx-div-accent .blk + .blk { border-top: calc(var(--w-bw) * 3) solid var(--w-accent) }
.fx-div-space  .blk + .blk { margin-top: calc(var(--w-secy) * 0.5) }
.fx-div-wave   .blk + .blk { position: relative; border-top: 0 }
.fx-div-wave   .blk + .blk::before {
  content: ''; position: absolute; left: 0; right: 0; top: -1px; height: 10px; z-index: 1;
  background: radial-gradient(circle at 10px -4px, transparent 10px, var(--w-border) 10px, var(--w-border) 11px, transparent 11.5px);
  background-size: 20px 10px; background-repeat: repeat-x; pointer-events: none;
}

/* Пресеты вида блока (theme.looks) и локальные роли card / btn: правило
   блока стоит ниже правила корня и той же силы, поэтому побеждает. */
.blk-cs-border  .w-card { background: var(--w-surface); border: var(--w-bw) solid var(--w-border); box-shadow: none }
.blk-cs-shadow  .w-card { background: var(--w-surface); border: 0; box-shadow: 0 6px 24px rgb(0 0 0/.09) }
.blk-cs-plain   .w-card { background: transparent; border: 0; box-shadow: none }
.blk-cs-fill    .w-card { background: var(--w-soft); border: 0; box-shadow: none }
.blk-cs-outline .w-card { background: var(--w-surface); border: var(--w-bw) solid var(--w-accent); box-shadow: none }

.blk-bs-solid   .w-btn:not(.ghost) { background: var(--w-accent); color: var(--w-accent-tx); border-color: var(--w-accent); box-shadow: none; text-decoration: none; height: var(--w-btn-h); padding: 0 var(--w-btn-x) }
.blk-bs-outline .w-btn:not(.ghost) { background: transparent; color: var(--w-accent); border-color: var(--w-accent); box-shadow: none }
.blk-bs-soft    .w-btn:not(.ghost) { background: color-mix(in srgb, var(--w-accent) 14%, transparent); color: var(--w-accent); border-color: transparent; box-shadow: none }
.blk-bs-shadow  .w-btn:not(.ghost) { background: var(--w-accent); color: var(--w-accent-tx); border-color: var(--w-accent); box-shadow: 0 8px 22px color-mix(in srgb, var(--w-accent) 35%, transparent) }
/* Кнопка-ссылка: фона и рамки нет, но высота остаётся пальцевой —
   26 px по чистому тексту в палец не попадают (`tools/adaptive.py`). */
.blk-bs-link    .w-btn:not(.ghost) { background: none; border: 0; padding: 0; height: auto; min-height: 32px; color: var(--w-accent); text-decoration: underline; text-underline-offset: 4px; box-shadow: none }

/* ══════════════════════════════════════════════════════════════
   ЧЕТЫРЕ СТИЛЯ (U-08): нео, технический, яркий, минимализм.
   Новые значения реестра: cardStyle/btnStyle «hard», headStyle
   «outline», pattern «scanline» и «blobs», флаг «corners».
   Всё из токенов; движение выключается prefers-reduced-motion.
   ══════════════════════════════════════════════════════════════ */
/* Жёсткая тень — необрутализм: смещённая тень цвета рамки без размытия. */
.cs-hard .w-card, .blk-cs-hard .w-card {
  background: var(--w-surface); border: var(--w-bw) solid var(--w-border);
  box-shadow: calc(var(--w-bw) * 3) calc(var(--w-bw) * 3) 0 var(--w-border);
}
.fx-lift.cs-hard .w-card:hover, .fx-lift .blk-cs-hard .w-card:hover {
  transform: translate(-3px, -3px);
  box-shadow: calc(var(--w-bw) * 4) calc(var(--w-bw) * 4) 0 var(--w-border);
}
.bs-hard .w-btn:not(.ghost), .blk-bs-hard .w-btn:not(.ghost) {
  background: var(--w-accent); color: var(--w-accent-tx); border-color: var(--w-border);
  box-shadow: calc(var(--w-bw) * 2.5) calc(var(--w-bw) * 2.5) 0 var(--w-border);
  transition: transform 120ms, box-shadow 120ms;
}
.bs-hard .w-btn:not(.ghost):hover, .blk-bs-hard .w-btn:not(.ghost):hover {
  transform: translate(2px, 2px); box-shadow: var(--w-bw) var(--w-bw) 0 var(--w-border);
}
/* Контурные заголовки: первая строка h1 залита, остальное — контур цветом текста. */
.hs-outline h1 { -webkit-text-stroke: 0; }
.hs-outline h1 em, .hs-outline h2 em {
  font-style: normal; color: var(--w-bg);
  -webkit-text-stroke: max(2px, calc(var(--w-bw) * 1)) var(--w-tx); paint-order: stroke fill;
}
/* Технический: сетка + сканлайн + свечение акцента сверху. */
.pt-scanline {
  background-image:
    repeating-linear-gradient(0deg, transparent 0 3px, color-mix(in srgb, var(--w-dark) 30%, transparent) 3px 4px),
    linear-gradient(color-mix(in srgb, var(--w-tx) 5%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--w-tx) 5%, transparent) 1px, transparent 1px),
    radial-gradient(60% 40% at 70% 0%, color-mix(in srgb, var(--w-accent) 14%, transparent), transparent 70%);
  background-size: 100% 4px, 56px 56px, 56px 56px, 100% 100%;
}
/* Яркий: три размытых пятна медленно плывут. Только CSS, без скриптов. */
.pt-blobs { position: relative; isolation: isolate; overflow: clip }
.pt-blobs::before, .pt-blobs::after {
  content: ''; position: absolute; z-index: -1; border-radius: 50%;
  width: 46vw; height: 46vw; filter: blur(60px); opacity: .5; pointer-events: none;
  animation: w-blob 18s ease-in-out infinite alternate;
}
.pt-blobs::before { left: -12vw; top: -14vw; background: var(--w-accent) }
.pt-blobs::after  { right: -14vw; top: 30vh; background: var(--w-soft-tx); animation-delay: -7s }
@keyframes w-blob { to { transform: translate(8vw, 6vh) scale(1.12) } }
/* Уголки-скобки на карточках — «прицел» технического стиля. */
.fx-corners .w-card { position: relative }
.fx-corners .w-card::before, .fx-corners .w-card::after {
  content: ''; position: absolute; width: 14px; height: 14px; z-index: 3;
  border: 2px solid var(--w-accent); pointer-events: none;
}
.fx-corners .w-card::before { left: -1px; top: -1px; border-right: 0; border-bottom: 0 }
.fx-corners .w-card::after  { right: -1px; bottom: -1px; border-left: 0; border-top: 0 }
@media (prefers-reduced-motion: reduce) {
  .pt-blobs::before, .pt-blobs::after { animation: none }
  .bs-hard .w-btn, .blk-bs-hard .w-btn, .cs-hard .w-card, .blk-cs-hard .w-card { transition: none }
}

/* Вторая волна стилей (U-09): «Люкс» и «Игровой».
   Стеклянные карточки — полупрозрачная подложка с размытием и рамкой
   с примесью акцента; пунктирные — рамка текстом, толщина из темы. */
.cs-glass .w-card, .blk-cs-glass .w-card {
  background: color-mix(in srgb, var(--w-surface) 65%, transparent);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: var(--w-bw) solid color-mix(in srgb, var(--w-accent) 28%, var(--w-border));
  box-shadow: none;
}
.cs-dashed .w-card, .blk-cs-dashed .w-card {
  background: var(--w-surface); border: max(2px, var(--w-bw)) dashed var(--w-tx); box-shadow: none;
}

/* ═══════════════════════════════════════════════════════════════
   КОНТРАКТ ТЕМЫ v3 (Z-01): ритм, шапка, подвал, надзаголовок,
   плотность сетки.

   Почему это в теме, а не в блоках: разбор четырнадцати покупных
   шаблонов (docs/design-research-2026-09-17.md) показал, что шаблоны
   различаются ровно этим, а не палитрой. Правила цепляются к тем же
   общим классам, что и остальные режимы, — документ блока не меняется.
   ═══════════════════════════════════════════════════════════════ */

/* Ритм: первый экран и полоса. Значения приходят токенами темы
   (--w-heroy, --w-bandy); блок выбирает роль `pad`. */
.blk-pad-hero .sec { padding-block: var(--w-heroy) }
.blk-pad-band .sec { padding-block: var(--w-bandy) }

/* Надзаголовок — мелкая строка с разрядкой над крупным заголовком.
   Появился в v3: во всех разобранных шаблонах он есть, а у нас роли
   не было и блоки писали подзаголовок обычным текстом. */
.w-eyebrow {
  display: block; font-family: var(--w-fb);
  font-size: var(--w-eyebrow); font-weight: var(--w-eyebrow-w);
  letter-spacing: var(--w-eyebrow-t); text-transform: var(--w-eyebrow-c);
  color: var(--w-accent); margin-bottom: calc(var(--w-headgap) * 0.4);
}
.al-center .w-eyebrow, .blk-al-center .w-eyebrow { text-align: center }

/* Плотность сетки: три карточки в ряд или четыре — на весь сайт.
   `!important` нужен по той же причине, что у вариантов раскладки
   (U-13): колонки блок задаёт inline-стилем из своей схемы.

   Плотность действует только на сетки карточек — те, у которых число
   колонок вообще спрашивают у блока (`grid_bind`, класс `.w-cols`).
   Раскладки «текст и фото» — это не плотность: пока правило цеплялось
   к любому `.w-grid`, тема с «тремя в ряд» превращала первый экран в
   три колонки, из которых одна пустая, и заголовок ломался переносами
   посреди слова. */
.w-cols-2 .w-grid.w-cols { grid-template-columns: repeat(2, minmax(0, 1fr)) !important }
.w-cols-3 .w-grid.w-cols { grid-template-columns: repeat(3, minmax(0, 1fr)) !important }
.w-cols-4 .w-grid.w-cols { grid-template-columns: repeat(4, minmax(0, 1fr)) !important }
@media (max-width: 1023px) {
  .w-cols-3 .w-grid.w-cols, .w-cols-4 .w-grid.w-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
@media (max-width: 640px) {
  .w-cols-2 .w-grid.w-cols, .w-cols-3 .w-grid.w-cols, .w-cols-4 .w-grid.w-cols {
    grid-template-columns: minmax(0, 1fr) !important;
  }
}

/* ── Шапка ──────────────────────────────────────────────────────
   Блок шапки один, видов четыре. Разбор показал: в модерне шапка
   прозрачная и лежит поверх первого экрана, в классике — высокая
   полоса с телефоном и режимом работы.

   `!important` здесь не лень: отступы и линию шапка задаёт инлайновым
   стилем из своего документа (как и все блоки), а вид приходит от темы
   — иначе тема не смогла бы его переопределить. Та же причина, что
   у вариантов раскладки (U-13). */
.hdr-overlay .blk-header {
  position: absolute; left: 0; right: 0; top: 0; z-index: 5;
}
/* Поверх — только фотографии. Без фото под шапкой первый заголовок, и
   «поверх» значит «на заголовке»: на витрине компонентов меню лежало на
   h1. Признак тот же, что у цвета подписи ниже: картинка первого экрана
   сразу за шапкой. Нет её — шапка в потоке, как обычная. */
.hdr-overlay:not(:has(.blk-header + .blk .w-over .w-img-el)) .blk-header { position: static }
.hdr-overlay .blk-header > .wrap {
  background: transparent !important; border-bottom: 0 !important;
}
/* Светлая подпись в прозрачной шапке — только когда под ней фотография
   первого экрана. Без фото там фон страницы, и белое меню на светлом
   фоне просто исчезает: шапка есть, а прочитать её нельзя. Отличаем по
   тому, что видно в разметке, — картинка первого экрана сразу за
   шапкой. */
.hdr-overlay .blk-header a, .hdr-overlay .blk-header span, .hdr-overlay .blk-header b {
  color: var(--w-tx);
}
.hdr-overlay:has(.blk-header + .blk .w-over .w-img-el) .blk-header a,
.hdr-overlay:has(.blk-header + .blk .w-over .w-img-el) .blk-header span,
.hdr-overlay:has(.blk-header + .blk .w-over .w-img-el) .blk-header b {
  color: var(--w-dark-tx);
}
/* Кнопка действия в шапке — исключение: её подпись живёт в `span`, и
   правило выше красило её в цвет шапки, то есть в цвет фона кнопки. */
.hdr-overlay .blk-header a.w-btn:not(.ghost),
.hdr-overlay .blk-header a.w-btn:not(.ghost) span { color: var(--w-accent-tx) }
/* На телефоне шапка поверх первого экрана перестаёт быть поверх: первый
   экран там начинается сразу под ней, и прозрачная шапка ложилась прямо
   на заголовок — два текста друг на друге. Приём модерна остаётся на
   компьютере, где для него есть воздух (герой берёт 140–200 px сверху). */
@media (max-width: 720px) {
  .hdr-overlay .blk-header { position: static }
  .hdr-overlay .blk-header > .wrap { background: var(--w-bg) !important }
  .hdr-overlay .blk-header a, .hdr-overlay .blk-header span,
  .hdr-overlay .blk-header b { color: var(--w-tx) }
  .hdr-overlay .blk-header a.w-btn:not(.ghost),
  .hdr-overlay .blk-header a.w-btn:not(.ghost) span { color: var(--w-accent-tx) }
  .hdr-overlay .blk-header a.w-btn.ghost span { color: var(--w-tx) }
}
.hdr-topbar .blk-header > .wrap {
  box-shadow: inset 0 3px 0 var(--w-accent);
  padding-block: calc(var(--w-secy) * 0.5) !important;
}
.hdr-compact .blk-header > .wrap { padding-block: calc(var(--w-secy) * 0.18) !important }
/* Узкая шапка ужимает кнопки, но не ниже пальца. Переменная не может
   ссылаться на саму себя (`--w-btn-h: calc(var(--w-btn-h) * .82)` — это
   цикл, и значение становится недействительным): кнопки в узкой шапке
   оставались 28 px, то есть высотой по тексту. */
.hdr-compact .blk-header .w-btn { height: max(36px, calc(var(--w-btn-h) * 0.82)) }

/* Верхняя полоса шапки: объявление, режим работы, телефон. Блок печатает
   её, когда заполнена строка над шапкой; вид решает, как она выглядит.
   В «классике» это плашка на мягком фоне (в разобранных шаблонах она
   поднимает высоту шапки до 158–175 px), в остальных видах — тонкая
   строка. На телефоне остаётся одно: объявление, ради которого она и
   нужна, — иначе три надписи занимают пол-экрана. */
.w-topbar {
  background: var(--w-soft); color: var(--w-soft-tx);
  font-size: var(--w-small);
}
.w-topbar > .wrap { padding-block: calc(var(--w-secy) * 0.12) }
.hdr-topbar .w-topbar { background: var(--w-dark); color: var(--w-dark-tx) }
.hdr-overlay .w-topbar { background: transparent; color: var(--w-dark-tx) }
@media (max-width: 720px) {
  /* `!important` — раскладку группы задаёт инлайновый стиль из документа
     блока, и без него строка с режимом работы оставалась на телефоне
     второй строкой (та же причина, что у вариантов раскладки U-13). */
  .w-topbar-side { display: none !important }
}

/* ── Подвал ─────────────────────────────────────────────────────
   Тёмная плита (классика), мягкая плита (модерн-светлый) и узкая
   строка. Цвета — роли темы, литералов здесь нет. */
/* Вид подвала перекрывает фон, который подвал красит сам (`bg-soft` в
   документе блока): без этого тёмная плита оставалась светлой, а текст
   на ней — светлым, то есть невидимым. Та же причина, что у видов
   шапки: вид приходит от темы, документ блока не меняется (U-13). */
.ftr-dark .blk-footer .sec, .ftr-soft .blk-footer .sec,
.ftr-slim .blk-footer .sec {
  background: transparent;
}
.ftr-dark .blk-footer { background: var(--w-dark); color: var(--w-dark-tx) }
.ftr-dark .blk-footer a, .ftr-dark .blk-footer b { color: var(--w-dark-tx) }
.ftr-dark .blk-footer .w-soft { color: color-mix(in srgb, var(--w-dark-tx) 70%, transparent) }
.ftr-soft .blk-footer { background: var(--w-soft); color: var(--w-soft-tx) }
.ftr-soft .blk-footer a, .ftr-soft .blk-footer b { color: var(--w-tx) }
.ftr-dark .blk-footer .w-chip {
  background: color-mix(in srgb, var(--w-dark-tx) 14%, transparent);
  color: var(--w-dark-tx); border-color: transparent;
}
.ftr-slim .blk-footer > .wrap, .ftr-slim .blk-footer .sec {
  padding-block: var(--w-bandy) !important;
}
.ftr-slim .blk-footer .w-grid { grid-template-columns: minmax(0, 1fr) auto !important }
/* Узкая строка — это строка: колонки ссылок в ней не помещаются, и
   вместо подвала получался бы список в три экрана. Остаются марка и
   контакты. */
.ftr-slim .blk-footer .w-grid > :nth-child(2) { display: none }

/* ── Строка корзины: общая основа для всех шести видов ──────────
   Раскладку задаёт вид, размеры полей и промежутки — эта секция.
   `!important` — раскладку строки задаёт инлайновый стиль документа
   блока, а вид приходит от темы (правило U-13). */

/* Поле количества. В `.w-form` поля тянутся во всю ширину
   (`.w-input { width: 100% }`), и это ломало два вида сразу: в
   «карточках» поле растягивалось на треть экрана, в «узкой колонке»
   наезжало на название товара. Ширина фиксирована везде. */
.w-cart-row input[type="number"] {
  width: calc(var(--w-btn-h) * 1.5) !important;
  flex: 0 0 auto !important;
  text-align: center;
}
/* Кнопки в строке не тянутся и не переносятся по слогам. */
.w-cart-row .w-btn { width: auto; flex: 0 0 auto; white-space: nowrap }
/* Формы действий — часть строки, а не отдельные карточки: собственный
   отступ `.w-form` в целый `--w-gap` добавлял строке полсотни пикселей. */
.w-cart-row .w-form {
  padding: 0;
  gap: calc(var(--w-gap) * 0.4);
  align-items: center;
  width: auto;
}
.w-cart-row .w-form-row { flex-wrap: nowrap }

/* Промежуток между товарами. Без него карточки слипались в одно полотно
   с волосяными линиями, и глазом не отделить один товар от другого. */
.w-cart-row + .w-cart-row { margin-top: var(--w-cardgap) }

/* Строка по умолчанию: фото, название (тянется), количество, сумма,
   «убрать». Пять элементов разной ширины во `flex-wrap` не помещались в
   колонку и уезжали в три этажа. У названия задан минимум: без него
   колонка сжималась до нуля и текст наезжал на соседей. */
.w-cart-row {
  display: grid !important;
  grid-template-columns: auto minmax(8rem, 1fr) auto auto auto auto;
  align-items: center !important;
  gap: calc(var(--w-gap) * 0.6) !important;
  padding: var(--w-gap) !important;
}
.w-cart-row > b { text-align: right; white-space: nowrap }

/* Цена за штуку: приглушена и мельче суммы — в эталонах кегль строки 14
   при основном 16, то есть примерно наш `--w-small`. Сумма остаётся в
   основном кегле, иначе строка читается как две одинаковые цены. */
.w-cart-unit { color: var(--w-soft-tx); font-size: var(--w-small) }

/* Крестик удаления. У эталонов на него уходит 23 px против наших 105 у
   кнопки со словом — именно этой ширины не хватало названию товара. */
.w-cart-x {
  /* Квадрат, а не полоса: без явной высоты кнопка наследовала высоту
     строки и сплющивалась в узкий вертикальный прямоугольник. */
  width: calc(var(--w-btn-h) * 0.82) !important;
  height: calc(var(--w-btn-h) * 0.82) !important;
  min-width: 0;
  padding: 0 !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25em;
  line-height: 1;
}

/* Две колонки: фото слева, всё остальное справа. Нужны и телефону, и
   узкой колонке — пять колонок в 520 px наезжают друг на друга, что и
   было видно на снимке «Узкая колонка». */
/* Шесть колонок, по числу элементов строки: фото, название, цена штуки,
   количество, сумма, крестик. Когда цена стала отдельной колонкой,
   здесь осталось пять — и шестой элемент, крестик, переносился на
   отдельную строку под фотографией. Число колонок и число элементов
   строки обязаны совпадать. */
.blk-cv-narrow .w-cart-row,
.blk-cv-split .w-cart-row {
  grid-template-columns: auto minmax(0, 1fr) auto auto auto auto;
}
@media (max-width: 900px) {
  .blk-cv-split .w-cart-row { grid-template-columns: auto minmax(0, 1fr) }
  .blk-cv-split .w-cart-row > :nth-child(n+3) { grid-column: 2 }
  .blk-cv-split .w-cart-row { align-items: start !important }
}
@media (max-width: 640px) {
  .w-cart-row {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start !important;
  }
  .w-cart-row > :nth-child(n+3) { grid-column: 2 }
  /* `!important`: у суммы инлайновый `text-align: right` и `min-width`
     из документа блока — на телефоне они отрывали её от названия. */
  .w-cart-row > b { text-align: left !important; min-width: 0 !important }

  /* Плиточные виды остаются плитками: общее правило уводило фото в
     левую колонку, и плитка на телефоне становилась узкой вертикальной
     полосой с пустотой справа. */
  .blk-cv-steps .w-cart-row,
  .blk-cv-cards .w-cart-row { grid-template-columns: minmax(0, 1fr) !important }
  .blk-cv-steps .w-cart-row > :nth-child(n+3),
  .blk-cv-cards .w-cart-row > :nth-child(n+3) { grid-column: 1 }
}

/* ── Виды корзины (Z-03) ────────────────────────────────────────
   Строка корзины одна, видов три. Правила цепляются к `.w-cart-row`
   и перебивают инлайновую раскладку блока — как варианты U-13.

   Почему это не три блока: состав строки один и тот же (название,
   фасовка, количество, сумма, «убрать»), различается только раскладка.
   Три документа означали бы три места, где чинить одну ошибку. */
.blk-cv-cards .w-grid, .blk-cv-cards > .sec > .wrap { display: block }
/* Карточка занимает ширину, а не жмётся в левую треть. Раскладка в две
   строки: сверху фото, название и цена штуки, снизу количество, сумма и
   крестик — по краям карточки. Одной колонкой, как было, содержимое
   вытягивалось в узкий столбец, а три четверти карточки оставались
   пустыми. */
.blk-cv-cards .w-cart-row {
  display: grid !important;
  grid-template-columns: auto minmax(0, 1fr) auto auto !important;
  gap: var(--w-gap) !important;
  align-items: center !important;
  text-align: left;
}
.blk-cv-cards .w-cart-row > .w-img { grid-column: 1; grid-row: 1 / span 2 }
.blk-cv-cards .w-cart-row > div:not(.w-img) { grid-column: 2; grid-row: 1 }
.blk-cv-cards .w-cart-row > .w-cart-unit { grid-column: 3 / -1; grid-row: 1; text-align: right }
.blk-cv-cards .w-cart-row > form:nth-of-type(1) { grid-column: 2; grid-row: 2 }
.blk-cv-cards .w-cart-row > b {
  grid-column: 3; grid-row: 2;
  text-align: right !important; min-width: 0 !important;
  font-size: var(--w-h4);
}
.blk-cv-cards .w-cart-row > form:nth-of-type(2) { grid-column: 4; grid-row: 2 }
/* Фото в карточке крупнее, чем в строке: карточка для того и нужна. */
.blk-cv-cards .w-cart-row .w-cart-pic {
  width: calc(var(--w-btn-h) * 2.8) !important;
  height: calc(var(--w-btn-h) * 3.2) !important;
}

.blk-cv-table .w-cart-row {
  border-radius: 0 !important; box-shadow: none !important;
  border-width: 0 0 var(--w-bw) 0 !important;
  /* Поля по горизонтали остаются — см. «узкая колонка»: подложка
     карточки есть, и без них содержимое прилипает к её краю. */
  padding-inline: var(--w-gap) !important;
  gap: calc(var(--w-gap) * 0.5) !important;
}
/* Таблица — сплошная: промежуток между строками разорвал бы её на
   отдельные карточки, а это уже другой вид. */
.blk-cv-table .w-cart-row + .w-cart-row { margin-top: 0 }
.blk-cv-table .w-cart-row:first-child { border-top: var(--w-bw) solid var(--w-border) !important }

/* ── Товары слева, итог справа ──────────────────────────────────
   Раскладка покупных магазинов: список слева, сводка заказа справа и
   прилипшая к экрану, чтобы итог и кнопка были видны на любой длине
   списка. Собирается сеткой по соседям внутри `wrap` — товары идут в
   первую колонку, `.w-cart-sum` уезжает во вторую и растягивается на
   все строки списка: только тогда `sticky` есть куда ехать.

   `max-width` у `wrap` перебивается: документ блока держит корзину в
   0.7 контейнера (одной колонке этого хватает), двум колонкам — нет. */
.blk-cv-split > .sec > .wrap {
  max-width: var(--w-container) !important;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
  gap: var(--w-gap);
  align-items: start;
  /* Неявные строки — по содержимому. Иначе сводка, которая охватывает
     шестьдесят строк, растягивает их под свою высоту, и под коротким
     списком товаров повисает пустота в полэкрана. */
  grid-auto-rows: min-content;
}
.blk-cv-split > .sec > .wrap > * { grid-column: 1 }
/* Строка задаётся явно. Сводка занимает вторую колонку со второй строки
   до конца (`grid-row: 2 / -1`), и заголовок, которому нужна вся ширина,
   автоматической расстановкой уезжал в строку ПОСЛЕ сводки — то есть
   под список товаров. */
.blk-cv-split > .sec > .wrap > h1 { grid-column: 1 / -1; grid-row: 1 }
/* Селектор повторяет путь правила выше и добавляет класс: правило со
   звёздочкой специфичнее одиночного `.w-cart-sum`, и сводка оставалась
   в первой колонке во всю ширину. */
.blk-cv-split > .sec > .wrap > .w-cart-sum {
  grid-column: 2;
  /* Охват задан числом, а не `-1`. Явных строк у сетки нет (задаются
     только колонки), строки создаются неявно под товары, и `-1` не к
     чему привязать: сводка занимала одну строку, а список уезжал под
     неё. Пустые неявные строки нулевой высоты ничего не стоят. */
  grid-row: 2 / span 60;
  position: sticky;
  top: var(--w-gap);
  align-self: start;
}
/* Итог в узкой колонке читается слева: прижатый вправо, он отрывается
   от подписей строк и висит в пустоте. */
.blk-cv-split .w-cart-sum > div[style*="text-align"] { text-align: left !important }

/* ── По шагам, товары плитками ──────────────────────────────────
   Товар — плитка с фото сверху, как на витрине; оформление ниже разбито
   на пронумерованные шаги (промокод, доставка, итог, данные). Номер
   рисует счётчик CSS, а не разметка: шагов столько, сколько включено в
   настройках магазина, и блок об этом не знает. */
.blk-cv-steps > .sec > .wrap {
  max-width: var(--w-container) !important;
  display: grid;
  /* `auto-fit`, а не `auto-fill`: при трёх товарах `auto-fill`
     оставляет пустые дорожки, плитки жмутся к минимуму и ряд
     обрывается пустотой справа. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: var(--w-cardgap);
  /* Плитки одной высоты: при `start` они тянулись по своему тексту, и
     ряд выглядел рваным — у товара с длинным названием плитка выше. */
  align-items: stretch;
}
.blk-cv-steps > .sec > .wrap > h1,
.blk-cv-steps .w-cart-sum { grid-column: 1 / -1 }
.blk-cv-steps .w-cart-row {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr) !important;
  gap: calc(var(--w-gap) * 0.45) !important;
  align-items: start !important;
  text-align: left;
  padding: 0 0 var(--w-gap) 0 !important;
  overflow: hidden;
}
/* Плитки — соседи в сетке, промежуток даёт сама сетка (`gap`). Внешний
   отступ строки здесь лишний: он сдвинул бы вторую и третью плитку вниз
   относительно первой. */
.blk-cv-steps .w-cart-row + .w-cart-row { margin-top: 0 }
.blk-cv-steps .w-cart-row { align-content: start }
.blk-cv-steps .w-cart-row .w-cart-pic {
  width: 100% !important;
  height: var(--w-img-h-md) !important;
  flex: none !important;
}
.blk-cv-steps .w-cart-row > :not(.w-img) { padding-inline: var(--w-gap) }
/* Кнопка в плитке ужимается и переносится: «количество + Обновить» не
   помещалось в ширину плитки, и подпись кнопки обрезалась краем. */
.blk-cv-steps .w-cart-row .w-form-row { flex-wrap: wrap }
.blk-cv-steps .w-cart-row .w-btn { flex: 1 1 auto; min-width: 0 }
.blk-cv-steps .w-cart-row > b { text-align: left !important; min-width: 0 !important;
  font-size: var(--w-h4) }
.blk-cv-steps .w-cart-sum { counter-reset: cart-step }
.blk-cv-steps .w-cart-sum > * {
  position: relative;
  padding-left: calc(var(--w-gap) * 1.9);
}
.blk-cv-steps .w-cart-sum > *::before {
  counter-increment: cart-step;
  content: counter(cart-step);
  position: absolute; left: 0; top: 0;
  width: calc(var(--w-gap) * 1.2); height: calc(var(--w-gap) * 1.2);
  display: grid; place-items: center;
  border-radius: 999px;
  background: var(--w-accent); color: var(--w-accent-tx);
  font-size: var(--w-small); font-weight: 600;
}

/* ── Узкая колонка ──────────────────────────────────────────────
   Корзина в ширину читаемой строки: список без «хрома», фото мелкое,
   всё подряд одной вертикалью. Годится телефону и коротким заказам. */
.blk-cv-narrow > .sec > .wrap { max-width: calc(var(--w-container) * 0.46) !important }
/* Две колонки на любой ширине: колонка узкая по определению, и пять
   колонок в ней наезжают друг на друга — на снимке название товара
   лежало поверх поля количества. Фото слева, остальное справа. */
.blk-cv-narrow .w-cart-row {
  grid-template-columns: auto minmax(0, 1fr) !important;
  align-items: start !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  border-width: 0 0 var(--w-bw) 0 !important;
  /* Поля по горизонтали остаются: подложка карточки никуда не делась,
     и без них фото прилипало к её краю. Вид убирает рамку и тень, а не
     внутренние отступы. */
  padding-inline: var(--w-gap) !important;
  gap: calc(var(--w-gap) * 0.5) !important;
}
/* Две строки вместо четырёх: сверху фото и название, снизу количество,
   сумма и «убрать» в одну линию. Без этого каждый элемент занимал свою
   строку, и товар в узкой колонке растягивался на 274 px.
   `text-align` с `!important`: у суммы инлайновый стиль из документа
   блока, а он сильнее любого класса. */
.blk-cv-narrow .w-cart-row {
  grid-template-columns: auto minmax(0, 1fr) auto auto !important;
  align-items: center !important;
}
.blk-cv-narrow .w-cart-row > .w-img { grid-row: 1 / span 2; grid-column: 1 }
.blk-cv-narrow .w-cart-row > div:not(.w-img) { grid-column: 2; grid-row: 1 }
.blk-cv-narrow .w-cart-row > .w-cart-unit { grid-column: 3 / -1; grid-row: 1; text-align: right }
.blk-cv-narrow .w-cart-row > form:nth-of-type(1) { grid-column: 2; grid-row: 2 }
.blk-cv-narrow .w-cart-row > b {
  grid-column: 3; grid-row: 2;
  text-align: right !important; min-width: 0 !important;
}
.blk-cv-narrow .w-cart-row > form:nth-of-type(2) { grid-column: 4; grid-row: 2 }
.blk-cv-narrow .w-cart-row + .w-cart-row { margin-top: 0 }
.blk-cv-narrow .w-cart-row:first-of-type { border-top: var(--w-bw) solid var(--w-border) !important }
.blk-cv-narrow .w-cart-row .w-cart-pic {
  width: calc(var(--w-btn-h) * 1.6) !important;
  height: calc(var(--w-btn-h) * 1.6) !important;
}

/* Телефон: любая раскладка корзины становится одной колонкой. Две
   колонки на 390 px — это сводка шириной в слово. */
@media (max-width: 768px) {
  .blk-cv-split > .sec > .wrap { grid-template-columns: minmax(0, 1fr) }
  .blk-cv-split > .sec > .wrap > *,
  .blk-cv-split > .sec > .wrap > .w-cart-sum { grid-column: 1 }
  .blk-cv-split > .sec > .wrap > .w-cart-sum { grid-row: auto; position: static }
  .blk-cv-narrow > .sec > .wrap { max-width: none !important }
}

/* ── Первый экран: варианты документа (A-139, контракт block-doc §2.6) ──
   Здесь раскладка, а не характер: сетки, смещения, пропорции. Цвет,
   радиус, тень и ритм приходят токенами, как везде. Три композиции по
   мотивам покупных наборов, разметка и правила свои. */

/* Фото со смещением за край: сетка во всю ширину экрана, текст выровнен
   по контейнеру, фотография уходит в правый край без полей. */
.w-hero-offset {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
}
.w-hero-offset-text {
  display: flex; flex-direction: column; justify-content: center;
  padding-block: var(--w-heroy);
  padding-right: calc(var(--w-gap) * 2);
  padding-left: max(var(--w-pad), calc((100vw - var(--w-container)) / 2 + var(--w-pad)));
}
.w-hero-offset > .w-img { border-radius: 0; min-height: var(--w-hero-h) }
@media (max-width: 900px) {
  .w-hero-offset { grid-template-columns: minmax(0, 1fr) }
  .w-hero-offset-text { padding: var(--w-secy) var(--w-pad) }
  .w-hero-offset > .w-img { min-height: 0; height: auto !important; aspect-ratio: 4 / 3 }
}

/* Плитки фото справа: текст и две колонки вертикальных фото, левая
   колонка поднята — плитки идут лесенкой. */
.w-hero-tiles {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: calc(var(--w-gap) * 2); align-items: center;
  padding-block: calc(var(--w-heroy) - var(--w-secy));
}
.w-hero-tiles-pics { display: grid; grid-template-columns: 1fr 1fr; gap: var(--w-gap); align-items: end }
.w-hero-tiles-col { display: grid; gap: var(--w-gap) }
.w-hero-tiles-col:first-child { padding-bottom: 28% }
.w-hero-tiles-col > .w-img { height: auto !important; aspect-ratio: 2 / 3; width: 100% }
@media (max-width: 900px) {
  .w-hero-tiles { grid-template-columns: minmax(0, 1fr); padding-block: 0 }
  .w-hero-tiles-col:first-child { padding-bottom: 0 }
}

/* Текст карточкой поверх фото: широкая фотография, карточка с текстом
   наезжает на её нижний край. Карточка — обычная .w-card, поэтому вид
   карточек характера (рамка, тень, стекло) работает и здесь. */
.w-hero-card { position: relative }
.w-hero-card-img { height: auto !important; aspect-ratio: 2 / 1; min-height: calc(var(--w-hero-h) * 0.7) }
/* Заголовок в карточке — ступенью ниже: h1 первого экрана в половине ширины ломается по слову. */
.w-hero-card-box h1 { font-size: var(--w-h2) }
.w-hero-card-box {
  position: relative; z-index: 1;
  margin: calc(var(--w-gap) * -3) 0 0 calc(var(--w-gap) * 2);
  max-width: min(48%, 36em); padding: var(--w-cardpad);
}
@media (max-width: 900px) {
  .w-hero-card-box { margin: calc(var(--w-gap) * -1.5) var(--w-gap) 0; max-width: none }
}

/* ── Иерархия внутри карточки (A-143) ───────────────────────────
   Разбор витрин: название обычным начертанием, цена крупнее названия,
   подпись мелко. У нас было наоборот — жирное название, цена мелким
   жирным, и карточка читалась как строка таблицы. Инлайн документа
   перебивается по правилу U-13. */
.w-card .w-name { font-weight: 500 !important }
.w-card .w-price > span:first-child { font-size: var(--w-h4); font-weight: var(--w-hw) !important;
  font-family: var(--w-fh); letter-spacing: var(--w-track) }
.w-card .w-price s { font-size: var(--w-small) }
.w-svc-grid .w-meta > span { font-size: var(--w-h4); color: var(--w-tx) }
.w-svc-grid .w-card-body { gap: var(--w-s2) }
/* Карточки этапов и преимуществ: заголовок пункта — ступень h4 всегда,
   подпись — обычный кегль; мелкая подпись в просторной карточке терялась. */
.w-card > div > h3 { font-size: var(--w-h4) !important }

/* ── Шапка и подвал: варианты документа (A-144) ────────────────── */
.w-hdr-logo-c { text-align: center }
.w-hdr-row2 .w-nav { flex: 1; justify-content: center }
.w-hdr-row2 .w-nav-sp { display: none }
.w-hdr-navrow { border-top: var(--w-bw) solid var(--w-border); padding-top: var(--w-s2); margin-top: var(--w-s2) }
@media (max-width: 900px) {
  .w-hdr-row2 .w-nav, .w-hdr-navrow .w-nav { justify-content: flex-start }
}
.w-ftr-simple { display: flex; align-items: center; gap: var(--w-gap); flex-wrap: wrap }
.w-ftr-links { display: flex; gap: var(--w-gap); flex-wrap: wrap; flex: 1; justify-content: center }
.w-ftr-side { display: flex; align-items: center; gap: var(--w-s2); flex-wrap: wrap }
@media (max-width: 640px) { .w-ftr-links { justify-content: flex-start } }
.w-ftr-mission { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: calc(var(--w-gap) * 2); align-items: start }
.w-ftr-mission > div:last-child { justify-content: flex-end }
.w-ftr-contacts-row { margin-top: var(--w-s4); padding-top: var(--w-s4); border-top: var(--w-bw) solid var(--w-border) }
.w-ftr-contacts-row > div { flex-direction: row !important; flex-wrap: wrap; gap: var(--w-gap) !important; align-items: baseline }
@media (max-width: 900px) { .w-ftr-mission { grid-template-columns: minmax(0, 1fr) } .w-ftr-mission > div:last-child { justify-content: flex-start } }

/* ── Формы, контакты, тарифы, команда, бенто (A-145) ─────────────── */
.w-form-center { width: 100%; max-width: 34em }
.w-form-wide .w-form { flex-direction: row; flex-wrap: wrap; align-items: flex-end; padding: 0 }
.w-form-wide .w-form > label { flex: 1 1 14em; min-width: 0 }
.w-form-wide .w-form > button { flex: 0 0 auto }
.w-form-wide .w-form > label:has(textarea) { flex-basis: 100% }
/* Форма на фото первого экрана: карточка кликабельна, текст светлый. */
.w-hero-form-photo { background: linear-gradient(to right, color-mix(in srgb, #000 55%, transparent), color-mix(in srgb, #000 20%, transparent)) }
.w-hero-form-photo h1, .w-hero-form-photo .w-soft { color: #fff }
.w-hero-form-photo .w-hero-form-card { pointer-events: auto; color: var(--w-tx) }
.w-hero-form-photo .w-hero-form-card .w-soft { color: var(--w-soft-tx) }
/* Контакты полосой под картой: по факту в колонку. */
.w-contacts-row { grid-template-columns: repeat(auto-fit, minmax(14em, 1fr)); gap: var(--w-gap) }
.w-contacts-row > div { grid-template-columns: minmax(0, 1fr) !important; gap: var(--w-s1) !important }
/* Тарифы: выделенный крупнее; строками. */
.w-price-emph { align-items: center }
.w-price-emph > [data-featured="true"] { transform: scale(1.04); box-shadow: var(--w-shadow); z-index: 1 }
@media (max-width: 900px) { .w-price-emph > [data-featured="true"] { transform: none } }
.w-price-rows { display: grid; border-top: var(--w-bw) solid var(--w-border); text-align: left }
.w-price-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 2fr) auto auto; gap: var(--w-gap);
  align-items: center; padding: var(--w-s3) 0; border-bottom: var(--w-bw) solid var(--w-border) }
.w-price-row[data-featured="true"] { background: var(--w-soft); padding-inline: var(--w-s3); border-radius: var(--w-r) }
@media (max-width: 720px) { .w-price-row { grid-template-columns: minmax(0, 1fr) auto } .w-price-row > p { grid-column: 1 / -1 } }
.al-center .w-price-rows, .blk-al-center .w-price-rows { text-align: left }
/* Команда строками: маленькое круглое фото слева. */
.w-team-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--w-s4) calc(var(--w-gap) * 2); text-align: left }
.w-team-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--w-s3); align-items: center }
.w-team-ava { width: calc(var(--w-btn-h) * 2); height: calc(var(--w-btn-h) * 2) !important; border-radius: 999px; flex: 0 0 auto }
@media (max-width: 640px) { .w-team-rows { grid-template-columns: minmax(0, 1fr) } }
.al-center .w-team-rows, .blk-al-center .w-team-rows { text-align: left }
/* Бенто: первая плитка крупная на две колонки и два ряда. */
.w-bento { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: auto }
.w-bento > :first-child { grid-column: span 2; grid-row: span 2 }
.w-bento > :first-child .w-img { height: 100% !important; aspect-ratio: auto; flex: 1 }
.w-bento > :first-child .w-name { font-size: var(--w-h3) !important }
.w-bento-even > :first-child { grid-column: auto; grid-row: auto }
.w-bento-even > :first-child .w-img { height: auto !important; aspect-ratio: 4 / 3 }
.w-bento-even > :first-child .w-name { font-size: var(--w-h4) !important }
@media (max-width: 900px) { .w-bento { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (max-width: 640px) { .w-bento { grid-template-columns: minmax(0, 1fr) } .w-bento > :first-child { grid-column: auto; grid-row: auto } }

/* ── Варианты документов по категориям (A-142) ─────────────────
   Раскладки скелетов: сетки, колонки, разделители. Цвет и форма —
   токенами характера, как везде. */

/* Строка цифр под текстом первого экрана. */
.w-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(9em, 1fr)); gap: var(--w-gap);
  margin-top: var(--w-s5); padding-top: var(--w-s4); border-top: var(--w-bw) solid var(--w-border) }
.w-fact b { display: block; font-family: var(--w-fh); font-weight: var(--w-hw); font-size: var(--w-h3);
  letter-spacing: var(--w-track); line-height: 1.15 }

/* Первый экран на фото: карточка на фото и текст внизу. */
.w-hero-cardbox { max-width: 36em; padding: var(--w-cardpad); pointer-events: auto; color: var(--w-tx) }
.w-hero-cardbox h1, .w-hero-cardbox .w-soft { color: inherit }
.w-hero-cardbox .w-soft { color: var(--w-soft-tx) }
.hero-over.w-hero-bottom { align-items: flex-end; padding-bottom: calc(var(--w-heroy) * 0.6);
  background: linear-gradient(to top, color-mix(in srgb, #000 66%, transparent) 30%, color-mix(in srgb, #000 22%, transparent)) }
.hero-over.w-hero-bottom h1, .hero-over.w-hero-bottom .w-soft, .hero-over.w-hero-bottom .w-eyebrow { color: #fff }
.hero-over.w-hero-bottom .w-soft { opacity: .85 }

/* Заголовок слева, содержимое справа: преимущества, вопросы, цифры. */
.w-split { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: calc(var(--w-gap) * 2); align-items: start; text-align: left }
.w-split-head .w-sec-head { margin-bottom: 0; position: sticky; top: var(--w-gap) }
.w-split-items { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--w-s5) var(--w-gap) }
@media (max-width: 900px) { .w-split { grid-template-columns: minmax(0, 1fr) } }
@media (max-width: 640px) { .w-split-items { grid-template-columns: minmax(0, 1fr) } }
.al-center .w-split, .blk-al-center .w-split { text-align: left }
.al-center .w-split .w-sec-text, .blk-al-center .w-split .w-sec-text { align-items: flex-start; margin-inline: 0 }
.al-center .w-split .w-dot, .al-center .w-split .w-icon, .al-center .w-split .w-num { margin-left: 0 }

/* Преимущества строками: значок слева, текст справа. */
.w-feat-rows, .al-center .w-feat-rows, .blk-al-center .w-feat-rows { text-align: left }
.al-center .w-feat-rows .w-dot, .al-center .w-feat-rows .w-icon { margin: 0.35em 0 0 }
.w-feat-rows .w-dot { margin-top: 0.45em }

/* Услуги: карточками в сетке и таблицей. */
.w-svc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)) }
@media (max-width: 900px) { .w-svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (max-width: 640px) { .w-svc-grid { grid-template-columns: minmax(0, 1fr) } }
.w-svc-table { border-top: var(--w-bw) solid var(--w-border); text-align: left }
.w-svc-row { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 2fr) auto; gap: var(--w-gap);
  padding: var(--w-s3) 0; border-bottom: var(--w-bw) solid var(--w-border); align-items: baseline }
@media (max-width: 640px) {
  .w-svc-row { grid-template-columns: minmax(0, 1fr) auto }
  .w-svc-row > .w-soft { grid-column: 1 / -1 }
}
.al-center .w-svc-table, .blk-al-center .w-svc-table { text-align: left }

/* Текст с фото до края: та же сетка, что у первого экрана со смещением. */
.w-ti-bleed > .w-img { min-height: calc(var(--w-hero-h) * 0.7) }
.w-ti-bleed .w-hero-offset-text { padding-block: var(--w-secy) }

/* Этапы строками: номер слева, текст справа. */
.w-step-rows { display: grid; gap: var(--w-s4); max-width: 44em; text-align: left }
.w-step-row { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--w-s3); align-items: start }
.al-center .w-step-rows, .blk-al-center .w-step-rows { text-align: left }
.al-center .w-step-row .w-num, .blk-al-center .w-step-row .w-num { margin: 0 }

/* Вопросы: две колонки, список справа, раскрывающиеся без скрипта. */
.w-faq-two { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--w-s5) calc(var(--w-gap) * 2); text-align: left }
@media (max-width: 640px) { .w-faq-two { grid-template-columns: minmax(0, 1fr) } }
.w-faq-list { display: grid; gap: var(--w-s4) }
.w-faq-item { padding-bottom: var(--w-s4); border-bottom: var(--w-bw) solid var(--w-border) }
.w-acc-list { max-width: 48em; border-top: var(--w-bw) solid var(--w-border); text-align: left }
.w-acc { border-bottom: var(--w-bw) solid var(--w-border); padding: var(--w-s3) 0 }
.w-acc summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; gap: var(--w-gap);
  font-family: var(--w-fh); font-size: var(--w-h4); font-weight: var(--w-hw) }
.w-acc summary::-webkit-details-marker { display: none }
.w-acc summary::after { content: '+'; color: var(--w-accent); flex: 0 0 auto }
.w-acc[open] summary::after { content: '\2212' }
.al-center .w-faq-two, .al-center .w-acc-list, .blk-al-center .w-faq-two, .blk-al-center .w-acc-list { text-align: left }
.al-center .w-acc-list { margin-inline: auto }

/* Отзывы: крупные цитаты и строки с именем слева. */
.w-quotes { display: grid; gap: var(--w-s5); max-width: 46em; margin-inline: auto; text-align: center }
.w-quote { margin: 0; padding: 0 }
.w-quote-text { font-family: var(--w-fh); font-weight: var(--w-hw); font-size: var(--w-h3);
  line-height: 1.35; letter-spacing: var(--w-track) }
.w-quote-text::before { content: '\00AB' }
.w-quote-text::after { content: '\00BB' }
.w-quote-by { margin-top: var(--w-s3); display: flex; flex-direction: column; gap: 2px }
.w-rev-rows { border-top: var(--w-bw) solid var(--w-border); text-align: left }
.w-rev-row { display: grid; grid-template-columns: minmax(8em, 14em) minmax(0, 1fr); gap: var(--w-gap);
  padding: var(--w-s4) 0; border-bottom: var(--w-bw) solid var(--w-border) }
.w-rev-by { display: flex; flex-direction: column; gap: 2px }
@media (max-width: 640px) { .w-rev-row { grid-template-columns: minmax(0, 1fr); gap: var(--w-s2) } }
.al-center .w-rev-rows, .blk-al-center .w-rev-rows { text-align: left }

/* Сетка цифр: колонок столько, сколько чисел, плотность темы не спорит
   (правило «число колонок равно числу элементов», layout-rules §2). */
.site .w-grid.w-cols.w-stats.w-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)) !important }
.site .w-grid.w-cols.w-stats.w-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)) !important }
.site .w-grid.w-cols.w-stats.w-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important }
@media (max-width: 640px) { .site .w-grid.w-cols.w-stats { grid-template-columns: repeat(2, minmax(0, 1fr)) !important } }
/* Цифры полосой: разделители между ячейками. */
.w-stat-band > * { border-left: var(--w-bw) solid var(--w-border); padding-left: var(--w-gap) }
.w-stat-band > :first-child { border-left: 0; padding-left: 0 }
@media (max-width: 640px) { .w-stat-band > * { border-left: 0; padding-left: 0 } }

/* Полоса призыва карточкой; кнопка на акценте — инверсией, иначе невидима. */
.w-band-card { border: 0 }
.bg-accent .w-btn:not(.ghost), .bg-accent a.w-btn:not(.ghost) { background: var(--w-accent-tx); color: var(--w-accent); border-color: var(--w-accent-tx) }
.bg-accent .w-btn:not(.ghost) span { color: inherit }

/* Команда: круглые фото без карточек. */
.w-team-round .w-card { background: transparent !important; border: 0 !important; box-shadow: none !important; text-align: center; align-items: center }
.w-team-round .w-card > .w-img { width: 62%; aspect-ratio: 1 / 1; height: auto !important; border-radius: 999px; margin: var(--w-s2) auto 0 }
.w-team-round .w-card > div { align-items: center }

/* ── Вид сетки: карточками, плитками, строками, первая крупная ───
   (Z-03, роль `gridView`)

   Состав карточки один и тот же — меняется раскладка. Так в разобранных
   шаблонах и устроено: у магазина Porto товар вообще без «хрома»
   (квадратное фото, название, цена), у блога первая статья крупная, у
   услуг — строки с фото слева. Три документа блока означали бы три
   места, где чинить одну ошибку (та же причина, что у видов корзины).

   `!important` — потому что раскладку карточки задаёт её собственный
   стиль из документа блока, а вид приходит от темы (правило U-13). */

/* Плитками: фото квадратом, никакого фона, рамок и теней — как витрина
   в Porto shop. Подпись и цена идут прямо под фотографией. */
.blk-gv-tile .w-card {
  background: transparent !important; border: 0 !important;
  box-shadow: none !important; border-radius: 0 !important;
}
.blk-gv-tile .w-card > .w-img {
  aspect-ratio: 1 / 1; height: auto !important; border-radius: var(--w-rimg);
}
.blk-gv-tile .w-card-body { padding: calc(var(--w-gap) * 0.5) 0 0 !important }
.blk-gv-tile .w-name { font-size: var(--w-body) !important }

/* Строками: фото слева, текст справа. На телефоне возвращается колонка —
   иначе фото ужимается до почтовой марки. */
/* `.w-cols` в селекторе — чтобы перебить плотность темы: у неё
   тот же `!important`, и без второго класса «строками» оставалось
   тремя колонками. */
.blk-gv-rows .w-grid, .blk-gv-rows .w-grid.w-cols {
  grid-template-columns: minmax(0, 1fr) !important;
}
.blk-gv-rows .w-card { flex-direction: row; align-items: stretch }
.blk-gv-rows .w-card > .w-img {
  width: 34%; max-width: 280px; height: auto !important; aspect-ratio: 4 / 3;
  flex: 0 0 auto;
}
.blk-gv-rows .w-card-body { flex: 1 }
@media (max-width: 640px) {
  .blk-gv-rows .w-card { flex-direction: column }
  .blk-gv-rows .w-card > .w-img { width: 100%; max-width: none }
}

/* Первая крупная: первая карточка занимает всю ширину сетки и внутри
   раскладывается строкой. Приём из блогов и кейсов — «главный
   материал», остальные обычными карточками. */
.blk-gv-big .w-grid > :first-child { grid-column: 1 / -1 }
.blk-gv-big .w-grid > :first-child .w-card { flex-direction: row; align-items: stretch }
.blk-gv-big .w-grid > :first-child .w-card > .w-img {
  width: 50%; height: auto !important; aspect-ratio: 16 / 9; flex: 0 0 auto;
}
.blk-gv-big .w-grid > :first-child .w-name { font-size: var(--w-h3) !important }
@media (max-width: 720px) {
  .blk-gv-big .w-grid > :first-child .w-card { flex-direction: column }
  .blk-gv-big .w-grid > :first-child .w-card > .w-img { width: 100% }
}

/* Текст на фото: карточка — это фотография, подпись лежит поверх неё на
   затемнении снизу. Приём с витрин одежды и кейсов, где фото и есть
   товар. Затемнение обязательно: светлый текст на светлом фото
   нечитаем, а фото клиент кладёт любое. */
.blk-gv-overlay .w-card {
  position: relative;
  border: 0 !important;
  background: var(--w-img-bg);
}
.blk-gv-overlay .w-card > .w-img {
  height: auto !important;
  aspect-ratio: 3 / 4;
  width: 100%;
}
.blk-gv-overlay .w-card-body {
  position: absolute; inset-inline: 0; bottom: 0;
  /* Тело прижато к низу фотографии, поэтому его высота задаёт положение
     цены. Любая разница в содержимом — обёрнутая старая цена, лишний
     значок — разводит цены соседних карточек по разной высоте
     (правило 22). Геометрия фиксируется: строки сетки заданы, хвост
     скрыт, цена держится в одну строку. */
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: end;
  padding: var(--w-gap) !important;
  background: linear-gradient(to top,
    color-mix(in srgb, #000 74%, transparent),
    color-mix(in srgb, #000 30%, transparent) 62%,
    transparent);
  color: #fff;
}
.blk-gv-overlay .w-card-body a,
.blk-gv-overlay .w-name,
.blk-gv-overlay .w-price,
.blk-gv-overlay .w-price b { color: #fff }
.blk-gv-overlay .w-meta, .blk-gv-overlay .w-soft {
  color: color-mix(in srgb, #fff 76%, transparent);
}
.blk-gv-overlay .w-chip {
  border-color: color-mix(in srgb, #fff 45%, transparent);
  color: #fff;
}
.blk-gv-overlay .w-meta { display: none }
.blk-gv-overlay .w-price { flex-wrap: nowrap; white-space: nowrap; overflow: hidden }

/* Плотная: фото мельче, поля уже, имя в одну строку. Нужна прайсам и
   длинным каталогам, где на экран должно влезать вдвое больше позиций.
   Имя всё равно резервирует свою высоту — ряд обязан оставаться ровным
   (правило 22). */
.blk-gv-compact .w-card > .w-img {
  height: auto !important;
  aspect-ratio: 1 / 1;
}
.blk-gv-compact .w-card-body {
  padding: calc(var(--w-gap) * 0.5) !important;
  gap: calc(var(--w-gap) * 0.25) !important;
}
.blk-gv-compact .w-name {
  font-size: var(--w-small) !important;
  -webkit-line-clamp: 1;
  min-height: 1.25em;
}
.blk-gv-compact .w-price { font-size: var(--w-small) }
.blk-gv-compact .w-chips { display: none }

/* ── Вид полосы: логотипы и галерея (роль `stripView`) ───────────
   Лента прокручивается пальцем и не растягивает страницу: прокрутка
   живёт внутри полосы (`overflow-x: auto`), а не у окна. */
.blk-sv-strip .w-grid, .blk-sv-strip .w-grid.w-cols {
  display: flex !important; overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: calc(var(--w-gap) * 0.5); scrollbar-width: thin;
  grid-template-columns: none !important;
}
.blk-sv-strip .w-grid > * {
  flex: 0 0 auto; width: min(72vw, 320px); scroll-snap-align: start;
}
/* Полоса логотипов — не сетка, а строка (`.w-strip`): лентой она
   прокручивается, а не переносится. */
.blk-sv-strip .w-strip {
  flex-wrap: nowrap; overflow-x: auto; justify-content: flex-start;
  scroll-snap-type: x mandatory;
}
.blk-sv-strip .w-strip > * { flex: 0 0 auto; scroll-snap-align: start }

/* Название партнёра вместо логотипа: пока картинку не загрузили, полоса
   доверия остаётся полосой доверия, а не рядом пустых прямоугольников. */
.w-logo-name {
  font-family: var(--w-fh); font-weight: var(--w-hw);
  font-size: var(--w-h4); color: var(--w-soft-tx);
  letter-spacing: var(--w-track); white-space: nowrap;
}
.blk-sv-mono .w-logo-name { opacity: .72 }
.blk-sv-mosaic .w-grid > :first-child { grid-column: span 2; grid-row: span 2 }
.blk-sv-mosaic .w-grid > :first-child .w-img { height: 100% !important }
@media (max-width: 640px) {
  .blk-sv-mosaic .w-grid > :first-child { grid-column: auto; grid-row: auto }
}
/* Обесцвеченные: приём для логотипов партнёров — чужие фирменные цвета
   не спорят с палитрой сайта, а под курсором показываются как есть. */
.blk-sv-mono .w-img, .blk-sv-mono img { filter: grayscale(1); opacity: .72 }
.blk-sv-mono .w-img:hover, .blk-sv-mono img:hover { filter: none; opacity: 1 }

/* Форма в строку: поле и кнопка рядом, согласие — под ними во всю
   ширину. Обычная `.w-form` — колонка (заявка с тремя полями), и в
   подписке поле сплющивалось в двадцать пикселей: `flex: 1` в колонке
   это высота, а не ширина. */
.w-form-row { flex-direction: row; flex-wrap: wrap; align-items: center;
  /* Форма стоит в строке рядом с заголовком: без этого её минимальная
     ширина считается по содержимому (поле + кнопка), и на телефоне она
     вылезала за экран на три десятка пикселей. Основа ограничена (A-145):
     иначе максимальная ширина считается по строке согласия в 900 px,
     форма забирает всю строку, а заголовок рядом рассыпается по буквам
     в столбик шириной 50 px. На телефоне строка переносится. */
  min-width: 0; max-width: min(100%, 34em) }
/* Не через flex-basis: та же форма стоит и в колонке (полоса подписки на
   акценте), где основа считалась бы по высоте — форма вырастала до 544 px. */
.w-form-row > label { flex-basis: 100% }
/* Перенесённые строки формы не разъезжаются по высоте контейнера. */
.w-form-row { align-content: flex-start; row-gap: var(--w-s2) }
.w-form-row .w-input { width: auto; flex: 1 1 10rem; min-width: 0 }
