/* ============================================================
   tokens.css — единственный источник значений дизайн-системы.
   Origin Financial (структура) × DeepSeek (айдентика).
   Правила и обоснования: см. DESIGN.md
   Хардкод значений в компонентах запрещён — только var().
   ============================================================ */

:root {
  /* ---------- Цвет: нейтральная база (DeepSeek slate) ---------- */
  --canvas: #ffffff;
  --canvas-alt: #f8fafc;
  --surface: #f1f5f9;
  --surface-hover: #e2e8f0;
  --hairline: #e5e7eb;

  /* Три уровня текста, а не четыре. Был ещё --ink-subtle #94a3b8,
     но он давал 2.34:1 на подписях и 2.56:1 на лейблах — мимо AA
     во всех шести местах, где нёс текст. Светло-серый лейбл выглядит
     аккуратно ровно до момента, когда его нужно прочитать.
     Иерархию мелких надписей теперь держат размер, вес и трекинг. */
  --ink: #0f172a;
  --ink-body: #334155;
  --ink-muted: #64748b;
  /* Алиас, а не отдельное значение: так уровни не разъедутся при следующей
     правке палитры. Имя оставлено, чтобы не переписывать шесть компонентов. */
  --ink-subtle: var(--ink-muted);
  --ink-inverse: #ffffff;

  /* Приглушённый текст, откалиброванный под --surface, а не под --canvas.
     --ink-muted считался от белого и даёт на нём 4.76:1, но на #f1f5f9
     проседает до 4.34:1 — мимо AA. Разница между этими двумя значениями
     на глаз не читается, рядом с соседними лейблами уровень тот же.
     Брать здесь --ink-body нельзя: 9.45:1 сделали бы подпись самой тёмной
     надписью в 11px на странице и сломали бы иерархию мелкого текста. */
  --ink-muted-surface: #5b6b80;  /* на --surface 4.97:1, на белом 5.45:1 */

  /* Только для декоративных штрихов и разделителей, никогда для текста:
     на белом даёт 2.56:1 — этого хватает линии, но не букве. */
  --stroke-faint: #94a3b8;

  /* ---------- Цвет: синий ----------
     --blue      брендовая марка DeepSeek, только декор и логотип
     --blue-ink  текст и заливки под белым текстом, AA 5.63:1
     --blue-deep hover primary CTA
     --blue-wash мягкая подложка бейджей */
  --blue: #4d6bfe;
  --blue-ink: #3d57e8;
  --blue-deep: #2f45c4;
  --blue-wash: #eef2ff;

  /* ---------- Цвет: хроматика модулей ----------
     Цвет — единственный различитель направления.
     Каждый затемнён до прохождения AA с белым текстом 16px. */
  --m-deck: #3d57e8;   /* Презентации — 5.63:1 */
  --m-photo: #0e7c99;  /* Фото        — 4.81:1 */
  --m-text: #334155;   /* Текст       — 10.4:1 */
  --m-song: #b44ba8;   /* Песни       — 4.65:1 */
  --m-video: #6d4ae0;  /* Видео       — 5.67:1 */

  /* ---------- Цвет: состояния ---------- */
  --focus-ring: #3d57e8;
  --success: #0f766e;

  /* ---------- Шрифтовые семейства ---------- */
  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-ui: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* ---------- Веса ----------
     Display — только 400. Bold на display запрещён. */
  --weight-display: 400;
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;

  /* ---------- Типографическая шкала ----------
     Minor Third (1.2) от 16px, срезана под длину русского текста. */
  /* Верхняя ступень срезана до 64px: ТЗ §4 задаёт H1 desktop 52–64,
     и на 46% колонке первого экрана 76px рвал заголовок на четыре строки. */
  --text-display: clamp(2.25rem, 5vw, 4rem);     /* 36 → 64 */
  --text-h1: clamp(2.125rem, 4.6vw, 3.5rem);     /* 34 → 56 */
  --text-h2: clamp(1.875rem, 3.6vw, 2.75rem);    /* 30 → 44 */
  --text-h3: clamp(1.375rem, 1.8vw, 1.625rem);   /* 22 → 26 */
  --text-lead: clamp(1.125rem, 1.4vw, 1.25rem);  /* 18 → 20 */
  --text-body: clamp(1rem, 1.1vw, 1.0625rem);    /* 16 → 17 */
  --text-sm: 0.875rem;                           /* 14 */
  --text-label: 0.6875rem;                       /* 11 */

  /* ---------- Выключка ---------- */
  --lh-display: 0.92;
  --lh-h1: 0.94;
  --lh-h2: 1;
  --lh-h3: 1.2;
  --lh-lead: 1.5;
  --lh-body: 1.6;
  --lh-sm: 1.65;
  --lh-label: 1.8;

  /* ---------- Трекинг ---------- */
  --tracking-display: -0.02em;
  --tracking-h2: -0.015em;
  --tracking-h3: -0.01em;
  --tracking-label: 0.14em;

  /* ---------- Мера строки ----------
     62ch, как в DESIGN.md §2, а не 66ch: единица ch считается по глифу «0»
     Inter, который шире средней строчной кириллицы, поэтому 66ch давали
     79 знаков в строке — за комфортным пределом в 75. */
  --measure-body: 62ch;
  --measure-lead: 54ch;
  --measure-display: 18ch;

  /* ---------- Отступы: база 4px ---------- */
  --space-4: 0.25rem;
  --space-8: 0.5rem;
  --space-12: 0.75rem;
  --space-16: 1rem;
  --space-20: 1.25rem;
  --space-24: 1.5rem;
  --space-32: 2rem;
  --space-40: 2.5rem;
  --space-48: 3rem;
  --space-60: 3.75rem;
  --space-68: 4.25rem;
  --space-100: 6.25rem;
  --space-120: 7.5rem;
  --space-140: 8.75rem;

  /* Минимальная зона нажатия для основных интерактивов. */
  --tap-target: 2.75rem;

  /* ---------- Раскладка ---------- */
  --container: 1200px;
  --container-narrow: 720px;
  --gutter: 1.5rem;

  /* Отступ секции считается на ОДНУ сторону, а между двумя соседними
     секциями он складывается вдвое. 120px с каждой стороны давали
     240px пустоты — страница разваливалась на несвязанные острова. */
  --section-gap: clamp(2.75rem, 4vw, 4rem);

  /* Внутри группы плотно, между группами свободно.
     Раньше было наоборот: карточка на 32px внутри и 16px до соседней. */
  --card-padding: 1.5rem;
  --grid-gap: clamp(0.75rem, 1.25vw, 1.25rem);
  --element-gap: 0.75rem;
  --header-height: 4rem;
  --head-gap: clamp(1.5rem, 2vw, 2rem);

  /* ---------- Радиусы ----------
     Промежуточных значений не существует. */
  --radius-control: 8px;  /* кнопки, инпуты, навигация */
  --radius-card: 16px;    /* карточки, стат-блоки */
  --radius-tile: 24px;    /* плитки модулей, демо-рамки */
  --radius-pill: 9999px;

  /* ---------- Тени ----------
     В системе ровно одна. Элевация выражается шагом цвета. */
  --shadow-sticky: 0 1px 12px rgba(15, 23, 42, 0.06);

  /* ---------- Движение ---------- */
  --duration-state: 0.2s;
  --duration-reveal: 0.6s;
  --ease-state: ease;
  --ease-reveal: cubic-bezier(0.455, 0.03, 0.515, 0.955);

  /* ---------- Слои ---------- */
  --z-behind: -1;
  --z-local: 1;
  --z-header: 100;
  --z-skip-link: 300;
}

@media (max-width: 640px) {
  :root {
    --gutter: 1.25rem;
    --card-padding: 1.5rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-state: 0.01ms;
    --duration-reveal: 0.01ms;
  }
}

/* Самохостинг шрифтов. Сгенерировано scripts/fonts.mjs, файлы в public/fonts/.
   Три голоса системы: Playfair Display (display), Inter (UI), IBM Plex Mono (лейблы).

   Кириллица — стандартные подмножества целиком.
   Латиница — контентный сабсет: в тексте сайта её горстка, а полное
   latin-подмножество Google весит больше, чем вся кириллица страницы.
   Отсюда же отсутствие latin-ext и второго начертания IBM Plex Mono.

   Состав латиницы, глифов: 83. Пробел и неразрывный показаны как ␣:
   ␣!"%'(),-./0123456789:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz␣«·»–—…

   Вариативные семейства отдаются одним файлом на подмножество,
   поэтому в их имени нет веса. Имена стабильны между перегенерациями —
   на них ссылается preload в <head>. */

@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/playfair-display-400-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/playfair-display-400-latin.woff2") format("woff2");
  unicode-range: U+20-22, U+25, U+27-29, U+2c-3b, U+3f, U+41-5a, U+61-7a, U+a0, U+ab, U+b7, U+bb, U+2013-2014, U+2026;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/fonts/inter-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/inter-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/fonts/inter-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/inter-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+20-22, U+25, U+27-29, U+2c-3b, U+3f, U+41-5a, U+61-7a, U+a0, U+ab, U+b7, U+bb, U+2013-2014, U+2026;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+20-22, U+25, U+27-29, U+2c-3b, U+3f, U+41-5a, U+61-7a, U+a0, U+ab, U+b7, U+bb, U+2013-2014, U+2026;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+20-22, U+25, U+27-29, U+2c-3b, U+3f, U+41-5a, U+61-7a, U+a0, U+ab, U+b7, U+bb, U+2013-2014, U+2026;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-500-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-500-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
  unicode-range: U+20-22, U+25, U+27-29, U+2c-3b, U+3f, U+41-5a, U+61-7a, U+a0, U+ab, U+b7, U+bb, U+2013-2014, U+2026;
}

/* ============================================================
   base.css — сброс, базовая типографика и поверхности браузера.
   Все значения только через var() из tokens.css.
   ============================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Шапка фиксированная и всегда стоит поверх первых 64px вьюпорта,
     поэтому цель якоря обязана останавливаться ниже неё. Плюс --space-24,
     чтобы заголовок секции не прилипал к нижней границе шапки. */
  scroll-padding-top: calc(var(--header-height) + var(--space-24));
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  min-height: 100vh;
  /* Шапка fixed и выпала из потока: без этого отступа первый экран
     и первая якорная секция уезжали бы под неё. Ровно --header-height —
     столько же занимает шапка вместе со своей нижней границей,
     поэтому контент начинается впритык под hairline, без шва.
     box-sizing: border-box выше — паддинг входит в 100vh, лишнего
     скролла на коротких страницах не появляется. */
  padding-top: var(--header-height);
  background: var(--canvas);
  color: var(--ink-body);
  font-family: var(--font-ui);
  font-size: var(--text-body);
  font-weight: var(--weight-regular);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1;
  /* Русские кавычки-ёлочки и правильные дефисы приходят из текста, не из CSS */
}

img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

/* ---------- Заголовки: голос Display ---------- */

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  color: var(--ink);
  text-wrap: balance;
}

h1 {
  font-size: var(--text-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--tracking-display);
}

h2 {
  font-size: var(--text-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--tracking-h2);
}

h3 {
  font-size: var(--text-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--tracking-h3);
}

p {
  max-width: var(--measure-body);
  text-wrap: pretty;
}

/* ---------- Ссылки ---------- */

a {
  color: var(--blue-ink);
  text-decoration-color: color-mix(in srgb, var(--blue-ink) 35%, transparent);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  transition: color var(--duration-state) var(--ease-state),
    text-decoration-color var(--duration-state) var(--ease-state);
}

/* ---------- Списки ---------- */

ul,
ol {
  padding-left: 1.25em;
}

li {
  max-width: var(--measure-body);
}

li + li {
  margin-top: var(--space-8);
}

/* ---------- Формы и кнопки ---------- */

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}

/* ============================================================
   Поверхности браузера.
   То, что мы не рисовали, но что всё равно несёт дизайн:
   выделение, каретка, кольцо фокуса, скроллбар, цифры.
   ============================================================ */

::selection {
  background: var(--blue-wash);
  color: var(--ink);
}

:root {
  caret-color: var(--blue-ink);
  accent-color: var(--blue-ink);
  /* Скроллбар в тон системы, а не серый по умолчанию */
  scrollbar-color: var(--surface-hover) var(--canvas);
  scrollbar-width: thin;
}

::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

::-webkit-scrollbar-track {
  background: var(--canvas);
}

::-webkit-scrollbar-thumb {
  background: var(--surface-hover);
  border: 3px solid var(--canvas);
  border-radius: var(--radius-pill);
}

/* Кольцо фокуса — одно на весь сайт, видимое на любой поверхности.
   Радиус здесь не задаём: outline и так повторяет форму элемента, а
   принудительные 8px скругляли фокус у <summary>, логотипа и ссылок подвала. */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* Мышью кольцо не показываем, с клавиатуры — обязательно */
:focus:not(:focus-visible) {
  outline: none;
}

/* Цифры в данных — моноширинные по ширине, чтобы столбцы не плясали */
time,
[data-numeric] {
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   Служебное
   ============================================================ */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* fixed, а не absolute: страницу можно открыть по якорю уже прокрученной,
   и тогда absolute-ссылка всплывала бы за верхним краем экрана.
   z-index выше шапки — ссылка перекрывает её, а не прячется под ней. */
.skip-link {
  position: fixed;
  top: var(--space-8);
  left: var(--space-8);
  z-index: var(--z-skip-link);
  padding: var(--space-12) var(--space-20);
  background: var(--ink);
  color: var(--ink-inverse);
  border-radius: var(--radius-control);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  transform: translateY(-200%);
  transition: transform var(--duration-state) var(--ease-state);
}

.skip-link:focus {
  transform: translateY(0);
  color: var(--ink-inverse);
}

/* ---------- Раскладка ---------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow {
  max-width: calc(var(--container-narrow) + var(--gutter) * 2);
}

.section {
  padding-block: var(--section-gap);
}

/* Чередование полос: белая канва → холодная подложка */
.section--alt {
  background: var(--canvas-alt);
}

/* Мера строки для вводных абзацев */
.lead {
  font-size: var(--text-lead);
  font-weight: var(--weight-light);
  line-height: var(--lh-lead);
  color: var(--ink-body);
  max-width: var(--measure-lead);
}

/* Мono-лейбл — третий голос системы */
.label {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  line-height: var(--lh-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* ============================================================
   Наведение — только там, где указатель умеет наводить.

   Без этого условия тач-устройства залипают: после тапа браузер
   оставляет элемент в :hover до касания в другом месте. Замер на
   эмуляции тача показал 62.6% площади кнопки шапки в hover-цвете
   после обычного тапа и плитки, зависшие приподнятыми на 2px.
   Пользователь при этом ничего не наводил — он нажал и ушёл.

   Правила вынесены целиком, а не погашены обратными значениями:
   на тач-устройстве состояния наведения просто не существует,
   и описывать его, чтобы тут же отменить, значит держать в системе
   код, который ничего не делает.
   ============================================================ */
@media (hover: hover) {
  a:hover {
    color: var(--blue-deep);
    text-decoration-color: currentColor;
  }

  /* Ползунок — деталь хрома, а не текст: берём штриховой токен */
  ::-webkit-scrollbar-thumb:hover {
    background: var(--stroke-faint);
  }
}

/* ============================================================
   components.css — компоненты сайта.
   Только var() из tokens.css. Теней нет нигде, кроме залипшей шапки.
   Элевация выражается шагом цвета.
   ============================================================ */

/* ============================================================
   Шапка
   ============================================================ */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  /* Высота задана здесь, а не содержимым: граница входит внутрь
     --header-height (box-sizing: border-box), поэтому шапка занимает
     ровно те 64px, на которые отступает контент в base.css.
     Иначе граница добавила бы 65-й пиксель и якоря съехали бы на 1px. */
  height: var(--header-height);
  /* Граница постоянная, а не по скроллу: шапка стоит поверх иллюстраций
     и светлых секций, и её нижний край должен читаться всегда. */
  border-bottom: 1px solid var(--hairline);
  transition: box-shadow var(--duration-state) var(--ease-state);
}

/* Стекло вынесено в псевдоэлемент: контент шапки остаётся отдельным
   плоским слоем, а размытие применяется только к её подложке. */
.header::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Отрицательный слой — поверх фона шапки, но под её содержимым.
     Без него абсолютный псевдоэлемент закрасил бы логотип и навигацию. */
  z-index: var(--z-behind);
  /* Фолбэк для тех, у кого backdrop-filter нет (часть Firefox-сборок,
     режим экономии, старые вебвью): подложка почти непрозрачная,
     чтобы текст шапки читался поверх любой картинки без размытия. */
  background: color-mix(in srgb, var(--canvas) 94%, transparent);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header::before {
    /* С размытием подложка может быть легче: 78% канвы плюс blur дают
       на белом тексте секции контраст выше 4.5:1 у любого содержимого,
       которое проезжает под шапкой. */
    background: color-mix(in srgb, var(--canvas) 78%, transparent);
    backdrop-filter: blur(24px) saturate(1.6);
    -webkit-backdrop-filter: blur(24px) saturate(1.6);
  }
}

/* Единственная тень системы — признак отрыва от верха. Появляется
   по скроллу: у верха страницы отрывать шапку не от чего. */
.header[data-stuck="true"] {
  box-shadow: var(--shadow-sticky);
}

/* Под прокрученной шапкой едет контент, поэтому подложка уплотняется:
   на 78% сквозь стекло просвечивают тёмные плитки направлений. */
.header[data-stuck="true"]::before {
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-32);
  height: 100%;
}

.header__logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--tap-target);
  text-decoration: none;
  color: var(--ink);
  flex-shrink: 0;
}

.header__logo svg {
  flex-shrink: 0;
}

.header__wordmark {
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-right: auto;
}

.nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  padding: var(--space-8) var(--space-12);
  border-radius: var(--radius-control);
  color: var(--ink-body);
  font-size: 0.9375rem;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--duration-state) var(--ease-state),
    color var(--duration-state) var(--ease-state);
}

.nav__link[aria-current="page"] {
  color: var(--ink);
  background: var(--surface);
}

.header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  flex-shrink: 0;
}

/* ============================================================
   Кнопки.

   Одна система размеров на все варианты: высота, паддинги, кегль
   и слот иконки приходят из локальных переменных, а варианты меняют
   только их значения. Раньше .btn (14px паддинга) и .btn--sm (9px)
   задавали высоту случайными числами и не совпадали ни с чем.

   Состояний ровно шесть, и все обязательны:
   default · hover · focus-visible · active · disabled · loading.
   ============================================================ */

.btn {
  /* Высота с шага 4px: --space-48 = 48px, комфортная цель нажатия
     на телефоне (WCAG 2.2 SC 2.5.8 требует минимум 24, Apple/Google — 44). */
  --btn-height: var(--space-48);
  --btn-pad-y: var(--space-12);
  --btn-pad-x: var(--space-24);
  --btn-font: 1rem;
  /* Слот иконки. 18px — это размер стрелки из ui.mjs; индикатор загрузки
     обязан быть ровно таким же, иначе кнопка прыгает по ширине. */
  --btn-icon: 18px;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  /* min-height, а не height: на узком экране ярлык переносится
     в две строки, и кнопка должна вырасти, а не обрезать текст. */
  min-height: var(--btn-height);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  /* Рамка есть у всех вариантов, у заливных — прозрачная. Иначе
     secondary с рамкой был бы на 2px выше соседа в одном ряду. */
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font-size: var(--btn-font);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--duration-state) var(--ease-state),
    color var(--duration-state) var(--ease-state),
    border-color var(--duration-state) var(--ease-state),
    opacity var(--duration-state) var(--ease-state),
    transform var(--duration-state) var(--ease-state);
}

/* Компактная — плотные строки вроде шапки */
.btn--sm {
  --btn-height: var(--tap-target);
  --btn-pad-y: var(--space-8);
  --btn-pad-x: var(--space-16);
  --btn-font: 0.9375rem;
}

.btn--block {
  width: 100%;
}

.btn__arrow {
  transition: transform var(--duration-state) var(--ease-state);
}

/* ---------- Заливка вариантов (default) ---------- */

/* Единственная заливная кнопка в системе */
.btn--primary {
  background: var(--blue-ink);
  color: var(--ink-inverse);
}

.btn--secondary {
  background: transparent;
  color: var(--ink);
  border-color: var(--hairline);
}

/* На белом внутри цветной плитки */
.btn--onColor {
  background: var(--canvas);
  color: var(--ink);
}

/* Нажатие. Сдвиг делает transform, а не margin: раскладка не двигается,
   соседи не прыгают, перерасчёта макета нет. */
.btn:where(:not([disabled], [aria-disabled="true"], [data-loading])):active {
  transform: translateY(1px);
}

/* Затемнение поверх сдвига: на тач-устройствах hover не наступает,
   и нажатие обязано читаться само по себе. */
.btn--primary:where(:not([disabled], [aria-disabled="true"], [data-loading])):active {
  background: color-mix(in srgb, var(--blue-deep) 86%, var(--ink));
}

.btn--secondary:where(:not([disabled], [aria-disabled="true"], [data-loading])):active,
.btn--onColor:where(:not([disabled], [aria-disabled="true"], [data-loading])):active {
  background: var(--surface-hover);
}

/* ---------- focus-visible ----------
   Кольцо общее и приходит из base.css: 2px --focus-ring с отступом 3px.
   На белой канве и на --canvas-alt оно видно у всех вариантов, включая
   заливную синюю — кольцо лежит за границей кнопки, на фоне страницы.
   Исключение одно: белая кнопка на плитке направления. Там фон плитки
   и есть синий, и синее кольцо на нём исчезает — берём белое. */

.btn--onColor:focus-visible {
  outline-color: var(--ink-inverse);
}

/* ---------- disabled ----------
   У ссылки нет атрибута disabled, поэтому признака два. CSS может только
   показать неработоспособность: отменить переход по <a aria-disabled>
   обязан обработчик, разметке полагается ещё и tabindex="-1" либо
   preventDefault. Заливка уходит в серую поверхность, а не гасится
   прозрачностью: полупрозрачный синий всё ещё читается как рабочая кнопка. */

.btn[disabled],
.btn[aria-disabled="true"] {
  background: var(--surface);
  border-color: var(--hairline);
  color: var(--ink-muted);
  cursor: not-allowed;
  /* Страховка: если кнопку выключили в момент нажатия, она не должна
     остаться вдавленной. */
  transform: none;
}

/* Стрелка обещает переход, которого не будет, — гасим её вместе с текстом */
.btn[disabled] .btn__arrow,
.btn[aria-disabled="true"] .btn__arrow {
  opacity: 0.5;
}

/* ---------- loading ----------
   Ширина кнопки не меняется НИ У ОДНОГО варианта — это правило,
   а не пожелание: скачок кнопки дёргает всю строку вокруг неё.

   Индикатор выведен из потока и центрирован по кнопке, а содержимое
   гасится прозрачностью, сохраняя занимаемое место. Первая версия
   подставляла индикатор в слот стрелки — это работало на «Создать
   презентацию →», но кнопка шапки стрелки не имеет, и слот добавлялся
   к ширине: замер дал 143px → 169px. Отсюда правило: место под
   индикатор не добавляем, а берём у текста. */

.btn[data-loading] {
  position: relative;
  cursor: progress;
  /* Мышь гасим здесь. Активацию с клавиатуры снимает JS —
     ему же полагается выставить aria-busy="true". */
  pointer-events: none;
}

/* Содержимое остаётся в потоке и держит ширину, но не видно */
.btn[data-loading] > * {
  opacity: 0;
}

/* Подпись обёрнута в .btn__label в разметке, а не оставлена голым
   текстовым узлом. Голый текст можно погасить только через color
   у самой кнопки, а это война со специфичностью: вариант .btn--primary
   объявляет свой цвет и с равным весом побеждает по порядку.
   Элемент скрывается напрямую и предсказуемо — правило выше
   (.btn[data-loading] > *) уже его покрывает. */

.btn[data-loading]::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  margin: calc(var(--btn-icon) / -2) 0 0 calc(var(--btn-icon) / -2);
  width: var(--btn-icon);
  height: var(--btn-icon);
  border: 2px solid var(--btn-spinner, currentColor);
  /* Разрыв кольца — единственное, что делает вращение заметным */
  border-top-color: transparent;
  border-radius: var(--radius-pill);
  animation: btn-spin 0.7s linear infinite;
}

/* color: transparent гасит и currentColor у индикатора,
   поэтому каждому варианту цвет кольца задаётся явно. */
.btn--primary[data-loading] { --btn-spinner: var(--ink-inverse); }
.btn--secondary[data-loading],
.btn--onColor[data-loading] { --btn-spinner: var(--ink); }

@keyframes btn-spin {
  to {
    transform: rotate(1turn);
  }
}

/* При запрете движения убирается вращение, но не сам индикатор:
   иначе кнопка выглядит просто нажатой и молчащей. Кольцо становится
   сплошным и пульсирует прозрачностью — движения по кругу нет,
   сигнал «идёт работа» остаётся. */
@media (prefers-reduced-motion: reduce) {
  .btn[data-loading]::after {
    border-top-color: currentColor;
    animation: btn-pulse 1.4s ease-in-out infinite;
  }
}

@keyframes btn-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.3;
  }
}

/* ============================================================
   Бейдж-надзаголовок.
   Несёт факт, которого нет в заголовке, — не декоративный ярлык.
   ============================================================ */

.eyebrow {
  display: inline-block;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--blue-wash);
  color: var(--blue-ink);
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  line-height: 1.6;
  text-transform: uppercase;
}

/* ============================================================
   Хлебные крошки
   ============================================================ */

.breadcrumbs {
  padding-top: var(--space-20);
}

.breadcrumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8);
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.breadcrumbs__list li {
  max-width: none;
  margin-top: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
}

.breadcrumbs__list li + li::before {
  content: "/";
  color: var(--ink-subtle);
}

/* padding-block доводит зону нажатия с 22.4px до 30px: WCAG 2.2 SC 2.5.8
   требует 24×24. Ссылка проходила по исключению «интервал», то есть
   формально нарушения не было, но попадать пальцем в строку высотой
   22px на телефоне всё равно неудобно. */
.breadcrumbs a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  color: var(--ink-muted);
  text-decoration: none;
}

.breadcrumbs [aria-current="page"] {
  color: var(--ink-body);
}

/* ============================================================
   Первый экран
   ============================================================ */

.hero {
  padding-top: var(--space-32);
  padding-bottom: var(--space-40);
  background: linear-gradient(180deg, var(--canvas-alt) 0%, var(--canvas) 100%);
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  gap: var(--space-48);
  align-items: center;
}

/* Без min-width: 0 колонка грида не сжимается ниже min-content
   вложенного содержимого, и первый экран вылезает за узкий экран. */
.hero__copy,
.hero__media {
  min-width: 0;
}

.hero__media {
  position: relative;
  display: grid;
  align-items: center;
}

.hero__copy > * + * {
  margin-top: var(--space-20);
}

.hero__copy .eyebrow + .hero__title,
.taskbar + .hero__note {
  margin-top: var(--space-12);
}

.hero__title {
  font-size: var(--text-display);
  line-height: var(--lh-display);
  max-width: 16ch;
}

.hero__lead {
  font-size: var(--text-lead);
  font-weight: var(--weight-light);
  line-height: var(--lh-lead);
  color: var(--ink-body);
  max-width: var(--measure-lead);
}

.hero__benefits {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8) var(--space-16);
  padding: 0;
  list-style: none;
}

.hero__benefits li {
  display: flex;
  flex: 1 1 12rem;
  align-items: flex-start;
  gap: var(--space-8);
  max-width: none;
  color: var(--ink-body);
  font-size: var(--text-sm);
  line-height: 1.45;
}

.hero__benefits li + li {
  margin-top: 0;
}

.hero__benefit-icon {
  flex: 0 0 auto;
  margin-top: 0.15em;
  color: var(--blue-ink);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-12);
  padding-top: var(--space-8);
}

.hero__note {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  max-width: 44ch;
}

/* У каждого направления свой сгенерированный визуальный сюжет. Он не
   изображает интерфейс продукта и поэтому подписан как арт-концепция,
   а не как недоказанный скриншот результата. */
.hero-art {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  margin: 0;
  overflow: hidden;
  isolation: isolate;
  border: 1px solid color-mix(in srgb, var(--blue) 20%, var(--hairline));
  border-radius: var(--radius-tile);
  background: #0c101a;
  box-shadow:
    0 32px 80px color-mix(in srgb, var(--blue) 14%, transparent),
    0 2px 10px color-mix(in srgb, var(--ink) 10%, transparent);
}

.hero-art::before,
.hero-art::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
}

.hero-art::before {
  background:
    linear-gradient(135deg, color-mix(in srgb, #ffffff 16%, transparent), transparent 28%),
    radial-gradient(circle at 82% 14%, color-mix(in srgb, var(--blue) 18%, transparent), transparent 34%);
  mix-blend-mode: screen;
}

.hero-art::after {
  background: linear-gradient(180deg, transparent 52%, rgba(5, 9, 19, 0.84) 100%);
}

.hero-art__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-art__caption {
  position: absolute;
  z-index: 2;
  left: var(--space-24);
  right: var(--space-24);
  bottom: var(--space-24);
  display: grid;
  gap: var(--space-8);
  color: var(--ink-inverse);
}

.hero-art__label {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: color-mix(in srgb, var(--ink-inverse) 72%, transparent);
}

.hero-art__text {
  max-width: 30ch;
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
  line-height: 1.18;
  text-wrap: balance;
}

/* ============================================================
   Заголовок секции
   ============================================================ */

/* Ширина в rem, а не в ch: единица ch считается от шрифта самого
   элемента, а .section-head набран Inter 17px — заголовок Playfair 44px
   внутри такой коробки схлопывается втрое. */
.section-head {
  max-width: 34rem;
  margin-bottom: var(--head-gap);
}

.section-head--wide {
  max-width: 46rem;
}

.section-head__lead {
  margin-top: var(--space-12);
  font-size: var(--text-lead);
  font-weight: var(--weight-light);
  line-height: var(--lh-lead);
  color: var(--ink-body);
  max-width: var(--measure-lead);
}

/* ============================================================
   Плитки направлений.
   Цвет — единственный различитель. Шестая ячейка — панель CTA,
   она решает арифметику сетки из пяти и добавляет точку конверсии.
   ============================================================ */

.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap);
}

.tile {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--card-padding);
  min-height: 196px;
  border-radius: var(--radius-tile);
  color: var(--ink-inverse);
  text-decoration: none;
  transition: transform var(--duration-state) var(--ease-state),
    background var(--duration-state) var(--ease-state),
    border-color var(--duration-state) var(--ease-state);
}

.tile__title {
  font-family: var(--font-display);
  font-size: var(--text-h3);
  font-weight: var(--weight-display);
  line-height: var(--lh-h3);
  letter-spacing: var(--tracking-h3);
  color: var(--ink-inverse);
}

.tile__desc {
  font-size: 1rem;
  line-height: 1.5;
  /* Полностью белый, без подмешивания прозрачности. Приглушение до 82%
     роняло контраст до 3.66:1 на четырёх плитках из пяти — вторичность
     должна выражаться размером и весом, а не потерей читаемости. */
  color: var(--ink-inverse);
  max-width: 30ch;
}

.tile__go {
  margin-top: auto;
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-inverse);
}

.tile--deck { background: var(--m-deck); }
.tile--photo { background: var(--m-photo); }
.tile--text { background: var(--m-text); }
.tile--song { background: var(--m-song); }
.tile--video { background: var(--m-video); }

/* Шестая ячейка. Единственная без хроматики, чтобы не спорить с пятью цветными */
.tile--cta {
  background: var(--canvas);
  border: 1px solid var(--hairline);
  color: var(--ink);
  justify-content: space-between;
}

.tile--cta .tile__title {
  color: var(--ink);
}

.tile--cta .tile__desc {
  color: var(--ink-muted);
}

/* ============================================================
   Карточки возможностей
   ============================================================ */

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap);
}

.cards--two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.card {
  padding: var(--card-padding);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
}

.card__title {
  margin-bottom: var(--space-12);
}

.card__text {
  color: var(--ink-body);
  font-size: 1rem;
  line-height: 1.6;
}

/* ---------- Редакционный список вместо сетки карточек ----------
   Там, где пунктов много и они однородные, сетка одинаковых карточек
   читается как заглушка. Список с линейками — честнее и легче. */

.rows {
  border-top: 1px solid var(--hairline);
}

.row {
  display: grid;
  grid-template-columns: minmax(0, 20ch) minmax(0, 1fr);
  gap: var(--space-32);
  padding: var(--space-24) 0;
  border-bottom: 1px solid var(--hairline);
  align-items: baseline;
}

.row__term {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: var(--weight-display);
  color: var(--ink);
  letter-spacing: var(--tracking-h3);
}

.row__desc {
  color: var(--ink-body);
  font-size: 1rem;
  line-height: 1.6;
  margin: 0;
  /* Это <dd>, а общая мера в base.css висит на <p> и сюда не достаёт:
     без ограничения строка растягивалась до 101 знака на 1440. */
  max-width: var(--measure-body);
}

/* ============================================================
   Как это работает.
   Нумерация оставлена: порядок шагов несёт смысл, его нельзя переставить.
   ============================================================ */

.steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--hairline);
}

.step {
  padding: var(--space-24) var(--space-32) var(--space-8) 0;
  border-right: 1px solid var(--hairline);
}

.step:last-child {
  border-right: none;
}

.step:not(:first-child) {
  padding-left: var(--space-32);
}

.step__num {
  display: block;
  margin-bottom: var(--space-16);
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-subtle);
  font-variant-numeric: tabular-nums;
}

.step__title {
  margin-bottom: var(--space-12);
}

.step__text {
  color: var(--ink-body);
  font-size: 1rem;
  line-height: 1.6;
}

/* ============================================================
   Кому подходит
   ============================================================ */

.audience {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-32) var(--space-60);
}

.audience__item {
  padding-top: var(--space-20);
  border-top: 1px solid var(--hairline);
}

.audience__who {
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--ink);
  margin-bottom: var(--space-8);
  letter-spacing: var(--tracking-h3);
}

.audience__job {
  color: var(--ink-body);
  font-size: 1rem;
  line-height: 1.6;
}

/* ============================================================
   Перелинковка
   ============================================================ */

.crosslinks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap);
}

.crosslink {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding: var(--space-24);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  background: var(--canvas);
  text-decoration: none;
  transition: border-color var(--duration-state) var(--ease-state),
    background var(--duration-state) var(--ease-state);
}

.crosslink__reason {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.crosslink__to {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--ink);
  letter-spacing: var(--tracking-h3);
}

/* Метка направления перед анкором. Стоит в строке, а не бейджем над
   карточкой: набор одинаковых карточек «иконка сверху, заголовок, текст»
   это шаблон, а тут иконка выполняет работу указателя — сообщает, к
   какому из пяти направлений ведёт ссылка, до того как прочитан анкор.

   Цвет — ink, не хроматика модуля: DESIGN.md §10 запрещает цвет
   направления на мелких элементах, он живёт только на full-bleed плитках.
   На hover уходит в --blue-ink вместе с анкором, одним движением. */
.crosslink__icon {
  flex-shrink: 0;
  color: var(--ink-muted);
  transition: color var(--duration-state) var(--ease-state);
}

/* ============================================================
   FAQ. Открыт в разметке: контент должен быть виден роботу.
   ============================================================ */

.faq {
  border-top: 1px solid var(--hairline);
  max-width: calc(var(--measure-body) + 8ch);
}

.faq__item {
  border-bottom: 1px solid var(--hairline);
}

.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-24);
  padding: var(--space-24) 0;
  cursor: pointer;
  list-style: none;
  font-size: 1.0625rem;
  font-weight: var(--weight-medium);
  color: var(--ink);
  transition: color var(--duration-state) var(--ease-state);
}

.faq__q::-webkit-details-marker {
  display: none;
}

/* Знак «+/−» сообщает состояние, а не украшает, поэтому цвет текстовый:
   штриховой --stroke-faint дал бы 2.56:1 и провалил SC 1.4.11 (нужно 3:1). */
.faq__sign {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-top: 5px;
  position: relative;
  color: var(--ink-subtle);
}

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  background: currentColor;
  transition: transform var(--duration-state) var(--ease-state);
}

.faq__sign::before {
  top: 7.5px;
  left: 0;
  width: 16px;
  height: 1.5px;
}

.faq__sign::after {
  top: 0;
  left: 7.5px;
  width: 1.5px;
  height: 16px;
}

.faq__item[open] .faq__sign::after {
  transform: scaleY(0);
}

.faq__a {
  padding-bottom: var(--space-24);
  color: var(--ink-body);
  line-height: 1.7;
}

.faq__a p + p {
  margin-top: var(--space-12);
}

/* ============================================================
   Финальный призыв
   ============================================================ */

.final-cta {
  padding-block: var(--section-gap);
  background: var(--canvas-alt);
  border-top: 1px solid var(--hairline);
}

.final-cta__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-32);
}

.final-cta__title {
  font-size: var(--text-h2);
  max-width: 20ch;
}

.final-cta__text {
  margin-top: var(--space-12);
  color: var(--ink-body);
  max-width: 46ch;
}

/* ============================================================
   Подвал
   ============================================================ */

.footer {
  /* Вдвое компактнее прежнего: 60/40 под шесть ссылок давали
     полэкрана пустоты. */
  padding-block: var(--space-40) var(--space-32);
  background: var(--canvas);
  border-top: 1px solid var(--hairline);
}

/* Строка с переносом вместо колоночной сетки: колонки под шесть
   пунктов растягивали футер по вертикали и оставляли дыру
   между брендом и единственной колонкой ссылок. */
.footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-32) var(--space-60);
}

.footer__brand-block {
  min-width: 0;
}

.footer__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--tap-target);
  color: var(--ink);
  text-decoration: none;
}

.footer__tagline {
  margin-top: var(--space-8);
  font-size: var(--text-sm);
  color: var(--ink-muted);
  max-width: 34ch;
}

.footer__col {
  min-width: 0;
}

.footer__heading {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-subtle);
  margin-bottom: var(--space-12);
}

/* Ссылки в строку: пять коротких названий занимают одну строку
   вместо пяти и убирают основную высоту футера. */
.footer__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8) var(--space-20);
  list-style: none;
  padding: 0;
  margin: 0;
}

.footer__list li {
  max-width: none;
  margin-top: 0;
}

.footer__list a {
  color: var(--ink-body);
  font-size: 0.9375rem;
  text-decoration: none;
  /* Строка 18px по высоте — ниже минимума 24×24 (WCAG 2.2 SC 2.5.8).
     У строчного элемента вертикальный паддинг не двигает раскладку,
     но увеличивает зону нажатия: 18 + 4 + 4 = 26px. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
}

/* ============================================================
   Поле задачи в первом экране.
   Инструмент как герой — паттерн, выигрывающий во всех пяти
   кластерах. Генерации здесь нет: поле передаёт введённое
   в роут регистрации.
   ============================================================ */

.taskbar {
  display: flex;
  gap: var(--space-8);
  padding: var(--space-8);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  /* 16px, а не прежние 12px: промежуточных радиусов в системе нет,
     а 8px паддинга + 8px радиуса кнопки внутри дают ровно эту дугу. */
  border-radius: var(--radius-card);
  /* Ширину задаёт колонка первого экрана: своё ограничение отбирало
     у поля место и обрезало плейсхолдер кнопкой. */
  transition: border-color var(--duration-state) var(--ease-state);
}

/* Кольцо фокуса висит на обёртке, а не на input: поле и кнопка читаются
   как один элемент, и обводить надо их вместе. Текстовому полю браузер
   выдаёт :focus-visible даже по клику мышью, так что :focus-within
   срабатывает ровно тогда же. Смена цвета рамки одна индикатором быть
   не может — 1px и только оттенок. */
.taskbar:focus-within {
  border-color: var(--blue-ink);
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* Кольцо на обёртке нужно полю ввода — у него своего нет. Когда
   с клавиатуры доходят до кнопки, у неё появляется собственное кольцо,
   и второе вокруг всей строки читается как двойная рамка. */
.taskbar:has(.taskbar__submit:focus-visible) {
  outline: none;
}

.taskbar__input {
  flex: 1;
  min-width: 0;
  min-height: var(--tap-target);
  padding: 0 var(--space-12);
  border: none;
  background: none;
  font-size: 1rem;
  color: var(--ink);
}

.taskbar__input::placeholder {
  /* Плейсхолдер держит контраст 4.5:1 — не светлее --ink-muted */
  color: var(--ink-muted);
}

/* Своё кольцо у поля погашено намеренно: его несёт обёртка,
   иначе при фокусе получаются два кольца одно в другом. */
.taskbar__input:focus {
  outline: none;
}

.taskbar__submit {
  flex-shrink: 0;
}

.hero__secondary {
  font-size: 0.9375rem;
  color: var(--ink-body);
  text-decoration-color: var(--hairline);
}

/* Повторный призыв внутри секции */
.section__cta {
  margin-top: var(--space-32);
}

/* ============================================================
   Мелочи каркаса
   ============================================================ */

.nav__list {
  display: contents;
  list-style: none;
  margin: 0;
  padding: 0;
}

.tile__desc--block {
  display: block;
  margin-top: var(--space-12);
}

/* ============================================================
   Адаптив
   ============================================================ */

@media (max-width: 1024px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-32);
  }

  .hero__title {
    max-width: 18ch;
  }

  .hero-art {
    aspect-ratio: 16 / 9;
  }

}

@media (max-width: 900px) {
  .nav {
    display: none;
  }

  .header__inner {
    gap: var(--space-16);
    justify-content: space-between;
  }

  .header__actions {
    margin-left: auto;
  }

  .tiles,
  .cards,
  .crosslinks {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .steps {
    grid-template-columns: minmax(0, 1fr);
  }

  .step {
    padding: var(--space-24) 0;
    border-right: none;
    border-bottom: 1px solid var(--hairline);
  }

  .step:last-child {
    border-bottom: none;
  }

  .step:not(:first-child) {
    padding-left: 0;
  }
}

/* До 430px в шапке должны помещаться два сценария: вход и регистрация.
   Словесную марку убираем только визуально; aria-label сохраняет имя ссылки. */
@media (max-width: 430px) {
  .header__wordmark {
    display: none;
  }

  .header__inner {
    gap: var(--space-8);
  }

  .header__actions {
    gap: var(--space-4);
  }

  /* Высота цели остаётся 44px, сокращаются только горизонтальные поля. */
  .header__actions .btn--sm {
    --btn-pad-x: var(--space-12);
  }
}

@media (max-width: 640px) {
  .hero {
    padding-top: var(--space-24);
  }

  .hero-art {
    aspect-ratio: 4 / 3;
  }

  .hero-art__caption {
    left: var(--space-16);
    right: var(--space-16);
    bottom: var(--space-16);
  }

  .tiles,
  .cards,
  .cards--two,
  .crosslinks,
  .audience {
    grid-template-columns: minmax(0, 1fr);
  }

  .row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-8);
  }

  .footer__inner {
    gap: var(--space-24);
  }

  .hero__actions .btn {
    flex: 1 1 100%;
  }

  /* В строку поле и кнопка не помещаются: на «Создать презентацию»
     от поля остаётся пара символов. Складываем в колонку. */
  .taskbar {
    flex-direction: column;
  }

  .taskbar__input {
    padding: var(--space-8) var(--space-8);
  }

  .taskbar__submit {
    width: 100%;
  }

  /* Кнопка во всю ширину колонки: на 320px «Создать презентацию»
     занимала 262px из 264px — при nowrap следующий такой ярлык уже
     обрежется. Пусть лучше ляжет в две строки. */
  .taskbar__submit,
  .hero__actions .btn,
  .btn--block {
    white-space: normal;
  }

  .final-cta__inner {
    align-items: flex-start;
  }

  .tile {
    min-height: 0;
  }
}

/* ============================================================
   Сцена направления.

   Один визуальный якорь в середине дочерней страницы. До него
   середина полотна шла шестью текстовыми секциями подряд без
   единого изображения — на 8500px высоты это читается стеной.

   Стоит в блоке «Кому подходит», а не отдельной декоративной
   полосой: у полосы не было бы работы, кроме как занять место,
   а здесь сцена показывает результат направления рядом со
   списком тех, кому он нужен.

   Рамка сцены — граница действия запретов на градиенты и тени
   (DESIGN.md §8): внутри рисунка тональные переходы разрешены,
   снаружи поверхности остаются плоскими.
   ============================================================ */
.usecases__lead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
}

/* Заголовок секции внутри пары сбрасывает свой нижний отступ: расстояние
   до списка задаёт уже сама пара, иначе отступ складывается вдвое. */
.usecases__lead .section__head {
  margin-bottom: 0;
}

.scene {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-tile);
  /* 8:5 — пропорция viewBox всех пяти сцен. Держим её и снаружи: при
     другой высоте preserveAspectRatio добавит поля по бокам, и рамка
     перестанет совпадать с рисунком. Резерв места нужен до разбора SVG,
     иначе соседний столбец дёрнется при первой отрисовке. */
  aspect-ratio: 8 / 5;
}

/* На узком экране сцена уходит под заголовок и не спорит с ним за ширину:
   два столбца ниже 900px превращали и заголовок, и рисунок в кашу. */
@media (max-width: 900px) {
  .usecases__lead {
    grid-template-columns: minmax(0, 1fr);
  }

  .scene {
    max-width: 460px;
  }
}

/* ============================================================
   Зоны нажатия под палец.

   Запрос по указателю, а не по ширине: ширина не говорит о способе
   ввода. Ноутбук с тачскрином на 1440px нуждается в тех же зонах,
   что и телефон, а узкое окно на десктопе — нет. Мышиная раскладка
   ниже не меняется вообще: компактная шапка держится на 40px и
   остаётся такой.

   Порог. WCAG 2.2 SC 2.5.8 требует 24×24, и его сайт проходил и до
   этого блока — ни одной цели меньше нормы не было. 44×44 это
   рекомендация Apple HIG: не соответствие, а запас против промаха.
   Крупные элементы страницы (кнопки 48px, плитки 188px, вопросы FAQ
   75–102px) в запасе уже были — отставали только компактные варианты
   в шапке и подвале.

   Приём для марки и логотипа: зона растягивается псевдоэлементом,
   а не размерами. Раскладка шапки на 375px имеет около 28px свободы,
   и увеличение самого элемента до 44px её съедало бы — на 320px
   строка бы разъехалась. Наложение зоны раскладку не двигает.
   ============================================================ */
@media (pointer: coarse) {
  .header__actions .btn--sm {
    --btn-height: var(--tap-target);
  }

  /* Поле и кнопка отправки — одна строка ввода, ведут себя одинаково. */
  .taskbar__input {
    min-height: var(--tap-target);
  }

  /* Зона марки не меньше 44px даже при компактной высоте самой строки. */
  .header__logo,
  .footer__brand {
    position: relative;
  }

  .header__logo::after,
  .footer__brand::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    translate: -50% -50%;
    width: max(100%, var(--tap-target));
    height: var(--tap-target);
  }

  /* Ссылки подвала получают полную зону 44×44 px, включая короткие
     подписи «Фото» и «Текст». Между соседними целями остаётся gap 8px. */
  .footer__list a {
    padding-block: var(--space-12);
  }

  /* Крошки живут только на пяти дочерних страницах, поэтому на главной
     этой цели нет вовсе. Паддинг доводил зону до 30px — по норме, но
     «Главная» это путь назад, самая частая ссылка на странице. */
  .breadcrumbs a {
    padding-block: var(--space-12);
  }
}

/* ============================================================
   Наведение — только там, где указатель умеет наводить.

   Без этого условия тач-устройства залипают: после тапа браузер
   оставляет элемент в :hover до касания в другом месте. Замер на
   эмуляции тача показал 62.6% площади кнопки шапки в hover-цвете
   после обычного тапа и плитки, зависшие приподнятыми на 2px.
   Пользователь при этом ничего не наводил — он нажал и ушёл.

   Правила вынесены целиком, а не погашены обратными значениями:
   на тач-устройстве состояния наведения просто не существует,
   и описывать его, чтобы тут же отменить, значит держать в системе
   код, который ничего не делает.
   ============================================================ */
@media (hover: hover) {
  /* Логотип — ссылка на главную, и вести себя должен как ссылка.
     Прежнее правило задавало тот же --ink, что и базовое состояние:
     ноль изменённых пикселей на всех шести страницах, то есть кода
     было, а обратной связи не было. Уводим в цвет ссылок системы. */
  .header__logo:hover {
    color: var(--blue-ink);
  }

  /* Поле задачи не имело наведения совсем, хотя это самый крупный
     интерактивный элемент первого экрана. Подсвечиваем рамку всей
     строки ввода, а не самого input: визуально строка — один объект,
     и реагировать она должна целиком, как при :focus-within. */
  .taskbar:hover {
    border-color: var(--stroke-faint);
  }

  .nav__link:hover {
    background: var(--surface);
    color: var(--ink);
  }

  /* ---------- hover и active ----------
     Оба состояния снимаются с выключенной и с занятой кнопки одним
     и тем же фильтром. :where() не добавляет специфичности, поэтому
     правила остаются такими же «весомыми», как обычный .btn--x:hover,
     и порядок объявления ниже по файлу продолжает решать. */
  
  .btn:where(:not([disabled], [aria-disabled="true"], [data-loading])):hover .btn__arrow {
    transform: translateX(3px);
  }

  .btn--primary:where(:not([disabled], [aria-disabled="true"], [data-loading])):hover {
    background: var(--blue-deep);
    color: var(--ink-inverse);
  }

  .btn--secondary:where(:not([disabled], [aria-disabled="true"], [data-loading])):hover {
    background: var(--surface);
    border-color: var(--stroke-faint);
    color: var(--ink);
  }

  /* Белая кнопка на цветной плитке: шаг к --surface виден и на синей,
     и на пурпурной подложке, а --canvas-alt на них не читался вовсе. */
  .btn--onColor:where(:not([disabled], [aria-disabled="true"], [data-loading])):hover {
    background: var(--surface);
    color: var(--ink);
  }

  .breadcrumbs a:hover {
    color: var(--ink);
    text-decoration: underline;
  }

  .tile:hover {
    transform: translateY(-2px);
    color: var(--ink-inverse);
  }

  /* Рамка на hover — штрих, а не текст: тёмный --ink-subtle после
     затемнения токена читался бы как рамка ошибки. Заодно шаг фона,
     как у .crosslink: состояние не должно держаться на одной 1px-линии
     в 2.56:1 — элевация в системе выражается цветом. */
  .tile--cta:hover {
    transform: none;
    border-color: var(--stroke-faint);
    background: var(--canvas-alt);
    color: var(--ink);
  }

  /* Тот же случай: штрих, не буква */
  .crosslink:hover {
    border-color: var(--stroke-faint);
    background: var(--canvas-alt);
  }

  .crosslink:hover .crosslink__to {
    color: var(--blue-ink);
  }

  .crosslink:hover .crosslink__icon {
    color: var(--blue-ink);
  }

  .faq__q:hover {
    color: var(--blue-ink);
  }

  .footer__list a:hover {
    color: var(--ink);
    text-decoration: underline;
  }

  .hero__secondary:hover {
    color: var(--blue-ink);
  }
}

/* ============================================================
   demos.css — демонстрации продукта, собранные кодом.

   Реальных скриншотов продукта нет (см. PRODUCT.md → Evidence on Hand).
   Поэтому:
   • Слайды, текст и карточка трека рендерятся целиком и честно —
     их результат типографический, его можно показать как есть.
   • Фото и видео дают изобразительный результат. Подделать его
     нельзя, поэтому рисуется интерфейс инструмента, а место
     результата — плоская заливка цветом модуля с mono-меткой.
     Это очевидный слот, а не выдающий себя за реальность скриншот.

   Каждый слот заменяется реальным изображением заменой одного блока.
   Вес демонстраций — ноль байт, сдвига макета не дают.
   ============================================================ */

/* ---------- Общая рамка ---------- */

.demo {
  padding: var(--space-40);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-tile);
}

.demo__canvas {
  background: var(--canvas);
  border-radius: var(--radius-card);
  overflow: hidden;
}

/* Единственная надпись, лежащая прямо на подложке .demo, а не на белой
   карточке внутри неё. Остальной приглушённый текст демонстраций живёт
   на белом и обходится --ink-subtle. */
.demo__caption {
  margin-top: var(--space-16);
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-muted-surface);
}

/* Строка задачи — общая для всех демонстраций, где есть ввод */
.demo__prompt {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  padding: var(--space-12) var(--space-16);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-control);
  font-size: 0.9375rem;
  color: var(--ink-body);
}

.demo__prompt-label {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-subtle);
  flex-shrink: 0;
}

/* Текст задачи переносится, а не режется многоточием: формулировка —
   это и есть содержание демонстрации. Строка длиннее слота даже
   на 1920, поэтому nowrap + ellipsis прятал её на любом экране,
   а на 320 съедал до 71% фразы. Лучше две строки, чем «Кадр вышел…». */
.demo__prompt-text {
  min-width: 0;
  overflow-wrap: break-word;
}

/* ---------- Слой авторской графики ----------
   Нарисованные сцены вместо цветных заглушек. Каждая иллюстрация
   заполняет свою ячейку целиком, подпись лежит поверх. */

.art {
  display: block;
  width: 100%;
  height: 100%;
}

/* Обёртка picture не участвует в раскладке: сеткой и флексом
   управляет сама картинка, иначе обёртка ломает object-fit
   и заполнение ячейки. */
picture {
  display: contents;
}

img.art {
  object-fit: cover;
}

/* ---------- Обработка одного и того же снимка ----------
   Исходник намеренно тёмный. «До» — он же с приглушением,
   «после» — с вытянутыми тенями и восстановленным цветом.
   Один файл, два состояния: демонстрируется характер правки,
   а не подменяется картинка. */

.photo--raw {
  filter: brightness(0.58) saturate(0.45) contrast(0.86);
}

.photo--fixed {
  filter: brightness(1.22) saturate(1.28) contrast(1.06);
}

.photo--still {
  filter: grayscale(0.9) brightness(1.05) contrast(0.92);
}

/* Раскадровка: панорама по кадру плюс уходящий свет.
   Пять ячеек читаются как последовательность, а не как копии. */
/* Четыре варианта цветокоррекции одного снимка — то, что такой
   инструмент реально возвращает на выбор. */
.grade--0 { filter: brightness(1.2) saturate(1.45) sepia(0.18) hue-rotate(-8deg); }
.grade--1 { filter: brightness(1.16) saturate(1.15) hue-rotate(14deg); }
.grade--2 { filter: brightness(1.1) contrast(1.35) saturate(1.3); }
.grade--3 { filter: brightness(1.24) contrast(0.86) saturate(1.05); }

.frame--0 { object-position: 18% 50%; filter: brightness(1.24) saturate(1.3); }
.frame--1 { object-position: 33% 50%; filter: brightness(1.16) saturate(1.26); }
.frame--2 { object-position: 50% 50%; filter: brightness(1.08) saturate(1.22); }
.frame--3 { object-position: 67% 50%; filter: brightness(0.98) saturate(1.16); }
.frame--4 { object-position: 82% 50%; filter: brightness(0.88) saturate(1.1); }

/* min-width обязателен всюду, где у ячейки есть aspect-ratio: при
   автоминимуме браузер выводит ШИРИНУ из высоты содержимого, и ячейка
   раздувается за пределы колонки — та же болезнь, что была у слайда. */
.art-cell {
  position: relative;
  margin: 0;
  min-width: 0;
  overflow: hidden;
  border-radius: var(--radius-control);
  background: var(--surface-hover);
  line-height: 0;
}

/* Подпись поверх иллюстрации. Тёмная подложка держит контраст
   на любой сцене — от светлого неба до тёмного холма. */
/* Подпись не может быть шире своей ячейки: ячейка режет по overflow,
   и «Контрастнее» превращалось в «КОНТР». Отступ слева сохраняем,
   правым полем жертвуем раньше, чем читаемостью; если и этого мало —
   подпись переносится по словам и растёт вверх от нижнего края. */
.art__tag {
  position: absolute;
  left: 8px;
  bottom: 8px;
  max-width: calc(100% - 8px);
  overflow-wrap: break-word;
  padding: 3px 7px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--ink) 62%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0.08em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--ink-inverse);
}

/* «До» на снимке: слабее по обеим осям — и подложка легче, и текст мягче.
   Контраст от этого не страдает, кадр «до» намеренно тёмный. */
.art__tag--dim {
  background: color-mix(in srgb, var(--ink) 45%, transparent);
  color: color-mix(in srgb, var(--ink-inverse) 82%, transparent);
}

/* ============================================================
   1. Презентации — каскад слайдов.
   Результат типографический, показан целиком.
   ============================================================ */

.deck {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.32fr);
  gap: var(--space-12);
}

.slide {
  /* width обязателен: без него aspect-ratio при нехватке высоты
     считает ШИРИНУ из высоты содержимого, и слайд раздувается
     за пределы контейнера. Ширину задаёт колонка, высоту — пропорция. */
  width: 100%;
  min-width: 0;
  aspect-ratio: 16 / 10;
  padding: var(--space-24);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  container-type: inline-size;
}

.slide__rule {
  width: 40px;
  height: 3px;
  border-radius: 2px;
  background: var(--m-deck);
  flex-shrink: 0;
}

/* Заголовки внутри демонстраций — не заголовки документа.
   Это содержимое изображения, поэтому они размечены как <p>:
   иначе после H1 первого экрана шёл бы H3 и ломал иерархию. */
.slide__title {
  font-family: var(--font-display);
  font-size: clamp(1rem, 2.6cqi, 1.5rem);
  line-height: 1.15;
  color: var(--ink);
  letter-spacing: -0.01em;
  max-width: none;
}

.slide__bullets {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.slide__bullets li {
  position: relative;
  padding-left: 14px;
  margin-top: 0;
  max-width: none;
  font-size: clamp(0.625rem, 1.5cqi, 0.8125rem);
  line-height: 1.45;
  color: var(--ink-body);
}

.slide__bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px;
  height: 1.5px;
  background: var(--ink-subtle);
}

.slide__foot {
  margin-top: auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-subtle);
}

.deck__thumbs {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.thumb {
  flex: 1;
  padding: var(--space-12);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-control);
  display: flex;
  flex-direction: column;
  gap: 6px;
  justify-content: center;
}

.thumb__bar {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-hover);
}

.thumb__bar--head {
  height: 6px;
  width: 55%;
  background: var(--ink-subtle);
}

.thumb__bar--short {
  width: 70%;
}

/* ============================================================
   2. Фото — интерфейс инструмента.
   Результат изобразительный: показан интерфейс, места
   изображений — заливки цветом модуля.
   ============================================================ */

.photo-tool {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--space-16);
}

.photo-tool__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Перенос внутри пилюли не запрещаем: строка ряда обычная, поэтому
   пилюля ломается только тогда, когда одна не влезает в ряд целиком.
   С nowrap она в этом случае вылезала за поле и обрезалась. */
.chip {
  max-width: 100%;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--hairline);
  background: var(--canvas);
  font-size: 0.75rem;
  color: var(--ink-muted);
}

.chip[data-active="true"] {
  background: var(--blue-wash);
  border-color: transparent;
  color: var(--blue-ink);
}

/* Колонок столько, сколько влезает, а не всегда четыре: подпись варианта
   («Контрастнее») требует ~105px, а четыре колонки на телефоне давали 48px
   и резали её до «КОНТР». Ниже ~520px сетка сама уходит в три и две
   колонки — вариантов видно столько же, но каждый читается. */
.photo-tool__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: var(--space-8);
}

.photo-tool__grid .art-cell {
  aspect-ratio: 1 / 1;
}

/* Полоса «до и после» */
/* minmax(0, 1fr) вместо 1fr: обычный 1fr не даёт колонке уехать ниже
   минимума содержимого, и половина с фотографией распирала полосу. */
.beforeafter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  border-radius: var(--radius-control);
  overflow: hidden;
}

.beforeafter__half {
  position: relative;
  width: 100%;
  min-width: 0;
  aspect-ratio: 2 / 1;
  line-height: 0;
}

/* Стык половин: тонкая светлая линия вместо рамки вокруг всего */
.beforeafter__half:last-child::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 2px;
  background: var(--canvas);
  z-index: var(--z-local);
}

/* ============================================================
   3. Текст — результат показан целиком и честно.
   ============================================================ */

.text-out {
  padding: var(--space-24);
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
}

.text-out__doc {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.text-out__h {
  font-family: var(--font-display);
  font-size: 1.375rem;
  line-height: 1.2;
  color: var(--ink);
  letter-spacing: -0.01em;
  max-width: none;
}

.text-out__sub {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--ink-subtle);
}

.text-out__p {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--ink-body);
  max-width: none;
}

.text-out__list {
  padding-left: 1.1em;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--ink-body);
}

.text-out__list li {
  max-width: none;
}

.text-out__list li + li {
  margin-top: 4px;
}

/* Каретка — единственный намёк на то, что текст пишется */
.caret {
  display: inline-block;
  width: 2px;
  height: 1em;
  vertical-align: -0.15em;
  margin-left: 2px;
  background: var(--blue-ink);
  animation: caret-blink 1.1s steps(1, end) infinite;
}

@keyframes caret-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .caret {
    animation: none;
  }
}

/* ============================================================
   4. Песни — карточка трека.
   Waveform это данные, а не изображение: рисуется честно.
   ============================================================ */

.track {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--space-20);
  padding: var(--space-20);
  align-items: center;
}

.track__cover {
  min-width: 0;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-control);
  overflow: hidden;
  line-height: 0;
}

.track__body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.track__title {
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--ink);
  letter-spacing: -0.01em;
}

.track__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.track__player {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  margin-top: var(--space-4);
}

.track__play {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--m-song);
  color: var(--ink-inverse);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.wave {
  flex: 1;
  min-width: 0;
  height: 34px;
  display: block;
  color: var(--m-song);
}

.track__time {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--ink-subtle);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   5. Видео — кадр и раскадровка.
   ============================================================ */

.video-out {
  padding: var(--space-16);
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.video-out__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius-control);
  line-height: 0;
}

.video-out__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--canvas) 92%, transparent);
  color: var(--m-video);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.video-out__strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}

.video-out__strip .art-cell {
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  opacity: 0.55;
  transition: opacity var(--duration-state) var(--ease-state);
}

/* Текущий кадр читается яркостью, а не рамкой */
.video-out__strip .art-cell[data-current="true"] {
  opacity: 1;
}

/* Связка «фото → кадр ролика» */
/* Стрелка занимает свою ширину, кадры делят остальное и умеют сжиматься:
   с голым 1fr колонка держалась за минимум содержимого кадра. */
.morph {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-12);
}

.morph__arrow {
  color: var(--ink-subtle);
}

.morph .art-cell {
  aspect-ratio: 4 / 3;
}

/* ============================================================
   6. Главная — мозаика из пяти результатов.
   Показывает, а не ведёт: навигацию несут плитки ниже.
   ============================================================ */

.mosaic {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--space-8);
  padding: var(--space-16);
}

.mosaic__cell {
  border-radius: var(--radius-control);
  overflow: hidden;
  border: 1px solid var(--hairline);
  background: var(--canvas);
  display: flex;
  flex-direction: column;
  min-height: 108px;
}

/* Первая ячейка крупнее: она задаёт масштаб чтения мозаики */
.mosaic__cell--wide {
  grid-column: span 2;
}

.mosaic__head {
  padding: 8px 10px;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: var(--weight-medium);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-subtle);
  border-bottom: 1px solid var(--hairline);
}

.mosaic__body {
  flex: 1;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  justify-content: center;
}

/* Ячейки с типографическим результатом показывают настоящий мелкий
   текст, а не серые полосы: скрывать в них нечего. */
.mosaic__title {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  line-height: 1.2;
  color: var(--ink);
  letter-spacing: -0.01em;
  max-width: none;
}

.mosaic__bullets {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.mosaic__bullets li {
  position: relative;
  padding-left: 9px;
  margin-top: 0;
  max-width: none;
  font-size: 0.5rem;
  line-height: 1.5;
  color: var(--ink-muted);
}

.mosaic__bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 4px;
  height: 1px;
  background: var(--cell-accent, var(--ink-subtle));
}

.mosaic__body-text {
  font-size: 0.5rem;
  line-height: 1.55;
  color: var(--ink-muted);
  max-width: none;
}

.mosaic__line {
  height: 4px;
  border-radius: 2px;
  background: var(--surface-hover);
}

/* Заглавная линия в цвете модуля: ячейка читается как миниатюра
   конкретного направления, а не как скелетон загрузки. */
.mosaic__line--head {
  height: 7px;
  width: 60%;
  background: var(--cell-accent, var(--ink-subtle));
}

.mosaic__head {
  color: var(--cell-accent, var(--ink-subtle));
}

.mosaic__line--short { width: 72%; }
.mosaic__line--mid { width: 88%; }

.mosaic__fill {
  flex: 1;
  min-height: 40px;
  border-radius: 5px;
  overflow: hidden;
  line-height: 0;
}

.mosaic__cover {
  display: block;
  width: 34px;
  height: 34px;
  border-radius: 4px;
  overflow: hidden;
  line-height: 0;
}

.mosaic__wave {
  width: 100%;
  height: 22px;
  display: block;
  color: var(--m-song);
}

/* ============================================================
   Единственный авторский момент движения на сайте:
   демонстрация собирается при загрузке первого экрана.
   Секции при скролле не анимируются — одинаковый въезд на каждой
   секции это не движение, а шум.
   ============================================================ */

@media (prefers-reduced-motion: no-preference) {
  .demo[data-animate] .slide,
  .demo[data-animate] .thumb,
  .demo[data-animate] .photo-tool__grid .slot,
  .demo[data-animate] .video-out__strip .slot,
  .demo[data-animate] .mosaic__cell,
  .demo[data-animate] .beforeafter {
    animation: demo-in 0.7s cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }

  .demo[data-animate] .thumb:nth-child(1) { animation-delay: 0.08s; }
  .demo[data-animate] .thumb:nth-child(2) { animation-delay: 0.14s; }
  .demo[data-animate] .photo-tool__grid .slot:nth-child(1) { animation-delay: 0.04s; }
  .demo[data-animate] .photo-tool__grid .slot:nth-child(2) { animation-delay: 0.1s; }
  .demo[data-animate] .photo-tool__grid .slot:nth-child(3) { animation-delay: 0.16s; }
  .demo[data-animate] .photo-tool__grid .slot:nth-child(4) { animation-delay: 0.22s; }
  .demo[data-animate] .video-out__strip .slot:nth-child(1) { animation-delay: 0.06s; }
  .demo[data-animate] .video-out__strip .slot:nth-child(2) { animation-delay: 0.11s; }
  .demo[data-animate] .video-out__strip .slot:nth-child(3) { animation-delay: 0.16s; }
  .demo[data-animate] .video-out__strip .slot:nth-child(4) { animation-delay: 0.21s; }
  .demo[data-animate] .video-out__strip .slot:nth-child(5) { animation-delay: 0.26s; }
  .demo[data-animate] .mosaic__cell:nth-child(2) { animation-delay: 0.06s; }
  .demo[data-animate] .mosaic__cell:nth-child(3) { animation-delay: 0.12s; }
  .demo[data-animate] .mosaic__cell:nth-child(4) { animation-delay: 0.18s; }
  .demo[data-animate] .mosaic__cell:nth-child(5) { animation-delay: 0.24s; }

  @keyframes demo-in {
    from {
      opacity: 0;
      transform: translateY(10px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }
}

/* ============================================================
   Адаптив демонстраций.
   При нехватке ширины демонстрация упрощается, а не сжимается
   целиком до нечитаемости.
   ============================================================ */

@media (max-width: 640px) {
  .demo {
    padding: var(--space-16);
  }

  /* Лейбл встаёт над строкой задачи: в две колонки на телефоне тексту
     оставалось 119px из 400 нужных, а сам по себе он короткий. */
  .demo__prompt {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
  }

  /* У слайдов пропадают миниатюры — крупный слайд важнее */
  .deck {
    grid-template-columns: minmax(0, 1fr);
  }

  /* На узком экране пропорция 16:10 сжимает слайд в щель, куда текст
     не влезает. Отпускаем высоту: пусть слайд будет по содержимому. */
  .slide {
    aspect-ratio: auto;
    min-height: 260px;
  }

  .deck__thumbs {
    display: none;
  }

  /* Вариантов на телефоне меньше в ряд и они крупнее (см. auto-fit выше).
     Квадрат при этом уступает пропорции самого снимка: на 100px кадр 1:1
     обрезан до неузнаваемости, а 3:2 показывает сцену и экономит высоту. */
  .photo-tool__grid .art-cell {
    aspect-ratio: 3 / 2;
  }

  /* У видео пропадает раскадровка */
  .video-out__strip {
    display: none;
  }

  /* Зазор между «было» и «стало» отдаём кадрам: подписи внутри них
     длиннее самих кадров, каждые 4px ширины идут в дело. */
  .morph {
    gap: var(--space-8);
  }

  /* В две колонки карточка трека на телефоне зажимается: теги встают
     по одному в строку. Обложка уезжает на свою строку. */
  .track {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-16);
  }

  .track__cover {
    width: 72px;
  }

  /* Мозаика с шести ячеек уходит на две колонки */
  .mosaic {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto;
  }

  .mosaic__cell--wide {
    grid-column: span 2;
  }
}

/* ---------- Самые узкие телефоны ----------
   Ниже 360px парные кадры перестают вмещать собственные подписи:
   половина полосы «до и после» тут 107px при подписи в 116px, кадр
   в связке «было → стало» — 90px при подписи в 89px. Подпись накрывала
   кадр целиком и ломалась надвое. Освобождаем ширину: пара встаёт
   в столбик, декоративная стрелка уходит. Содержательное не прячем —
   подписи демонстраций обещают и коррекцию, и варианты. */

@media (max-width: 360px) {
  .beforeafter {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Стык из вертикального становится горизонтальным вместе с раскладкой */
  .beforeafter__half:last-child::before {
    inset: 0 0 auto 0;
    width: auto;
    height: 2px;
  }

  /* Стрелка между «было» и «стало» декоративна (aria-hidden), а её колонка
     стоит 30px из 214: без неё подпись «Стало видео» встаёт в строку вместо
     двух ярусов поверх кадра. Направление держат сами подписи. */
  .morph {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .morph__arrow {
    display: none;
  }
}
