/* Шрифты свои, рядом с сайтом. Раньше они тянулись с Google:
   витрина ходила за начертаниями наружу, а посетитель — вместе с ней.
   Для магазина в России это ещё и точка отказа, которую мы
   не контролируем.

   Путь относительный намеренно: адрес в CSS считается от самого
   файла стилей, а он лежит в корне витрины рядом с папкой fonts/.
   Так одинаково работает и с сервера, и с диска. Абсолютный «/fonts/»
   с диска указывал в корень файловой системы, и витрину нельзя было
   проверить локально — она открывалась без шрифтов. */
@font-face {
  font-family: 'Oswald';
  src: url('fonts/Oswald-Bold.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}
@font-face {
  font-family: 'Golos Text';
  src: url('fonts/GolosText-Regular.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}

/* ФалофонЪ — витрина. Направление A «Ценник».
 *
 * Бумага и чернила, прямые углы, один сигнальный цвет. Выбрано потому,
 * что конкуренты в нише все тёмно-премиальные: светлый утилитарный
 * магазин на их фоне не теряется.
 *
 * Три правила, без которых токены не работают:
 *   1. Тёмной темы нет. Тёмная версия — другой бренд, а не тот же
 *      бренд ночью.
 *   2. Красный только на цене и главной кнопке. Крупные тёмные
 *      плоскости — чернильные. Красная плашка допустима одна
 *      на страницу, в финальном призыве.
 *   3. Цена крупнее названия магазина. Буквально.
 */

:root {
  /* Поверхности */
  --bg:        #F4F2ED;
  --bg-card:   #FFFFFF;
  --bg-soft:   #F0EEE8;
  --bg-ink:    #16181C;
  --line:      #DCD8CE;
  --line-soft: #EDEAE3;

  /* Текст */
  --text:      #16181C;
  --text-dim:  #55524A;
  --text-mute: #6B675E;
  --text-on-ink:     #F4F2ED;
  --text-on-ink-dim: #A9A498;

  /* Смысловые */
  --accent:      #D62828;
  /* Цена в плитке — 14 px жирного, по бумаге #D62828 даёт 4,48:1 (норма 4,5).
     Кегль не помогает: порог 3:1 включается от 18,66 px жирного.
     Темнее только эта пара, общий акцент не тронут (задание №25, В1). */
  --accent-tile: #C41E1E;
  --accent-dark: #A81E1E;
  --accent-on:   #FFFFFF;
  --ok:          #1E7A4B;
  --warn:        #C98A16;

  /* Форма */
  --radius:    0;
  --radius-sm: 0;
  /* Скругление карточек ряда на главной — один токен на весь блок
     (задание №30, З2). Направление проекта записано выше: прямые
     углы. Apple-подача — крупные скругления. Одно с другим
     не совместимо, и это вопрос вкуса владельца, а не разработки:
     собраны обе редакции. Павел выбрал вариант Б — 18px (задание
     №31, К1, датированное решение владельца). Переключается здесь
     одним числом: 0 или 18px. */
  --radius-card: 18px;
  --gap:       16px;
  --content:   1180px;
  /* Высота шапки — переменной: от неё считают липкий столбец
     каталога и отступ якорей. Число в трёх местах разъедется. */
  --header-h:  60px;

  --font:         'Golos Text', 'Helvetica Neue', Arial, sans-serif;
  --font-display: 'Oswald', 'Arial Narrow', 'Arial', sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

/* Ссылка — чернила с подчёркиванием, а не красный.
   Красный на витрине означает ровно одно: цена и главная кнопка.
   Когда им же набраны «Как добраться», «источник» и «Все отзывы»,
   он перестаёт что-либо означать — и заодно даёт 4,48:1 по бумаге
   и 3,55:1 по чернилам, то есть ниже нормы для мелкого текста.
   Чернила дают 15,89:1. */
a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line);
}
a:hover { text-decoration-color: currentColor; }

/* Подчёркивание — у текстовых ссылок. Кнопка, пункт меню, плитка
   и карточка ссылками выглядят и без него: у них есть форма. */
.btn,
.top a,
footer .links a,
.item,
.item a,
.tile,
.model,
.chip { text-decoration: none; }
.top a:hover, footer .links a:hover { text-decoration: underline; }

/* Внутри чернильных плашек ссылка бумажная: там фон тёмный. */
footer a { color: var(--text-on-ink); }

.wrap { max-width: var(--content); margin: 0 auto; padding: 0 16px; }

/* Заголовки — Oswald заглавными. В абзаце он не читается,
   поэтому только заголовки, кнопки и цены. */
h1, h2, h3, .display {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  margin: 0 0 12px;
  line-height: 1.12;
  /* «Плёнка самовосстанавливающаяся, глянец» — двадцать три буквы
     одним словом в Oswald 30px. На экране 375 px страница семейства
     выезжала за край на 117 px (замер mobile, 14.09). Переносим
     по слогам, а где словарь не помог — рвём слово: горизонтальная
     прокрутка хуже переноса. */
  hyphens: auto;
  overflow-wrap: break-word;
}
h1 { font-size: 30px; }
h2 { font-size: 21px; margin-top: 32px; }
h3 { font-size: 16px; }
p { margin: 0 0 16px; }

.lead { color: var(--text-dim); font-size: 17px; }
.dim { color: var(--text-dim); }
.mute { color: var(--text-mute); }
.small { font-size: 14px; }
.tiny { font-size: 14px; color: var(--text-mute); }

/* Шапка и подвал — чернильные плашки */
/* Шапка липнет к верху: телефон в ней должен быть виден всегда. */
.top { background: var(--bg-ink); color: var(--text-on-ink); position: sticky; top: 0; z-index: 40; }
.top .wrap { display: flex; align-items: center; gap: 16px; height: var(--header-h); }
html { scroll-padding-top: calc(var(--header-h) + 8px); }
.brand {
  font-family: var(--font-display); font-weight: 700; font-size: 21px;
  letter-spacing: 0.04em; color: var(--text-on-ink); text-transform: uppercase;
}
.brand:hover { text-decoration: none; color: var(--text-on-ink); }
.brand b { color: var(--accent); font-weight: 700; }
.nav { display: flex; gap: 16px; margin-left: auto; overflow-x: auto; scrollbar-width: none; }
.nav::-webkit-scrollbar { display: none; }
.nav a {
  color: var(--text-on-ink-dim); font-size: 14px; white-space: nowrap;
  font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.06em;
}
.nav a:hover, .nav a[aria-current] { color: var(--text-on-ink); text-decoration: none; }

main { padding: 24px 0 40px; }

/* Карточки и плашки */
.card {
  background: var(--bg-card);
  border: 1px solid var(--line);
  padding: 16px;
}
.ink {
  background: var(--bg-ink); color: var(--text-on-ink);
  padding: 24px 16px;
}
.ink h2, .ink h3 { color: var(--text-on-ink); }
.ink .dim, .ink .small { color: var(--text-on-ink-dim); }
/* Красный на чернилах даёт 3,55:1 — ниже нормы для мелкого
   текста, и красный тут не значит ни цену, ни кнопку. */
.ink a { color: var(--text-on-ink); }

.grid { display: grid; gap: var(--gap); grid-template-columns: 1fr; }
@media (min-width: 640px) { .grid.two { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .grid.three { grid-template-columns: repeat(3, 1fr); } }

/* Кнопки. Красная — одна главная на экран. */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 16px 24px; width: 100%; text-align: center; cursor: pointer;
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: 0.06em; font-weight: 600; font-size: 15px;
  background: var(--accent); color: var(--accent-on); border: none;
}
.btn:hover { background: var(--accent-dark); color: var(--accent-on); text-decoration: none; }
.btn.ghost {
  background: transparent; color: var(--text);
  border: 1px solid var(--text); 
}
.btn.ghost:hover { background: var(--text); color: var(--bg); }
/* Призрачная кнопка на красной плашке финального призыва: чернила
   по красному дают 3,55:1 при норме 4,5 — белое по красному 5,01:1,
   и это та самая пара, что уже стоит на главной кнопке. Нашёл замер
   по отрисованному DOM: списка пар «текст на .callout» не было
   вовсе (задание №30, З7.4). */
.callout .btn.ghost { color: var(--accent-on); border-color: var(--accent-on); }
.callout .btn.ghost:hover { background: var(--accent-on); color: var(--accent); }
.btn.ink { background: var(--bg-ink); color: var(--text-on-ink); }
.btn.ink:hover { background: #000; color: var(--text-on-ink); }
@media (min-width: 640px) { .btn { width: auto; } }

/* Обещания на чернильной плашке */
.promise { display: flex; gap: 12px; padding: 8px 0; align-items: flex-start; }
/* Галочка рисуется, а не набирается символом. «✓» — это знак
   из блока дингбатов, и в направлении, где эмодзи нет по построению,
   ему не место: сторож эмодзи ловит его наравне с флагами, и это
   правильно — ослаблять сторож под один символ значит открыть
   его для следующего. */
.promise .mark {
  flex: none;
  position: relative;
  width: 20px; height: 20px;
  background: var(--accent);
}
.promise .mark::after {
  content: "";
  position: absolute;
  left: 6px; top: 4px;
  width: 5px; height: 9px;
  border: solid var(--accent-on);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.promise b { display: block; font-weight: 600; }

/* Товары */
.items { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 560px) { .items { grid-template-columns: 1fr 1fr; } }
@media (min-width: 900px) { .items { grid-template-columns: repeat(3, 1fr); } }

.item {
  background: var(--bg-card); border: 1px solid var(--line);
  display: flex; flex-direction: column;
  /* Скругление 12 px на карточках товара — как в кабинете (задание №24, Б3). */
  border-radius: 12px; overflow: hidden;
}
.item:hover { border-color: var(--text); text-decoration: none; }
.item .head { padding: 12px 12px 0; display: flex; gap: 8px; flex-wrap: wrap; }
.item .body { padding: 12px 12px 16px; display: flex; flex-direction: column; gap: 4px; flex: 1; }
.item .name {
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: 0.04em; font-weight: 600; font-size: 15px; color: var(--text);
}
/* Цена крупнее названия магазина — буквальное правило направления */
.item .price {
  font-family: var(--font-display); font-weight: 700; font-size: 27px;
  color: var(--accent-tile); line-height: 1.1; margin-top: auto;
}
.item .was {
  font-family: var(--font-display); font-size: 16px; color: var(--text-mute);
  text-decoration: line-through; margin-left: 8px; font-weight: 500;
}
.item .terms { font-size: 14px; color: var(--text-mute); }

.tag {
  display: inline-block; padding: 4px 8px; font-size: 14px;
  font-family: var(--font-display); letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--bg-ink); color: var(--text-on-ink);
}
.tag.light { background: var(--bg-soft); color: var(--text-mute); }
.tag.ok { background: transparent; color: var(--ok); border: 1px solid var(--ok); }

/* Фильтры */
.filters { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; }
.filters input[type="search"] {
  flex: 1 1 100%; min-width: 0; padding: 12px 16px; font-size: 16px;
  background: var(--bg-card); border: 1px solid var(--line);
  color: var(--text); font-family: var(--font);
}
.chip {
  padding: 8px 16px; font-size: 14px; cursor: pointer;
  font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.06em;
  background: var(--bg-card); border: 1px solid var(--line); color: var(--text-mute);
}
.chip[aria-pressed="true"] { background: var(--bg-ink); border-color: var(--bg-ink); color: var(--text-on-ink); }
.count { color: var(--text-mute); font-size: 14px; margin-bottom: 12px; }

/* Уровни фильтра. Порядок строк — порядок сужения: бренд, раздел,
   модель, симка. Он не декоративный: до появления бренда «Телефоны»
   показывали Apple вперемешку с Xiaomi, а фильтр по симке стоял
   рядом с техникой для волос.

   Подпись уровня занимает всю ширину и переносит чипы на строку ниже:
   без неё четыре ряда кнопок читаются как один длинный ряд, и человек
   не видит, что нажатие сверху сужает то, что снизу. */
.filter-row {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 8px; margin: 0 0 12px;
}
/* Без этой строки скрытый ряд остаётся на странице: `display: flex`
   в правиле выше перебивает встроенное браузерное `[hidden] {
   display: none }`, и ряд из 52 моделей занимал 1 231 px, будучи
   «скрытым». Атрибут стоял, кнопки не нажимались, высота была.
   Проверка по атрибуту этого не видит — только замер по отрисовке. */
.filter-row[hidden] { display: none; }
.filter-label {
  flex: 1 1 100%;
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: 0.08em; font-size: 14px; color: var(--text-mute);
  margin-bottom: -2px;
}
/* Число за чипом — сколько карточек за ним стоит **с учётом уже
   выбранного сверху**. Чип с нулём не гаснет, а исчезает: кнопка,
   ведущая в пустоту, хуже отсутствующей кнопки. */
.chip .n {
  margin-left: 8px; font-size: 14px; letter-spacing: 0;
  color: var(--text-mute); font-family: var(--font);
}
.chip[aria-pressed="true"] .n { color: var(--text-on-ink); opacity: .65; }
.chip.ghost {
  background: transparent; border-style: dashed; color: var(--text-mute);
}
/* Ряд моделей самый длинный из четырёх, поэтому чипы в нём мельче:
   у Apple их тридцать один, и в полный кегль они занимают экран
   целиком. Прокрутку вбок здесь не делаем — спрятанные за краем
   кнопки на витрине не находит никто. */
.filter-row[data-level="m"] .chip {
  padding: 8px 12px; font-size: 14px; letter-spacing: 0.04em;
}

/* Таблицы */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-size: 15px; }
th, td { text-align: left; padding: 12px 12px; border-bottom: 1px solid var(--line-soft); white-space: nowrap; }
th {
  color: var(--text-mute); font-weight: 500; font-size: 14px;
  font-family: var(--font-display); text-transform: uppercase; letter-spacing: 0.08em;
}
td.price { font-family: var(--font-display); font-weight: 700; color: var(--accent); font-size: 17px; }
/* Артикул под ценой — обычным шрифтом, приглушённо, не сливается с суммой. */
td.price .article { display: block; font-family: var(--font); font-weight: 400; font-size: 14px; letter-spacing: .02em; }
table.prose td, table.prose th { white-space: normal; }
table.prose td:first-child { white-space: nowrap; }

/* Заметки */
.note {
  border-left: 3px solid var(--warn); background: var(--bg-soft);
  padding: 12px 16px; margin: 16px 0;
}
.note.ok { border-left-color: var(--ok); }
.badge {
  display: inline-block; padding: 2px 8px;
  background: var(--bg-soft); border: 1px solid var(--line);
  font-size: 14px; color: var(--text-mute);
}
/* Незаполненное значение набирается приглушённым и никогда акцентом.
   Красная скобка на блоке «Где мы» была самым заметным на странице
   и читалась как акция — то есть заглушка привлекала ровно то
   внимание, которого не заслуживает. */
.stub {
  color: var(--text-mute);
  font-weight: 400;
  border-bottom: 1px dashed var(--line);
}
/* В подвале фон чернильный, и приглушённый по бумаге даёт там
   3,15:1. Замер по отрисованной странице это поймал, а список
   пар — нет: он не знал, что заглушка стоит на двух разных фонах. */
.ink .stub, footer .stub {
  color: var(--text-on-ink-dim);
  border-bottom-color: rgba(169, 164, 152, .4);
}

/* Финальный призыв — единственная красная плашка на странице */
.callout { background: var(--accent); color: var(--accent-on); padding: 24px 16px; margin: 32px 0 0; }
.callout h2 { color: var(--accent-on); margin-top: 0; }
.callout p { color: rgba(255, 255, 255, 0.92); }

footer { background: var(--bg-ink); color: var(--text-on-ink-dim); padding: 24px 0 32px; font-size: 14px; }
footer .brand { display: inline-block; margin-bottom: 12px; }
footer a { color: var(--text-on-ink-dim); }
footer a:hover { color: var(--text-on-ink); }
footer .links { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
/* Реквизиты продавца — свёрнутыми (просьба владельца 24.09.2026):
   на виду только подпись, сами реквизиты — по нажатию. */
footer details.legal { margin: 0 0 12px; }
footer details.legal summary { cursor: pointer; list-style: none; display: inline-block;
  text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }
footer details.legal summary::-webkit-details-marker { display: none; }
footer details.legal summary::marker { content: ""; }
footer details.legal summary::after { content: " ▸"; }
footer details.legal[open] summary::after { content: " ▾"; }
footer details.legal p { margin: 8px 0 0; }


/* Ролики с точек. Вертикальные, беззвучные, играют сами.
   Плеера Telegram здесь нет намеренно: он тянет чужие скрипты. */
/* Ролики на главной — сетка два на два, а не четыре в столбик.
   В столбик они занимали 2 911 px из 7 685: человек листал три
   экрана видео, чтобы дойти до отзывов. Доказательство «всё на виду»
   от этого не становилось убедительнее — оно становилось длиннее. */
.clips {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin: 16px 0;
}
.clip { margin: 0; }
/* Кадр вертикальный, потому что вертикальны сами ролики: 360×644.
   Стояла фиксированная высота 260 px с object-fit: cover — это резало
   вертикальный кадр в горизонтальную полосу и выбрасывало из него
   больше половины: у ремонта пропадали руки мастера, у витрины —
   всё, кроме середины полки. Съёмка с точки перестала быть
   доказательством «всё на виду».
   9/16 — та же доля, что у исходника (360/644 = 0,559), обрезка
   меньше процента. Высоту задаёт ширина колонки, а не число в стилях:
   при любой ширине экрана кадр остаётся кадром. */
.clip video {
  width: 100%;
  aspect-ratio: 9 / 16;
  height: auto;
  object-fit: cover;
  display: block;
  background: var(--bg-ink);
}
.clip figcaption { padding: 8px 2px 0; font-size: 14px; }
.clip figcaption .small { display: none; }

/* Блок «Где мы»: две строки на точку и ссылка справа. */
.point-line {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 12px 12px;
  margin-bottom: 8px;
  line-height: 1.35;
}
.point-line span { display: block; }
.point-line .small { font-size: 14px; }
.point-line a { flex: none; white-space: nowrap; font-size: 14px; }

/* Плитки категорий на главной — те же, что в мини-аппе.
   Сетка отзывчивая: на телефоне две колонки, на широком экране
   столько, сколько влезет. Жёстко заданные две колонки оставляли
   на 1440 px половину экрана пустой. */
.items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(165px, 1fr));
  gap: 12px;
}
.tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px;
  background: var(--card);
  border: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
}
.tile:hover { border-color: var(--accent); text-decoration: none; }
.tile-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.tile-price {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: .06em;
  text-transform: uppercase;
  /* Тот же тёмный акцент, что у цены в карточке: 14 px — это нижний
     предел витрины, и порог 3:1 для крупного здесь не включается.
     У --accent по бумаге 4,48:1 при норме 4,5. Токен --accent-tile
     заведён в №25, В1 ровно для этого, но в плитку не доехал. */
  color: var(--accent-tile);
}
.tile svg { color: var(--text); }

/* Силуэт на карточке товара — водяным знаком в углу, за текстом.
   В потоке он переносится на свою строку вместе с метками
   и добавляет карточке высоту, а карточек пятьдесят две.
   Рядом с ценой он на неё налезал: колонка узкая, свободного
   угла в ней нет. */
.item { position: relative; overflow: hidden; }
.item > svg {
  position: absolute;
  right: -8px;
  top: 50%;
  color: var(--text);
  opacity: .07;
  pointer-events: none;
}

/* Страница «Как мы работаем». Ролики целиком, со звуком, по нажатию.
   Крупнее, чем на главной: сюда пришли смотреть, а не проходили мимо.
   object-fit: contain, а не cover — обрезать то, ради чего человек
   нажал, значит выбросить главное из кадра. */
.clips-full { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.clip-full video { aspect-ratio: 9 / 16; object-fit: contain; }

/* Отзывы. Цитата — как есть, подпись со ссылкой на источник.

   Ширина строки ограничена (задание №27, В2): на 1280 px отзыв шёл
   во всю колонку — около 150 знаков в строке при норме 60–80. Глаз
   на такой длине теряет начало следующей строки, и человек бросает
   читать на третьем отзыве. Сетку страницы это не трогает: сужается
   только текст внутри карточки. */
.review blockquote {
  margin: 0 0 8px;
  font-size: 1.02rem;
  max-width: 65ch;
}
.review figcaption { color: var(--dim); }

/* «Называем после диагностики» стоит в колонке цены, но ценой
   не является: узкий Oswald красным читается как число и обещает
   то, чего в ячейке нет. */
.price .dim {
  font-family: var(--font);
  font-weight: 400;
  color: var(--text-dim);
  text-transform: none;
}


/* Три обещания услуг — в строку, а не столбиком. Подписи короткие,
   и в столбик они занимали 281 px там, где хватает ста. */
.grid.three { grid-template-columns: repeat(3, 1fr); gap: 8px; }
.grid.three .card { padding: 12px 8px; }
.grid.three .display { font-size: 14px !important; line-height: 1.2; }
.grid.three .tiny { font-size: 14px; }

/* Отзыв на главной — врезка, а не карточка в полстраницы. */
.review blockquote { margin: 0 0 8px; }

/* Финальный призыв — короче на одну строку: он последний на странице,
   и длинный текст там никто не дочитывает. */
.callout { padding: 16px 16px; }
.callout h2 { margin-top: 0; }


/* Фотография товара, если она есть. Файла нет — на её месте
   силуэт водяным знаком, и карточка выглядит намеренно,
   а не сломанно: крупное название, крупная цена, воздух. */
.item .shot {
  display: block;
  aspect-ratio: 1 / 1;
  background: var(--bg-soft);
  margin: 8px 0 4px;
  overflow: hidden;
}
.item .shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* У карточки с фотографией водяного силуэта нет: он бы просвечивал
   сквозь снимок. */
.item.with-photo > svg { display: none; }


/* Цены ремонта: линейка раскрывается, внутри модели по очереди.
   Тридцать шесть свёрнутых блоков подряд занимали две трети
   страницы — человек листал их, чтобы дойти до «Как это происходит». */
.repair-model { padding: 12px 0; border-top: 1px solid var(--line); }
.repair-model:first-child { border-top: 0; }
.repair-name {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: 14px;
  margin-bottom: 4px;
}
.repair-model table { margin: 0; }


/* ——— Витрина под аудиторию 25–35 ————————————————————————————
   Мега-меню, печатающаяся строка, промо-полоса, движение.
   Всё движение выключается одним prefers-reduced-motion внизу. */

/* Скрытый текст для читалок: дубль печатающейся строки. */
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0; padding: 0; margin: -1px;
}
.mega-toggle:focus-visible, .mega-panel a:focus-visible,
.btn:focus-visible, .chip:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* Печать второй строки заголовка. Курсор — символ, не картинка. */
.typed-wrap { display: block; }
.typed-cursor {
  display: inline-block; margin-left: 2px; font-weight: 400;
  animation: blink 1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* Появление карточек при прокрутке: не больше 12 px и 240 мс.
   Класс ставит скрипт — без него карточки видны сразу. */
.reveal { opacity: 0; transform: translateY(10px); }
.reveal.in { opacity: 1; transform: none; transition: opacity .22s ease, transform .22s ease; }
/* Ховер: подъём на 2 px и тень. Без увеличения — оно ломает сетку. */
.item, .tile { transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease; }
.item:hover, .tile:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(22, 24, 28, .12); }

/* Промо-полоса: высота задана до загрузки видео, иначе страница
   прыгает. На узком экране параллакса нет — кадр ровно по полосе. */
.promo {
  position: relative; overflow: hidden; background: var(--bg-ink);
  height: 60vh; min-height: 300px; max-height: 720px; margin: 32px 0 0;
}
.promo-video {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; background: var(--bg-ink);
}
/* Текст читается только с затемняющей подложкой: кадры и белые,
   и чёрные, и оранжевые. Плашка — сплошные чернила, то есть
   ровно та пара «текст на чернильной плашке», что в check_contrast. */
.promo-shade {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(22, 24, 28, .55), rgba(22, 24, 28, .05) 60%);
}
.promo-text { position: absolute; left: 0; right: 0; bottom: 26px; }
.promo-plate {
  display: inline-block; margin: 0; padding: 12px 16px;
  background: var(--bg-ink); color: var(--text-on-ink);
  font-family: var(--font-display); font-weight: 700; font-size: 18px;
  text-transform: uppercase; letter-spacing: .06em; line-height: 1.2;
}
@media (min-width: 900px) {
  /* Слой выше полосы на 30 %: есть чем двигаться при параллаксе. */
  .promo-video { top: -15%; height: 130%; will-change: transform; }
  .promo-plate { font-size: 24px; }
}

/* Мега-меню: рисуется только от 900 px. Пальцем не наводят —
   на узком экране остаются чипы фильтра в каталоге. */
.mega-panel { display: none; }
@media (min-width: 900px) {
  .top { position: relative; }
  .mega-panel {
    display: block; position: absolute; left: 0; right: 0; top: 100%;
    background: var(--bg-card); color: var(--text);
    border-bottom: 1px solid var(--line);
    box-shadow: 0 14px 28px rgba(22, 24, 28, .18); z-index: 30;
  }
  .mega-panel[hidden] { display: none; }
  /* Селектор с .top намеренно: правило «.top .wrap» делает обёртку
     шапки flex-строкой высотой 60 px, и панель внутри шапки
     наследовала бы ровно это — 61 px высоты и содержимое наружу. */
  .top .mega-inner {
    display: grid; grid-template-columns: 240px 1fr; height: auto;
    align-items: stretch; gap: 0;
  }
  .mega-sections { list-style: none; margin: 0; padding: 12px 0; border-right: 1px solid var(--line); }
  .mega-sections a {
    display: flex; align-items: center; gap: 12px; padding: 8px 16px;
    color: var(--text); font-family: var(--font-display); font-weight: 600;
    text-transform: uppercase; letter-spacing: .06em; font-size: 14px;
    text-decoration: none;
  }
  .mega-sections a[aria-selected="true"], .mega-sections a:hover {
    /* Тёмный акцент, а не общий: 14 px полужирного по --bg-soft
       даёт у --accent 4,32:1 при норме 4,5, у --accent-tile — 5,10:1.
       Решение №25, В1 («темнее только эта пара»), просто не доехало
       сюда: список пар в check_contrast про --bg-soft не знал, и это
       нашёл замер по отрисованному DOM (задание №30, З7.4). */
    background: var(--bg-soft); color: var(--accent-tile); text-decoration: none;
  }
  .mega-sections svg { color: var(--text); flex: none; }
  .mega-content { display: flex; flex-direction: column; }
  .mega-group {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 8px 24px; padding: 16px 24px; flex: 1;
  }
  .mega-group[hidden] { display: none; }
  .mega-col a { display: block; font-size: 14px; color: var(--text); padding: 4px 0; text-decoration: none; }
  .mega-col a:hover { color: var(--accent); text-decoration: underline; }
  .mega-col .mega-head {
    font-family: var(--font-display); font-weight: 700; font-size: 14px;
    text-transform: uppercase; letter-spacing: .06em; margin-bottom: 4px;
  }
  .mega-line {
    font-size: 14px; color: var(--text-mute); text-transform: uppercase;
    letter-spacing: .06em; margin: 8px 0 2px;
  }
  .mega-all { padding: 12px 24px 16px; border-top: 1px solid var(--line-soft); font-size: 14px; }
  /* Две ссылки внизу панели — своими блоками, с промежутком (задание №26). */
  .mega-all-one { display: inline-block; margin-right: 24px; }
}

/* Один выключатель на всё движение. Не вкусовщина: людям
   с вестибулярными нарушениями движущийся фон физически неприятен. */
@media (prefers-reduced-motion: reduce) {
  .typed-cursor { animation: none; }
  .reveal, .reveal.in { opacity: 1; transform: none; transition: none; }
  .item, .tile { transition: none; }
  .item:hover, .tile:hover { transform: none; box-shadow: none; }
  .promo-video { transform: none !important; top: 0; height: 100%; }
  /* Карточка ряда: тень остаётся — она говорит «сюда можно нажать»,
     движение снимается целиком (задание №31, К4 и К5). */
  .home-card { transition: box-shadow .14s ease; }
  .home-card:hover, .home-card:focus-visible { transform: none; }
  .card-shot img { animation: none !important; transform: none !important; }
  .cards-progress::before { animation: none !important; transform: none !important; }
}


/* ——— Правки владельца, 4 сентября ————————————————————————————— */

/* Телефон — второй основной канал: рядом с кнопкой Telegram
   как равноценный выбор, а не мелкой строкой. */
/* Пара кнопок — один компонент везде (задание №25, А5): до 480 px —
   в столбик на всю ширину, шире — в строку, основная слева. От узкого
   к широкому, как вся вёрстка. */
.two-ways { display: flex; flex-direction: column; align-items: stretch; gap: 12px; }
.two-ways .btn { margin: 0; width: 100%; }
@media (min-width: 481px) { .two-ways { flex-direction: row; flex-wrap: wrap; align-items: center; } .two-ways .btn { width: auto; } }
.btn.tel { white-space: nowrap; }
.foot-phone { margin: 0 0 12px; }
.foot-tel {
  font-family: var(--font-display); font-weight: 700; font-size: 20px;
  letter-spacing: .04em; color: var(--text-on-ink); text-decoration: none;
}
.foot-tel:hover { text-decoration: underline; }

/* «Где мы»: метро рядом с адресом читаемым размером, карта — ссылкой. */
.point-metro { font-size: 15px; color: var(--text-on-ink); }
.point-line .point-links { display: flex; flex-direction: column; gap: 8px; text-align: right; }
.point-line .point-links a { font-size: 14px; white-space: nowrap; }
.point-line .small a { color: var(--text-on-ink-dim); }
.point-address { font-size: 18px; margin-bottom: 4px; }
.point-metro-line { font-size: 16px; margin-bottom: 12px; }

/* Ролики «Как мы работаем»: четыре в ряд на десктопе, два на узком.
   Два в ряд на широком экране давали кадр 900×1600 — «очень и очень
   большие». Потолок ширины ролика держит ряд на мониторе 1600 px. */
.clips { grid-template-columns: repeat(2, minmax(0, 300px)); }
@media (min-width: 900px) { .clips { grid-template-columns: repeat(4, minmax(0, 300px)); } }

/* ——— Ряд карточек на главной ————————————————————————————————
   Задание №30, блок З. Здесь лежал чернильный блок обещаний
   с роликом фоном (`.ink.promises`, `.ink-video`, `.ink-shade`,
   `.promises-text`, `.promises .small`) и токен `--text-on-video-dim`
   к нему. Всё снято вместе с блоком: `.ink` без `.promises` живёт
   дальше — на нём стоят «Где мы» и кнопка `.btn.ink`.

   Ряд вырывается из `.wrap` на всю ширину вьюпорта (поля 16 px):
   в колонке текста пять карточек с зазором 16 px дают 217 px, и выше
   1196 px вьюпорта эта ширина не растёт — контейнер упёрся
   в `max-width`. Вырванный ряд даёт (W − 32 − 4×16) / 5: на 1280 —
   237 px, на 1440 — 269 px, на 1920 — 365 px.

   До 1280 ряд прокручивается сам, со `scroll-snap`, и край следующей
   карточки выглядывает. Прокручивается именно ряд: горизонтальной
   прокрутки страницы нет ни на одной ширине — это меряет
   `scripts/measure_row.py`. Ни скрипта карусели, ни стрелок,
   ни автолистания: без JS ряд остаётся рядом и листается пальцем
   и колесом. */
.cards-strip { margin: 24px 0 32px; }
.home-cards {
  display: grid;
  grid-auto-flow: column;
  /* Ниже порога карточка фиксированной ширины: 72vw на телефоне —
     это одна карточка и выглядывающий край следующей. */
  grid-auto-columns: clamp(224px, 72vw, 300px);
  gap: 16px;
  padding: 0 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 16px;
  overscroll-behavior-x: contain;
  /* Полоса прокрутки скрыта, но прокрутка работает: и свайп,
     и колесо. Скрыта — потому что ряд и так показывает край
     следующей карточки, а полоса под светлыми карточками
     читается как линейка в вёрстке. */
  scrollbar-width: none;
}
.home-cards::-webkit-scrollbar { width: 0; height: 0; }

.home-card {
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Карточки высокие: вертикали хватает на четыре строки текста
     и картинку. Тесно по ширине, а не по высоте. 5:9 — это 0,56,
     то есть выше, чем 3:4 на всех трёх референсах. */
  aspect-ratio: 5 / 9;
  /* Ширина задана явно, иначе `max-height` ниже ужимает не высоту,
     а ШИРИНУ: при соотношении и двух авто-размерах браузер решает
     обратную задачу и на 1920 давал карточку 311 px вместо 365
     (замерено measure_row.py). */
  width: 100%;
  /* Потолок высоты: на 1920 карточка 365 px, и без него она вырастала
     до 657 px, уводя новинки с 620 на 976 px (замер до и после).
     560 при 365 — это 0,65, всё ещё выше, чем 3:4. */
  max-height: 560px;
  padding: 16px;
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  color: inherit;
  text-decoration: none;
  overflow: hidden;
}
/* Оживание при наведении и с клавиатуры (задание №31, К4). Подъём
   на 3 px и тень, смещённая влево-вниз, — как у поднятого со стола
   листа бумаги. `:focus-visible` обязателен наравне с `:hover`:
   с клавиатуры карточка должна отзываться так же, а `outline`
   остаётся — тень его не заменяет. Переход 140 мс. */
.home-card {
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.home-card:hover, .home-card:focus-visible {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: -8px 12px 24px rgba(22, 24, 28, .10);
}
.home-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.card-head { display: flex; flex-direction: column; gap: 4px; }
/* Надзаголовок карточки — акцентом (задание №31, К2).
   ДАТИРОВАННОЕ РЕШЕНИЕ ВЛАДЕЛЬЦА 12.09.2026, перекрывающее направление.
   Направление проекта (шапка этого файла) говорит: «красный только
   на цене и главной кнопке, красная плашка допустима одна на страницу».
   Пять красных надзаголовков в ряд этому противоречат и разбавляют
   единственную красную кнопку — это сказано Павлу прямо, и правка
   сделана по его прямой просьбе после живого осмотра.
   Цвет — --accent-tile (#C41E1E), он заведён в №25 ровно для мелкого
   акцентного текста: 5,91:1 по белой карточке против 5,01:1 у общего
   красного. Вторая редакция (чернильные надзаголовки с красной
   точкой-маркером) снята рядом на снимке — если Павел передумает,
   переключается тремя строками ниже. */
.card-eyebrow {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 14px; letter-spacing: .06em; color: var(--accent-tile);
}
.card-title {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 19px; line-height: 1.15; color: var(--text);
}
.card-note { font-size: 14px; line-height: 1.35; color: var(--text-dim); }
.card-body { display: flex; flex-direction: column; gap: 12px; flex: 1 1 auto; }
.card-promise { display: flex; flex-direction: column; gap: 2px; }
.card-promise b { font-size: 14px; line-height: 1.3; color: var(--text); }

/* Оттиск знака на карточке гарантии (задание №31, К7). Стоит в пустом
   низу карточки, ПОД текстом, а не поверх: обещания читаются по белому,
   как и читались, и контраст не трогается. Плотность 0,16 и поворот
   на 8° — как у настоящей печати на талоне. Для читалки это украшение:
   `aria-hidden` стоит в разметке. */
.card-seal {
  margin-top: auto; align-self: flex-end;
  width: 88px; height: 88px; opacity: .16;
  transform: rotate(-8deg);
  pointer-events: none;
}
.card-seal img { width: 100%; height: 100%; display: block; }

/* Коробка картинки — с фиксированным соотношением, картинка вписана:
   без этого первый экран едет, пока снимок догружается. */
.card-shot {
  position: relative; flex: 1 1 auto; min-height: 0;
  display: flex; align-items: flex-end; justify-content: center;
}
.card-shot img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
/* Два рендера внахлёст — как на референсе Apple. */
.card-stack img { position: absolute; bottom: 0; max-height: 100%; }
.card-stack img:first-child { left: 4%; max-height: 92%; }
.card-stack img:last-child { right: 2%; max-height: 74%; }
/* Два телефона рядом. Половина ширины каждому: рендеры каталога —
   композиции из двух-трёх ракурсов, и без потолка второй уезжает
   под обрез карточки. */
.card-pair { gap: 8px; }
.card-pair img { max-height: 100%; max-width: calc(50% - 4px); }

/* Карточка бота: наша плашка, а не снимок кабинета и не силуэт
   чужого аппарата. Скругление своё — это изображение, а не элемент
   интерфейса витрины, и к --radius-card оно отношения не имеет. */
.bot-plate {
  align-self: center; width: 62%; max-height: 100%; aspect-ratio: 9 / 16;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  background: var(--bg-ink); border-radius: 14px;
}
.bot-plate-brand {
  font-family: var(--font-display); text-transform: uppercase;
  font-size: 18px; color: var(--text-on-ink); letter-spacing: .02em;
}
.bot-plate-line {
  font-size: 14px; line-height: 1.3; text-align: center;
  padding: 0 8px; color: var(--text-on-ink-dim);
}

/* Кнопка в карточке. Красная — одна на весь ряд, в карточке
   каталога: направление разрешает одну красную плашку на страницу. */
.card-go { margin-top: auto; align-self: flex-start; font-size: 14px; }
.btn.card-go { border-radius: var(--radius-card); }
.ghost-go {
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: .04em; color: var(--text);
  border-bottom: 2px solid var(--line); padding-bottom: 2px;
}
.home-card:hover .ghost-go { border-bottom-color: var(--accent); }

/* Полоса хода под рядом — вторая половина подсказки, что ряд тянется
   (задание №31, К3). Первая половина уже есть: край следующей карточки
   выглядывает. Стрелки-кнопки нет намеренно — это орган управления
   каруселью, а карусели у нас нет.

   Двигается САМА ПРОКРУТКА, а не скрипт: `scroll-timeline` на ряду,
   `animation-timeline` на полосе. Имя таймлайна видно полосе через
   `timeline-scope` на секции — они соседи, а не предок с потомком.
   Браузер без поддержки просто показывает полосу в начале: анимация
   заперта в `@supports`, и это не поломка. */
.cards-progress {
  height: 4px; margin: 12px 16px 0;
  background: var(--line-soft); overflow: hidden;
}
.cards-progress::before {
  content: ""; display: block; height: 100%; width: 26%;
  background: var(--text-mute);
}
@supports (animation-timeline: scroll()) {
  .cards-strip { timeline-scope: --ход-ряда; }
  .home-cards { scroll-timeline: --ход-ряда inline; }
  .cards-progress::before {
    animation: ход-ряда linear both;
    animation-timeline: --ход-ряда;
  }
  @keyframes ход-ряда {
    from { transform: translateX(0); }
    to   { transform: translateX(285%); }
  }
}

@media (min-width: 1280px) {
  /* Порог «видны все пять». Ниже — прокрутка ряда, от него — нет. */
  .home-cards { grid-auto-columns: minmax(0, 1fr); }
  .card-title { font-size: 20px; }
  /* От порога ряд не прокручивается — подсказка о прокрутке лишняя. */
  .cards-progress { display: none; }
}

/* Параллакс внутри карточки (задание №31, К5) — узко и по условиям.
   Только CSS, `animation-timeline: view()`; двигается ТОЛЬКО картинка,
   сама карточка стоит; ход 14 px (с −7 до +7); включён от 1280 px,
   где ряд не прокручивается и жест пальцем ему не мешает; браузер
   без поддержки показывает статику. Соседние блоки не двигаются
   по построению: `transform` не участвует в раскладке. */
@media (min-width: 1280px) {
  @supports (animation-timeline: view()) {
    .card-shot img {
      animation: ход-картинки linear both;
      animation-timeline: view();
      animation-range: entry 15% exit 85%;
    }
    @keyframes ход-картинки {
      from { transform: translateY(7px); }
      to   { transform: translateY(-7px); }
    }
  }
}

/* Мега-меню и столбец: списки без маркеров и отступов. Список,
   а не голые ссылки, — чтобы без стилей это был столбик ссылок. */
.mega-col ul, .side-body ul, .mega-sections { list-style: none; margin: 0; padding: 0; }

/* Страница каталога и раздел аксессуаров: столбец разделов слева,
   чипы и карточки справа.

   На узком экране столбец не исчезает, а прячется за кнопку
   (задание №41, В4). До 18.09 он был `display: none` до 900 px:
   на телефоне разделов каталога не было вовсе, оставались чипы,
   а они отвечают на другой вопрос — «сузь до моего», а не «покажи,
   что у вас есть». Кнопка сама не схлопывается: закрывает её только
   повторное нажатие. */
.side-toggle {
  display: block; width: 100%; margin: 0 0 12px; padding: 12px;
  background: var(--bg-card); border: 1px solid var(--line);
  color: var(--text); font-family: var(--font-display); font-weight: 600;
  text-transform: uppercase; letter-spacing: .06em; font-size: 14px;
  text-align: left; cursor: pointer;
}
.side-list { display: none; list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); background: var(--bg-card); }
.side.open .side-list { display: block; }
.side-item + .side-item { border-top: 1px solid var(--line-soft); }
.side-head {
  display: flex; align-items: center; gap: 12px; padding: 12px 12px;
  color: var(--text); font-family: var(--font-display); font-weight: 600;
  text-transform: uppercase; letter-spacing: .06em; font-size: 14px; text-decoration: none;
}
/* Тёмный акцент — как в мега-меню: по --bg-soft общий даёт 4,32:1. */
.side-head[aria-expanded="true"], .side-head:hover { background: var(--bg-soft); color: var(--accent-tile); text-decoration: none; }
.side-head svg { color: var(--text); flex: none; }
/* Стрелка говорит, что заголовок раскрывает, а не уводит: кликом
   по нему раздел открывается и закрывается, а «весь раздел» —
   отдельной строкой внизу тела. */
.side-arrow {
  margin-left: auto; flex: none; width: 8px; height: 8px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .15s ease;
}
.side-head[aria-expanded="true"] .side-arrow { transform: rotate(-135deg); }
.side-body { padding: 4px 12px 12px 40px; }
.side-body[hidden] { display: none; }
.side-body a { display: block; font-size: 14px; color: var(--text); padding: 4px 0; text-decoration: none; }
.side-body a:hover { color: var(--accent); text-decoration: underline; }
.side-brand { font-family: var(--font-display); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; margin-top: 8px; }
.side-line { font-size: 14px; color: var(--text-mute); text-transform: uppercase; letter-spacing: .06em; margin: 8px 0 2px; }
.side-all { color: var(--accent-tile); margin-top: 8px; }
@media (min-width: 900px) {
  .catalog-layout { display: grid; grid-template-columns: 240px 1fr; gap: 24px; align-items: start; }
  /* Столбец липнет под шапку и прокручивается сам: он длиннее экрана,
     и без своей полосы прокрутки до Samsung приходилось листать
     половину каталога. overscroll-behavior: contain — иначе прокрутка,
     дойдя до конца столбца, перескакивает на страницу. */
  .side {
    display: block; position: sticky; top: calc(var(--header-h) + 12px);
    max-height: calc(100vh - var(--header-h) - 24px);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .side-toggle { display: none; }
  .side-list { display: block; }
}

/* Страница модели: снимок и факты рядом, дальше варианты.
   Раньше это была вёрстка технической справки: заголовок, строка,
   таблица. Снимок — тот же, что на карточке; без файла — силуэт. */
.crumbs a { text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.model-hero { display: grid; grid-template-columns: 1fr; gap: 16px; margin: 8px 0 24px; }
@media (min-width: 720px) { .model-hero { grid-template-columns: minmax(240px, 420px) 1fr; gap: 32px; } }
.model-shot {
  aspect-ratio: 1 / 1; background: var(--bg-soft); border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  border-radius: 12px;
}
.model-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Колонка со снимком: сам снимок и подпись под ним. Обёртка нужна
   потому, что .model-hero — сетка из двух колонок, и подпись без неё
   уехала бы третьей ячейкой под фотографию слева (задание №33, Б2). */
.model-shot-col { display: grid; gap: 8px; align-content: start; }
/* Снимка нет — квадрат под силуэт съедает весь первый экран телефона.
   На 390 px это 358 px серого поля, и имя вещи уезжает под сгиб: замер
   first_screen 14.09 показал 525 px при потолке 500 на всех страницах
   семейств аксессуаров. Пустому боксу столько места не нужно — силуэт
   читается и в полосе. Класс `with-photo` на `.model-hero` ставился
   с №25 и до сих пор ничего не значил; вот его работа.
   Правило от узкого к широкому: узкий экран — полоса, с 720 px, где
   колонка становится боковой, возвращается квадрат. `max-width`
   здесь запрещён и ловится проверкой — вёрстка мобильная сначала. */
.model-hero:not(.with-photo) .model-shot { aspect-ratio: 5 / 2; }
@media (min-width: 720px) {
  .model-hero:not(.with-photo) .model-shot { aspect-ratio: 1 / 1; }
}
/* Тот же 525 px, что выше, — но теперь со снимком, а не с силуэтом
   (задание №44, А2). Как только у семейств появились фотографии,
   `with-photo` включился по-настоящему, квадрат вернулся, и имя вещи
   на телефоне снова уехало под потолок: замер 19.09 дал 525 px при
   потолке 500 на шестнадцати страницах.
   Здесь другое лечение, чем у пустого бокса: снимок не выбрасывается,
   а становится ниже. Кадр снят с полем 15 % вокруг предмета
   (`scripts/crop_acc.py`), и обрезка сверху и снизу до 4:3 срезает
   поле, а не товар. Карточке телефона это правило не достаётся:
   у неё пресс-рендер, своя высота и свой запас — там 496 px при том
   же потолке, и трогать её этим заданием незачем. */
.acc-hero.with-photo .model-shot { aspect-ratio: 4 / 3; }
@media (min-width: 720px) {
  .acc-hero.with-photo .model-shot { aspect-ratio: 1 / 1; }
}
.shot-note { margin: 0; }
.model-shot svg { color: var(--text); opacity: .18; }
.model-facts h1 { margin-bottom: 8px; }
.model-price {
  font-family: var(--font-display); font-weight: 700; font-size: 34px;
  letter-spacing: .04em; color: var(--accent); margin: 0 0 8px; line-height: 1.1;
}
.perks { margin-top: 16px; border-top: 1px solid var(--line); }
.perk { padding: 12px 0; border-bottom: 1px solid var(--line-soft); }
.perk b { display: block; font-weight: 600; }
.perk span { display: block; font-size: 14px; color: var(--text-dim); }

/* Страница трейд-ина: три шага. */
.steps .step { display: flex; flex-direction: column; gap: 8px; text-align: left; padding: 16px; }
.step-n {
  font-family: var(--font-display); font-weight: 700; font-size: 26px;
  color: var(--accent); line-height: 1;
}
ul.plain { margin: 0; padding-left: 16px; }
ul.plain li { margin-bottom: 8px; }


/* ——— Правки владельца, 4 сентября, вторая порция ————————————— */

/* Телефон в шапке: на узком экране — значок трубки с aria-label,
   а не обрезанный номер. */
.top-tel {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  color: var(--text-on-ink); text-decoration: none;
  font-family: var(--font-display); font-weight: 700; font-size: 15px; letter-spacing: .04em;
}
.top-tel:hover { color: var(--text-on-ink); text-decoration: underline; }
.top-tel svg { flex: none; }
.top-tel-text { display: none; }
@media (min-width: 640px) { .top-tel-text { display: inline; } }
/* Мега-меню под липкой шапкой: шапка выше по слою, панель — под ней. */
.mega-panel { z-index: 30; }

/* Карточки каталога: общая сетка по вертикали.
   Бокс под картинку одной высоты у всех — с фото и с силуэтом,
   картинка внутри по contain; строка памяти всегда занимает место;
   цена не переносится. Тогда название и цена всего ряда стоят
   на одной линии. */
.item .shot { aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; }
/* Ряд меток над картинкой — фиксированной высоты: у одних карточек
   метка «Только eSIM» есть, у других нет, и без этого картинка
   начиналась на 23 px ниже. Название — до двух строк, место под две
   зарезервировано; строка памяти — одна, с многоточием. Замер
   `scripts/measure_cards.py` держит всё это, а не глаз. */
.item .head { height: 33px; overflow: hidden; align-items: flex-start; }
.item .name {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; line-height: 1.15; min-height: 2.3em;
}
.item .tiny { height: 1.4em; min-height: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item .shot img { object-fit: contain; background: var(--bg-card); }
.item .shot.shot-empty svg { color: var(--text); opacity: .18; }
.item > svg { display: none; }
.item .price { white-space: nowrap; }

/* Плитка — не ссылка целиком (задание №41, В1). Плашки версий внутри
   неё сами ведут в карточку с выбранной конфигурацией, а ссылка внутри
   ссылки — разметка, которую браузер чинит по-своему. Нажимаемой
   остаётся вся плитка: ссылка названия растянута псевдоэлементом
   на весь бокс, плашки-ссылки лежат выше по слою. */
.item .name a { color: inherit; }
.item .name a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.item .head a.tag { position: relative; z-index: 2; }
.item .head a.tag:hover { text-decoration: underline; }
/* У модели с двумя версиями плашек две, и в колонку 171 px (пять
   карточек на 1280) они в строку не встают: «Обычная симка» — 127 px,
   «Только eSIM» — 100 px, «Wi-Fi + Cellular» — 124 px. Ряд меток
   становится двухстрочным — и сразу у ВСЕЙ сетки, иначе соседи по ряду
   разъезжаются по вертикали; держит это measure_cards.py, а не глаз.
   76 = 12 отступа сверху + две плашки по 30 с зазором 4 между строками:
   вторая плашка обязана быть видна целиком, иначе плитка снова
   рассказывает про одну версию из двух. */
.items.marks-two .item .head { height: 76px; row-gap: 4px; }

/* Красная метка «Трейд-ин» на карточке модели — тем же приёмом,
   что метки на карточках каталога. */
.tag.accent { background: var(--accent); color: var(--accent-on); }
/* Метка — строчная, а не на всю ширину: правило «.perk span { display:
   block }» иначе растягивало её в красную полосу. */
.perk .tag { display: inline-block; width: auto; margin-bottom: 4px; }

/* Заказ с доставкой на карточке модели. */
.delivery-line { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: center; margin: 12px 0 0; }
.delivery-line .btn { margin: 0; }

/* Услуги на главной: четвёртая карточка (канал Б/У) появляется
   по флагу — сетка подстраивается, а не ломается. */

/* ——— Телефон: ничего не шире экрана ——————————————————————————
   Замер `scripts/measure_mobile.py` открывает каждую страницу
   на 375 px и падает, если документ шире экрана. Правила, как
   и везде в файле, идут от узкого к широкому: сначала телефон,
   потом min-width возвращает то, чему на широком экране есть место. */

/* Страница не расползается вширь ни от чего: даже длинное слово
   или широкая таблица не уведут шапку за край. clip — не hidden:
   он не делает html прокручиваемым и не ломает липкую шапку. */
html { overflow-x: clip; }

/* Первая колонка таблиц без переносов только там, где ей есть
   место. На телефоне «Замена стекла камеры» переносится, иначе
   вся таблица — и страница с ней — шире экрана. */
table.prose td:first-child { white-space: normal; }
@media (min-width: 640px) { table.prose td:first-child { white-space: nowrap; } }

/* Таблица услуг ремонта на телефоне — не три колонки, а строки:
   работа слева, цена справа, примечание под ними на всю ширину.
   Три колонки на 343 px ставили «называем после диагностики»
   в три строки и рвали названия по слогам. */
table.services thead { display: none; }
table.services tr {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 12px;
  align-items: baseline; padding: 12px 0; border-bottom: 1px solid var(--line-soft);
}
table.services tr:last-child { border-bottom: 0; }
table.services td { display: block; padding: 0; border: 0; white-space: normal; }
table.services td.price { text-align: right; max-width: 45vw; }
table.services td.svc-note { grid-column: 1 / -1; }
/* Название работы полужирным: примечание под ним набрано тем же
   кеглем, и на телефоне строки сливались («Замена экрана» и
   «Оригинальные и совместимые модули» читались одним абзацем). */
table.services td:first-child { font-weight: 600; }
@media (min-width: 640px) {
  table.services thead { display: table-header-group; }
  table.services tr { display: table-row; padding: 0; border-bottom: 0; }
  table.services tr:last-child { border-bottom: 0; }
  table.services td {
    display: table-cell; padding: 12px 12px; border-bottom: 1px solid var(--line-soft);
  }
  table.services td.price { text-align: left; max-width: none; }
  table.services td.svc-note { grid-column: auto; }
}

/* Шаги доставки и трейд-ина: три колонки — только там, где в них
   помещаются слова. На телефоне три колонки по 100 px рвали
   «Позже — на следующий день» на пять строк; теперь шаги идут
   столбиком, с полями обычной карточки. */
.grid.three.steps { grid-template-columns: 1fr; gap: var(--gap); }
.grid.three.steps .card { padding: 16px; }
@media (min-width: 640px) { .grid.three.steps { grid-template-columns: repeat(3, 1fr); gap: 8px; } }

/* Меню на телефоне: кнопка «Меню» в шапке и список разделов
   строками под ней. Это <details>, без скрипта: закрывается
   переходом по ссылке или повторным нажатием. Прокручиваемая
   строка разделов до этого резала слова пополам («-ин Доставка»).
   Строка разделов возвращается с 900 px — вместе с мега-меню. */
.nav { display: none; }
.mnav { display: block; margin-left: auto; flex: none; }
.mnav summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center;
  gap: 8px; min-height: 44px; padding: 0 0 0 12px;
  color: var(--text-on-ink); font-family: var(--font-display);
  text-transform: uppercase; letter-spacing: .06em; font-size: 14px; font-weight: 600;
  -webkit-tap-highlight-color: transparent;
}
.mnav summary::-webkit-details-marker { display: none; }
.mnav summary::marker { content: ""; }
.mnav-list {
  position: absolute; left: 0; right: 0; top: 100%;
  display: flex; flex-direction: column;
  background: var(--bg-ink); padding: 4px 16px 16px;
  border-top: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 14px 28px rgba(22, 24, 28, .35);
}
.mnav-list a {
  display: block; padding: 12px 0; text-decoration: none;
  color: var(--text-on-ink-dim); font-family: var(--font-display);
  text-transform: uppercase; letter-spacing: .06em; font-size: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.mnav-list a[aria-current] { color: var(--text-on-ink); font-weight: 700; }
.mnav-list a.mnav-tel {
  color: var(--text-on-ink); font-weight: 700; text-transform: none;
  letter-spacing: .02em; border-bottom: 0; padding-top: 16px;
}
.mnav-list a.mnav-tel .small { color: var(--text-on-ink-dim); font-family: var(--font); font-weight: 400; }
@media (min-width: 900px) {
  .nav { display: flex; }
  .mnav { display: none; }
}

/* Отзыв — <figure>, а у него браузерные поля по 40 px с боков:
   на телефоне карточка отзыва стояла уже страницы и со сдвигом. */
figure.review { margin: 0; }


/* Лист ожидания на новинки (задание №24, блок В): блок на главной
   вторым экраном после обещаний, кнопки в бота по модели. */
.novinki { margin: 24px 0 8px; }

/* Снимок новинок и слова — одной сеткой (задание №50, блок А).
   Было: квадратная картинка 1000×1000 с прозрачными полями в 286 px
   сверху и снизу, вписанная по центру в блок, который держал свою
   высоту сам. На 1440 устройства выходили 29 % ширины контента,
   а вокруг стояло пустое поле; заголовок и кнопки при этом жались
   к левому краю. Спорили центр и левый край — и это видно глазом.

   Чинится с двух сторон сразу, потому что причин было две: поля
   вырезаны в самом файле (`scripts/novinki_shot.py`), а высоту блока
   теперь задаёт снимок, а не потолок в пикселях.

   Снимок в разметке первый — так он и читается на телефоне. На
   десктопе его переставляет `order`, а не порядок в разметке. */
.novinki-hero { display: grid; gap: 12px; }
/* Колонка снимка тянется на всю высоту строки (`stretch` — умолчание
   сетки, и здесь его не отменяют намеренно), а снимок стоит в ней
   по центру. Так «вровень с левой колонкой» становится измеримым:
   колонка выше снимка — это пустое поле, и `measure_novinki.py`
   меряет его от КОЛОНКИ. Поставь тут `align-items: center` — колонка
   схлопнется по снимку, пустое поле исчезнет из замера, и проверка
   останется зелёной на любой разнице высот. */
.novinki-photo { display: flex; align-items: center; margin: 0 0 4px; min-width: 0; }
.novinki-photo picture { display: block; width: 100%; }
.novinki-words { min-width: 0; }
.novinki-words h2 { margin-top: 0; }
/* Ширина — по колонке контента, высота — своя, по пропорциям кадра.
   Потолка в пикселях здесь нет: у `.shot-fit` он есть и держал
   высоту блока в отрыве от картинки. После обрезки кадра снимок
   до прежних 420 px и не дорастает — колонка контента шире 1148 px
   не становится, — но заводить потолок заново незачем: высоту здесь
   задаёт ширина колонки, и больше ничего. */
.novinki-shot {
  display: block; width: 100%; height: auto; border-radius: 12px;
}
@media (min-width: 1024px) {
  /* Правая колонка шире левой: у кадра пропорции 1,92:1, и при равных
     колонках снимок выходит ниже слов — то есть не вровень с ними.
     Доли подобраны замером (`measure_novinki.py`), а не на глаз. */
  .novinki-hero {
    grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
    gap: 32px;
  }
  .novinki-photo { order: 2; margin: 0; }
  .novinki-words { order: 1; align-self: center; }
  /* Кнопки «Забронировать» — в столбик. Общее правило даёт от 640 px
     три колонки, и в колонке шириной 460 px подпись «Забронировать:
     iPhone 18 Pro Max» ломается на две строки у каждой кнопки.
     Ширина здесь — колонки, а не экрана, и медиазапрос по экрану
     про неё не знает. */
  .novinki-words .wait-buttons { grid-template-columns: 1fr; }
}
.wait-buttons { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 8px 0 12px; }
@media (min-width: 640px) { .wait-buttons { grid-template-columns: repeat(3, 1fr); } }
.wait-buttons .btn { width: 100%; padding: 12px 8px; font-size: 14px; }
.wait-card h3 { margin-bottom: 4px; }
.wait-card .btn { width: 100%; }
.novinki-line { margin: -6px 0 16px; }
.import-line { font-weight: 600; }

/* ——— Селекторы конфигурации на карточке модели (задание №24, Б1) ————
   Память, цвет и симка кнопками; цена и артикул меняются на месте.
   Недоступное гасится, а не исчезает: погашенная кнопка объясняет,
   почему нельзя, исчезнувшая — заставляет гадать. */
.variants .selector { display: flex; flex-direction: column; gap: 8px; margin: 0 0 16px; }
.sel-label {
  font-family: var(--font-display); text-transform: uppercase;
  letter-spacing: .08em; font-size: 14px; color: var(--text-mute);
}
.sel-line { margin: 0 0 12px; }
.sel-line .sel-label { margin-right: 8px; }
.opts { display: flex; flex-wrap: wrap; gap: 8px; }
.opt {
  font: inherit; font-size: 14px; line-height: 1.2; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--bg-card); color: var(--text); cursor: pointer;
}
.opt.on { border-color: var(--text); box-shadow: inset 0 0 0 1px var(--text); }
.opt.off { opacity: .35; pointer-events: none; text-decoration: line-through; }
/* Задание №52, Б1–Б2: опция другой конфигурации — обычная, с мелкой
   пометкой, что поменяется; цвет не из прайса — пунктиром. */
.opt-note { display: block; font-size: 14px; color: var(--text-mute); margin-top: 2px; }
.opt-note:empty { display: none; }
.opt.missing { border-style: dashed; color: var(--text-mute); }
.sel-missing { margin: -4px 0 16px; }
.sel-missing .btn { margin-left: 8px; }
.chosen { display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px; margin: 8px 0 12px; }
.v-price {
  font-family: var(--font-display); font-weight: 700; font-size: 34px;
  letter-spacing: .04em; color: var(--accent); line-height: 1.1;
}

/* ——— Карточки новинок (задание №25, А2) и липкая полоса действия (Б1) ———— */
/* Снимок новинки не растягивается выше своего натурального размера
   и не выше потолка в пикселях: три файла вертикальные (434×707 и т. п.),
   и `width: 100%` раздувал их на десктопе до гигантских (правка Павла 10.09).
   Размеры width/height в разметке — настоящие, поэтому место под снимок
   занимается сразу и страница не прыгает.

   Потолок именно в пикселях, а не в `vh` (задание №26, А1). `60vh`
   привязывает высоту картинки к высоте окна, а не к макету: на ноутбуке
   с низким окном снимок ведёт себя не так, как на мониторе, и «больше
   половины экрана под одну картинку» остаётся на любом экране. */
.shot-fit {
  display: block; margin: 0 auto;
  max-width: 100%; width: auto; height: auto;
  max-height: 300px; object-fit: contain; border-radius: 12px;
}
@media (min-width: 720px) { .shot-fit { max-height: 420px; } }
.novinki-intro { margin: 0 0 16px; }
/* Бокс плитки — постоянного соотношения 4:3 у всех шести карточек,
   снимок внутри целиком (задание №26, А3). Исходники по пропорциям
   несопоставимы — 600×620, 1425×801, 434×707, — и бокс фиксированной
   высоты давал в сетке рваный ряд: квадратный кадр выходил вдвое
   мельче широкого. */
.wait-shot {
  display: block; margin: -16px -16px 12px; border-radius: 12px 12px 0 0;
  overflow: hidden; background: var(--bg-soft); aspect-ratio: 4 / 3;
}
.wait-shot .shot-fit { width: 100%; height: 100%; max-height: none; object-fit: contain; border-radius: 0; }
.wait-card h3 a { text-decoration: none; }
/* Первый экран карточки новинки (задание №26, А1): снимок в своей
   колонке, название и кнопка — в соседней. Сетка — общая с карточкой
   модели (`.model-hero`), второй такой не заводится (Р64); здесь только
   бокс под снимок, потому что товар нельзя подрезать, как `.model-shot`
   подрезает витринное фото по квадрату. */
.novinka-hero { margin: 0; align-self: start; }
.novinka-second { margin: 16px 0 24px; }
.swatches { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 0 0 16px; }
.swatch { display: inline-flex; align-items: center; gap: 8px; font-size: 16px; }
.swatch .dot { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--line); display: inline-block; }
.hours-status { display: inline-block; font-size: 14px; }
.hours-status.open::before, .hours-status.closed::before {
  content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 8px; vertical-align: middle;
}
.hours-status.open::before { background: var(--ok); }
.hours-status.closed::before { background: var(--text-mute); }
/* Полоса внизу экрана на мобильном: цена выбранной конфигурации слева,
   кнопка справа; появляется, когда основная кнопка ушла вверх (JS).
   На десктопе полосы нет: кнопка и так на экране. */
.sticky-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px; padding: 12px 16px;
  background: var(--bg-card); border-top: 1px solid var(--line);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, .06);
}
.sticky-cta[hidden] { display: none; }
.sticky-cta .btn { width: auto; flex: 1; padding: 12px 16px; }
.sticky-price {
  font-family: var(--font-display); font-weight: 700; font-size: 24px;
  letter-spacing: .04em; color: var(--accent); white-space: nowrap;
}
.sticky-title { font-family: var(--font-display); font-weight: 600; font-size: 14px; text-transform: uppercase; letter-spacing: .06em; }
@media (min-width: 900px) { .sticky-cta { display: none !important; } }

/* Страница, которой не хватает первого экрана: отступы над блоками
   ужаты на шаг сетки (32 → 16 у заголовков, 16 → 12 у карточек).
   Ставится обёрткой
   вокруг всего содержимого страницы, текст не трогается.
   Задание №27, В3: на /trade-in/ кнопка стояла на 805 px при экране
   800 — ровно настолько ниже сгиба, чтобы её не заметили. */
.tight h2 { margin-top: 16px; }
.tight .card { padding: 12px 16px; }
.tight .grid { gap: 12px; }
.tight .lead { margin-bottom: 12px; }

/* «Не нашли свою модель?» — строкой под поиском (задание №27, В1).
   Кнопка здесь мелкая и вторичная: главное действие каталога —
   выбрать из того, что есть, а это запасной ход для тех, кто
   не нашёл. Раньше такое предложение стояло только внизу страницы,
   на 4 435 px. */
.ask-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 16px; color: var(--text-dim);
}
.ask-line .small-btn { width: auto; padding: 8px 16px; font-size: 14px; }

/* ——— Характеристики и «О модели» (задание №25, блок Г) ——————————— */
.specs summary { list-style: none; cursor: pointer; }
.specs summary::-webkit-details-marker { display: none; }
.specs summary h2 { display: inline-block; margin-right: 8px; }
.specs summary::after { content: "▾"; font-size: 16px; color: var(--text-mute); }
.specs:not([open]) summary::after { content: "▸"; }
.specs-table th { width: 38%; color: var(--text-dim); font-weight: 500; font-family: var(--font); text-transform: none; letter-spacing: 0; font-size: 14px; vertical-align: top; }
.specs-table td { white-space: normal; }
.specs-source { margin: 12px 0 0; }
.specs-about p { margin: 0; }

/* «Варианты и цены» — сразу под снимком, в колонке рядом с ним (просьба
   Павла 10.09): заголовок компактнее, чем разделы ниже. */
.variants-title { font-size: 20px; margin: 16px 0 8px; }
.model-facts .variants { margin-bottom: 8px; }
