/* ==========================================================================
   Witto — site.css
   Правило файла: каждый компонент повторяет свой аналог из приложения.
   Ссылки на исходник стоят над компонентом.
   ========================================================================== */

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, p, ul, ol, figure, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }

/* ---------- база ----------
   SF Rounded во всём: приложение не использует ни одного не-rounded стиля
   в продуктовой типографике (Theme.Typography, все шесть — design: .rounded). */
body {
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: 1.35;              /* плотность абзаца как на экране телефона */
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* Видимый фокус с клавиатуры — обязателен, системного контура нам мало
   на янтарной заливке. */
:focus-visible {
  outline: 3px solid var(--text-on-color);
  outline-offset: 3px;
  border-radius: 4px;
}
a:focus-visible, .btn:focus-visible { outline-color: var(--text); }

.site-head__link { color: var(--text-muted); text-decoration: none; }
.site-head__link:hover { color: var(--text); text-decoration: underline; }

.skip-link {
  position: absolute; left: var(--sp-l); top: -100px;
  background: var(--surface); color: var(--text);
  padding: var(--sp-m) var(--sp-l); border-radius: var(--r-button);
  font-weight: var(--fw-bold); z-index: 10;
}
.skip-link:focus { top: var(--sp-l); }

/* ---------- сетка страницы ----------
   Поля 16px — ровно как поля экрана в приложении
   (OnboardingComponents.swift:67, замер на скриншоте: 48px @3x). */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.section { padding-block: 40px; }
.section--tight { padding-block: var(--sp-xxl); }

/* Ритм между блоками внутри секции держится на 16 и 12 —
   двух самых частых отступах приложения. */
.stack-l > * + * { margin-top: var(--sp-l); }
.stack-m > * + * { margin-top: var(--sp-m); }
.stack-s > * + * { margin-top: var(--sp-s); }

/* Отступ от блока до блока внутри секции. Ставится классом в разметке, а не
   правилом на тег: в одной секции между заголовком и контентом воздуха нужно
   больше, чем между двумя абзацами. */
.mt-m   { margin-top: var(--sp-m); }
.mt-l   { margin-top: var(--sp-l); }
.mt-xl  { margin-top: var(--sp-xl); }
.mt-xxl { margin-top: clamp(28px, 3vw, 44px); }

/* ---------- типографика ---------- */
.display {
  font-size: var(--fs-display);
  font-weight: var(--fw-heavy);
  line-height: 1.08;
  letter-spacing: -0.4px;
}
.h-screen {
  font-size: var(--fs-screen);
  font-weight: var(--fw-heavy);
  line-height: 1.12;
  letter-spacing: -0.3px;
}
.h-title    { font-size: var(--fs-title);    font-weight: var(--fw-bold); line-height: 1.18; }
.h-headline { font-size: var(--fs-headline); font-weight: var(--fw-bold); line-height: 1.25; }
.body       { font-size: var(--fs-body);     font-weight: var(--fw-medium); }
.caption    { font-size: var(--fs-caption);  font-weight: var(--fw-semibold); }
.muted      { color: var(--text-muted); }
.measure    { max-width: var(--measure); }

/* Надстрочная строка карточки модуля: «MODULE 1 · FOCUS».
   Источник: MapView.swift:645-648 — caption + .kerning(0.5) + uppercase. */
.eyebrow {
  font-size: var(--fs-caption);
  font-weight: var(--fw-heavy);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Диапазон возраста мозга: очень крупно, янтарём, с en-dash.
   Источник: OnboardingRevealScreen.swift:33-36 (56pt heavy, Colors.primary). */
.range {
  font-size: var(--fs-range);
  font-weight: var(--fw-heavy);
  color: var(--primary);
  line-height: 1;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
}

/* ---------- КНОПКА НА ОБЪЁМЕ ----------
   Главный узнаваемый элемент. Источник: DepthActionButton.swift.
   Грань лежит на СПЛОШНОЙ подложке глубиной 6px (не тень, не блюр:
   box-shadow с нулевым размытием), при нажатии грань съезжает вниз
   ровно на глубину, а подложка схлопывается — габарит не меняется. */
.btn {
  display: inline-flex;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  align-items: center;
  justify-content: center;
  gap: var(--sp-s);
  min-height: var(--btn-height);
  width: 100%;
  /* DepthActionButton.swift:36-37; вертикаль разведена на 0.0275em —
     см. «оптическая центровка» ниже. */
  padding: calc(var(--sp-l) + 0.03em) var(--sp-m) calc(var(--sp-l) - 0.03em);
  border: 0;
  border-radius: var(--r-button);
  background: var(--primary);
  color: var(--text-on-color);
  font-family: inherit;
  font-size: var(--fs-headline);      /* Theme.Typography.headline() */
  font-weight: var(--fw-bold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 var(--depth-button) 0 var(--primary-deep);
  transform: translateY(0);
  transition: transform var(--dur-press-up) var(--ease-up),
              box-shadow var(--dur-press-up) var(--ease-up);
}
.btn:active {
  transform: translateY(var(--depth-button));
  box-shadow: 0 0 0 var(--primary-deep);
  transition-duration: var(--dur-press-down);
  transition-timing-function: var(--ease-down);
}
/* Вторичная кнопка: та же механика, серая грань.
   Источник: DepthActionButton.secondary (строки 193-197). */
.btn--secondary {
  background: var(--surface-alt);
  color: var(--text);
  box-shadow: 0 var(--depth-button) 0 var(--surface-alt-deep);
}
.btn--secondary:active { box-shadow: 0 0 0 var(--surface-alt-deep); }

/* Кнопка без адреса: место оставлено, но нажимать нечего.
   Соответствует .disabled(true) + .opacity(0.5) в приложении
   (OnboardingComponents.swift:62-63). */
/* Кнопка без адреса. Разметка — <span>, а не <a>: ссылки, которая никуда не
   ведёт, в документе быть не должно. Цвет при этом полный — заливка #EF9F27,
   грань #BA7517, подпись #412402 (решение владельца): кнопка выглядит
   обычной, а то, что ссылки пока нет, говорит подпись «выходит скоро» под
   ней. Контраст подписи на заливке 6.54:1. */
.btn[aria-disabled="true"] {
  /* Ссылки пока нет, но кнопка живая: под пальцем объём выдавливается, как в
     приложении. pointer-events: none тут был лишним — он глушил и :active. */
  cursor: pointer;
}
.btn-note {
  margin-top: var(--sp-m);
  text-align: center;
  color: var(--text-muted);
}

/* ---------- КАРТОЧКА ----------
   Источник: Card.swift. Ни кромки, ни тени — секцию отделяет
   от фона одна только светлота поверхности. */
.card {
  background: var(--surface);
  border-radius: var(--r-card);
  padding: var(--sp-l);
}
.card--section { border-radius: var(--r-section); padding: var(--sp-xl) var(--sp-l); }
.card--panel   { border-radius: var(--r-panel); }
.card--flat    { background: var(--surface-alt); }

/* ---------- ПОЛОСА-«СТАКАН» (FluidBar) ----------
   Источник: FluidBar.swift + FluidMetrics.
   Трек — капсула; заливка вставлена внутрь с отступом 14% высоты СО ВСЕХ
   сторон (поэтому трек виден и сверху, и снизу); поверх заливки блик —
   белая капсула 22% прозрачности у верхней кромки. */
.bar {
  position: relative;
  height: var(--bar-h);
  border-radius: var(--r-pill);
  background: var(--bar-track);
  padding: calc(var(--bar-h) * var(--bar-inset));
  overflow: hidden;
}
.bar__fill {
  position: relative;
  height: 100%;
  min-width: calc(var(--bar-h) * (1 - 2 * var(--bar-inset)));
  border-radius: var(--r-pill);
  background: var(--bar-color, var(--primary));
}
.bar__fill::after {                 /* блик: 18% толщины, отступ 22% сверху */
  content: "";
  position: absolute;
  left: 12%; right: 12%;
  top: 22%;
  height: 18%;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, var(--bar-gloss-a));
}

/* ---------- ЧИП / КАПСУЛА ----------
   Капсулы шапки приложения: pill, светлая заливка, тёмное число.
   Источник: HeaderComponents.swift:171-173 + glassCapsule. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-s);
  padding: var(--sp-s) var(--sp-m);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  color: var(--text);
}
.chip__num { font-size: var(--fs-headline); font-weight: var(--fw-heavy); }

/* ==========================================================================
   ШАПКА САЙТА
   ========================================================================== */
.site-head { padding-block: var(--sp-m); }

/* Липкая шапка. В самом верху страницы фона нет вовсе — полотно под ней то же.
   Стоит странице сдвинуться, добавляется класс is-scrolled: полупрозрачная
   подложка и размытие, чтобы контент проезжал под шапкой читаемо, но не
   перекрывался глухой плашкой. Класс ставит assets/site.js. */
.site-head--sticky {
  position: sticky;
  top: 0;
  z-index: 30;
  background: transparent;
  transition: background-color var(--dur-press-up) linear;
}
.site-head--sticky.is-scrolled {
  /* Тот же тон, что фон страницы, но прозрачный — размытие должно быть видно. */
  background: rgba(233, 225, 214, 0.72);
  -webkit-backdrop-filter: blur(16px) saturate(1.15);
          backdrop-filter: blur(16px) saturate(1.15);
}
/* Размытия нет (старый Firefox, отключено настройкой) — подложка становится
   непрозрачной, иначе текст поедет по тексту. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-head--sticky.is-scrolled { background: var(--bg); }
}

/* Три колонки: слева маскот и язык, по центру вордмарк, справа кнопка.
   Крайние колонки равны, поэтому вордмарк стоит по центру СТРАНИЦЫ,
   а не по центру остатка. */
.site-head__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-l);
}
.site-head__side {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  min-width: 0;
}
.site-head__side--end { justify-content: flex-end; }
.site-head__mark { display: flex; flex: 0 0 auto; }
.site-head__face { width: 40px; height: 40px; }

.site-head__logo { display: flex; justify-self: center; }
/* На лендинге вордмарк уже стоит в герое, поэтому в шапке он ждёт, пока
   первый экран уедет наверх, и только тогда проявляется. */
.site-head__logo--reveal {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--dur-press-up) var(--ease-up),
              transform var(--dur-press-up) var(--ease-up),
              visibility 0s linear var(--dur-press-up);
}
.site-head.is-past-hero .site-head__logo--reveal {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

/* Вордмарк — logo.svg, красится в текстовый цвет через маску, как
   .renderingMode(.template) в SplashView.swift:145-149.
   Показан меньше натуральных 104×33: рядом капсула языка 33.5 и кнопка 36,
   и в полный рост он перевешивал обе. Пропорция сохранена (104/33 = 3.152). */
.wordmark {
  display: block;
  width: 82px; height: 26px;
  background: var(--text);
  -webkit-mask: url("../assets/brand/witto-wordmark.svg?v=ea829fc5") no-repeat center / contain;
          mask: url("../assets/brand/witto-wordmark.svg?v=ea829fc5") no-repeat center / contain;
}
.wordmark--amber { background: var(--primary); }

/* На узком экране в строку помещаются маскот, переключатель языка и вордмарк
   по центру — он проявляется, когда первый экран уезжает наверх, ровно как на
   десктопе. Кнопка справа скрыта: она дублирует кнопку героя и втроём с
   переключателем в 390 px не встаёт. Ссылка на поддержку живёт в подвале. */
@media (max-width: 767px) {
  /* Вордмарка по центру на телефоне нет вовсе: строка узкая, а слева уже
     стоят маскот с языком, справа — кнопка. */
  .site-head__logo { display: none; }
  .site-head__row { grid-template-columns: 1fr auto; gap: var(--sp-s); }
  .site-head__side { gap: var(--sp-s); }
  .site-head__face { width: 36px; height: 36px; }
  /* Подложка стоит всегда, а не только по классу от скрипта: без неё шапка
     на телефоне сливалась с полотном и «пропадала» при прокрутке. */
  .site-head--sticky {
    background: rgba(233, 225, 214, 0.72);
    -webkit-backdrop-filter: blur(16px) saturate(1.15);
            backdrop-filter: blur(16px) saturate(1.15);
  }
  /* Список языков раскрывается ВПРАВО от капсулы: она стоит у левого края,
     и список, привязанный к её правой кромке, уезжал за экран. */
  .langs__list { right: auto; left: 0; min-width: 0; width: max-content; max-width: 78vw; }
}

/* Компактная кнопка шапки. */
/* ОПТИЧЕСКАЯ ЦЕНТРОВКА подписи в цветной плашке.
   Замер: от верха плашки до верха прописной было на 0.6–1.3 px меньше, чем
   от базовой линии до низа, — подпись «висела», снизу воздуха больше.
   Причина в метриках Nunito (ascent 1.011em / descent 0.353em) и в том, что
   браузер округляет их до целых пикселей. Сдвиг 0.03em вниз выравнивает все
   три плашки в пределах ±0.25 px. Сумма паддингов не меняется — высота та же. */
.btn--sm {
  min-height: 36px;
  width: auto;
  padding: calc(var(--sp-s) + 0.03em) var(--sp-l) calc(var(--sp-s) - 0.03em);
  font-size: var(--fs-caption);
  box-shadow: 0 4px 0 var(--primary-deep);
  min-width: 0;                       /* в шапке кнопка компактная, а не на 280px */
}
/* Грань у мелкой кнопки 4px, значит и вдавливается она на 4px. */
.btn--sm:active { transform: translateY(4px); box-shadow: 0 0 0 var(--primary-deep); }

/* ==========================================================================
   ПЕРЕКЛЮЧАТЕЛЬ ЯЗЫКА
   Капсула, как капсулы шапки приложения (HeaderComponents.swift:171-173):
   pill, светлая заливка, тёмный текст. Раскрывается на <details> — без
   единой строчки JS, с нативной клавиатурой (Enter/Space на summary).
   ========================================================================== */
.langs { position: relative; }
.langs > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-s);
  /* вертикаль разведена на 0.03em — см. «оптическая центровка» выше */
  padding: calc(var(--sp-s) + 0.03em) var(--sp-m) calc(var(--sp-s) - 0.03em);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  color: var(--text-on-color);        /* #412402 — как подпись кнопки */
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}
.langs > summary::-webkit-details-marker { display: none; }
.langs > summary::after {                 /* та же «галка», что у FAQ */
  content: "";
  width: 7px; height: 7px;
  border-right: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
  border-radius: 1px;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-press-up) var(--ease-up);
}
.langs[open] > summary::after { transform: translateY(1px) rotate(225deg); }

.langs__list {
  position: absolute;
  right: 0;
  top: calc(100% + var(--sp-s));
  z-index: 20;
  min-width: 200px;
  padding: var(--sp-s);
  border-radius: var(--r-card);
  background: var(--surface);
  /* Единственная тень на сайте: список ВСПЛЫВАЕТ над контентом, и без
     отделения он читается как часть страницы под ним. Мягкая и короткая —
     ближе всего к тени стеклянной капсулы (GlassNav.swift:154). */
  box-shadow: 0 6px 24px rgba(42, 32, 21, 0.16);
}
.langs__list a {
  display: block;
  padding: var(--sp-s) var(--sp-m);
  border-radius: var(--r-chip);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--text);
  text-decoration: none;
}
.langs__list a:hover { background: var(--surface-alt); }
.langs__list a[aria-current="true"] {
  background: var(--primary);
  color: var(--text-on-color);
  font-weight: var(--fw-bold);
}

/* ==========================================================================
   ГЕРОЙ — повторяет экран хука онбординга (HookScreen)
   Источник: OnboardingSimpleScreens.swift:44-86.
   Порядок сверху вниз: вордмарк по центру → заголовок → подзаголовок →
   маскот, стоящий кроссовками НА ВЕРХНЕЙ ГРАНИ кнопки → кнопка.
   Наезд маскота на кнопку: .padding(.bottom, -30) в приложении.
   ========================================================================== */
/* Первый экран занимает окно целиком на любой ширине: на невысоком мониторе
   иначе сверху оставался лишний воздух, а низ сцены уходил за край.
   100svh — «маленькая» высота вьюпорта: на мобильных она не скачет от
   появления и исчезновения адресной строки. */
/* На телефоне первый экран НЕ растянут на всё окно: высоту задаёт сама
   сцена, и следующий блок начинается сразу за ней, а не через пустоту.
   Окно целиком экран занимает только на десктопе (см. адаптив), где сцена
   широкая и низкая. 100svh — «маленькая» высота вьюпорта: она не скачет от
   появления и исчезновения адресной строки. */
.hero {
  display: grid;
  align-content: center;
  /* Снизу воздуха больше, чем сверху: под сценой сразу начинается плита
     второго блока, и с прежними 24 px камни почти упирались в неё. */
  padding-block: var(--sp-m) clamp(36px, 12vw, 56px);
  text-align: center;
}
.hero__soon {
  margin-top: var(--sp-m);
  text-align: center;
  font-weight: var(--fw-bold);
  /* Не --primary-deep: на фоне #E9E1D6 он даёт 2.87:1. --text-on-color —
     тот же тёплый коричневый приложения, 10.96:1. */
  color: var(--text-on-color);
}
.hero__req { margin-top: var(--sp-xs); text-align: center; }
/* Серый текст под заголовком: мера шире общей (640 → 720), но только на
   широком экране. Число из замера по девяти языкам: самая длинная подпись
   (немецкая у «возраста мозга») требует ровно 660 px, чтобы уложиться
   в две строки, а общие 640 давали ей третью. */
.measure-c { max-width: var(--measure); margin-inline: auto; }
@media (min-width: 768px) { .measure-c { max-width: 720px; } }
.center { text-align: center; }
.hero__sub { margin-top: var(--sp-l); color: var(--text-muted); }

/* --------------------------------------------------------------------------
   СЦЕНА ГЕРОЯ
   Мобильный порядок — обычный поток: вордмарк, строка, кнопка. Декор и
   маскоты выключены: на 390px они наложились бы на текст.
   Десктоп (см. адаптив) — сцена с фиксированной пропорцией, всё внутри
   позиционировано в процентах, поэтому композиция масштабируется целиком.
   -------------------------------------------------------------------------- */
.hero__stage { position: relative; }
.hero__title { margin: 0; }
.hero__logo {
  display: block;
  width: 100%;
  max-width: 640px;
  height: auto;
  margin-inline: auto;
}
.hero__claim {
  display: block;
  margin-top: var(--sp-l);
  font-size: var(--fs-title);
  font-weight: var(--fw-bold);
  line-height: 1.2;
}
.hero__act { margin-top: var(--sp-l); }
/* Вне сцены (печать, очень старый браузер без aspect-ratio) декор и два
   маскота из трёх скрыты: они наложились бы на текст. */
.hero__deco { display: none; }
.hero__mascot { display: none; }


/* Сцена на телефоне. Пропорция вертикальная: 662×980 — коробка макета.
   Внутри всё в процентах от неё, поэтому композиция целиком тянется от 320
   до 767 px и нигде не разъезжается. Всё правило ЦЕЛИКОМ в медиазапросе:
   в общем слое эти строки перебивали десктопную сцену — лого уезжало, а
   строка садилась под кнопку. */
@media (max-width: 767px) {
  .hero__stage {
    aspect-ratio: 662 / 980;
    width: 100%;
    margin-inline: auto;
  }
  .hero__deco,
  .hero__mascot { display: block; position: absolute; }
  .hero__deco { height: auto; }
  .hero__deco--back  { z-index: 0; }
  .hero__title       { z-index: 1; }
  .hero__mascot      { z-index: 2; }
  .hero__deco--front { z-index: 3; }
  /* Заголовок растянут на всю сцену, а лого и строка под ним позиционируются
     от НЕЁ: если оставить коробку заголовка по размеру лого, проценты у
     строки считались бы от её собственной высоты и строка села бы на буквы. */
  .hero__title { position: absolute; inset: 0; }
  /* Ширина задана явно: у абсолютно позиционированной картинки width:auto
     берёт СВОЙ размер (1096 px), а не расстояние между left и right. */
  .hero__logo {
    position: absolute;
    left: 5%; top: 23%;
    width: 90%;
    max-width: none;
    height: auto;
  }
  .hero__claim {
    position: absolute;
    left: 0; right: 0; top: 57%;
    margin: 0;
    font-size: clamp(19px, 5.2vw, 26px);
  }
  .hero__act { position: absolute; left: 0; right: 0; top: 70%; margin: 0; z-index: 1; }
  /* Кнопка по содержимому, а не во всю ширину: поля вокруг подписи такие же,
     как у кнопки в шапке. */
  .hero__act .btn { width: auto; min-width: 0; padding-inline: var(--sp-xxl); }
}


/* Плеер рисует svg внутрь контейнера. Контейнер — сам кадр Lottie
   (1254×1254, квадрат с полями вокруг фигуры); статичный SVG под ним ужат в
   --still = 1/lottieScale и центрирован, чтобы до загрузки плеера и при
   «меньше движения» фигура стояла на том же месте. Множитель — из
   MapBiomes.json карты приложения. */
.hero__mascot { aspect-ratio: 1; }          /* сторона кадра Lottie */
.hero__mascot > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero__mascot > img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--still, 1) * 100%);     /* фигура без полей кадра */
  height: auto;
  transform: translate(-50%, -50%);
}
.hero__mascot.is-live > img { visibility: hidden; }

/* ==========================================================================
   ПРОБЛЕМА — повторяет экран чек-листа симптомов (ChecklistScreen)
   Плашки-строки на surface-alt, сгруппированные заголовками категорий.
   ========================================================================== */
.symptoms { display: grid; gap: var(--sp-xl); }
.symptom-group__title { margin-bottom: var(--sp-m); }
.symptom-list { display: grid; gap: var(--sp-s); }
.symptom {
  padding: var(--sp-m) var(--sp-l);
  border-radius: var(--r-chip);
  background: var(--surface);
  font-size: var(--fs-body);
}
.problem__figure { margin-top: var(--sp-l); text-align: center; }
.problem__mascot { width: 168px; height: 168px; margin-inline: auto; }

/* ==========================================================================
   КАК ЭТО РАБОТАЕТ — три шага
   Кружок с номером повторяет кружок стадии таймлайна пейволла:
   сплошной круг 40×40 с тёмным штрихом (PaywallView.swift:169-172).
   ========================================================================== */
.steps { display: grid; gap: var(--sp-m); }
.step { display: flex; gap: var(--sp-m); align-items: flex-start; }
.step__num {
  flex: 0 0 40px;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--text-on-color);
  font-size: var(--fs-headline);
  font-weight: var(--fw-heavy);
  display: grid; place-items: center;
}
.step__num--coral { background: var(--accent); }   /* последняя стадия — коралл */
.step__body { padding-top: 6px; }
.step__body p { margin-top: 3px; }                 /* PaywallView.swift:179 spacing: 3 */
.disclaimer {
  margin-top: var(--sp-xl);
  text-align: center;
  color: var(--text-muted);
  opacity: 0.8;                                    /* OnboardingRevealScreen.swift:21 */
}

/* Демонстрация результата: тот же приём, что на экране reveal —
   заголовок 30px над очень крупным янтарным диапазоном. */
.result-demo { text-align: left; }
.result-demo__title { font-size: 30px; font-weight: var(--fw-bold); }
.result-demo__range { margin-top: 2px; }           /* spacing: 2 в исходнике */

/* ==========================================================================
   ПЯТЬ ЗОН — карточки-обложки
   Обложка нарисована дизайнером под 390×240 и 592×240 и вставлена картинкой,
   поэтому карточка держит её пропорцию сама. Ряды сходятся по ширине и по
   высоте: 3·390 + 2g = 2·592 + g при зазоре g = 14/1198 ширины контейнера,
   а высота у всех обложек одна — 240.
   Маскот кладётся поверх обложки: на карте в приложении он живой, и здесь
   тоже. Кадр Lottie квадратный с полями вокруг фигуры, статичный SVG под ним
   ужат в --still = 1/lottieScale — тот же приём, что у героя.
   ========================================================================== */
/* Зазор между карточками в ряду и между рядами один и тот же: у колонок он
   задан процентом ширины, а между рядами — margin-top тем же процентом
   (процентный вертикальный отступ тоже считается от ШИРИНЫ контейнера,
   поэтому в пикселях выходит ровно столько же). Процентный row-gap так бы не
   сработал: он считается от высоты, а она у сетки автоматическая. */
.zones { display: grid; }
/* Пока карточки идут в столбик, столбик не растягивается на всю страницу:
   на планшете 900 px карточка выходила 782×415 — подпись в углу и пустая
   середина. 480 px — верхняя граница, за которой карточка перестаёт быть
   карточкой. На телефоне ограничение не работает: там ширина и так меньше. */
@media (max-width: 1099px) {
  .zones { max-width: 480px; margin-inline: auto; }
}
/* Три колонки включаются НЕ на 768, а когда карточка дорастает до проектных
   390 px. На планшете 800 px три в ряд давали карточку 230 px: подпись
   в длинных языках занимала там четыре строки и ложилась прямо на арт.
   До 1100 px карточки идут в столбик — по одной, в полную ширину. */
.zones__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-m);
  list-style: none;
  margin: 0;
  padding: 0;
}
.zones__row + .zones__row { margin-top: var(--sp-m); }

/* Зазор между карточками в ряду и между рядами один и тот же: у колонок он
   задан процентом ширины, а между рядами — margin-top тем же процентом
   (процентный вертикальный отступ тоже считается от ШИРИНЫ контейнера,
   поэтому в пикселях выходит ровно столько же). Процентный row-gap так бы не
   сработал: он считается от высоты, а она у сетки автоматическая. */
@media (min-width: 1100px) {
  /* Поля плиты по бокам (32) меньше нижнего (56), и ряд карточек стоял
     к краям ближе, чем к низу. Разницу добираем полем самого ряда, а не
     полем плиты: заголовок с подписью центрованы и от этого не зависят. */
  .zones { margin-inline: calc(var(--slab-pad-y) - var(--slab-pad-x)); }
  .zones__row--3 { grid-template-columns: repeat(3, 1fr); }
  .zones__row--2 { grid-template-columns: repeat(2, 1fr); }
  .zones__row { gap: 1.1686%; }
  .zones__row + .zones__row { margin-top: 1.1686%; }
}

/* Карточка обрезает всё, что вылезло за её край: маскот стоит у правой
   кромки и без этого свешивался бы на фон секции. Фон — CSS-градиент
   (наклон и цвета в build.py::ZONES), поверх него объект биома и маскот
   отдельными слоями: положение задаётся числами, а не запечено в картинку.
   База — УЗКАЯ карточка: пропорция взята из исходника Фигмы (358×190),
   она заметно ниже прежней 390×240, скругление крупнее, а объект с маскотом
   опущены ниже — подпись на узкой карточке занимает верхнюю половину. */
.zone {
  position: relative;
  min-width: 0;
  /* Ширина задана явно, иначе aspect-ratio выводит её из ВЫСОТЫ, а высоту
     держит min-height: на окне 360 карточка раздувалась до 358 и страница
     уезжала вбок на 14 px. С width: 100% ширину диктует колонка, а
     min-height поднимает только высоту. */
  width: 100%;
  overflow: hidden;
  /* Карточка — контейнер запроса: кегль подписи считается от ЕЁ ширины,
     а не от ширины окна. Ширина карточки меняется тремя способами (столбик,
     ряд по три, ряд по два), и привязка к окну для каждого из них давала бы
     своё правило. */
  container-type: inline-size;
  border-radius: 40px;
  aspect-ratio: 358 / 174;
  /* Нижний предел высоты. Маскот тянется за ШИРИНОЙ карточки, а подпись
     сверху от ширины не зависит: на экранах уже 390 px пропорция давала
     карточку, в которой голова маскота поднималась на строку подписи.
     174 — высота под фигуру, уменьшенную против натуральной на 12.6%:
     коробка подписи кончается на 66.4, буквы на 64.4, а краска маскота
     начинается на 66.6 у самой тесной из пяти («Память»). */
  min-height: 174px;
}

/* Объект биома стоит в левом нижнем углу. Размер задан ВЫСОТОЙ в процентах
   от высоты карточки: у обоих рядов десктопа высота одна, поэтому объекты
   во всех пяти карточках одного масштаба, а на узкой уменьшаются вместе
   с ней. Экспорт из Фигмы обрезан по краске, поэтому одного отступа хватает
   на все пять — подгонять каждую не нужно. Левое поле то же, что у подписи:
   объект встаёт ровно под заголовком. */
.zone__deco {
  position: absolute;
  left: 24px;
  /* 14 px от низа карточки высотой 174. Раньше стояло 2% — это 3.6 px,
     объект почти лежал на кромке. */
  bottom: 8.05%;
  width: auto;
  max-width: 62%;
}

@media (min-width: 1100px) {
  .zone { border-radius: 32px; aspect-ratio: 390 / 240; }
  /* Поле объекта слева: база задаёт телефонные 24 px, здесь возвращается
     прежний clamp. Подпись переопределяется НИЖЕ, после своего базового
     правила: оно идёт в файле после этого медиазапроса и перебило бы его. */
  .zone__deco { left: clamp(22px, 1.6vw, 24px); }
  .zone__cap { margin-top: 4px; }
  /* Второй ряд шире, но той же высоты: 3·390 + 2g = 2·592 + g. */
  .zones__row--2 .zone { aspect-ratio: 592 / 240; }
  .zone__deco { bottom: 8%; }
}

/* Поля подписи считаются в пикселях, а не в процентах: проценты сверху и
   слева берутся от разных сторон карточки, и в широком ряду поле слева
   выходило вдвое больше, чем сверху. */
.zone__label {
  position: absolute;
  left: 24px;
  /* Поле сверху меньше бокового: высоту узкой карточки задаёт подпись плюс
     маскот, и каждый пиксель сверху — это пиксель её высоты. На широкой
     карточке поля снова равны (см. медиазапрос ниже). */
  top: 18px;
  /* Подпись занимает всю ширину карточки: на маскота она не наезжает,
     потому что стоит ОДНОЙ строкой (см. .zone__cap) и заканчивается выше,
     чем начинается его краска. */
  right: 24px;
  color: #fff;
}
.zone__name {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: var(--fw-bold);
  line-height: 1.1;
}
.zone__cap {
  /* На узкой карточке зазор до подписи меньше: её высоту задаёт текст сверху
     плюс маскот, и два пикселя здесь — два пикселя высоты карточки. */
  margin-top: 2px;
  /* Никогда не переносится: вторая строка легла бы маскоту на голову.
     Чтобы строка помещалась на ЛЮБОЙ ширине карточки, кегль привязан к ней:
     4.55% ширины карточки, но не больше основного кегля и не меньше 14 px.
     Число выведено из самой длинной подписи всех девяти языков (немецкая
     у Фокуса, 309 px при кегле 16): при таком множителе она занимает 87.9%
     ширины карточки, то есть до правого края остаётся 12% минус поле. */
  white-space: nowrap;
  font-size: clamp(14px, 4.55cqi, var(--fs-body));
  font-weight: var(--fw-medium);
  line-height: 1.25;
  color: rgba(255, 255, 255, 0.82);
}

/* Широкая карточка: поля подписи те же, что были до правки телефона —
   16 сверху и clamp по бокам. Блок стоит ЗДЕСЬ, а не выше вместе с
   остальными правилами ширины: базовое .zone__label идёт в файле после
   того медиазапроса и перебивало бы его. */
@media (min-width: 1100px) {
  .zone__label { top: 16px;
                 left: clamp(22px, 1.6vw, 24px);
                 right: clamp(22px, 1.6vw, 24px); }
}

.zone__mascot { position: absolute; aspect-ratio: 1; }
.zone__mascot > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.zone__mascot > img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--still, 1) * 100%);
  height: auto;
  transform: translate(-50%, -50%);
}
.zone__mascot.is-live > img { visibility: hidden; }

/* ==========================================================================
   ШКАЛА ВОЗРАСТОВ — ЛЕГЕНДА, А НЕ ПРОГРЕСС
   Восемь ступеней — ровно те, что считает ProgressHeroSection.stage(ageMid:)
   в приложении. Плитки равны между собой: здесь СОЗНАТЕЛЬНО нет ни стрелки
   «до и после», ни перехода между ступенями — «тренируешься → маскот
   молодеет» было бы визуальным заявлением об улучшении способностей.
   Полоса под плитками показывает только ПОРЯДОК диапазонов: слева младший,
   справа старший.
   ========================================================================== */
.agescale { text-align: center; }

/* Дорожка прокрутки. Плитки не влезают в контейнер ни на одном разумном
   экране (8 × 200 px), поэтому ряд едет по горизонтали; обрезанная плитка
   у правого края и есть подсказка, что дальше есть ещё.

   Дорожка лежит ВНЕ .wrap и занимает всю ширину секции, поэтому ряд режется
   краем ОКНА, а не контейнером. Первая плитка при этом стоит ровно на
   внутренней кромке контейнера: боковой отступ повторяет вычисление .wrap —
   контейнер шириной --wrap по центру с полем --gutter внутри, а когда окно
   уже контейнера, остаётся одно поле. Проценты в padding считаются от ширины
   родителя (то есть секции), а не от 100vw, — поэтому полоса прокрутки окна
   не сбивает выравнивание. */
.agescale__track {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;              /* Firefox */
  /* Тень фокуса не должна обрезаться дорожкой. */
  padding-block: 2px;
  padding-inline: max(var(--gutter), calc((100% - var(--wrap)) / 2 + var(--gutter)));
  /* Прилипание считается от кромки ПОЛЯ прокрутки, а не от поля отступа:
     без этой строки браузер при первой же раскладке подтягивал первую
     плитку к самому краю окна и съедал отступ слева. */
  scroll-padding-inline: max(var(--gutter), calc((100% - var(--wrap)) / 2 + var(--gutter)));
}
.agescale__track::-webkit-scrollbar { display: none; }

/* На широком экране прилипания нет: скрипт ставит ленту серединой по центру,
   а «proximity» подтягивал её к ближайшей плитке и сбивал центровку на
   полсотни пикселей. На телефоне прилипание остаётся — там им листают. */
@media (min-width: 768px) {
  .agescale__track { scroll-snap-type: none; }
}

/* Общая ширина ряда: полоса и подписи «острее / медленнее» лежат внутри
   этой же коробки, поэтому едут вместе с плитками, а не стоят на месте. */
.agescale__inner { width: max-content; min-width: 100%; }

.agescale__row {
  display: flex;
  gap: clamp(10px, 1.4vw, 20px);
  align-items: end;
  list-style: none;
  margin: 0;
  padding: 0;
}
.agescale__item {
  display: grid;
  justify-items: center;
  gap: var(--sp-m);
  width: clamp(124px, 13vw, 200px);
  scroll-snap-align: start;
}
.agescale__tile {
  width: 100%;
  height: auto;
  display: block;
  border-radius: clamp(22px, 2.4vw, 36px);
}
.agescale__label {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-title);
  font-weight: var(--fw-bold);
  color: var(--text);
  white-space: nowrap;
}

/* Полоса: зелёный слева — красный справа. Это порядок диапазонов, а не
   оценка человека, поэтому у неё нет ни бегунка, ни отметки «ты здесь». */
.agescale__bar {
  height: 10px;
  border-radius: var(--r-pill);
  margin-top: clamp(16px, 1.8vw, 26px);
  background: linear-gradient(90deg,
    #6FBF3B 0%, #A6C93A 24%, #E3C13C 50%, #E5953E 74%, #DC5F44 100%);
}
/* На телефоне подпись под плиткой мельче и стоит к ней ближе: карусель едет
   по одному-двум кадрам, и крупная цифра забирала внимание у самой сцены. */
@media (max-width: 767px) {
  /* Плитка крупнее: 13vw из общего правила давало на телефоне минимум 124 px,
     и сцена внутри читалась хуже подписи под ней. */
  .agescale__item { gap: var(--sp-s); width: min(44vw, 180px); }
  .agescale__label { font-size: var(--fs-headline); }
}

.agescale__ends {
  display: flex;
  justify-content: space-between;
  margin-top: var(--sp-s);
  color: var(--text);
}

/* ==========================================================================
   ЧТО ВНУТРИ — реальные скриншоты
   Радиус экрана телефона, на котором они сняты; тени нет — как у карточек.
   ========================================================================== */
.shots {
  display: grid;
  grid-template-columns: repeat(2, 1fr);   /* на телефоне — 2 в ряд, иначе секция
                                              съедает треть страницы прокруткой */
  gap: var(--sp-m);
  align-items: start;
}
.shot { text-align: center; min-width: 0; }
.shot img {
  width: 100%; height: auto;
  /* Радиус КОРПУСА iPhone 17 Pro, на котором сняты кадры (не токен приложения:
     это снимок устройства, а не карточка). 52pt при кадре 402×874 →
     52/402 = 12.94% ширины и 52/874 = 5.95% высоты: угол остаётся круглым
     на любом размере превью. */
  border-radius: 12.94% / 5.95%;
  background: var(--surface-alt);
}
.shot figcaption { margin-top: var(--sp-m); color: var(--text-muted); }
/* Телефоны в блоке «как устроено движение». Ширина макета — 402 pt, но в
   секции он нужен маленьким: снимок читается как иллюстрация, а не как
   вторая копия приложения. */
/* Кадры того же размера, что в блоке «вот как это выглядит»: два блока рядом,
   и разный масштаб телефонов между ними читался бы как небрежность. */
.shots--3 { gap: clamp(16px, 3vw, 40px); align-items: center; }
.shots--3 > .shot { width: 100%; max-width: 265px; margin-inline: auto; }
.shots--3 > .shot--mid { max-width: 294px; }
.shots--3 .shot__cap { display: grid; gap: 2px; margin-top: var(--sp-l); }

/* На телефоне три кадра едут каруселью, а не сеткой: сеткой они вставали в
   два ряда, и третий кадр оставался один в пустой строке. Дорожка выходит на
   поля секции, поэтому кадр обрезается краем окна. */
@media (max-width: 767px) {
  .shots--3 {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-l);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }
  .shots--3::-webkit-scrollbar { display: none; }
  /* На телефоне все три одного размера — как в карусели соседнего блока. */
  .shots--3 > .shot,
  .shots--3 > .shot--mid {
    flex: 0 0 auto;
    width: min(62vw, 260px);
    max-width: none;
    margin-inline: 0;
    scroll-snap-align: start;
  }
}
.counts {
  display: flex; flex-wrap: wrap; gap: var(--sp-s);
  justify-content: center;
  margin-bottom: var(--sp-xl);
}

/* ==========================================================================
   ЧЕСТНОСТЬ
   ========================================================================== */
.honest { display: grid; gap: var(--sp-m); }

/* Карточка решения. Фон FFF9F0 — решение дизайнера для этого блока: он
   светлее общей плиты F7EDE0, чтобы карточки читались на песочном фоне
   страницы без кромки и тени. */
.honest__item {
  background: #FFF9F0;
  border-radius: var(--r-section);
  padding: clamp(16px, 1.5vw, 22px);
}
/* Заголовок и иконка в одной строке: иконка прижата вправо и выровнена по
   ВЕРХНЕЙ строке заголовка, чтобы не плавала, когда заголовок в две строки. */
.honest__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-l);
  margin-bottom: var(--sp-s);
}
.honest__top h3 { margin: 0; min-width: 0; }
.honest__icon { flex: none; width: 34px; height: 34px; margin-top: -1px; }

/* На телефоне карточка одна в ряд и занимает всю ширину — в ней можно дать
   больше воздуха и крупнее значок, чем в паре колонок на десктопе. */
@media (max-width: 767px) {
  .honest { gap: var(--sp-l); }
  .honest__item { padding: 20px; }
  .honest__top { margin-bottom: 10px; gap: var(--sp-m); }
  .honest__icon { width: 40px; height: 40px; margin-top: -2px; }
  /* Заголовок карточки на телефоне мельче общего --fs-title: 24 px из токена
     приложения там стоят в макете во всю ширину экрана, а здесь у карточки
     свои поля плюс поля секции, и строка выходила тяжелее текста под ней. */
  .honest__top h3 { font-size: 21px; }
}

/* ==========================================================================
   FAQ — <details>, без JS
   ========================================================================== */
/* Список уже контейнера: строка вопроса короткая, и на всю ширину секции
   плюс уезжал от текста на пол-экрана. Фон и радиус — те же, что у карточек
   решений выше, чтобы карточка на сайте была одна и та же. */
.faq { display: grid; gap: var(--sp-m); max-width: min(100%, 1000px); margin-inline: auto; }
/* Поля у карточки НУЛЕВЫЕ: их несут строка вопроса и ответ. Иначе нажималась
   бы только полоса внутри полей, а по краям карточки нажатие уходило
   в пустоту — карточка выглядит кнопкой целиком, значит и работать должна
   целиком. */
.faq__item {
  --plus: var(--text);
  background: #FFF9F0;
  border-radius: var(--r-section);
  overflow: hidden;
  transition: background-color var(--dur-press-up) var(--ease-up);
}
/* Наведение: карточка чуть светлеет, плюс становится янтарным. Без тени и
   сдвига — на сайте нигде нет ни того, ни другого. */
.faq__item:hover { --plus: var(--primary-deep); background: #FFFDF8; }
.faq__item summary {
  font-size: var(--fs-headline);
  font-weight: var(--fw-bold);
  cursor: pointer;
  list-style: none;
  padding: clamp(18px, 1.8vw, 26px) clamp(20px, 2vw, 32px);
  border-radius: var(--r-section);
  /* Серая плашка, которую Android рисует по тапу, повторяла форму строки
     и читалась как чужая полоса поперёк карточки. Своё наведение у карточки
     уже есть. */
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  /* По центру, а не по верхней строке: у вопроса в две строки плюс иначе
     висел у первой строки и выглядел сбитым. */
  display: flex; align-items: center; gap: var(--sp-m);
}
/* Рамка фокуса уходит ВНУТРЬ: строка теперь во всю карточку, а у карточки
   overflow: hidden — общая рамка с отступом наружу срезалась бы целиком. */
.faq__item summary:focus-visible { outline-color: var(--text); outline-offset: -4px; }
.faq__item summary::-webkit-details-marker { display: none; }
/* Плюс — файл дизайнера, положенный маской: так он перекрашивается
   переменной --plus при наведении, как раньше рисованные полосы.
   Открытая карточка доворачивает его в крестик. */
.faq__item summary::after {
  content: "";
  flex: 0 0 24px;
  width: 24px; height: 24px;
  margin-left: auto;
  background-color: var(--plus);
  -webkit-mask: url("../assets/icons/plus.svg?v=054f760b") no-repeat center / contain;
          mask: url("../assets/icons/plus.svg?v=054f760b") no-repeat center / contain;
  transition:
    transform 380ms cubic-bezier(.22, .61, .36, 1),
    background-color var(--dur-press-up) var(--ease-up);
}
.faq__item[open] summary::after { transform: rotate(135deg); }
.faq__a {
  margin: 0;
  padding: 0 clamp(20px, 2vw, 32px) clamp(18px, 1.8vw, 26px);
  color: var(--text-muted);
  max-width: var(--measure);
}

/* Раскрытие. Сам по себе <details> открывается рывком: содержимое просто
   возникает. ::details-content — та часть, которую браузер прячет; ей можно
   задать высоту и провести переход. interpolate-size разрешает анимацию
   к auto — без него высота auto не интерполируется вовсе, а фиксированную
   тут не поставить: ответы разной длины. Где ::details-content не
   поддержан, карточка открывается как раньше, мгновенно, и ничего не ломается —
   ответ всё равно проявляется, это отдельная анимация ниже. */
@media (prefers-reduced-motion: no-preference) {
  :root { interpolate-size: allow-keywords; }
  .faq__item::details-content {
    block-size: 0;
    overflow: hidden;
    transition:
      block-size 380ms cubic-bezier(.22, .61, .36, 1),
      content-visibility 380ms allow-discrete;
  }
  .faq__item[open]::details-content { block-size: auto; }
  /* Ответ не просто появляется вместе с высотой, а всплывает следом за ней —
     работает в любом браузере, потому что это обычная анимация на элементе,
     который стал видимым. */
  .faq__item[open] .faq__a {
    animation: faq-answer 400ms 40ms cubic-bezier(.22, .61, .36, 1) both;
  }
}
@keyframes faq-answer {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* Перенос строки, который живёт только на широком экране. На телефоне
   заголовок и подпись переносятся сами по ширине колонки, а заранее
   выбранное место там дало бы рваную строку. */
/* Переносы, выбранные заранее, работают не на всякой ширине.
   .br-narrow — только телефон: серый текст под заголовком там ломается по
   предложениям (так решено раньше).
   .br-wide — только настоящий десктоп, от 840 px: именно там колонка текста
   дорастает до 720 px, при которых обе половины помещаются в строку.
   Между 768 и 840 не работает ни один: колонка ещё узкая, и любой заранее
   выбранный перелом дал бы там третью строку — текст переносится сам. */
.br-wide { display: none; }
@media (min-width: 840px) { .br-wide { display: inline; } }
@media (min-width: 768px) { .br-narrow { display: none; } }

/* ==========================================================================
   ПОСЛЕДНИЙ ПРИЗЫВ — короткая полоса, не полный экран
   ========================================================================== */
.section--final { padding-block: var(--sp-xxl); background: var(--surface-alt); }
/* Последний призыв. Сцена и текст лежат в ОДНОЙ ячейке сетки: высоту плиты
   задаёт та из них, что выше, и текст ложится поверх пейзажа, как на макете.
   Сцена расширена на поля плиты и уходит под её скругление (overflow). */
/* Поля у последнего призыва равны со всех сторон: текст стоит от верхней
   кромки на столько же, на сколько от левой, и кнопка — от нижней. */
.final { position: relative; display: grid; overflow: hidden; }
/* Два класса — чтобы правило перебило поля плиты из медиазапроса ниже.
   Только на десктопе: там текст и кнопка разведены по краям плиты и поля
   должны совпасть со всех сторон. На телефоне у плиты обычное верхнее поле,
   как у соседних цветных секций. */
@media (min-width: 768px) {
  .slab.final { --slab-pad-y: var(--slab-pad-x); }
  /* Кнопка приподнята над нижней кромкой: её объём (тень-подложка) вплотную
     к скруглению плиты читался как обрез. Два класса — ниже в файле стоит
     .final__act { margin: 0 } и при равной специфичности перебивал бы. */
  .final .final__act { margin-bottom: var(--sp-m); }
}
.final > * { grid-area: 1 / 1; }
/* Сцена подрезана сверху: в исходнике над маскотом ещё треть пустого неба,
   из-за неё плита выходила вдвое выше текста. object-position прижимает кадр
   к низу, поэтому земля и фигура целы. */
.final__scene {
  align-self: end;
  display: block;                 /* иначе строчный бокс добавляет снизу пробел */
  width: calc(100% + 2 * var(--slab-pad-x));
  max-width: none;                /* общий сброс img{max-width:100%} обрезал бы вылет */
  /* Срезано ровно столько, сколько над маскотом пустого неба: голова в
     исходнике начинается на y=78 из 457, поэтому кадр не выше 1360×400 —
     при 1360×360 макушку срезало. */
  aspect-ratio: 1360 / 400;
  object-fit: cover;
  object-position: 50% 100%;
  height: auto;
  margin-inline: calc(-1 * var(--slab-pad-x));
  margin-bottom: calc(-1 * var(--slab-pad-y));
}
/* Текст растянут на всю высоту плиты: заголовок с подписью вверху, кнопка
   внизу — их разводит space-between, а не отступ на глаз. */
.final__text {
  align-self: stretch;
  max-width: 56%;
  display: grid;
  align-content: space-between;
  gap: var(--sp-xl);
}
.final__head { min-width: 0; }
.final__act { margin: 0; }
/* Кнопка последнего призыва — по содержимому. Общий min-width 280 px из
   медиазапроса ниже держал строку «Скачать в App Store»; со словом «Начать»
   он превращал кнопку в пустую полосу на треть плиты. */
.final .btn { width: auto; min-width: 0; padding-inline: var(--sp-xxl); }

/* На телефоне сцена уходит вниз отдельной строкой: поверх неё текст не
   помещается, а маскот в 390 px шириной был бы с ноготь. */
@media (max-width: 767px) {
  .final { grid-template-rows: auto auto; }
  .final__text { grid-area: 1 / 1; max-width: none; text-align: center; }
  /* Кнопка шире содержимого: «Начать» — одно короткое слово, и по ширине
     текста она выходила вдвое уже кнопки первого экрана. Нижняя граница
     в 62% колонки, но не больше самой колонки — в самых длинных языках
     («Commencer») кнопка растёт по тексту сама. */
  .final__act .btn {
    width: auto;
    min-width: min(62%, 100%);
    padding-inline: var(--sp-xxl);
  }
  /* Сцена ближе к кнопке и подрезана под ногами: плита обрезает низ кадра
     (у .final overflow: hidden), поэтому пустая полоса земли не тянет блок.
     Кадр ШИРЕ плиты в 2.889 раза и сдвинут влево. Так сделано потому, что
     object-fit подрезает кадр только по той оси, по которой он не влезает:
     при кадре шириной в плиту масштаб задавала ВЫСОТА, все 457 строк
     исходника были видны, и над макушкой оставалось 78 строк пустого неба.
     Широкий кадр переводит масштаб на ширину, и лишнее уходит сверху
     (object-position по вертикали — 100%, низ со ступнями и землёй цел).
     Числа выведены, а не подобраны: масштаб фигуры k·ширина/1360 — тот же,
     что был; сдвиг m = 0.5 − (1063/1360)·k ставит ОСЬ МАСКОТА (x = 1063
     в исходнике, замер по краске головы, майки и кроссовок) ровно в центр
     плиты. Оба числа от ширины не зависят. */
  .final__scene {
    grid-area: 2 / 1;
    margin-top: var(--sp-s);
    /* Нижнее поле плиты плюс 28 px: первое доводит землю до её кромки
       (иначе полосу съедало бы поле), второе срезает пустую землю под
       ногами. Клип даёт .final с overflow: hidden. */
    margin-bottom: calc(-1 * var(--slab-pad-y) - 28px);
    width: 288.9%;
    margin-left: -175.85%;
    margin-right: 0;
    /* 406 из 457 строк: над макушкой остаётся 27 строк неба вместо 78. */
    aspect-ratio: 1360 / 406;
    object-position: 0 100%;
  }
}

/* ==========================================================================
   ФУТЕР
   ========================================================================== */
/* Две полосы: светлая с контактами и тёмная с юридической строкой. Цвета
   заданы прямо здесь — это две плашки футера, а не токены темы. */
.site-foot { margin-top: var(--sp-xxl); }
.foot__top { background: #DDCFBD; padding-block: clamp(28px, 3vw, 44px); }
/* Две колонки одной высоты: у левой лого сверху, ссылки снизу, у правой
   почта сверху, лейбл Dravoss снизу. Из-за space-between нижние строки обеих
   колонок стоят на одной линии — ссылки ровно по нижней кромке лейбла. */
.foot__grid {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: space-between;
  align-items: stretch;
  gap: var(--sp-xl);
}
.foot__brand,
.foot__contact {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-xl);
  min-width: 0;
}
/* «Поддержка» и почта — одна пара: без обёртки колонка разводила их наравне
   с лейблом, и подпись отрывалась от адреса. */
.foot__reach { display: grid; gap: 2px; }
.foot__contact { text-align: right; }

.foot__logo { display: flex; }
/* Голова и вордмарк — одна ссылка на главную. */
.foot__home { display: inline-flex; align-items: center; gap: var(--sp-m); }
/* Размеры подобраны по ЧЕРНИЛАМ, а не по коробкам: у головы вокруг рисунка
   поле (краска занимает 75.8 % высоты файла), у вордмарка почти нет (97.3 %),
   поэтому при равной высоте коробок надпись выглядела выше головы.
   Вордмарк: 108/3.152 × 0.973 = 33.3 краски. Голове дана 40 — на пятую часть
   больше: круглая форма при равной высоте читается мельче прямых букв,
   это обычная оптическая поправка. 40/0.758 = 52. */
.foot__logo img:first-child { width: 52px; height: auto; }
.foot__word { width: 108px; height: auto; }

/* «Поддержка» — подпись, а не ссылка: подсвечивать её не за что. */
.foot__sup { display: block; color: var(--text-muted); }
.foot__mail {
  display: inline-block;
  font-size: clamp(19px, 1.7vw, 25px);
  font-weight: var(--fw-bold);
  color: var(--text);
  text-decoration: none;
}
.foot__mail:hover { color: var(--primary-deep); text-decoration: underline; }
.foot__by { margin: 0; }
/* Выравнивание держит ссылка: картинка внутри неё уже не может
   прижаться к правому краю сама. */
.foot__dravoss { display: block; width: max-content; margin-left: auto; }
.foot__by img { display: block; width: 116px; height: auto; }

.foot__links { display: flex; flex-wrap: wrap; gap: var(--sp-xl); }
.foot__links a { color: var(--text); font-size: var(--fs-body); font-weight: var(--fw-semibold); text-decoration: none; }
.foot__links a:hover,
.foot__mail:hover { text-decoration: underline; }

/* На телефоне колонки футера идут друг под другом. Двумя колонками они не
   влезали: почта и немецкие «Datenschutz Nutzungsbedingungen» вместе шире
   360 px, и страница уезжала вбок на 7 px. */
@media (max-width: 767px) {
  .foot__grid { grid-template-columns: 1fr; gap: var(--sp-xl); }
  .foot__brand,
  .foot__contact { gap: var(--sp-xl); }
  .foot__contact { text-align: left; }
  .foot__dravoss { margin-left: 0; }
  /* Ссылки в столбик: в строку они читались как одна строка мелкого текста,
     а в столбик каждая — самостоятельный пункт, как на макете. */
  .foot__links { flex-direction: column; align-items: flex-start; gap: var(--sp-l); }
  /* На телефоне обе крупнее, поправка та же: краска вордмарка 35.8,
     головы 56 × 0.758 = 42.4. */
  .foot__logo img:first-child { width: 56px; }
  .foot__word { width: 116px; }
  .foot__mail { font-size: 24px; }
}

.foot__legal { background: #8D7B64; padding-block: var(--sp-l); }
.foot__legal p { color: #fff; text-align: center; }

/* ==========================================================================
   ДОКУМЕНТЫ (privacy / terms / support)
   ========================================================================== */
.doc { padding-block: var(--sp-xl) 40px; }
.doc__title { margin-bottom: var(--sp-s); }
.doc__meta { color: var(--text-muted); margin-bottom: var(--sp-xl); }
.doc h2 { font-size: var(--fs-title); font-weight: var(--fw-bold); margin-top: var(--sp-xxl); margin-bottom: var(--sp-m); }
.doc h3 { font-size: var(--fs-headline); font-weight: var(--fw-bold); margin-top: var(--sp-xl); margin-bottom: var(--sp-s); }
.doc p, .doc li { color: var(--text); }
.doc p + p { margin-top: var(--sp-m); }
.doc ul { margin-top: var(--sp-m); display: grid; gap: var(--sp-s); }
.doc li { padding-left: var(--sp-l); position: relative; }
.doc li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--primary);
}
.doc table { width: 100%; border-collapse: collapse; margin-top: var(--sp-m); font-size: var(--fs-caption); }
.doc th, .doc td { text-align: left; padding: var(--sp-m); border-bottom: 1px solid var(--stroke); vertical-align: top; }
.doc th { font-weight: var(--fw-bold); }
.doc__scroll { overflow-x: auto; }

/* Баннер вверху политики — ссылка на раздел удаления аккаунта. Это первое,
   что ищет ревьюер магазина приложений, поэтому он оформлен как выделенный
   блок, а не как обычный абзац: плашка с янтарной полосой слева.
   Полоса, а не рамка со всех сторон: рамка на плашке того же семейства, что
   и карточки страницы, читалась бы как ещё одна карточка. */
.doc__banner {
  display: block;
  margin: var(--sp-l) 0 var(--sp-xl);
  padding: var(--sp-l);
  border-left: 4px solid var(--primary);
  border-radius: var(--r-chip);
  background: var(--surface-alt);
}
.doc__banner p { margin: 0; }
.doc__banner a { color: var(--text); text-underline-offset: 3px; }

/* Якорь раздела удаления. Переход по ссылке ставит заголовок под липкую
   шапку, поэтому у самого якоря — запас сверху на её высоту с полем. */
.doc [id] { scroll-margin-top: 88px; }

/* Маркер незакрытого решения. Обязан быть ЗАМЕТНЫМ: он не должен уехать
   в прод незамеченным. */
.todo {
  display: inline-block;
  padding: 2px var(--sp-s);
  border-radius: var(--r-chip);
  background: var(--warning);
  color: var(--text-on-color);
  font-weight: var(--fw-bold);
  font-size: var(--fs-caption);
}
.todo-block {
  display: block;
  padding: var(--sp-m) var(--sp-l);
  margin-top: var(--sp-m);
  border-radius: var(--r-chip);
  background: var(--warning);
  color: var(--text-on-color);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-caption);
}

/* Крупный контакт поддержки — на первом экране, требование App Review. */
.support-hero { padding-block: var(--sp-xl) var(--sp-xxl); }
.support-hero__mail {
  display: inline-block;
  margin-top: var(--sp-l);
  font-size: var(--fs-screen);
  font-weight: var(--fw-heavy);
  /* Не --primary-deep: на фоне #E9E1D6 он даёт 2.87:1 — ниже 3.0:1 даже для
     крупного текста. --text-on-color на том же фоне 10.96:1. */
  color: var(--text-on-color);
  text-decoration: none;
  word-break: break-word;
}
.support-hero__mail:hover { text-decoration: underline; }

/* ==========================================================================
   ВОТ КАК ЭТО ВЫГЛЯДИТ — плита со скриншотами приложения
   ========================================================================== */
/* Плита шире контейнера: у неё свои поля внутри, а снаружи её держит поле
   секции. На телефоне поля нет — плита идёт от края до края экрана, как на
   макете: свои внутренние поля у неё всё равно есть. */
.section--slab { padding-block: 0; }
.section--slab > .slab { max-width: var(--wrap); margin-inline: auto; }
@media (min-width: 768px) {
  .section--slab { padding-inline: var(--gutter); }
}
/* Плита живёт на своём фоне, светлее полотна страницы, со скруглением и
   собственными полями — как отдельная карточка во всю ширину. */
.slab {
  /* Поля вынесены в переменные: сцена последнего призыва расширяется ровно
     на них, чтобы дойти до кромки плиты на любой ширине окна. */
  --slab-pad-y: var(--sp-xxl);
  --slab-pad-x: var(--gutter);
  background: #F7EDE0;
  border-radius: 40px;
  padding: var(--slab-pad-y) var(--slab-pad-x);
}
/* Заголовок плиты крупнее общего экранного: это витрина, а не рядовая
   секция. Между ним и строкой под ним воздуха больше, чем обычно. */
.slab > .h-screen,
.h-screen--big { font-size: clamp(30px, 3.2vw, 46px); line-height: 1.1; }
/* Заголовок → серая подпись: одно расстояние во всех секциях. */
.h-screen + .body,
.slab > .h-screen + .body { margin-top: var(--sp-m); }
.shots--screens {
  grid-template-columns: 1fr;
  justify-items: center;
  align-items: end;
  margin-top: var(--sp-xxl);
}
.shots--screens > .shot { width: 100%; max-width: 265px; }
.shots--screens > .shot--mid { max-width: 294px; }

/* На телефоне три кадра едут каруселью, и все ОДНОЙ высоты: приём десктопа
   «средний крупнее» здесь не работает — рядом видно от силы полтора кадра,
   и разная высота читалась бы как сбой, а не как акцент. Дорожка расширена
   на поля плиты, поэтому кадр обрезается её кромкой, а первый стоит ровно
   на внутренней кромке. */
@media (max-width: 767px) {
  .shots--screens {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-l);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    margin-inline: calc(-1 * var(--slab-pad-x));
    padding-inline: var(--slab-pad-x);
    scroll-padding-inline: var(--slab-pad-x);
  }
  .shots--screens::-webkit-scrollbar { display: none; }
  .shots--screens > .shot,
  .shots--screens > .shot--mid {
    flex: 0 0 auto;
    width: min(62vw, 260px);
    max-width: none;
    scroll-snap-align: start;
  }
}
/* Корпус телефона нарисован в самой картинке (макап от дизайнера, SVG с
   рамкой iPhone), поэтому здесь ни фона, ни скругления, ни тени — иначе
   вторая рамка поверх первой. */
.phone { position: relative; }
.phone picture, .phone img, .phone video { display: block; width: 100%; height: auto; }

/* Скриншот в корпусе iPhone. Кадр — растр от дизайнера (экран в нём чёрный и
   непрозрачный), поэтому снимок кладётся ПОВЕРХ и вписывается в окно.

   Числа сняты с самого PNG (1261×2611), а не с макета: корпус занимает
   x 7…1252, y 1…2610, боковые кнопки из обмера исключены. Кромка корпуса
   ровно 47 px со всех четырёх сторон — отсюда бокс окна. Угол корпуса — круг
   радиусом 224 px (подгонка по контуру, средняя ошибка 1.8 px), окно отстоит
   от него на те же 47 px, поэтому радиус окна 224 − 47 = 178 px. Ровно это
   и значит «скругление пропорционально корпусу»: раньше стояло 213 px, на
   20% круглее, и угол снимка выглядел обкусанным. */
.phone--frame .phone__frame {
  position: relative;
  z-index: 0;
  /* Силуэт телефона нарисован в самом PNG, включая прозрачные углы. Общее
     правило .shot img (оно для ГОЛЫХ скриншотов соседнего блока) красит под
     картинкой подложку и скругляет её по радиусу скриншота — вдвое меньшему,
     чем у корпуса. Из-под всех четырёх углов торчали светлые уголки этой
     подложки. Здесь она не нужна: PNG сам себе силуэт. */
  border-radius: 0;
  background: none;
}
.phone--frame picture { position: absolute; inset: 0; z-index: 1; }
/* Запись игры лежит в том же окне корпуса, что и скриншот: класс общий,
   поэтому размеры и скругление считать заново не нужно.

   z-index обязателен. Экран в макапе — непрозрачный чёрный растр, снимок
   кладётся ПОВЕРХ него; у <picture> это делал z-index: 1. Видео стоит в
   разметке ПЕРЕД рамкой, и без этой строки рамка красилась бы сверху и
   закрывала ролик своим чёрным экраном.

   Фон — на те доли секунды, пока постер ещё не нарисован. */
.phone--frame video.phone__screen { z-index: 1; background: #0B1A26; }
.phone--frame .phone__screen {
  position: absolute;
  background: none;
  left: 4.282%;
  top: 1.838%;
  width: 91.356%;
  height: 96.362%;
  object-fit: cover;
  object-position: 50% 0;
  /* 178 px от ширины окна (1152) и от его высоты (2516): угол круглый. */
  border-radius: 15.408% / 7.055%;
}
.shot__cap {
  display: grid;
  gap: 2px;
  margin-top: var(--sp-l);   /* один и тот же отступ от своего телефона */
  text-align: center;
}
.shot__name {
  font-size: var(--fs-headline);
  font-weight: var(--fw-bold);
  color: #2A2015;
}
/* Подзаголовок — тот же цвет в половину силы, как задано в макете. */
.shot__zone {
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: rgba(42, 32, 21, 0.5);
}

/* ==========================================================================
   ПОЯВЛЕНИЕ ПРИ ПРОКРУТКЕ

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

   Скрытое состояние живёт ТОЛЬКО под .reveal-on, а этот класс ставит скрипт
   и только когда есть IntersectionObserver и разрешено движение. Поэтому без
   скрипта, на старом браузере и при «меньше движения» ничего не прячется —
   страница просто статична. Ни один элемент первого экрана не помечен:
   скрипт отложенный, и до его запуска пометка не действует.

   Задержки заданы классами, а не скриптом: инлайновый style запрещён
   политикой (style-src 'self'), да и сборка его не пропустит.
   ========================================================================== */
.reveal-on .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 620ms cubic-bezier(.22, .61, .36, 1),
    transform 620ms cubic-bezier(.22, .61, .36, 1);
}
.reveal-on .reveal.is-in { opacity: 1; transform: none; }
.reveal-on .reveal--d1 { transition-delay: 70ms; }
.reveal-on .reveal--d2 { transition-delay: 140ms; }
.reveal-on .reveal--d3 { transition-delay: 210ms; }
.reveal-on .reveal--d4 { transition-delay: 280ms; }
/* Сцена последнего призыва прижата к нижней кромке плиты отрицательным
   полем: сдвигать её по вертикали нельзя — она отклеилась бы от земли.
   Ей остаётся только проявление. */
.reveal-on .reveal--fade { transform: none; }

/* Страховка на случай, если пометку кто-то поставит вручную, а движение
   у человека выключено: показываем всё сразу. */
@media (prefers-reduced-motion: reduce) {
  .reveal-on .reveal { opacity: 1; transform: none; transition: none; }
}

/* ==========================================================================
   АДАПТИВ
   Мобильный приоритет. Значения приложения (34/28/16) — это значения ДЛЯ
   ТЕЛЕФОНА; на широком экране растёт только герой и крупное число,
   остальная шкала не трогается, иначе плотность текста уедет от приложения.
   ========================================================================== */
@media (min-width: 768px) {
  .section { padding-block: 48px; }
  .slab { --slab-pad-y: 56px; --slab-pad-x: var(--sp-xxl); border-radius: 56px; }
  /* Средний экран крупнее боковых — как на макете. Выравнивание по низу
     КАДРОВ: подписи под ними разной высоты и не должны разводить телефоны. */
  /* Средний экран крупнее боковых — как на макете. Ширина задана в пикселях,
     а не долей колонки: телефон не должен раздуваться вместе с контейнером. */
  /* Колонки по содержимому, а не 1fr: доли растаскивали телефоны по всей
     ширине плиты, а на макете они стоят рядом.
     Телефоны центрируются по высоте, средний выступает вверх и вниз.
     Подпись идёт сразу за СВОИМ телефоном на общем отступе — общей линии для
     подписей нет: иначе у боковых между телефоном и подписью зияла дыра. */
  .shots--screens { grid-template-columns: repeat(3, auto);
                    justify-content: center; justify-items: center;
                    align-items: center;
                    column-gap: 28px; }
  /* Размеры макапов: боковые 265×540, средний 294×600 — как прислал дизайнер. */
  .shots--screens > .shot     { max-width: 265px; }
  .shots--screens > .shot--mid { max-width: 294px; }
  .shots--3 { grid-template-columns: repeat(3, auto); justify-content: center; }
  .site-head__nav .site-head__link { display: inline; }
  .site-head__nav .btn--sm { display: inline-flex; }
  .honest--2 { grid-template-columns: repeat(2, 1fr); }
  .hero { padding-block: 0; }
  /* Сцена тянется по окну, а не по текстовому контейнеру: --wrap задуман под
     длину строки, и на широком мониторе он оставлял огромные поля.
     Ограничения по ширине нет вовсе — размер держит высота окна: когда
     упирается max-height, aspect-ratio сам считает ширину, и композиция
     целиком остаётся в кадре. */
  .hero__wrap { max-width: none; }

  /* СЦЕНА держит пропорцию макета (1968×1130) — иначе композиция растягивается
     по горизонтали и объекты отрываются от букв: декор считается в процентах
     от сцены, а лого при растяжении упирается в свою высоту и перестаёт
     занимать те же 76%. Размер — максимум, который влезает: по ширине это
     окно минус поля, по высоте остаток экрана; что меньше, то и работает. */
  .hero__stage {
    display: block;
    aspect-ratio: 1968 / 1130;
    /* Ширина — меньшее из двух: вся полоса контейнера или та, что влезает по
       высоте (остаток окна × 1968/1130 = 1.7416). Через max-height этого не
       добиться: width:100% жёстко держит ширину, и пропорция всё равно
       растягивалась на пару процентов. */
    width: min(100%, calc((100svh - var(--head-h) - var(--sp-xl)) * 1.7416));
    margin-inline: auto;
  }
  /* Ширину, left/right и top задаёт styles/scene.css (его собирает build.py
     из HERO_DECO и HERO_MASCOTS). Здесь только раскладка — и НИКАКОЙ ширины:
     `width: auto` у :first-of-type перебивал бы .mascot-1 по специфичности,
     и первый маскот получал нулевую ширину. */
  .hero__deco,
  .hero__mascot,
  .hero__mascot:first-of-type {
    display: block;
    position: absolute;
    margin: 0;
    pointer-events: none;
  }
  /* Слои: камни и ёлка за буквами, вордмарк, маскоты и дерево перед ними —
     дерево работает точкой над i, поэтому обязано быть сверху. */
  .hero__deco              { height: auto; }
  .hero__deco--back        { z-index: 0; }
  .hero__title             { z-index: 1; }
  .hero__mascot            { z-index: 2; }
  .hero__deco--front       { z-index: 3; }
  .hero__title {
    position: absolute;
    left: 12%; right: 12%; top: 27.5%;  /* выше середины: под лого нужен воздух */
  }
  .hero__logo { max-width: none; }
  /* Подпись прижата к кнопке, а не к лого: кнопка стоит на 78% и не двигается,
     а строка под ней читается как одна пара с кнопкой. Процент считается от
     ШИРИНЫ строки заголовка (76% сцены) — это её содержащий блок. */
  .hero__claim {
    margin-top: 8.2%;
    font-size: clamp(16px, 1.6vw, 24px);
  }
  .hero__act { position: absolute; left: 0; right: 0; top: 78%; margin: 0; z-index: 1; }
  .hero__act .btn { min-width: 0; width: auto; padding-inline: var(--sp-xxl); }
  .steps { gap: var(--sp-l); }
  .honest { grid-template-columns: repeat(2, 1fr); gap: var(--sp-xl); }
  .btn { width: auto; min-width: 280px; }
  /* Кнопка шапки компактная: min-width из строки выше стоит ПОЗЖЕ правила
     .btn--sm и перебивал бы его при равной специфичности. */
  .btn--sm { min-width: 0; }
}

@media (min-width: 1024px) {
  :root { --fs-display: 44px; --fs-range: 72px; --wrap: 1200px; }
}

/* На большом мониторе поля по бокам становились непомерными — контейнер
   растёт вместе с окном, но не дальше предела читаемой строки в секциях. */
@media (min-width: 1600px) {
  :root { --wrap: 1440px; }
  .section { padding-block: 56px; }
}

/* ---------- уважение к системным настройкам ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .btn, .site-head, .shots { display: none; }
  body { background: #fff; }
}
