/* ============================================================
   NEWWEB — ожившая айдентика
   N = дверь. Лиза создаёт. Гоша соединяет.
   Линии связывают. Скролл — путешествие внутри одного мира.

   Палитра зафиксирована брендбордом: графит + молочный + медь.
   ============================================================ */

:root {
  /* пространство — тёплый уголь, не нейтральный графит:
     подтон уведён в медь (R > B), поэтому рендеры и свечение
     садятся в фон, а не спорят с ним холодной синевой */
  --void: #060404;        /* глубина сцены */
  --bg: #090706;          /* базовый уголь */
  --bg-2: #0F0C0A;        /* приподнятая плоскость */
  --bg-3: #150F0D;        /* панель */

  /* песочный — для светлых секций-пауз */
  --sand: #F3EDE6;

  /* вертикальный ритм секций — один на весь сайт, эталон hero (80px) */
  --pad-sec: clamp(56px, 7vw, 92px);
  --sand-2: #EBE2D8;
  --sand-panel: #FFFDFA;
  --sand-ink: #1A1310;
  --sand-ink-70: rgba(36, 28, 24, .72);
  --sand-line: rgba(138, 86, 72, .18);

  /* свет */
  --ink: #F1ECE7;
  --ink-70: rgba(241, 236, 231, .70);
  --ink-45: rgba(241, 236, 231, .45);
  --ink-25: rgba(241, 236, 231, .25);

  /* медь — металл, отражение, внутреннее свечение */
  --cu: #C98F86;
  --cu-hi: #E9BCA9;
  --cu-deep: #8A5648;
  --cu-line: rgba(201, 143, 134, .32);
  --cu-soft: rgba(201, 143, 134, .12);
  --glow: rgba(233, 188, 169, .55);

  --font-sans: 'Golos Text', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;
  --font-hand: 'Caveat', cursive;
}

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

html {
  scroll-behavior: smooth;
  /* режим «десктоп в масштабе» на телефоне (viewport 980 в index.html):
     без этого iOS Safari самовольно раздувает отдельные абзацы
     (font boosting) и ломает десктопную раскладку */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html { overflow-x: clip; }   /* страница не ездит вбок: ауры .halo шире
                                вьюпорта по замыслу (свет), но их выпуск
                                за край не должен давать горизонтальный
                                скролл — замер 27.08.2026: документ был
                                743px при вьюпорте 390 */
body {
  overflow-x: clip;
  /* базовый уголь; сам свет живёт в ::before отдельным слоем */
  background: #090706;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* не плоская чернота: крупные мягкие медные ауры + вертикальный градиент.
   ВАЖНО: раньше это был background-attachment: fixed на body — браузер
   перерисовывал весь градиент на каждом кадре прокрутки и сайт тормозил.
   Отдельный fixed-слой уезжает на GPU и рисуется один раз. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(1400px 1000px at 15% 8%, rgba(201, 143, 134, .055), rgba(201, 143, 134, .04) 13.6%, rgba(201, 143, 134, .0295) 23.8%, rgba(201, 143, 134, .0211) 32.64%, rgba(201, 143, 134, .0144) 40.8%, rgba(201, 143, 134, .0092) 47.6%, rgba(201, 143, 134, .0055) 53.72%, rgba(201, 143, 134, .0029) 58.48%, rgba(201, 143, 134, .0013) 62.56%, rgba(201, 143, 134, .0004) 65.28%, rgba(201, 143, 134, 0) 68%),
    radial-gradient(1200px 1100px at 85% 42%, rgba(138, 86, 72, .05), rgba(138, 86, 72, .0364) 14%, rgba(138, 86, 72, .0269) 24.5%, rgba(138, 86, 72, .0192) 33.6%, rgba(138, 86, 72, .0131) 42%, rgba(138, 86, 72, .0084) 49%, rgba(138, 86, 72, .005) 55.3%, rgba(138, 86, 72, .0027) 60.2%, rgba(138, 86, 72, .0011) 64.4%, rgba(138, 86, 72, .0004) 67.2%, rgba(138, 86, 72, 0) 70%),
    radial-gradient(1100px 900px at 40% 88%, rgba(201, 143, 134, .04), rgba(201, 143, 134, .0291) 13.6%, rgba(201, 143, 134, .0215) 23.8%, rgba(201, 143, 134, .0153) 32.64%, rgba(201, 143, 134, .0104) 40.8%, rgba(201, 143, 134, .0067) 47.6%, rgba(201, 143, 134, .004) 53.72%, rgba(201, 143, 134, .0021) 58.48%, rgba(201, 143, 134, .0009) 62.56%, rgba(201, 143, 134, .0003) 65.28%, rgba(201, 143, 134, 0) 68%),
    /* низ страницы сведён к var(--void) #060404 — тем же цветом, что
       заливка .finale и футера. Раньше фон кончался на #090706 и под
       футером просвечивал светлее его на 1.6 пункта: футер читался
       вставленной плитой (26.08.2026) */
    linear-gradient(180deg, #080605 0%, #0A0807 28%, #0C0908 58%, #0A0807 74%, #080605 88%, #070505 95%, #060404 100%);
}


img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }

:focus-visible { outline: 2px solid var(--cu); outline-offset: 4px; border-radius: 2px; }
::selection { background: rgba(201, 143, 134, .3); color: var(--ink); }

.skip-link {
  position: absolute; left: 50%; top: 0;
  transform: translate(-50%, -130%);
  z-index: 300;
  background: var(--bg-3); color: var(--ink);
  border: 1px solid var(--cu-line);
  border-radius: 0 0 10px 10px;
  padding: .9em 1.7em; font-size: .9rem;
  transition: transform .25s;
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

.wrap {
  max-width: 1400px;
  margin-inline: auto;
  padding-inline: clamp(18px, 4vw, 60px);
}
/* главы услуг идут от кромки экрана, как hero и «Процесс» (25.08.2026):
   в контейнере 1400px у них были поля ~200px, и они читались «вставкой»
   рядом с первыми двумя блоками, у которых текст стоит в 60px от края */
.wrap--full { max-width: none; width: 100%; }

/* ============================================================
   ТИПОГРАФИКА — крупная, с характером
   ============================================================ */

h1, h2, h3 { font-weight: 600; line-height: 1.05; letter-spacing: -.035em; }

/* заголовок-плакат: занимает экран, а не строку */
.mega {
  /* плакатный масштаб: кегль крупный, интерлиньяж плотнее высоты букв —
     строки смыкаются в единый блок (приём с эталонного сайта 22.08.2026) */
  font-size: clamp(2.9rem, 8.2vw, 8.4rem);
  font-weight: 800;
  line-height: .84;
  letter-spacing: -.05em;
  text-transform: uppercase;
}

.big { font-size: clamp(2.4rem, 7vw, 6.6rem); font-weight: 700; line-height: .88; letter-spacing: -.045em; }
.mid { font-size: clamp(1.7rem, 3.6vw, 3.2rem); font-weight: 600; line-height: 1.05; letter-spacing: -.02em; }

.cu { color: var(--cu); }
.outline {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--cu);
  paint-order: stroke fill;
}

.tag {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--cu);
}

/* спокойный вспомогательный текст: контраст с крупными заголовками
   строится на разнице масштабов, поэтому кегль держим скромным */
.body { color: var(--ink-70); font-size: clamp(.95rem, 1.05vw, 1.06rem); line-height: 1.62; max-width: 44ch; }


/* ============================================================
   КНОПКИ — физическое ощущение
   ============================================================ */

.btn {
  position: relative;
  display: inline-flex; align-items: center; gap: .7em;
  padding: 1.05em 2.1em;
  border-radius: 100px;
  font-weight: 500; font-size: .95rem;
  white-space: nowrap;
  min-height: 48px;
  transition: transform .4s cubic-bezier(.22,1,.36,1), box-shadow .4s;
}

.btn-main {
  background: linear-gradient(135deg, #F0CBB8 0%, var(--cu) 52%, var(--cu-deep) 100%);
  color: #180E0B;
  box-shadow: 0 0 0 1px rgba(240, 203, 184, .3), 0 10px 34px -14px var(--glow);
}
.btn-main:hover { transform: translateY(-3px) scale(1.02); box-shadow: 0 0 0 1px rgba(240,203,184,.5), 0 20px 46px -16px var(--glow); }
.btn-main:active { transform: translateY(-1px) scale(.99); }

.btn-line {
  color: var(--ink);
  border: 1px solid var(--cu-line);
  background: rgba(22, 24, 29, .5);
  backdrop-filter: blur(8px);
}
.btn-line:hover { border-color: var(--cu); transform: translateY(-3px); }

.btn .ar { transition: transform .4s cubic-bezier(.22,1,.36,1); }
.btn:hover .ar { transform: translateX(5px); }

/* ============================================================
   НАВИГАЦИЯ
   ============================================================ */

.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 200;
  transition: background .5s, border-color .5s;
  border-bottom: 1px solid transparent;
}
.nav.stuck {
  background: rgba(10, 11, 14, .78);
  backdrop-filter: blur(20px);
  border-bottom-color: rgba(241, 236, 231, .07);
}
/* ШАПКА — ТРИ ЗОНЫ НА ОДНОЙ ОСИ (26.08.2026, Георгий: «вся шапка криво
   стоит, сделай ровной»). Было: space-between + margin-left у nav —
   зазоры плясали от ширины экрана (77…96px), кнопка на 1600 вылезала
   за край. Стало: бренд | меню (растягивается, центрируется) | контакты.
   Все три зоны на одной вертикальной оси через align-items: center,
   а зазоры между зонами — один clamp, а не сумма разных margin */
.nav-in {
  display: flex; align-items: center;
  gap: clamp(1.6rem, 3vw, 3.4rem);
  height: 80px;
  /* ДЕФИЦИТ МЕСТА (замер 26.08.2026): меню требует 768px, а в контейнере
     .wrap 1400px после логотипа (122), контактов (385) и зазоров (109)
     остаётся 665 — не хватало 103px, и пункты выпирали на соседей.
     Шапка идёт от кромки окна, как hero: ширины хватает без ужимания */
  max-width: none;
  padding-inline: clamp(18px, 3vw, 46px);
}
/* меню забирает свободное место и стоит по центру своей зоны */
/* ЗОНА МЕНЮ (26.08.2026, две ловушки подряд):
   1) justify-content: center в сжатой зоне выталкивает содержимое за ОБА
      края — меню наезжало на логотип (gap -42);
   2) margin-inline: auto у списка растягивал его в зону контактов —
      телефон оказывался поверх «СТОИМОСТЬ».
   Правильно: зона НЕ сжимается (flex-shrink 0) и просто отдаёт остаток
   места соседям, а список стоит по своему левому краю. */
/* ГЛАВНАЯ ЛОВУШКА (26.08.2026): элемент <nav> — блочный контейнер, он
   растягивался ШИРЕ своего списка, и его невидимые поля наезжали на
   контакты — телефон рисовался поверх «О НАС», хотя зазор между
   .nav-links и .nav-act по замеру был положительным.
   width: max-content прижимает зону ровно к содержимому. */
.nav-in > nav { flex: 0 1 auto; display: flex; justify-content: center; min-width: 0; width: max-content; }
.nav-in > nav .nav-links { max-width: 100%; }
/* бренд и контакты не сжимаются — иначе кнопка обрезается краем */
.nav-in > .brand, .nav-in > .nav-act { flex: 0 0 auto; }
/* остаток места делится поровну слева и справа от меню */
.nav-in > nav { margin-inline: auto; }

.brand { display: inline-flex; align-items: center; min-height: 44px; gap: .7rem; font-weight: 600; font-size: 1.1rem; }
.brand img { width: 24px; height: 34px; object-fit: contain; filter: brightness(1.5); }
.brand .sp { color: var(--cu); font-size: .75em; transform: translateY(-.5em); display: inline-block; }
/* ЗВЁЗДОЧКА В ШАПКЕ = КАК В ФУТЕРЕ (26.08.2026, Георгий: «возьми пример
   с нижнего NewWeb»). Замер футера: font-size .75em, надстрочная
   (translateY(-.5em) по baseline — центр на .29em выше центра текста),
   без margin. Отдельное правило снято, шапка наследует базовое
   .brand .sp — оно уже даёт ровно эти значения */

.nav-links { display: flex; gap: clamp(.9rem, 1.7vw, 2rem); list-style: none; flex-wrap: nowrap; }
.nav-links a {
  display: inline-flex; align-items: center; min-height: 44px;
  font-size: .75rem; font-weight: 500; letter-spacing: .13em; text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink-45); transition: color .3s;
}
.nav-links a:hover, .nav-links a.on { color: var(--ink); }
/* ТЕЛЕФОН В ШАПКЕ (26.08.2026): стоит слева от кнопки, в одном ряду
   с разделами. Кегль близок к пунктам меню, но БЕЗ капса и разрядки —
   номер должен читаться номером, а не восьмым разделом; тон светлее
   (.7 против .45 у разделов), потому что это прямой контакт.
   Табличные цифры — группы номера стоят ровным строем */
/* блок контактов отделён от меню воздухом и тонкой медной чертой:
   при равных зазорах номер читался восьмым пунктом навигации */
.nav-act {
  display: flex; align-items: center;
  gap: clamp(.9rem, 1.6vw, 1.6rem);
  margin-left: clamp(.6rem, 1.4vw, 1.4rem);
  padding-left: clamp(1rem, 1.8vw, 1.8rem);
  position: relative;
}
.nav-act::before {
  content: ''; position: absolute; left: 0; top: 50%;
  width: 1px; height: 20px; margin-top: -10px;
  background: linear-gradient(180deg, rgba(201,143,134,0), var(--cu-line), rgba(201,143,134,0));
}
@media (max-width: 1560px) { .nav-act { margin-left: 0; padding-left: 0; } .nav-act::before { display: none; } }
.nav-tel {
  display: inline-flex; align-items: center; gap: .5em;
  min-height: 44px;
  font-size: .88rem; font-weight: 500;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  white-space: nowrap;
  color: var(--ink-70);
  transition: color .3s;
}
.nav-tel svg {
  flex: none; width: 1.05em; height: 1.05em;
  fill: none; stroke: var(--cu); stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
  transition: stroke .3s;
}
.nav-tel:hover { color: var(--ink); }
.nav-tel:hover svg { stroke: var(--cu-hi); }
/* ПОРОГ 1560px (замер): кнопка «Обсудить проект» обрезалась правым
   краем — на 1440 выходила на 1445, а после отступа меню и на 1500
   (1540 при экране 1500). Пороги 1240 / 1420 / 1460 не спасали.
   вылезала за правый край экрана — шапка не помещалась. Номер уходит
   первым, меню и кнопка остаются */
@media (max-width: 1560px) { .nav-tel { display: none; } }

/* ВАЖНО: у .btn стоит min-height: 48px, поэтому вертикальный padding
   в шапке НЕ РАБОТАЛ — высоту диктовал min-height, а боковой padding
   остался рассчитан на несуществующую вертикаль. Кнопка выходила
   приплюснутой: отношение боковой_padding/высота = 0.42 против 0.64
   у эталонной .btn в секциях.
   Высота 44px взята не произвольно — это min-height ссылок нава, так
   кнопка встаёт с ними в один оптический ряд (и это минимум тач-цели).
   При шапке 80px даёт поля по 18px сверху и снизу. */
.nav .btn {
  min-height: 44px;
  padding: 0 1.95em;
  font-size: .85rem;
}

.burger { display: none; width: 44px; height: 44px; position: relative; z-index: 202; }
.burger span { position: absolute; left: 10px; right: 10px; height: 1.6px; background: var(--ink); transition: transform .4s, opacity .3s; }
.burger span:nth-child(1) { top: 16px; }
.burger span:nth-child(2) { top: 22px; }
.burger span:nth-child(3) { top: 28px; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.sheet {
  position: fixed; inset: 0; z-index: 201;
  background: rgba(7, 8, 10, .97); backdrop-filter: blur(24px);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1rem;
  opacity: 0; visibility: hidden; transition: opacity .45s, visibility .45s;
}
.sheet.open { opacity: 1; visibility: visible; }
.sheet a { display: inline-flex; align-items: center; min-height: 52px; font-size: 1.7rem; font-weight: 600; color: var(--ink-70); }
.sheet a:hover { color: var(--cu); }

/* ============================================================
   СЦЕНА — общий контейнер эпизодов мира
   ============================================================ */

section[id] { scroll-margin-top: 84px; }

.scene { position: relative; overflow-x: clip; }
/* .hero и #journey держат .halo шире экрана — им тоже нужна отсечка */
.hero { overflow-x: clip; }

/* световое пятно сцены.
   blur(70px) на шести элементах пересчитывался при каждом кадре
   прокрутки — тот же мягкий край даёт многоступенчатый градиент,
   но уже без фильтра, поэтому слой просто композитится на GPU */
/* ВАЖНО (22.08.2026): свечение гасится в ТОТ ЖЕ цвет с нулевой альфой,
   а не в `transparent` — последний равен rgba(0,0,0,0), прозрачному
   ЧЁРНОМУ, и переход к нему идёт через сероватую зону.
   НЕ РАБОТАЕТ (проверено, откачено): растягивать затухание до 100%
   радиуса — пятно становится вдвое шире и читается светлым КРУГОМ
   на пол-экрана; шумовой дизеринг поверх (body::after / .halo::after) —
   зерно ложится ровным прямоугольником на весь вьюпорт и портит фон.
   blur(70px) тоже нельзя — пересчёт на каждом кадре прокрутки. */
.halo {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  /* Элементы увеличены в 1.32x (см. closest-side ниже): градиент теперь
     кончается на границе круга, а не на 71% — свет надо было вернуть.
     Компенсируем размером, а не альфой, иначе ядро стало бы вдвое ярче.
     Отрицательные margin держат ЦЕНТР пятна на прежнем месте: проценты
     в left/top считаются от разной ширины секций, пиксели надёжнее. */
  margin: -12% 0 0 -12%;
  /* НАСТОЯЩАЯ ПРИЧИНА КОНТУРА (найдена 22.08.2026):
     `radial-gradient(circle, ...)` БЕЗ указания размера растягивается до
     farthest-corner — для квадрата 900x900 это 636px, а `border-radius: 50%`
     обрезает элемент на 450px. То есть видимый край круга приходился на
     71% градиента, где альфа ещё ~5 уровней из 255 — и обрывалась в ноль
     мгновенно. Никакая правка стопов этого не лечит: резал сам border-radius.
     `closest-side` доводит градиент ровно до границы круга, поэтому на
     краю альфа уже честный ноль и обрезать нечего. */
  background: radial-gradient(circle closest-side,
    var(--cu-soft) 0%, rgba(201,143,134,.0874) 20%, rgba(201,143,134,.0644) 35%,
    rgba(201,143,134,.046) 48%, rgba(201,143,134,.0313) 60%,
    rgba(201,143,134,.0202) 70%, rgba(201,143,134,.012) 79%,
    rgba(201,143,134,.0064) 86%, rgba(201,143,134,.0028) 92%,
    rgba(201,143,134,.0009) 96%, rgba(201,143,134,0) 100%);
  z-index: 0;
}

/* поле частиц со связями — сквозная тема сайта (js/main.js -> fieldNet).
   ОДНО поле на всю страницу, фиксированное во вьюпорте: посекционные
   canvas обрезались по границам секций и на стыках была видна склейка.
   z-index: -1 — под контентом, но поверх фона body::before. */
.net-field {
  position: fixed;
  inset: 0;
  width: 100vw; height: 100vh;
  /* -1 — под контентом; body::before (фон) стоит на -2, иначе
     при равном z-index порядок зависел бы от разметки */
  z-index: -1;
  pointer-events: none;
}

/* ── БЕГУЩАЯ СТРОКА ─────────────────────────────────────────
   Стоит в самом верху #acts, маскирует стык с hero.
   Лента продублирована в разметке ровно дважды: трек едет на -50%,
   то есть ровно на длину одной копии — шов не виден никогда.
   Края растворяются маской, чтобы текст не обрывался о край экрана. */
.ticker {
  position: relative;
  z-index: 1;
  margin-bottom: clamp(.6rem, 1.4vh, 1.2rem);
  padding: clamp(.7rem, 1.5vh, 1.1rem) 0;
  overflow: hidden;
  border-block: 1px solid rgba(201, 143, 134, .16);
  background: linear-gradient(90deg,
    rgba(201,143,134,.045), rgba(201,143,134,.09) 50%, rgba(201,143,134,.045));
  -webkit-mask-image: linear-gradient(90deg,
    transparent, #000 9%, #000 91%, transparent);
  mask-image: linear-gradient(90deg,
    transparent, #000 9%, #000 91%, transparent);
}
.ticker-track {
  display: flex;
  width: max-content;
  animation: tickerRun 38s linear infinite;
}
.ticker-row {
  display: flex; align-items: center; gap: clamp(1.4rem, 3vw, 2.6rem);
  padding-right: clamp(1.4rem, 3vw, 2.6rem);
  white-space: nowrap;
}
.ticker-row b {
  font-family: var(--font-mono);
  font-size: clamp(.72rem, 1vw, .86rem);
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-70);
}
.ticker-row i {
  font-style: normal;
  color: var(--cu);
  opacity: .55;
}
@keyframes tickerRun {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* НЕ добавлять паузу по наведению (:hover -> animation-play-state:
   paused): лента идёт под шапкой во всю ширину, курсор попадает на неё
   мимоходом при движении к меню — движение дёргалось без намерения
   пользователя. Строка декоративная (aria-hidden), читать её не нужно. */

/* провода, идущие сквозь секции */
.wires { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; overflow: visible; }
.wire { fill: none; stroke: var(--cu); stroke-width: 1.4; opacity: .5; }
.wire-glow { fill: none; stroke: var(--cu-hi); stroke-width: 3; opacity: .18; filter: blur(4px); }
.node { fill: var(--cu-hi); filter: drop-shadow(0 0 8px var(--glow)); }

/* фигуры персонажей */

/* hero: светящиеся неоновые персонажи и кабель */
.hero-actors .wire { stroke: #F0BE9C; stroke-width: 2; opacity: .95; }
.hero-actors .node { fill: #FFE9CF; }
.hero-actors .plug { fill: #0F1013; stroke: #F0BE9C; stroke-width: 1.5; }

/* плавающие UI-объекты */
/* стили окна интерфейса (.ui-*) удалены 22.08.2026 вместе с консолью в hero */
.chip { fill: rgba(16, 18, 22, .95); stroke: var(--cu-line); stroke-width: 1.1; }
.chip-on { stroke: var(--cu); filter: drop-shadow(0 0 10px rgba(201,143,134,.35)); }
.mono-t { font-family: var(--font-mono); fill: var(--ink-70); letter-spacing: .1em; }

/* ============================================================
   HERO — сложная композиция, N в центре мира
   ============================================================ */

.hero {
  position: relative;
  /* svh — «малая» высота вьюпорта: на десктопе экран выше, и снизу
     выглядывал край следующей секции. dvh занимает реальную высоту */
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: 80px;
  padding-bottom: 24px;
  display: grid;
  align-items: center;
  overflow: hidden;
}

/* общее фотозерно: рендер и векторная графика становятся одним материалом */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  opacity: .055;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

.hero-stage { position: relative; width: 100%; }

/* На десктопе портал живёт внутри SVG (#portal) — в одной системе координат
   с фигурами и проводами. Этот <img> показывается только на мобильных. */
.portal { display: none; }

.portal-floor {
  position: absolute;
  left: 64%; top: 74%;
  transform: translate(-50%, 0);
  width: min(96vw, 1500px);
  height: 240px;
  background:
    radial-gradient(ellipse 34% 44% at 56% 42%, rgba(255, 217, 184, .22), rgba(255, 217, 184, .1602) 14%, rgba(255, 217, 184, .1181) 24.5%, rgba(255, 217, 184, .0843) 33.6%, rgba(255, 217, 184, .0574) 42%, rgba(255, 217, 184, .037) 49%, rgba(255, 217, 184, .022) 55.3%, rgba(255, 217, 184, .0117) 60.2%, rgba(255, 217, 184, .0051) 64.4%, rgba(255, 217, 184, .0016) 67.2%, rgba(255, 217, 184, 0) 70%),
    radial-gradient(ellipse 50% 50% at 50% 50%, rgba(233, 188, 169, .14), rgba(233, 188, 169, .1019) 14.4%, rgba(233, 188, 169, .0752) 25.2%, rgba(233, 188, 169, .0536) 34.56%, rgba(233, 188, 169, .0365) 43.2%, rgba(233, 188, 169, .0235) 50.4%, rgba(233, 188, 169, .014) 56.88%, rgba(233, 188, 169, .0074) 61.92%, rgba(233, 188, 169, .0032) 66.24%, rgba(233, 188, 169, .0011) 69.12%, rgba(233, 188, 169, 0) 72%);
  filter: blur(22px);
  pointer-events: none;
  z-index: 0;
}

/* текст поверх и вокруг портала — интегрирован в композицию */
.hero-copy { position: relative; z-index: 3; max-width: min(52%, 640px); }
/* УТП держит первый экран: крупно, но так, чтобы блок с кнопками
   влезал целиком и строки не доходили до портала */
/* ВАЖНО: это правило перебивает .mega — кегль hero задаётся здесь.
   Плакатный масштаб + плотный интерлиньяж (эталон 22.08.2026) */
.hero-h1 {
  font-size: clamp(2.1rem, 4.4vw, 4.4rem);
  letter-spacing: -.045em;
  /* .86 перекрывал строки на 10px: пять строк с Й, ё и запятыми
     не помещаются в интерлиньяж меньше кегля */
  line-height: 1.05;
}
.hero-h1 .outline { -webkit-text-stroke-width: 1.4px; }
/* «решить» — развязка фразы: залитая медь + свет из щели портала */
.solve { text-shadow: 0 0 28px rgba(201,143,134,.45), 0 0 6px rgba(201,143,134,.3); }
.hero-copy .tag { display: block; margin-bottom: 1.25rem; }
.hero-copy h1 { margin-bottom: 1.5rem; }
.hero-copy .body { margin-bottom: 2.1rem; }
.hero-cta { display: flex; gap: 1.2rem; flex-wrap: wrap; align-items: center; }

/* На десктопе Лиза и Гоша живут внутри SVG (#duoFigures) — в одной системе
   координат с проводами, поэтому связка не разъезжается при любой ширине.
   Этот <img> — только мобильный вариант. */
.duo-actors { display: none; }

/* слой персонажей и объектов hero */
.hero-actors { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.hero-actors svg { width: 100%; height: 100%; overflow: visible; }

/* подписи-аннотации, привязанные к объектам */
.note { position: absolute; z-index: 4; pointer-events: none; }

/* ============================================================
   СЕКЦИИ
   ============================================================ */

/* ЕДИНЫЙ ВЕРТИКАЛЬНЫЙ РИТМ (26.08.2026, Георгий: «слишком большое
   расстояние между краями блоков, привести к одному стандарту, стандарт
   взять из первого блока»). Эталон — hero: padding-top 80px. Было три
   разных ритма: .sec 90–180px, #sites/#apps 64–120px, у отдельных секций
   свои — отсюда пустые полуэкраны. Теперь один токен --pad-sec на все
   секции; частные переопределения оставлены только там, где секция
   технически не может жить по общему ритму (#journey с липкой 3D-сценой,
   #acts с бегущей строкой). */
.sec { position: relative; padding-block: var(--pad-sec); }

/* ── АТМОСФЕРА СЕКЦИЙ ───────────────────────────────────────
   Фон не чередуется заливками (рендеры живут на прозрачном
   свечении и на плашке гаснут) — вместо этого у каждой сцены
   своя температура и своя точка света. Скролл читается как
   путь: темнота у портала → свет разливается → вдох на ценах
   → тёплая медная ночь на финале.
   Слой строго под контентом и не ловит курсор. */
.scene::before {
  content: '';
  position: absolute;
  /* аура выходит далеко за границы секции и гаснет по краям через
     mask — свет соседних сцен перетекает друг в друга, поэтому
     стык не читается как «конец одного блока, начало другого».
     Раньше было inset: -10% 0 — пятно обрывалось ровно на границе */
  /* Слой сильно выше и ниже секции, а гашение — по всей его высоте
     плавной кривой. Тогда на самой границе секции аура ещё в силе и
     совпадает с аурой соседа, а гаснет она далеко за кадром, где
     перепад уже не читается как линия. */
  inset: -60% 0;
  z-index: 0; pointer-events: none;
  opacity: 1;
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,.02) 8%, rgba(0,0,0,.08) 16%, rgba(0,0,0,.2) 24%,
    rgba(0,0,0,.38) 32%, rgba(0,0,0,.6) 40%, rgba(0,0,0,.82) 46%, #000 50%,
    rgba(0,0,0,.82) 54%, rgba(0,0,0,.6) 60%, rgba(0,0,0,.38) 68%,
    rgba(0,0,0,.2) 76%, rgba(0,0,0,.08) 84%, rgba(0,0,0,.02) 92%, transparent 100%);
  mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,.02) 8%, rgba(0,0,0,.08) 16%, rgba(0,0,0,.2) 24%,
    rgba(0,0,0,.38) 32%, rgba(0,0,0,.6) 40%, rgba(0,0,0,.82) 46%, #000 50%,
    rgba(0,0,0,.82) 54%, rgba(0,0,0,.6) 60%, rgba(0,0,0,.38) 68%,
    rgba(0,0,0,.2) 76%, rgba(0,0,0,.08) 84%, rgba(0,0,0,.02) 92%, transparent 100%);
}

/* у портала — плотнее и глуше, свет только из щели.
   затемнение снизу мягче, иначе низ кадра проваливается в чёрное */
#top::before {
  background:
    radial-gradient(85% 70% at 50% 42%, rgba(201, 143, 134, .051), rgba(201, 143, 134, .0371) 14.8%, rgba(201, 143, 134, .0274) 25.9%, rgba(201, 143, 134, .0195) 35.52%, rgba(201, 143, 134, .0133) 44.4%, rgba(201, 143, 134, .0086) 51.8%, rgba(201, 143, 134, .0051) 58.46%, rgba(201, 143, 134, .0027) 63.64%, rgba(201, 143, 134, .0012) 68.08%, rgba(201, 143, 134, .0004) 71.04%, rgba(201, 143, 134, 0) 74%),
    radial-gradient(60% 50% at 12% 75%, rgba(138, 86, 72, .042), rgba(138, 86, 72, .0306) 14%, rgba(138, 86, 72, .0226) 24.5%, rgba(138, 86, 72, .0161) 33.6%, rgba(138, 86, 72, .011) 42%, rgba(138, 86, 72, .0071) 49%, rgba(138, 86, 72, .0042) 55.3%, rgba(138, 86, 72, .0022) 60.2%, rgba(138, 86, 72, .001) 64.4%, rgba(138, 86, 72, .0003) 67.2%, rgba(138, 86, 72, 0) 70%),
    radial-gradient(120% 80% at 50% 125%, rgba(8, 6, 5, .151), rgba(8, 6, 5, .1099) 12.4%, rgba(8, 6, 5, .0811) 21.7%, rgba(8, 6, 5, .0578) 29.76%, rgba(8, 6, 5, .0394) 37.2%, rgba(8, 6, 5, .0254) 43.4%, rgba(8, 6, 5, .0151) 48.98%, rgba(8, 6, 5, .008) 53.32%, rgba(8, 6, 5, .0035) 57.04%, rgba(8, 6, 5, .0011) 59.52%, rgba(8, 6, 5, 0) 62%);
}
/* «что мы делаем» — свет ушёл влево, справа тёплый добор */
#acts::before {
  background:
    radial-gradient(80% 70% at 8% 26%, rgba(201, 143, 134, .055), rgba(201, 143, 134, .04) 14.4%, rgba(201, 143, 134, .0295) 25.2%, rgba(201, 143, 134, .0211) 34.56%, rgba(201, 143, 134, .0144) 43.2%, rgba(201, 143, 134, .0092) 50.4%, rgba(201, 143, 134, .0055) 56.88%, rgba(201, 143, 134, .0029) 61.92%, rgba(201, 143, 134, .0013) 66.24%, rgba(201, 143, 134, .0004) 69.12%, rgba(201, 143, 134, 0) 72%),
    radial-gradient(65% 55% at 100% 82%, rgba(138, 86, 72, .042), rgba(138, 86, 72, .0306) 14%, rgba(138, 86, 72, .0226) 24.5%, rgba(138, 86, 72, .0161) 33.6%, rgba(138, 86, 72, .011) 42%, rgba(138, 86, 72, .0071) 49%, rgba(138, 86, 72, .0042) 55.3%, rgba(138, 86, 72, .0022) 60.2%, rgba(138, 86, 72, .001) 64.4%, rgba(138, 86, 72, .0003) 67.2%, rgba(138, 86, 72, 0) 70%);
}
/* процесс — тёплая полоса вдоль пути, шире по краям */
/* ВАЖНО: точка света уведена ВЛЕВО, под пару. Было `at 50% 50%` —
   центральное пятно светило в пустой центр между картинкой и текстом,
   а сама пара оставалась на голом фоне и выглядела плоской.
   Плотность поднята до уровня соседних секций (было .055/.032) */
#journey::before {
  background:
    radial-gradient(72% 62% at 26% 42%, rgba(201, 143, 134, .062), rgba(201, 143, 134, .0451) 14.4%, rgba(201, 143, 134, .0333) 25.2%, rgba(201, 143, 134, .0237) 34.56%, rgba(201, 143, 134, .0162) 43.2%, rgba(201, 143, 134, .0104) 50.4%, rgba(201, 143, 134, .0062) 56.88%, rgba(201, 143, 134, .0033) 61.92%, rgba(201, 143, 134, .0014) 66.24%, rgba(201, 143, 134, .0005) 69.12%, rgba(201, 143, 134, 0) 72%),
    radial-gradient(80% 55% at 72% 28%, rgba(138, 86, 72, .042), rgba(138, 86, 72, .0306) 14.8%, rgba(138, 86, 72, .0226) 25.9%, rgba(138, 86, 72, .0161) 35.52%, rgba(138, 86, 72, .011) 44.4%, rgba(138, 86, 72, .0071) 51.8%, rgba(138, 86, 72, .0042) 58.46%, rgba(138, 86, 72, .0022) 63.64%, rgba(138, 86, 72, .001) 68.08%, rgba(138, 86, 72, .0003) 71.04%, rgba(138, 86, 72, 0) 74%);
}
/* сайты — свет справа, зеркально предыдущей */
#sites::before {
  background:
    radial-gradient(78% 70% at 94% 30%, rgba(201, 143, 134, .055), rgba(201, 143, 134, .04) 14.4%, rgba(201, 143, 134, .0295) 25.2%, rgba(201, 143, 134, .0211) 34.56%, rgba(201, 143, 134, .0144) 43.2%, rgba(201, 143, 134, .0092) 50.4%, rgba(201, 143, 134, .0055) 56.88%, rgba(201, 143, 134, .0029) 61.92%, rgba(201, 143, 134, .0013) 66.24%, rgba(201, 143, 134, .0004) 69.12%, rgba(201, 143, 134, 0) 72%),
    radial-gradient(60% 55% at 0% 85%, rgba(138, 86, 72, .038), rgba(138, 86, 72, .0277) 14%, rgba(138, 86, 72, .0204) 24.5%, rgba(138, 86, 72, .0146) 33.6%, rgba(138, 86, 72, .0099) 42%, rgba(138, 86, 72, .0064) 49%, rgba(138, 86, 72, .0038) 55.3%, rgba(138, 86, 72, .002) 60.2%, rgba(138, 86, 72, .0009) 64.4%, rgba(138, 86, 72, .0003) 67.2%, rgba(138, 86, 72, 0) 70%);
}
/* слои и цепочка — глубже под 3D, но края подсвечены,
   чтобы «глубина» не читалась как дыра */
/* глубина этих сцен теперь целиком в ауре: слой растянут за границы
   и погашен маской, поэтому темнота не обрывается на стыке */
#layers::before,
#chain::before {
  background:
    /* «Автоматизация» — самая глубокая из трёх глав (26.08.2026, ритм
       «тепло → ярче → глубже»): затемнение по центру поднято .15 → .26 */
    radial-gradient(120% 60% at 50% 50%, rgba(6, 5, 4, .26), rgba(6, 5, 4, .1893) 14.4%, rgba(6, 5, 4, .1396) 25.2%, rgba(6, 5, 4, .0995) 34.56%, rgba(6, 5, 4, .0678) 43.2%, rgba(6, 5, 4, .0437) 50.4%, rgba(6, 5, 4, .026) 56.88%, rgba(6, 5, 4, .0138) 61.92%, rgba(6, 5, 4, .006) 66.24%, rgba(6, 5, 4, .0019) 69.12%, rgba(6, 5, 4, 0) 72%),
    radial-gradient(95% 75% at 50% 50%, rgba(138, 86, 72, .048), rgba(138, 86, 72, .0349) 14.8%, rgba(138, 86, 72, .0258) 25.9%, rgba(138, 86, 72, .0184) 35.52%, rgba(138, 86, 72, .0125) 44.4%, rgba(138, 86, 72, .0081) 51.8%, rgba(138, 86, 72, .0048) 58.46%, rgba(138, 86, 72, .0025) 63.64%, rgba(138, 86, 72, .0011) 68.08%, rgba(138, 86, 72, .0004) 71.04%, rgba(138, 86, 72, 0) 74%),
    radial-gradient(50% 60% at 2% 30%, rgba(201, 143, 134, .035), rgba(201, 143, 134, .0255) 13.6%, rgba(201, 143, 134, .0188) 23.8%, rgba(201, 143, 134, .0134) 32.64%, rgba(201, 143, 134, .0091) 40.8%, rgba(201, 143, 134, .0059) 47.6%, rgba(201, 143, 134, .0035) 53.72%, rgba(201, 143, 134, .0019) 58.48%, rgba(201, 143, 134, .0008) 62.56%, rgba(201, 143, 134, .0003) 65.28%, rgba(201, 143, 134, 0) 68%),
    radial-gradient(50% 60% at 98% 70%, rgba(201, 143, 134, .032), rgba(201, 143, 134, .0233) 13.6%, rgba(201, 143, 134, .0172) 23.8%, rgba(201, 143, 134, .0123) 32.64%, rgba(201, 143, 134, .0084) 40.8%, rgba(201, 143, 134, .0054) 47.6%, rgba(201, 143, 134, .0032) 53.72%, rgba(201, 143, 134, .0017) 58.48%, rgba(201, 143, 134, .0007) 62.56%, rgba(201, 143, 134, .0002) 65.28%, rgba(201, 143, 134, 0) 68%);
}
/* приложения — снова влево, ритм качается */
#apps::before {
  /* СВЕТЛАЯ ГЛАВА (26.08.2026): вместо тёмной ауры — тёплый румянец
     за сценой поверх песка, гаснет в прозрачность */
  background:
    radial-gradient(62% 58% at 30% 46%, rgba(201, 143, 134, .16), rgba(201, 143, 134, .1165) 14%, rgba(201, 143, 134, .0859) 24.5%, rgba(201, 143, 134, .0613) 33.6%, rgba(201, 143, 134, .0418) 42%, rgba(201, 143, 134, .0269) 49%, rgba(201, 143, 134, .016) 55.3%, rgba(201, 143, 134, .0085) 60.2%, rgba(201, 143, 134, .0037) 64.4%, rgba(201, 143, 134, .0012) 67.2%, rgba(201, 143, 134, 0) 70%);
  opacity: .8;
}
/* пара — тёмный акцент, зажатый между двумя светлыми паузами
   (#pricing до и #cases после): самый тёплый кадр на сайте */
#duo::before {
  background:
    radial-gradient(70% 65% at 26% 38%, rgba(201, 143, 134, .061), rgba(201, 143, 134, .0444) 14.4%, rgba(201, 143, 134, .0328) 25.2%, rgba(201, 143, 134, .0234) 34.56%, rgba(201, 143, 134, .0159) 43.2%, rgba(201, 143, 134, .0102) 50.4%, rgba(201, 143, 134, .0061) 56.88%, rgba(201, 143, 134, .0032) 61.92%, rgba(201, 143, 134, .0014) 66.24%, rgba(201, 143, 134, .0005) 69.12%, rgba(201, 143, 134, 0) 72%),
    radial-gradient(70% 65% at 74% 38%, rgba(233, 188, 169, .045), rgba(233, 188, 169, .0328) 14.4%, rgba(233, 188, 169, .0242) 25.2%, rgba(233, 188, 169, .0172) 34.56%, rgba(233, 188, 169, .0117) 43.2%, rgba(233, 188, 169, .0076) 50.4%, rgba(233, 188, 169, .0045) 56.88%, rgba(233, 188, 169, .0024) 61.92%, rgba(233, 188, 169, .001) 66.24%, rgba(233, 188, 169, .0003) 69.12%, rgba(233, 188, 169, 0) 72%),
    radial-gradient(90% 50% at 50% 100%, rgba(138, 86, 72, .042), rgba(138, 86, 72, .0306) 14%, rgba(138, 86, 72, .0226) 24.5%, rgba(138, 86, 72, .0161) 33.6%, rgba(138, 86, 72, .011) 42%, rgba(138, 86, 72, .0071) 49%, rgba(138, 86, 72, .0042) 55.3%, rgba(138, 86, 72, .0022) 60.2%, rgba(138, 86, 72, .001) 64.4%, rgba(138, 86, 72, .0003) 67.2%, rgba(138, 86, 72, 0) 70%);
}
/* кейсы — вторая светлая пауза: портфолио читается как разворот
   каталога. Здесь только скриншоты работ в карточках, свечения
   по прозрачному фону нет — светлый фон ничего не гасит */
#cases::before {
  background: radial-gradient(80% 45% at 50% 0%, rgba(255, 253, 250, .094), rgba(255, 253, 250, .0684) 12.4%, rgba(255, 253, 250, .0505) 21.7%, rgba(255, 253, 250, .036) 29.76%, rgba(255, 253, 250, .0245) 37.2%, rgba(255, 253, 250, .0158) 43.4%, rgba(255, 253, 250, .0094) 48.98%, rgba(255, 253, 250, .005) 53.32%, rgba(255, 253, 250, .0022) 57.04%, rgba(255, 253, 250, .0007) 59.52%, rgba(255, 253, 250, 0) 62%);
  opacity: .55;
}
/* финал — дверь распахнута; само свечение из щели живёт
   в .finale::before ниже, здесь только тёплый ореол вокруг */
#finale::after {
  content: '';
  /* ГРАНИЦА БЫЛА ВИДНА (26.08.2026, Георгий: «тут есть переход и его
     видно, убери»). Слой ореола светлее фона, а его край обрывался
     резко — на стыке с «О нас» читался горизонтальной линией. Растянут
     дальше за секцию и погашен по краям маской, как .scene::before.
     НИЗ ПРИЖАТ К ГРАНИЦЕ (26.08.2026): при inset -45% ореол свисал
     на 34px ниже секции и давал столько же лишней прокрутки — под
     футером открывалась щель, где просвечивал фон с полем частиц
     (12.33 против 6.33 у футера). Снизу соседа нет, растушёвывать
     там нечего; верх не трогаем — там стык с «О нас». */
  position: absolute; inset: -45% 0 0;
  z-index: 0; pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,.06) 12%, rgba(0,0,0,.25) 24%,
    rgba(0,0,0,.6) 36%, #000 50%, #000 100%);
  mask-image: linear-gradient(180deg,
    transparent 0%, rgba(0,0,0,.06) 12%, rgba(0,0,0,.25) 24%,
    rgba(0,0,0,.6) 36%, #000 50%, #000 100%);
  background:
    radial-gradient(110% 80% at 50% 100%, rgba(138, 86, 72, .071), rgba(138, 86, 72, .0517) 14%, rgba(138, 86, 72, .0381) 24.5%, rgba(138, 86, 72, .0272) 33.6%, rgba(138, 86, 72, .0185) 42%, rgba(138, 86, 72, .0119) 49%, rgba(138, 86, 72, .0071) 55.3%, rgba(138, 86, 72, .0038) 60.2%, rgba(138, 86, 72, .0016) 64.4%, rgba(138, 86, 72, .0005) 67.2%, rgba(138, 86, 72, 0) 70%),
    radial-gradient(70% 60% at 8% 15%, rgba(201, 143, 134, .038), rgba(201, 143, 134, .0277) 14%, rgba(201, 143, 134, .0204) 24.5%, rgba(201, 143, 134, .0146) 33.6%, rgba(201, 143, 134, .0099) 42%, rgba(201, 143, 134, .0064) 49%, rgba(201, 143, 134, .0038) 55.3%, rgba(201, 143, 134, .002) 60.2%, rgba(201, 143, 134, .0009) 64.4%, rgba(201, 143, 134, .0003) 67.2%, rgba(201, 143, 134, 0) 70%),
    radial-gradient(70% 60% at 92% 15%, rgba(201, 143, 134, .032), rgba(201, 143, 134, .0233) 14%, rgba(201, 143, 134, .0172) 24.5%, rgba(201, 143, 134, .0123) 33.6%, rgba(201, 143, 134, .0084) 42%, rgba(201, 143, 134, .0054) 49%, rgba(201, 143, 134, .0032) 55.3%, rgba(201, 143, 134, .0017) 60.2%, rgba(201, 143, 134, .0007) 64.4%, rgba(201, 143, 134, .0002) 67.2%, rgba(201, 143, 134, 0) 70%);
}
@media (prefers-reduced-motion: reduce) {
  .scene::before { transition: none; }
}

.sec-head { position: relative; z-index: 3; margin-bottom: clamp(2.5rem, 5vw, 4.5rem); }

/* название блока — крупная метка, единая во всех секциях.
   Селектор по секциям, а не по контейнерам: переименование обёртки
   больше не оставит метку мелкой (так уже случилось с «Сайтами») */
main > section:not(.hero):not(#layers) .tag {
  display: block;
  font-size: clamp(1.3rem, 2.15vw, 1.95rem);
  letter-spacing: .28em;
  line-height: 1;
  margin-bottom: 0;
  text-shadow: 0 0 22px rgba(201, 143, 134, .55);
}
.sec-head .tag { display: block; margin-bottom: 1.2rem; }
.sec-head .body { margin-top: 1.4rem; }

/* ============================================================
   УСЛУГИ — сцены разного размера, broken grid
   ============================================================ */

/* секция целиком укладывается в один экран */
/* верхнего отступа нет: бегущая строка стоит вплотную к стыку с hero
   и сама задаёт дистанцию до заголовка своим margin-bottom */
#acts { padding-top: 0; padding-bottom: clamp(34px, 4.2vh, 62px); }
#acts .sec-head { margin-bottom: clamp(1rem, 2.1vh, 1.7rem); }

/* заголовок секции — короткий и крупный, со свечением на акценте */
.acts-h {
  font-size: clamp(2rem, 3.8vw, 3.3rem);
  letter-spacing: -.04em;
}
.acts-h .cu {
  text-shadow: 0 0 30px rgba(201, 143, 134, .5), 0 0 8px rgba(201, 143, 134, .3);
}

/* ЖЁРДОЧКА в секции «Процесс»: вырастает из «ы» слова «системы» */
/* ВАЖНО: overflow-x снят именно здесь. У .scene стоит `overflow-x: clip`,
   а он создаёт scroll-контейнер и ЛОМАЕТ position: sticky у 3D-сцены
   внутри — липкий фон просто уезжал бы вместе с секцией.
   Горизонтальный скролл при этом не появится: `overflow-x: clip` уже
   стоит глобально на html, и он ловит всё, что вылезает вбок. */
#journey { overflow-x: visible; }

#journey {
  /* --perch-w/--perch-y удалены 22.08.2026: размер картинки задаёт
     сетка .journey-head, абсолютного позиционирования больше нет */
  /* ВАЖНО: кегль ровно как у .sites-h/.apps-h/.cases-h — это ЕДИНАЯ
     ступень всех разделов. Пробовали поднять до hero-масштаба
     (5.6vw/5.8rem) и откатили 22.08.2026: раздел получал вес первого
     экрана и читался как второй главный блок. Иерархия важнее размера —
     ранг здесь держат метка «Процесс» и лесенка шагов, а не кегль. */
  --perch-f: clamp(2rem, 3.8vw, 3.3rem);
  /* ВОЗДУХ ПОСЛЕ HERO (23.08.2026). Было clamp(24px,3vh,48px) = 27px при
     окне 900px: вместе с отступом ленты пауза выходила всего ~65px, тогда
     как у прочих секций .sec даёт 166px. Первый экран не успевал
     «закрыться», и вторая иллюстрация въезжала встык — читалось спешкой.
     Теперь пауза ~130px: меньше стандартной (лента сверху уже разделяет),
     но достаточная, чтобы hero отпустил взгляд.
     ВАЖНО: padding-bottom тоже задан явно. Раньше он наследовался из .sec
     (166px), и секция была асимметричной — сверху зажата, снизу провал. */
  /* ВАЖНО: отступ секции должен быть БОЛЬШЕ внутреннего разрыва
     голова->лесенка (118px), иначе граница блока читается слабее его
     собственного шва. Было 72px сверху — как раз такой случай. */
  padding-top: clamp(110px, 13vh, 170px);
  padding-bottom: clamp(110px, 13vh, 170px);
}
#journey .sec-head { position: relative; }
.journey-h { position: relative; }
/* «идеи» — полая, ещё замысел; «системы» — плотная и светится, уже результат */
.journey-h .outline { -webkit-text-stroke-width: 2px; }
.journey-h .solve { text-shadow: 0 0 34px rgba(201, 143, 134, .5), 0 0 8px rgba(201, 143, 134, .35); }
.journey-h {
  font-size: var(--perch-f);
  /* интерлиньяж как у прочих разделов: .88 был подобран под
     плакатный кегль, на секционном строки слипались */
  line-height: .95;
  letter-spacing: -.04em;
}

/* Лиза и Гоша на своей жёрдочке (она есть в самом рендере — рисованной нет).
   top считается от кегля заголовка, поэтому связка не разъезжается по ширинам */
/* якорь — само слово «системы»: жёрдочка идёт сразу за его «ы»
   при любой вёрстке строк и любой ширине экрана */
.journey-h .solve { position: relative; }
/* зеркальная раскладка: картинка слева, текст справа.
   Сетка вместо прежнего абсолютного позиционирования — так обе
   колонки выровнены по одной оси и не разъезжаются на разных ширинах */
/* ВАЖНО: свой контекст наложения. У .halo z-index: 0, и без этого
   пятно ложилось бы ПОВЕРХ картинки и текста, а не под них.
   На .scene > * общий z-index вешать нельзя (см. CLAUDE.md) */
/* ГОЛОВА СЕКЦИИ (пересобрана 23.08.2026).
   Прежние комментарии описывали СТАРУЮ картинку (1152px, «висящие ноги»)
   и противоречили друг другу — баланс держался на margin-top в 74px,
   подобранном на глаз. Замер нового рендера: масса лежит ровно в
   y=128..640 из 1024, оптический центр ≈40% высоты, свисающей части нет.
   С вернувшейся меткой-эпиграфом высота копи почти совпала с этим
   центром — расхождение всего 3–8px, поэтому выравнивание отдано
   ЦЕНТРУ СЕТКИ, а не ручному отступу. */
.journey-head {
  position: relative;
  z-index: 2;
  display: grid;
  /* Доля картинки поднята с 42% до 46% (23.08.2026). Причина: у кадра
     28% ширины — прозрачное поле, поэтому из 517px колонки видимая пара
     занимала лишь 374px, и отношение к тексту было 0.52 против 0.63 в
     hero — иллюстрация читалась мелкой. На 46% видимая пара 409px,
     отношение 0.62 = ровно как в hero. Заголовок при этом не рвётся:
     самая длинная строка ≈496px при колонке 665px. */
  grid-template-columns: minmax(300px, 46%) 1fr;
  gap: clamp(1.4rem, 3.2vw, 3rem);
  align-items: center;
  /* Разрыв голова->лесенка увеличен: был 80px при отступе секции 72px —
     внутренний шов оказывался ЗАМЕТНЕЕ границы блока, иерархия
     переворачивалась. Теперь 118px против 26px между карточками:
     голова и лесенка читаются двумя частями, а не одним потоком. */
  margin-bottom: clamp(3.2rem, 5.6vw, 5.2rem);
}
/* подложка именно под рендером: чуть теплее и плотнее обычного halo,
   иначе пара на прозрачном свечении висит в пустоте */
.halo--perch {
  /* closest-side + экспонента, как у базового .halo — иначе градиент
     тянулся до farthest-corner и border-radius резал его на 71% */
  background: radial-gradient(circle closest-side,
    rgba(233, 188, 169, .1),
    rgba(201, 143, 134, .0728) 20%,
    rgba(201, 143, 134, .0537) 35%,
    rgba(201, 143, 134, .0383) 48%,
    rgba(201, 143, 134, .0261) 60%,
    rgba(201, 143, 134, .0168) 70%,
    rgba(201, 143, 134, .01) 79%,
    rgba(201, 143, 134, .0053) 86%,
    rgba(201, 143, 134, .0023) 92%,
    rgba(201, 143, 134, .0008) 96%,
    rgba(201, 143, 134, 0) 100%);
  z-index: 0;
}
.journey-copy .tag { margin-bottom: clamp(.8rem, 1.6vh, 1.2rem); }
.journey-copy .journey-h { margin-bottom: clamp(.75rem, 1.6vh, 1.1rem); }
/* заголовок и абзац — один блок, а не две отдельные плиты.
   Медная линия держит их вместе и отбивает от лесенки шагов */
.journey-copy .body {
  max-width: 46ch;
  font-size: clamp(1rem, 1.15vw, 1.12rem);
  padding-left: clamp(.9rem, 1.5vw, 1.4rem);
  border-left: 2px solid rgba(233, 188, 169, .32);
}

/* ============================================================
   ШАПКА «ПРОЦЕССА» — ПЬЕДЕСТАЛ (переосмысление 23.08.2026)
   ============================================================
   Было: пара слева, заголовок справа — зеркальный повтор hero (там текст
   слева, пара справа). Читалось вторым hero, и пара казалась лишней.
   Стало: заголовок по центру как название главы; под ним пара сидит на
   своей светящейся линии ровно над осью рельса, и рельс выходит из-под
   них — они в начале пути, который дальше проходит пять шагов змейкой.
   Правила ниже ПЕРЕКРЫВАЮТ двухколоночную раскладку выше (она оставлена
   в истории: комментарии про пропорции колонок к ней). */
.journey-head {
  /* холст 100vh идёт перед шапкой в потоке — шапка поднимается на него.
     z-index у шапки СНЯТ (был 2): иначе она — один контекст, и холст не
     может встать между рендером и текстом */
  z-index: auto;
  margin-top: -100vh;
  margin-top: -100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* у рендера прозрачное поле сверху ~12% высоты — оно и есть зазор */
  gap: .25rem;
  margin-bottom: 0;
}
/* ПОДГОНКА ПОД ЭКРАН (23.08.2026, замер на 2000×1250): от бегущей строки
   до заголовка было 233px, шапка 760px — не влезала в экран. Верхний
   отступ секции ужат (у .sec 180px), заголовок + пара теперь укладываются
   в один экран: ~150px до заголовка, рендер ≤ 640px. */
#journey.sec { padding-top: clamp(3.5rem, 7vh, 6rem); padding-bottom: clamp(.8rem, 1.5vh, 1.2rem); /* низ ужимался трижды: общие 180px .sec давали пустой полуэкран после «Запускаем» */ }
/* МЕДНЫЕ НИТИ ОТ ПЕРЕКЛАДИНЫ + РОЛИ CREATE/CONNECT (25.08.2026).
   Бока шапки пустели на широком экране; Георгий выбрал из вариантов
   нити-кабели и метки-роли. Нити выходят из-под перекладины (у рендера
   она на ~72% высоты), провисают и гаснут наружу; на них узлы, как на
   кабеле пары в hero. Метки висят у концов нитей: CREATE у Лизы,
   CONNECT у Георгия. SVG растянут на 230% ширины рендера и жёстко
   привязан к нему — геометрия не зависит от ширины экрана. */
.perch-threads {
  position: absolute;
  left: 50%; top: 0;
  width: min(230%, 96vw);
  height: 100%;
  transform: translateX(-50%);
  z-index: 1;
  pointer-events: none;
  overflow: visible;
}
.perch-node--dim { fill: #C98F86; }
/* Метки-роли CREATE/CONNECT на нитях пробовали 25.08.2026 и убрали в тот
   же день (Георгий: «надписи выглядят очень иишно») — не возвращать. */
/* на узких экранах боков просто нет — нити убираются целиком */
@media (max-width: 1100px) {
}
@media (prefers-reduced-motion: reduce) {
}
/* ЗАГОЛОВОК — НАЗВАНИЕ ГЛАВЫ, А НЕ ВТОРОЙ HERO (итог 24.08.2026).
   Днём кегль подняли до 5.6vw, чтобы закрыть пустые бока, — и получили
   ровно то, чего нельзя: крупный текст по центру + рендер пары под ним
   дублировали композицию первого экрана, «Процесс» читался второй главной
   страницей. Пустота лечится НЕ кеглем: заголовок вернулся в подчинённый
   ранг (3.1vw против 7vw+ у hero — разница ~2.5x читается сразу), а кадр
   держат пара и поле частиц под ним. Ширину задаёт `ch` — в две строки
   заголовок обязан быть УЖЕ пары, иначе снова спорит с ней за главность. */
.journey-head .journey-h {
  margin-left: auto; margin-right: auto;
  max-width: 26ch; white-space: normal;
  font-size: clamp(1.6rem, min(3.1vw, 5.4vh), 3.1rem);
  line-height: 1.04;
  letter-spacing: -.03em;
}
.journey-head .body {
  margin-left: auto; margin-right: auto;
  padding-left: 0; border-left: 0;
  max-width: 46ch;
  color: rgba(241, 236, 231, .62);
  /* базовый 17px (см. «Типографика»): при заголовке-названии главы абзац
     не должен с ним конкурировать — контраст между ними держится малым */
  font-size: 1.0625rem;
  line-height: 1.55;
  margin-top: clamp(.7rem, 1.4vh, 1.1rem);
}

.acts {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(12px, 1.1vw, 18px);
  position: relative; z-index: 2;
}

/* ровная сетка: все карточки по одним горизонталям и вертикалям */
.act { grid-column: span 4; }

.act {
  position: relative;
  align-self: start;
  background:
    radial-gradient(130% 110% at 100% 0%, rgba(201, 143, 134, .13), rgba(201, 143, 134, .0946) 11.6%, rgba(201, 143, 134, .0698) 20.3%, rgba(201, 143, 134, .0498) 27.84%, rgba(201, 143, 134, .0339) 34.8%, rgba(201, 143, 134, .0218) 40.6%, rgba(201, 143, 134, .013) 45.82%, rgba(201, 143, 134, .0069) 49.88%, rgba(201, 143, 134, .003) 53.36%, rgba(201, 143, 134, .001) 55.68%, rgba(201, 143, 134, 0) 58%),
    linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid rgba(233, 188, 169, .3);
  border-radius: 18px;
  padding: clamp(1rem, 1.25vw, 1.36rem);
  overflow: hidden;
  display: flex; flex-direction: column;
  /* неоновая подсветка — как светящийся кабель в hero */
  box-shadow:
    0 0 22px -8px rgba(233, 188, 169, .45),
    inset 0 0 30px -14px rgba(233, 188, 169, .55);
  transition: border-color .45s, transform .45s cubic-bezier(.22,1,.36,1), box-shadow .45s;
}

.act:hover {
  border-color: rgba(233, 188, 169, .75);
  transform: translateY(-5px);
  box-shadow:
    0 0 36px -6px rgba(233, 188, 169, .6),
    inset 0 0 40px -12px rgba(233, 188, 169, .7),
    0 20px 46px -26px rgba(201, 143, 134, .65);
}

.act > *, .act summary > *:not(.act-ico) { position: relative; z-index: 1; }

/* ---- свёрнутое состояние: только номер, глиф и заголовок ---- */
.act summary {
  list-style: none;
  cursor: pointer;
  display: block;
  outline: none;
}
.act summary::-webkit-details-marker { display: none; }
.act summary::marker { content: ''; }
.act summary:focus-visible { outline: 2px solid var(--cu); outline-offset: 6px; border-radius: 10px; }

/* подсказка «Подробнее» с шевроном */
.act-more {
  display: inline-flex; align-items: center; gap: .45rem;
  margin-top: .7rem;
  font-family: var(--font-mono); font-size: .62rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--cu-hi);
  text-shadow: 0 0 10px rgba(233, 188, 169, .5);
  transition: gap .3s;
}
.act-more-t::before { content: 'Подробнее'; }
.act[open] .act-more-t::before { content: 'Свернуть'; }
.act-chev { width: 11px; height: 8px; transition: transform .35s cubic-bezier(.22,1,.36,1); }
.act[open] .act-chev { transform: rotate(180deg); }
.act summary:hover .act-more { gap: .7rem; }

/* ---- раскрытая часть ---- */
.act-body {
  margin-top: .75rem;
  padding-top: .85rem;
  border-top: 1px solid rgba(233, 188, 169, .16);
  animation: actReveal .34s cubic-bezier(.22,1,.36,1);
}
@keyframes actReveal {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.act[open] { align-self: start; }

/* светящийся глиф услуги */
.act-ico {
  position: absolute;
  top: clamp(1rem, 1.25vw, 1.36rem);
  right: clamp(1rem, 1.25vw, 1.36rem);
  width: 38px; height: 38px;
  pointer-events: none;
}
.act-ico svg {
  width: 100%; height: 100%; overflow: visible;
  filter: drop-shadow(0 0 5px rgba(233, 188, 169, .65));
  transition: filter .45s;
}
.act:hover .act-ico svg { filter: drop-shadow(0 0 9px rgba(255, 227, 194, .9)); }
.act-ico .gl { fill: none; stroke: #F0BE9C; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.act-ico .gld { fill: #FFE3C2; }
.act-ico .gld-f { fill: rgba(240, 190, 156, .5); }

/* нумерация 01–06 убрана из услуг 22.08.2026: это не последовательность,
   порядок ничего не сообщает. В #journey номера остались — там реальные шаги */
/* заголовок обнимает текст, чтобы подчёркивание шло ровно по словам */
.act h3 {
  position: relative;
  width: fit-content;
  max-width: calc(100% - 52px);
  font-size: clamp(1rem, 1.25vw, 1.2rem);
  margin: .4rem 0 .5rem;
  padding-bottom: .5rem;
}
/* короткий штрих в покое */
.act h3::after {
  content: '';
  position: absolute; left: 0; bottom: 0;
  width: 28px; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, #FFE3C2, transparent);
  box-shadow: 0 0 8px rgba(233, 188, 169, .8);
  transition: opacity .35s;
}
/* при наведении линия вбегает слева направо и подчёркивает слова */
.act h3::before {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, #FFF3E2, #FFE3C2 45%, #F0BE9C);
  box-shadow: 0 0 10px rgba(233, 188, 169, .95), 0 0 24px rgba(201, 143, 134, .6);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s cubic-bezier(.22,1,.36,1);
}
.act summary:hover h3::before,
.act summary:focus-visible h3::before,
.act[open] h3::before { transform: scaleX(1); }
.act summary:hover h3::after,
.act summary:focus-visible h3::after,
.act[open] h3::after { opacity: 0; }
.act-lead { color: var(--ink-70); font-size: .845rem; line-height: 1.45; margin: 0; }

/* что конкретно входит */
.act-list { list-style: none; display: flex; flex-wrap: wrap; gap: .32rem; margin-top: .7rem; }
.act-list li {
  font-size: .69rem; line-height: 1.2;
  color: var(--ink-70);
  border: 1px solid rgba(233, 188, 169, .38);
  background: rgba(201, 143, 134, .07);
  border-radius: 100px;
  padding: .3em .66em;
  box-shadow: 0 0 10px -5px rgba(233, 188, 169, .6);
  transition: border-color .4s, color .4s, box-shadow .4s;
}
.act:hover .act-list li {
  border-color: rgba(233, 188, 169, .7);
  color: var(--ink);
  box-shadow: 0 0 12px -3px rgba(233, 188, 169, .55);
}

/* строка результата прижата к низу — линии выравниваются по ряду */
.act-out {
  margin-top: auto; padding-top: .75rem;
  display: flex; flex-wrap: wrap; gap: .45rem; align-items: baseline;
  font-size: .8rem; color: var(--ink-70);
}
.act-out span {
  font-family: var(--font-mono); font-size: .6rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--cu-hi); white-space: nowrap;
  text-shadow: 0 0 10px rgba(233, 188, 169, .6);
}

/* ============================================================
   ПРОЦЕСС — путешествие камеры, а не пять карточек
   ============================================================ */

/* ШАГИ ПРОЦЕССА — блоки в шахматной геометрии, нанизанные на живой кабель */
/* лесенка подтянута вверх: карточка 01 стоит в правых колонках, под
   заголовком справа зияла пустота ~200px. Ноги пары свисают слева
   в тот же уровень, поэтому наложения не возникает */
/* margin-top: -2.6vw убран 23.08.2026. Он компенсировал свисающие ноги
   прежнего рендера, но в новой картинке ink занимает кадр целиком, а
   заголовки шагов выросли — в сумме зазор до лесенки уходил в МИНУС
   (замер: -17..-33px), и карточка «Исследуем» наезжала на подзаголовок. */
/* ДВЕ КОЛОНКИ (23.08.2026): шаги слева, 3D-модель справа.
   Шесть итераций сцена стояла ЗА карточками — и ни одна не дала эффекта,
   потому что её закрывали панели, гасила маска и глушила прозрачность.
   Фон не может быть зрелищем по определению. Теперь модель стоит рядом,
   крупно и в полную яркость, липнет к экрану и собирается, пока листаешь
   шаги. Это то же «едет со свайпом и раскрывается», но её наконец видно. */
/* ПОЛЕ ЧАСТИЦ НА ВЕСЬ ЭКРАН (23.08.2026). Плоская 3D-карточка в левой
   колонке «вау» не давала: слайд в пространстве. Теперь сцена — липкий
   слой на весь вьюпорт ЗА колонкой шагов, шаги едут поверх справа. */
.journey-wrap {
  position: relative;
  z-index: 2;
  /* шапки-пьедестала больше нет (25.08.2026): холст 100vh стоит первым в
     потоке, и колонку тезисов поднимаем прямо на него — иначе перед
     «Исследуем» пустовал целый экран поля частиц.
     ЗАЗОР ДО БЕГУЩЕЙ СТРОКИ — ОДИН СТАНДАРТ (правка Георгия): в hero от
     контента до строки 147px. ВАЖНО: зазор регулируется НЕ подъёмом
     колонки — фигура из частиц привязана к центру первого .leg
     (trackLeg в layers3d.js), и подъём тащит вниз по экрану и текст, и
     фигуру разом («все фигурки уехали вниз»). Колонка стоит вплотную к
     холсту, а воздух над первым тезисом снимается высотой .leg:first-child */
  margin-top: -100vh;
  margin-top: -100dvh;
}
.layers-stage.journey-3d {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  min-height: 0;
  /* ПОВЕРХ РЕНДЕРА (23.08.2026): частицы вылетают из ноутбуков и должны
     лететь над картинкой, а не за ней. Порядок: рендер 1 < холст 2 < тексты 3 */
  z-index: 2;
  opacity: 1;
  pointer-events: none;
  background: none;
}
.journey-3d canvas { border-radius: 0; }
/* колонка шагов начинается ПОД липким слоем и занимает правую половину */
/* ЗМЕЙКА (23.08.2026): рельс по центру экрана, тезисы чередуются —
   нечётные справа от рельса, чётные слева. Рисунок из частиц занимает
   свободную половину и перелетает при смене тезиса (см. layers3d.js).
   Так текст и картинка не спорят: они всегда в паре, на разных сторонах. */
/* колонка тезисов ВЫХОДИТ ИЗ .wrap на всю ширину экрана (25.08.2026,
   тот же приём, что у липкой сцены .layers-stage.journey-3d): тексты
   должны прижиматься к кромке экрана, как в hero, а .wrap ограничивал
   их своими ~250px полей. Центр колонки = центр экрана, рельс на месте */
.journey-col { margin-top: 0; width: 100vw; margin-left: calc(50% - 50vw); }

/* ============================================================
   ШАГИ ПРОЦЕССА — колонка состояний (23.08.2026)
   ============================================================
   Было: пять карточек шахматкой и змейка-кабель между ними. Читалось
   таблицей с закорючками и никак не было связано с моделью слева.
   Стало: каждый шаг занимает ~60vh прокрутки, активный — один (ближний
   к центру экрана), он же сажает свой слой в 3D-сборке. Шаг — не коробка,
   а крупный глагол + строка пояснения. Никаких панелей: текст живёт на
   том же фоне, что и модель, — они в одном кадре. */
.journey-col { position: relative; z-index: 3; }
/* РЕЛЬС-ЗМЕЙКА. Контейнер занимает всю ширину колонки (линия уходит
   вбок от центра), сам путь рисует SVG. Рельс поднят выше первого узла на
   величину подводки --lead, поэтому SVG охватывает и её. */
.journey-rail {
  position: absolute;
  left: 0; top: 0;
  width: 100%;
  z-index: 0;
  pointer-events: none;
}
.journey-rail-svg {
  position: absolute;
  left: 0; top: calc(-1 * var(--lead, 0px));
  width: 100%;
  height: calc(100% + var(--lead, 0px));
  overflow: visible;
}
.journey-rail-svg path { fill: none; stroke-linecap: round; }
/* подводка от шапки секции к первому узлу: заголовок — начало пути */
.journey-rail-lead { stroke: rgba(240, 190, 156, .34); stroke-width: 1.5; }
/* холодное русло — весь путь целиком */
.journey-rail-base { stroke: rgba(201, 143, 134, .16); stroke-width: 1.5; }
/* тёплая заливка — прочерчивается по мере прокрутки (stroke-dashoffset) */
.journey-rail-fill {
  stroke: #F0BE9C;
  stroke-width: 2;
  filter: drop-shadow(0 0 6px rgba(240, 190, 156, .65));
}
/* ползунок и узлы ездят по кривой: left/top ставит main.js из
   getPointAtLength(), поэтому центрирующий transform без процентов позиции */
.journey-rail-dot {
  position: absolute; left: 0; top: 0;
  width: 10px; height: 10px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: #FFF3E2;
  box-shadow: 0 0 0 4px rgba(240, 190, 156, .18), 0 0 22px 4px rgba(240, 190, 156, .6);
  transition: opacity .25s;
}
/* узел тезиса: пустое кольцо, пока ползунок не дошёл; дошёл — точка с
   ореолом, которая остаётся гореть. В момент остановки — пульс крупнее */
.journey-rail-node {
  position: absolute; left: 0; top: 0;
  width: 12px; height: 12px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: var(--bg);
  border: 1px solid rgba(201, 143, 134, .45);
  transition: background .4s, border-color .4s, box-shadow .5s, transform .45s cubic-bezier(.22,1,.36,1);
}
.journey-rail-node.is-lit {
  background: #FFE3C2;
  border-color: #FFE3C2;
  box-shadow: 0 0 0 4px rgba(240, 190, 156, .16), 0 0 20px 3px rgba(240, 190, 156, .55);
}
.journey-rail-node.is-here {
  transform: translate(-50%, -50%) scale(1.45);
  box-shadow: 0 0 0 6px rgba(240, 190, 156, .2), 0 0 34px 8px rgba(240, 190, 156, .7);
}

.journey {
  position: relative;
  z-index: 1;
  list-style: none;
  margin: 0;
  padding: 0;
}

.leg {
  position: relative;
  min-height: 46vh; /* 25.08.2026 ужаты с 58vh: Георгий — «очень много листать» между тезисами */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0;
  width: 40%;
  /* КОМПОЗИЦИЯ РАЗДВИНУТА К КРАЯМ (25.08.2026, правка Георгия: отступы
     от краёв — как в hero, там текст в 60px от кромки). Раньше тексты
     жались к центральному рельсу (старт на 50% + зазор), и по краям
     пустовало по 260-360px. Теперь тезис прижат к ВНЕШНЕЙ кромке и
     выровнен к ней (нечётные — правый край, как зеркало hero-текста);
     рисунок из частиц уходит к своей кромке (SIDE = 0.46*halfW в
     layers3d.js — центр рисунка всегда на ~27% ширины, как текст hero) */
  margin-left: auto;
  margin-right: clamp(40px, 3.5vw, 96px);
  align-items: flex-end;
  text-align: right;
}
.leg:nth-child(even) {
  /* чётные — у левой кромки, выровнены влево, ровно как текст hero */
  margin-left: clamp(40px, 3.5vw, 96px);
  margin-right: auto;
  align-items: flex-start;
  text-align: left;
}
/* первый и последний — на полный экран и по центру: их тезис встаёт
   ровно напротив формы, которая всегда в центре липкого слоя */
/* Первый шаг центрируется по своей высоте, поэтому ЕГО высота и есть
   воздух между бегущей строкой и «Исследуем». 92 → 78 → 62 (пока была
   шапка с парой) → 36vh (25.08.2026, после удаления шапки): при 62vh над
   заголовком висело 392px против 147px в hero. Правится именно здесь, а
   не подъёмом .journey-wrap — тот утаскивает вниз и текст, и фигуру */
.leg:first-child { min-height: 25vh; min-height: 25dvh; }
.leg:last-child  { min-height: 40vh; } /* ужимался четырежды: 72 → 58 → 50 → 46 → 40vh, хвост после «Запускаем» пустел */
/* неактивный шаг уходит в глубину: меньше, тусклее, чуть дальше */
.leg {
  opacity: .22;
  transform: translateX(12px);
  transition: opacity .55s ease, transform .65s cubic-bezier(.22,1,.36,1);
  will-change: opacity, transform;
}

/* СТАТИКА/reduced-motion (код-ревью 27.08.2026): journeySteps() не
   запускается за ранним return — без этих правил все пять шагов
   «Процесса» оставались на 22% непрозрачности, а ползунок рельса
   светился в углу поверх пустого пути. */
html.is-static .leg { opacity: 1; transform: none; }
html.is-static .journey-rail { display: none; }
.leg:nth-child(even) { transform: translateX(-12px); }
/* первый и последний шаг такие же, как остальные: сцена на весь экран,
   форма стоит в центре — текст должен стоять напротив неё */
.leg.is-on { opacity: 1; transform: none; }

/* Номера шагов 01–05 и засечка к ним УБРАНЫ по просьбе Георгия 24.08.2026
   («нужно везде убрать нумерацию и эту палку») — вместе с разметкой .leg-n. */
/* p-блоки сажает по кромке align-items на .leg — отдельные margin-правила
   не нужны (осталось от версии «тексты у рельса») */

.leg h3 {
  /* ПЛАКАТНЫЙ МАСШТАБ (25.08.2026, «нужно, чтобы смотрелось гармонично»):
     при 4.4vw глагол был вдвое мельче фигуры из частиц и проигрывал ей —
     половины кадра не были равными партнёрами. 5.4vw — глагол того же
     ранга, что фигура; hero (7vw+) всё ещё заметно главнее */
  font-size: clamp(2.6rem, 5.4vw, 5.2rem);
  line-height: .92;
  letter-spacing: -.045em;
  margin: 0 0 1rem;
  color: var(--ink);
  position: relative;
}
.leg.is-on h3 {
  text-shadow: 0 0 46px rgba(201, 143, 134, .5), 0 0 12px rgba(201, 143, 134, .22);
}
/* ВЫНОСКА ОТ РЕЛЬСА К ТЕЗИСУ (25.08.2026): тонкая медная линия на уровне
   заголовка, прочерчивается от текста в сторону рельса при активации.
   Связывает узел на оси с глаголом — центр кадра перестаёт быть разрывом
   между фигурой и текстом. Гаснет в прозрачность к рельсу (правило про
   края-прозрачность из CLAUDE.md). */
.leg h3::before {
  content: '';
  position: absolute;
  top: .52em;
  width: clamp(80px, 10vw, 190px);
  height: 2px;
  border-radius: 1px;
  transform: scaleX(0);
  transition: transform .9s cubic-bezier(.22, 1, .36, 1) .12s;
}
.leg:nth-child(odd) h3::before {
  right: calc(100% + 26px);
  transform-origin: right center;
  background: linear-gradient(270deg, rgba(240, 190, 156, .55), rgba(240, 190, 156, 0));
}
.leg:nth-child(even) h3::before {
  left: calc(100% + 26px);
  transform-origin: left center;
  background: linear-gradient(90deg, rgba(240, 190, 156, .55), rgba(240, 190, 156, 0));
}
.leg.is-on h3::before { transform: scaleX(1); }
/* АУРА ЗА АКТИВНЫМ ТЕЗИСОМ: мягкий тёплый свет, симметричный свечению
   фигуры на другой половине, — обе стороны кадра из одного материала */
.leg::after {
  content: '';
  position: absolute;
  z-index: -1;
  top: 50%;
  width: min(46vw, 660px);
  height: min(46vw, 660px);
  transform: translateY(-50%);
  background: radial-gradient(circle,
    rgba(201, 143, 134, .11) 0%,
    rgba(201, 143, 134, .04) 42%,
    rgba(201, 143, 134, 0) 68%);
  opacity: 0;
  transition: opacity .9s ease;
  pointer-events: none;
}
.leg:nth-child(odd)::after { right: min(-8vw, -60px); }
.leg:nth-child(even)::after { left: min(-8vw, -60px); }
.leg.is-on::after { opacity: 1; }
.leg p {
  color: rgba(241, 236, 231, .66);
  font-size: clamp(.98rem, 1.05vw, 1.06rem);
  line-height: 1.55;
  margin: 0;
  max-width: 40ch;
}

/* взлётная полоса: прокрутка, на которой ракета отрывается по свайпу */
.journey-runway { height: 26vh; } /* НЕ НИЖЕ: хвост после центра «Запускаем» (полшага 20vh + полоса + низ секции) обязан быть ≥ ~48vh, иначе липкая сцена уезжает вверх ДО центровки тезиса и ракета всегда «сильно сверху» (так было при 8vh и 14vh — весь 3D-мир съезжал на ~20vh). При 26vh сцена держит экран ровно до центра последнего тезиса */

/* ============================================================
   ШОВ МЕЖДУ СЕКЦИЯМИ — медная линия света
   ============================================================
   Разделитель для стыка «Процесс» → «Сайты». Вторую бегущую строку
   сюда ставить нельзя: приём перестал бы быть акцентом и превратился
   в рутину каждого стыка. Вместо этого — то, что уже обещано главной
   метафорой (CLAUDE.md): «медная линия света соединяет секции».
   Линия прочерчивается по прокрутке (js/main.js -> seamDraw), в центре
   тлеет узел. Края гаснут в ПРОЗРАЧНОСТЬ, а не в цвет — иначе на фоне
   с аурами проступила бы горизонтальная граница (правило про заливки). */

.seam {
  position: relative;
  z-index: 1;
  height: 1px;
  margin-block: clamp(10px, 2.2vh, 26px);
  display: grid;
  place-items: center;
  pointer-events: none;
}
/* ШОВ ПОДТЯНУТ ВВЕРХ ПОВЕРХ ХВОСТА ПОЛОСЫ (25.08.2026, правка Георгия:
   разрыв «Запускаем» → линия должен быть как между тезисами). Сам хвост
   внутри .journey-wrap укорачивать НЕЛЬЗЯ (см. правило у .journey-runway:
   липкая сцена уедет до центровки тезиса) — поэтому длина прокрутки
   остаётся, а шов и «Сайты» наезжают отрицательным отступом на пустой
   конец полосы, где ракета уже улетела. Холст прозрачный — наложение
   невидимо. Только десктоп: на ≤900px сцена не липкая и полосы нет. */
@media (min-width: 901px) {
  /* только шов после «Процесса»: остальные швы (между главами услуг,
     25.08.2026) стоят обычно — им наезжать не на что */
  .seam--journey { margin-top: -14vh; }
}
/* РАЗДЕЛИТЕЛЬ ГЛАВ УСЛУГ — ЛИНИЯ С РАЗРЫВОМ И ИСКРОЙ (25.08.2026).
   История правок Георгия: шов .seam между всеми главами — «дублирует
   предыдущее разграничение» (такой же стоит после «Процесса»); счётчик
   «02 ПРИЛОЖЕНИЯ» — «убери, можно просто дырку оставить»; затем «эта
   линия, но с дыркой, без текста» + «разграничение нужно обязательно».
   Итог: две линии, гаснущие к центру, между ними пустота ~15% ширины.
   В пустоте живёт СВЕТОВОЙ ИМПУЛЬС — раз в 7s искра пробегает слева
   направо и гаснет: тот же язык, что провод «Автоматизации» и рельс
   «Процесса», но тише. Мёртвой черты нет, повтора шва тоже. */
.chapter-gap {
  position: relative;
  width: min(1180px, 88vw);
  height: 1px;
  margin: clamp(2.4rem, 5.5vh, 4.5rem) auto;
  pointer-events: none;
  /* две линии: гаснут и к краям кадра, и к центральному разрыву */
  background:
    linear-gradient(90deg, rgba(233,188,169,0), rgba(233,188,169,.26) 60%, rgba(233,188,169,0)) left / 42.5% 100% no-repeat,
    linear-gradient(90deg, rgba(233,188,169,0), rgba(233,188,169,.26) 40%, rgba(233,188,169,0)) right / 42.5% 100% no-repeat;
}
/* Бегущая искра убрана 25.08.2026 («она лишняя»): разделитель — только
   две линии, гаснущие к центру. Анимацию не возвращать. */

.seam-line {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: min(1180px, 88vw);
  height: 1px;
  /* по краям — чистая прозрачность, в середине медь набирает силу */
  background: linear-gradient(90deg,
    rgba(201, 143, 134, 0) 0%,
    rgba(201, 143, 134, .05) 12%,
    rgba(201, 143, 134, .16) 30%,
    rgba(233, 188, 169, .34) 50%,
    rgba(201, 143, 134, .16) 70%,
    rgba(201, 143, 134, .05) 88%,
    rgba(201, 143, 134, 0) 100%);
  /* прочерчивание по скроллу: ширина растёт от центра к краям */
  transform-origin: 50% 50%;
}
.seam-node {
  position: relative;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #FFF3E2;
  box-shadow:
    0 0 10px 2px rgba(233, 188, 169, .55),
    0 0 22px 6px rgba(201, 143, 134, .28);
}

/* ============================================================
   САЙТЫ — «задумка превращается в сайт»
   ============================================================ */

/* ВОЗДУХ МЕЖДУ ГЛАВАМИ УСЛУГ (25.08.2026): было 20–38px здесь, 40–72 у
   .chain, 38–70 у #apps — три главы слипались в одну простыню, границ
   не было видно. Единый отступ у всех трёх + шов .seam между ними */
/* ритм общий (--pad-sec), частное правило снято 26.08.2026 */
/* каждая глава услуг — один экран, как hero и шаги «Процесса»:
   контент по центру высоты, вокруг воздух, а не стык за стыком */
#sites, #apps, .chain { min-height: 100vh; display: flex; align-items: center; }

/* левая половина — иллюстрация, правая — весь текст и типы сайтов:
   обе колонки заполнены, пустых провалов нет */
.sites-main {
  display: grid;
  /* текст слева, Лиза справа — как hero (текст | портал); дальше главы
     чередуются: «Приложения» — сцена слева, «Автоматизация» — текст слева */
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(1.5rem, 3.5vw, 3.4rem);
  align-items: center;
  /* иерархия отступов как в #journey: внутренний шов заметно крупнее
     ритма карточек, но меньше границы секции */
  /* ужато с 3.2–5.2rem (25.08.2026): чипы «А если нужно больше» стояли
     ближе к заголовку «Автоматизации», чем к своей секции */
  margin-bottom: 0;
}
.sites-art {
  width: min(100%, 540px);
  height: auto;
  /* резерв места под картинку 1206x1304: без него контент прыгает,
     пока грузится файл на 1.9 МБ (Core Web Vitals: CLS) */
  aspect-ratio: 1206 / 1304;
  /* Замер альфы: ink занимает 94% кадра, пустое поле слева всего 5.3%
     (~25px при ширине 470px) — в отличие от duo-perch, где было 28%.
     Прежние -64px перекомпенсировали и уводили рисунок за сетку. */
  justify-self: end;
  margin-left: 0;
  pointer-events: none;
}
.sites-col { display: flex; flex-direction: column; }
/* КЕГЛЬ ЗАГОЛОВКОВ ГЛАВ УСЛУГ = СТУПЕНЬ НИЖЕ HERO (25.08.2026): было 53px
   против 84px у hero и 83px у шага «Процесса» — главы читались мелкими
   вставками. Теперь ~70px на 1680 (общее правило .sites-h/.apps-h/.chain-h/
   .chain-h). Строки не ломаем <br> — колонка сама переносит */
.sites-h { font-size: clamp(2.3rem, 4.2vw, 4.4rem); margin: .85rem 0 1rem; max-width: 14ch; }
.sites-h .solve { text-shadow: 0 0 30px rgba(201,143,134,.5), 0 0 8px rgba(201,143,134,.35); }
/* абзац — базовые 17px, как в hero и «Процессе» (было .93rem ≈ 15px) */
.sites-main .body { max-width: 46ch; }

/* ГОЛОГРАММА САЙТА рядом с Лизой (25.08.2026, «нет вау-элемента»):
   окно из медных линий, дорисовывается под каждый пункт списка
   (main.js → siteHolo). Висит слева от рендера, чуть наезжая на него,
   с тёмной полупрозрачной подложкой — читается окном перед сценой.
   Свечение — одним drop-shadow на весь svg, не blur на каждой линии */
.sites-scene { position: relative; justify-self: end; width: min(100%, 560px); }
.sites-scene .sites-art { display: block; width: 100%; margin: 0; }
/* МАТЕРИАЛ = МАТЕРИАЛ РЕНДЕРА (25.08.2026, третья правка Георгия:
   «относительно других блоков консоль не супер выглядит»). Крупный кадр
   показал причину: у Лизы всё объёмное, скруглённое, светится насквозь и
   связано дугами, а голограмма была плоским прямоугольником из ровных
   линий, висящим отдельно. Теперь это ЕЩЁ ОДНА ЕЁ ПАНЕЛЬ: наклон в
   перспективе (rotateY), скруглённая рамка, мягкое внутреннее свечение
   и медная дуга, которая связывает её с кругом вокруг Лизы. */
.holo {
  position: absolute;
  /* панель летит в её световом круге, слева-впереди: замер альфы
     liza-design.png — чернила с x=2.1%, кадр занят целиком, поэтому
     наезжаем только на пустой левый край свечения, не на предметы */
  /* ВАЖНО: при rotateY панель визуально шире своего box — правый край
     уходит вправо. -46% давало наезд на Лизу, поэтому -62% */
  left: -62%; top: 12%;
  width: 50%;
  /* ЦВЕТ = ЦВЕТ РЕНДЕРА (замер по liza-design.png): яркие контуры
     #F2BDC3, свечение #C56D77 — оттенок 350–360°, розовый неон.
     Не менять на --cu-hi (оттенок 20°): он для линий интерфейса,
     а здесь материал рендера. */
  color: #F2BDC3;
  filter:
    drop-shadow(0 0 5px rgba(242, 189, 195, .5))
    drop-shadow(0 0 16px rgba(197, 109, 119, .45))
    drop-shadow(0 0 42px rgba(197, 109, 119, .25));
  transform: perspective(900px) rotateY(17deg) rotateX(4deg) rotateZ(-2deg);
  transform-origin: 80% 50%;
  animation: holoFloat 8s ease-in-out infinite;
  overflow: visible;
}
@keyframes holoFloat {
  0%, 100% { transform: perspective(900px) rotateY(17deg) rotateX(4deg) rotateZ(-2deg) translateY(0); }
  50%      { transform: perspective(900px) rotateY(15deg) rotateX(3deg) rotateZ(-2deg) translateY(-10px); }
}
/* подложка почти прозрачная: рендер живёт на свечении по прозрачному
   фону, и плотная плашка рядом с ним читалась «дырой» */
.holo-bg { fill: rgba(9, 7, 6, .34); stroke: rgba(242, 189, 195, .45); stroke-width: 1.5; }
.holo-chrome circle { fill: rgba(242, 189, 195, .65); }
.holo-url { fill: rgba(242, 189, 195, .12); }
.holo .s {
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.holo .s.w { stroke-width: 5; }
.holo .f { fill: rgba(242, 189, 195, .26); stroke: none; }
/* до JS и в статичном режиме виден первый вариант; остальные ждут */
.holo-l { opacity: 0; }
.holo:not(.is-live) .holo-l:first-of-type, .holo-l.is-on { opacity: 1; }
html.is-static .holo { animation: none; }
/* АКТИВНЫЙ ПУНКТ = ТОТ, ЧЕЙ САЙТ СЕЙЧАС НА ГОЛОГРАММЕ (25.08.2026,
   Георгий: «выглядит пусто, нет вау-эффекта»). Связь списка и сцены
   была почти невидимой — менялся только цвет заголовка, и левая
   половина читалась статичным текстом рядом с живой картинкой. Теперь
   активный пункт выезжает вперёд, подсвечивается тёплым полем и
   получает медный штрих слева: видно, что список УПРАВЛЯЕТ сценой. */
.rows li {
  transition: transform .55s cubic-bezier(.22,1,.36,1), opacity .5s;
}
/* пока сцена перебирает варианты, неактивные пункты приглушены */
.rows.is-linked li { opacity: .45; }
.rows.is-linked li.is-on { opacity: 1; }
.rows li.is-on { transform: translateX(clamp(8px, .9vw, 16px)); }
.rows li.is-on h3 { color: var(--cu-hi); text-shadow: 0 0 26px rgba(233, 188, 169, .55); }
/* тёплое поле за активным пунктом — тот же приём, что .leg::after
   в «Процессе»: свет на половине кадра, а не рамка */
.rows li::after {
  content: '';
  position: absolute;
  left: clamp(-1.4rem, -1.6vw, -.9rem); right: 12%;
  top: 0; bottom: 0;
  border-radius: 14px;
  background: radial-gradient(60% 120% at 8% 50%,
    rgba(233, 188, 169, .1), rgba(233, 188, 169, .045) 42%, rgba(233, 188, 169, 0) 78%);
  opacity: 0;
  transition: opacity .5s;
  pointer-events: none;
}
.rows li.is-on::after { opacity: 1; }
/* медный штрих слева — короткий, прочерчивается только у активного */
.rows li::before {
  content: '';
  position: absolute;
  left: clamp(-1.4rem, -1.6vw, -.9rem);
  top: clamp(1rem, 2vh, 1.5rem); bottom: clamp(1rem, 2vh, 1.5rem);
  width: 2px; border-radius: 2px;
  background: linear-gradient(180deg, #FFE3C2, #F0BE9C 60%, rgba(201, 143, 134, .35));
  box-shadow: 0 0 12px rgba(240, 190, 156, .7);
  transform: scaleY(0); transform-origin: center top;
  transition: transform .55s cubic-bezier(.22,1,.36,1);
}
.rows li.is-on::before { transform: scaleY(1); }
.rows li:first-child::before { top: 0; }

/* три типа сайтов */
.site-types {
  display: grid; grid-template-columns: 1fr;
  /* было 8–12px: при заголовках 33px карточки слипались в ленту */
  gap: clamp(14px, 1.2vw, 20px);
  margin-top: clamp(1.4rem, 2.4vh, 2rem);
}
/* Панель вместо рамки — единый приём с .leg в «Процессе» (23.08.2026):
   обведённые прямоугольники читались таблицей и сливались с фоном.
   Держат карточку панель #2A1F1A→#1B1411 (контраст к фону 1.25:1),
   медный кант сверху и глубокая тень. */
.site-card {
  border-radius: 16px;
  background:
    radial-gradient(120% 130% at 8% 0%, rgba(201, 143, 134, .12), rgba(201, 143, 134, .07) 22%, rgba(201, 143, 134, .036) 40%, rgba(201, 143, 134, .014) 58%, rgba(201, 143, 134, .004) 78%, rgba(201, 143, 134, 0) 100%),
    linear-gradient(155deg, #2A1F1A, #1B1411 72%);
  box-shadow:
    inset 0 1px 0 rgba(233, 188, 169, .16),
    0 20px 44px -28px rgba(0, 0, 0, .95);
  transition: transform .5s cubic-bezier(.22,1,.36,1), box-shadow .5s;
}
.site-card:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1px 0 rgba(233, 188, 169, .3),
    0 28px 56px -26px rgba(0, 0, 0, .95),
    0 0 44px -16px rgba(233, 188, 169, .3);
}

/* Аккордеон убран 23.08.2026: описания сократились до одной строки,
   прятать их за раскрытием больше незачем. Карточка — обычный блок. */
.site-card { padding: clamp(1.1rem, 1.5vw, 1.6rem) clamp(1.1rem, 1.5vw, 1.7rem); }

/* Плакатный контраст, как в .leg: было 1.15rem против текста .81rem —
   всего 1.34x, карточки читались ровной серой массой. Стало ~3x. */
.site-card h3 {
  position: relative;
  width: fit-content;
  font-size: clamp(1.5rem, 2.2vw, 2.3rem);
  line-height: .95;
  letter-spacing: -.03em;
  margin: 0 0 .5rem;
  transition: color .45s;
}
.site-card:hover h3 { color: var(--cu-hi); }
/* декоративная засечка убрана: на кегле 2.3rem она дробила заголовок
   (тот же вывод, что и для .leg h3::after) */
.site-card h3::after { content: none; }
.site-card h3::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, #FFF3E2, #FFE3C2 45%, #F0BE9C);
  box-shadow: 0 0 10px rgba(233,188,169,.95);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .5s cubic-bezier(.22,1,.36,1);
}
.site-card:hover h3::before { transform: scaleX(1); }


.site-card p {
  margin: 0;
  font-size: clamp(.92rem, 1vw, .98rem); line-height: 1.55;
  color: rgba(241, 236, 231, .62);
  max-width: 44ch;
}

/* возможности — важный блок, поэтому крупнее и с собственным весом */
/* Открытая фраза под карточками — она держит позиционирование:
   без неё три формата читались бы закрытым списком услуг.
   Медный кант слева связывает её с карточками, но кегль ниже
   заголовков, чтобы фраза не спорила с ними за внимание. */
/* ОБОСОБЛЕННЫЙ ХВОСТ «САЙТОВ» (25.08.2026, Георгий: «эти два я бы
   обособил, смысловая нагрузка другая»). Три формата живут на рельсе,
   а «сверх того» и «а если иначе» — под ним, отделённые полем и
   гаснущей линией; у каждого свой приём, чтобы они не читались
   продолжением списка и не спорили друг с другом. */
/* ХВОСТ «САЙТОВ» — ПРОДОЛЖЕНИЕ РЕЛЬСА (25.08.2026, Георгий: «всё ещё не
   красивая эта часть, линия тут не нужна, шрифты должны приятно читаться
   и хорошо вставать относительно других блоков»). Было: горизонтальная
   линия сверху (дублировала разделитель глав), перечисление через точки
   с висящим «CMS» на второй строке и приглушённая приписка — три разных
   кегля подряд. Стало: блок продолжает вертикальный рельс форматов (тот
   же отступ слева, свой узел на линии), кегль и интерлиньяж как у .rows p,
   всё перечисление — одной фразой без обрывов. */
/* ХВОСТ — ОТДЕЛЬНЫЙ БЛОК ВО ВСЮ ШИРИНУ КОЛОНКИ (25.08.2026, Георгий:
   «всё равно сливается и не выделяется, может подлиннее сделать текст
   в ширь, как-то бы выделить его красиво»). До правки он жил в узкой
   мере 46ch, а справа оставалось пустое поле — читался обрезком списка.
   Теперь: тёплое медное поле от левого края вправо (гаснет в прозрачность,
   правило палитры — заливка не кончается цветом), тонкая медная черта
   сверху и увеличенная мера строк. Блок видно как блок, но рамки нет. */
.sites-extra {
  position: relative;
  margin-top: clamp(2rem, 3.8vh, 3rem);
  padding: clamp(1.5rem, 2.8vh, 2.2rem) clamp(1.4rem, 2.4vw, 2.2rem) clamp(1.5rem, 2.8vh, 2.2rem) clamp(1.3rem, 2vw, 1.8rem);
  margin-left: clamp(-1.3rem, -2vw, -1.8rem);
  border-radius: 18px;
  /* Черта сверху убрана 25.08.2026 («линия лишняя»). Поле усилено:
     сливалось с фоном. Плотная тёплая подложка + медный отсвет из
     левого верхнего угла, гаснущий в прозрачность вправо (правило
     палитры: заливка не кончается цветом). Верх подсвечен внутренней
     линией inset — блок «приподнят» над фоном без рамки. */
  background:
    radial-gradient(120% 140% at 0% 0%,
      rgba(233, 188, 169, .13),
      rgba(233, 188, 169, .06) 38%,
      rgba(233, 188, 169, .02) 62%,
      rgba(233, 188, 169, 0) 86%),
    linear-gradient(160deg, #221815, #17100E 72%);
  box-shadow:
    inset 0 1px 0 rgba(233, 188, 169, .18),
    0 22px 48px -30px rgba(0, 0, 0, .9);
}
/* ХВОСТ — ЧЕТВЁРТЫЙ ПУНКТ «ПУЛЬТА» + ЖИВЫЕ СЛОВА (26.08.2026, Георгий:
   «выделен хорошо, но в купе с другими элементами не ВАУ»). Панель
   стояла под живой сценой мёртвым прямоугольником: у списка форматов есть
   голограмма, которая отвечает на каждый пункт, у панели — ничего.
   Теперь она отвечает на слой голограммы «если нужно больше» тем же
   языком, что пункты .rows.is-on: выезжает вперёд на 8–16px, отсвет из
   левого верхнего угла разгорается, заголовок светится. А слова
   возможностей внутри — кинетическая типографика ПО НАВЕДЕНИЮ (правка
   Георгия: «вид у слов меняется только когда на них курсор наводишь»):
   под словом под курсором встаёт медный штрих .live-mark, и слово
   показывает себя (волна букв, оборот, клик, разъезд, языки, печать —
   main.js → extraLive). Статика: без JS это обычный абзац. */
.sites-extra {
  transition: transform .55s cubic-bezier(.22,1,.36,1), box-shadow .6s;
}
.sites-extra::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  background: radial-gradient(75% 95% at 4% 6%,
    rgba(233, 188, 169, .2), rgba(233, 188, 169, .07) 40%, rgba(233, 188, 169, 0) 72%);
  opacity: 0;
  transition: opacity .7s;
  pointer-events: none;
}
/* текст — над отсветом (тот же приём, что z-index у .rows h3/p) */
.sites-extra > * { position: relative; z-index: 1; }
.sites-extra.is-on { transform: translateX(clamp(8px, .9vw, 16px)); }
.sites-extra.is-on::before { opacity: 1; }
.sites-extra.is-on .extra-t { text-shadow: 0 0 30px rgba(233, 188, 169, .7), 0 0 8px rgba(233, 188, 169, .3); }
.extra-t { transition: text-shadow .6s; }
/* живое слово: не рвётся на переносе (иначе штрих ляжет на две строки),
   держит буквы-спаны и кольцо клика */
.extra-line { position: relative; }
.extra-line .live {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  color: var(--ink);
  transition: color .35s, text-shadow .35s;
  cursor: default;
}
.extra-line .live.is-on, .extra-line .live:hover {
  color: var(--cu-hi);
  text-shadow: 0 0 18px rgba(233, 188, 169, .5);
}
.extra-line .live .ch { display: inline-block; }
/* inline-block даёт точку переноса после себя даже перед &nbsp; —
   «CMS —» держим вместе обёрткой */
.extra-line .nb { white-space: nowrap; }
/* «3D» крутится вокруг вертикальной оси — нужна перспектива на слове */
.extra-line .live[data-fx="spin"] { transform-style: preserve-3d; }
/* «интерактив»: кольцо клика расходится из центра слова */
.extra-line .live[data-fx="click"]::after {
  content: '';
  position: absolute;
  left: 50%; top: 55%;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 50%;
  border: 1.5px solid var(--cu-hi);
  opacity: 0;
  pointer-events: none;
}
.extra-line .live[data-fx="click"].play::after { animation: liveRipple .9s ease-out; }
@keyframes liveRipple {
  0%   { opacity: .9; transform: scale(.35); }
  100% { opacity: 0;  transform: scale(6); }
}
/* «CMS»: каретка редактора */
.extra-line .live .caret {
  display: inline-block;
  width: 2px; height: .95em;
  margin-left: 2px;
  vertical-align: -.12em;
  background: var(--cu-hi);
  box-shadow: 0 0 8px rgba(233, 188, 169, .8);
  animation: liveCaret .8s steps(1) infinite;
}
@keyframes liveCaret { 50% { opacity: 0; } }
/* медный штрих под словом под курсором: тот же материал, что штрих
   у активного пункта списка, только горизонтальный */
.live-mark {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(240, 190, 156, 0), #FFE3C2 30%, #F0BE9C 70%, rgba(240, 190, 156, 0));
  box-shadow: 0 0 12px rgba(240, 190, 156, .7);
  opacity: 0;
  pointer-events: none;
  will-change: transform, width;
}
html.is-static .live-mark, html.is-static .live .caret { display: none; }

/* ЛЕСТНИЦА КЕГЛЕЙ В ХВОСТЕ (25.08.2026, Георгий: «нужны более интересные
   шрифты, приятнее визуально, и размеры чтобы лучше было это углядеть»).
   Замер до правки: заголовки списка 32px, а весь хвост 12,5 / 17 / 19px —
   разрыв 32→17 читался обрывом, а mono-метка 12,5px почти не читалась.
   Третьего шрифта не добавляем (Caveat закреплён за одной фразой в «О нас»,
   см. правило про третью типографическую роль) — «интереснее» делаем
   масштабом и весом внутри Golos: метка 15px и ярче, перечисление 20px
   светлым, финальная фраза 24px. */
/* ЗАГОЛОВОК ХВОСТА — GOLOS, НЕ MONO-КАПС (25.08.2026, Георгий: «тут шрифт
   вообще не красивый, нужно изменить на более привлекательный»). Было:
   JetBrains Mono + uppercase + разрядка .22em — технический вид разреженных
   букв, уместный для мелких меток, но не для заголовка блока. Стало: тот же
   Golos, что у заголовков форматов, строчными, крупно и медью — заголовок
   читается как заголовок и рифмуется с «Лендинг / Сайт или магазин». */
.extra-t {
  display: block;
  font-family: var(--font-sans);
  font-size: clamp(1.3rem, 1.65vw, 1.65rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -.025em;
  text-transform: none;
  color: var(--cu-hi);
  text-shadow: 0 0 24px rgba(233, 188, 169, .45);
  margin-bottom: .6rem;
}
/* перечисление — крупнее базового текста и светлее: это не сноска,
   а вторая по важности мысль главы после форматов */
.extra-line {
  margin: 0;
  font-size: clamp(1.06rem, 1.25vw, 1.25rem);
  line-height: 1.5;
  letter-spacing: -.01em;
  color: rgba(241, 236, 231, .82);
  /* в ширину колонки: при 46ch строка рвалась на три и блок читался
     узким столбцом рядом с пустым полем (25.08.2026) */
  max-width: 62ch;
}
/* «а если иначе» — единственный акцент хвоста: крупнее, со стрелкой,
   ведёт к контактам. Отделён воздухом, а не линией */
/* «а если иначе» — смысловая фраза, а не призыв к заявке (25.08.2026:
   ссылку на #contacts и стрелку убрали по просьбе Георгия). Единственный
   акцент хвоста держит кегль и медное выделение второй половины фразы */
.sites-open {
  margin: clamp(1.6rem, 3vh, 2.4rem) 0 0;
  padding: 0;
  border: 0;
  /* самая крупная строка хвоста: 24px против 20px перечисления —
     лестница 32 → 20 → 24 читается, обрыва 32 → 17 больше нет */
  font-size: clamp(1.2rem, 1.5vw, 1.5rem);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -.022em;
  color: var(--ink);
  /* в ширину колонки, как .extra-line: узкая мера делала блок столбцом */
  max-width: 56ch;
}
.sites-open b {
  font-weight: 500;
  color: var(--cu-hi);
  text-shadow: 0 0 20px rgba(233, 188, 169, .5);
}
/* та же фраза-позиционирование в «Приложениях» стоит после сетки карточек */
/* та же роль в «Приложениях», но не ссылка: своё правило, потому что
   .sites-open стал inline-flex со стрелкой (25.08.2026) */
/* кегль и вес — как у .sites-open: обе фразы играют одну роль
   («а если иначе») и должны читаться одинаково (25.08.2026) */
/* .apps-open больше не своё правило (26.08.2026, «чтобы гармонировали»):
   фраза стоит в такой же панели .apps-extra и носит класс .sites-open —
   кант слева и меньший кегль убраны, обе фразы-выхода теперь одинаковы */
/* ЕДИНСТВЕННЫЙ БЛОК ХВОСТА «ПРИЛОЖЕНИЙ» — ВЫДЕЛЕН СИЛЬНЕЕ (26.08.2026,
   Георгий: «замени на один… и отдельно выдели его»). Раньше панель была
   продолжением списка форматов; теперь она осталась одна и должна
   читаться самостоятельным блоком: крупнее поле, ярче кант и отсвет,
   заголовок в кегле заголовков списка (не мелкая подпись). */
.apps-extra--solo {
  margin-top: clamp(2.2rem, 4vh, 3.2rem);
  padding: clamp(1.9rem, 3.4vh, 2.6rem) clamp(1.8rem, 2.8vw, 2.6rem);
  box-shadow:
    inset 0 1px 0 rgba(233, 188, 169, .26),
    0 26px 60px -34px rgba(0, 0, 0, .92);
}
.apps-extra--solo::before {
  background: radial-gradient(78% 100% at 4% 4%,
    rgba(233, 188, 169, .17), rgba(233, 188, 169, .07) 40%, rgba(233, 188, 169, 0) 74%);
  opacity: 1;
}
/* заголовок блока — как заголовки форматов в списке, а не мелкая метка */
.apps-extra--solo .extra-t {
  font-size: clamp(1.45rem, 2vw, 2rem);
  line-height: 1.05;
  letter-spacing: -.03em;
  margin-bottom: .7rem;
}
.apps-extra--solo .extra-line { max-width: 60ch; }

/* ============================================================
   СПИСКИ .rows — ЧИСТАЯ ТИПОГРАФИКА (25.08.2026, итог четырёх правок
   Георгия). Отвергнуто по очереди: (1) строки «заголовок | текст» с
   горизонтальными линиями — читались таблицей; (2) вертикальный медный
   рельс с узлами — «нужно вообще переосмыслить, я бы её заменил»,
   повторял рельс «Процесса» и выглядел технической шкалой; (3) крупные
   моно-номера 01/02/03 слева — «нумерация ещё хуже получилась».
   ИТОГ: никакой графики вообще. Пункт держат только заголовок, текст и
   воздух между пунктами; разделение — увеличенный интервал, а не линия.
   Ничего сюда не добавлять: любой маркер уже пробовали и отвергли.
   ============================================================ */
.rows {
  list-style: none;
  margin: clamp(1.4rem, 2.6vh, 2.2rem) 0 0;
  padding: 0;
}
.rows li { position: relative; padding: clamp(1rem, 2vh, 1.5rem) 0; }
.rows li:first-child { padding-top: 0; }
/* заголовок и текст — над подсветкой активного пункта */
.rows h3, .rows p { position: relative; z-index: 1; }
.rows h3 {
  margin: 0 0 .4rem;
  font-size: clamp(1.45rem, 2vw, 2rem);
  line-height: 1.05;
  letter-spacing: -.03em;
  color: var(--ink);
  transition: color .4s, text-shadow .4s;
}
.rows li:hover h3 { color: var(--cu-hi); text-shadow: 0 0 22px rgba(233, 188, 169, .5); }
.rows p {
  margin: 0;
  font-size: clamp(.95rem, 1.05vw, 1.06rem);
  line-height: 1.55;
  color: var(--ink-70);
  max-width: 46ch;
}
/* «Автоматизация»: шесть ситуаций в две колонки */
/* ОДНА КОМПОЗИЦИЯ НА ВСЕ ТРИ ГЛАВЫ УСЛУГ (26.08.2026, Георгий: «по
   сравнению с прошлыми блоками сейчас это выглядит не очень»). ЗАМЕР
   объяснил причину: у «Сайтов» текст 771px, у «Приложений» 790px — это
   колонка рядом с рендером, фирменная композиция главы. «Автоматизация»
   была растянута на 1400px в две колонки и читалась чужой. Теперь
   карточки идут ОДНОЙ колонкой под заголовком, в той же мере, что у
   соседей: текст слева, Гоша справа — зеркально «Сайтам». */
.rows--wide {
  display: grid;
  /* две колонки в мере колонки главы: шесть примеров одной колонкой
     растягивали секцию до 1745px против 1098 у «Сайтов» (26.08.2026) */
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(1.6rem, 2.6vw, 2.8rem);
  /* ВОЗДУХ МЕЖДУ РЯДАМИ (27.08.2026, Георгий: «некрасиво оформлены»).
     Был row-gap .2–.8rem (замер: 7.6px) — заголовок следующего пункта
     стоял почти вплотную к тексту предыдущего, шесть пунктов читались
     сплошной кашей. У соседних глав роль разделителя играет воздух,
     здесь его не было. */
  row-gap: clamp(1.6rem, 3.4vh, 2.9rem);
  margin-top: clamp(1.4rem, 2.6vh, 2.2rem);
}
/* ряды выровнены по верхнему краю ячейки, а пункты внутри тянутся на
   всю её высоту: иначе при коротком тексте («Данные», «Отчёты»)
   соседи по ряду съезжали друг относительно друга */
.rows--wide li {
  padding-bottom: 0;
  display: flex; flex-direction: column;
}
.rows--wide li:first-child, .rows--wide li:nth-child(2) { padding-top: 0; }
.rows--wide p { max-width: 34ch; }

/* Жёсткий border-top заменён линией, гаснущей в прозрачность по краям —
   тот же приём, что и у .seam: сплошная линия во всю ширину читалась
   рубцом, а по правилу палитры заливка не должна кончаться цветом. */
.site-skills {
  position: relative;
  padding-top: clamp(1.6rem, 3vh, 2.4rem);
  margin-top: clamp(1rem, 2vh, 1.6rem);
}
.site-skills-t {
  display: block;
  font-family: var(--font-mono);
  font-size: clamp(.78rem, 1.05vw, .95rem);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--cu-hi);
  text-shadow: 0 0 16px rgba(233, 188, 169, .65);
  margin-bottom: .95rem;
}
/* КОМПАКТНОЙ СТРОКОЙ (25.08.2026, правка Георгия «иишные блоки»): сетка
   в три колонки давала огромные дыры между плашками, и чипы читались
   случайными тегами. Теперь плашки стоят вплотную, как слова в строке */
.site-skills ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: .15rem 0;
  padding: 0; margin: 0;
}
/* НЕ ПИЛЮЛИ, А СТРОКА ТЕКСТА ЧЕРЕЗ ТОЧКИ (25.08.2026, третий заход,
   Георгий: «слишком много ии-слопа, много блоков»): 17 пилюль с рамками
   и свечением — главный маркер сгенерированного лендинга. Теперь
   возможности перечислены одной строкой, как в бегущей строке #acts */
.site-skills li {
  display: inline-flex; align-items: center;
  font-size: clamp(.95rem, 1.1vw, 1.04rem);
  line-height: 1.5;
  color: rgba(241, 236, 231, .78);
  transition: color .35s;
}
/* минималистичный глиф у каждой возможности */
/* Иконки убраны из чипов #sites (23.08.2026), чтобы блок возможностей
   не читался перечнем технических навыков. В #apps они остались —
   стиль сохранён и используется там. */
.skill-ico {
  flex: none;
  width: 1.15em; height: 1.15em;
  fill: none;
  stroke: #F0BE9C;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: #F0BE9C;
  filter: drop-shadow(0 0 4px rgba(233, 188, 169, .5));
  transition: stroke .35s, filter .35s;
}

/* Гоша и вся связка систем — закрывающий образ секции автоматизации */
.auto-art {
  position: relative;
  display: flex; justify-content: center;
  margin: clamp(1.4rem, 3vh, 2.6rem) auto 0;
  width: 100%;
}
.auto-art::before {
  content: '';
  position: absolute;
  left: 50%; top: 46%;
  width: min(92%, 700px); aspect-ratio: 1.15;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse 50% 50% at 50% 50%, rgba(201, 143, 134, .16), rgba(201, 143, 134, .1165) 14%, rgba(201, 143, 134, .0859) 24.5%, rgba(201, 143, 134, .0613) 33.6%, rgba(201, 143, 134, .0418) 42%, rgba(201, 143, 134, .0269) 49%, rgba(201, 143, 134, .016) 55.3%, rgba(201, 143, 134, .0085) 60.2%, rgba(201, 143, 134, .0037) 64.4%, rgba(201, 143, 134, .0012) 67.2%, rgba(201, 143, 134, 0) 70%);
  filter: blur(30px);
  pointer-events: none;
}
/* aspect-ratio — резерв места под картинку 1211x1299 (1.7 МБ), иначе CLS */
.auto-art img { position: relative; z-index: 1; width: min(80%, 600px); height: auto; aspect-ratio: 1211 / 1299; }

/* падающий код по бокам — «он программирует» */
.code-rain {
  /* height задан явно: canvas — replaced-элемент, ему bottom:0 высоту не растягивает */
  position: absolute; top: 0;
  height: 100%;
  /* шире (25% → 32%, 26.08.2026): «машинное отделение» Георгия —
     код занимает больше кадра, глава читается глубже соседних */
  width: clamp(150px, 32%, 420px);
  pointer-events: none;
  /* гаснет сверху-снизу и к центру, чтобы не спорить с фигурой */
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
.code-rain--l {
  left: 0;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent),
                      linear-gradient(90deg, #000 68%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent),
              linear-gradient(90deg, #000 68%, transparent 100%);
}
.code-rain--r {
  right: 0;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent),
                      linear-gradient(270deg, #000 68%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent),
              linear-gradient(270deg, #000 68%, transparent 100%);
}

/* ============================================================
   СБОРКА САЙТА ПО СЛОЯМ — 3D-сцена
   ============================================================ */


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


/* сцена */
.layers-stage {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: clamp(260px, 38vh, 560px);
  margin-inline: auto;
}
.layers-stage canvas { border-radius: 20px; }

/* запасной вариант, если WebGL недоступен.
   СКРЫТ ПО УМОЛЧАНИЮ (27.08.2026, Георгий: «после обновления свайпнуть —
   появится картинка человечка и уйдёт»): раньше подложка была видима,
   пока 3D-модуль грузится, и при быстром свайпе мелькала во весь экран.
   Теперь появляется ТОЛЬКО когда модуль сам сказал is-fallback
   (WebGL реально недоступен). */
.layers-fallback { display: none; }
.layers-stage.is-fallback .layers-fallback {
  display: block;
  position: absolute; inset: 0; margin: auto;
  max-height: 100%; width: auto;
  opacity: .85;
}

/* кнопка под сценой */


/* ============================================================
   АВТОМАТИЗАЦИЯ — всё в один экран: зачем, как, что именно, какая выгода
   ============================================================ */

.chain {
  position: relative;
  padding-block: var(--pad-sec);  /* общий ритм (26.08.2026) */
  /* вторая тёмная плита идёт сразу за .layers — она мельче
     по глубине и без верхней границы, иначе две слипаются в одну */
  /* без собственной плиты: любая заливка (даже гаснущая в
     прозрачность) даёт видимую линию на границе, потому что
     прозрачность != цвет фона под ней. Глубину даёт .chain::before */
  background: none;
}
.chain-h { font-size: clamp(2.3rem, 4.2vw, 4.4rem); margin: .85rem 0 1rem; max-width: 14ch; }
/* шапка «Автоматизации»: текст слева, Гоша справа — как .sites-main */
/* КОМПОЗИЦИЯ ГЛАВЫ (26.08.2026, Георгий: «блок визуально не доработан»).
   ДИАГНОЗ по кадру всей главы: align-items: center центрировал короткий
   заголовок по высоте рендера Гоши (579px), из-за чего между низом
   заголовка и началом карточек зияли ~200px пустоты во всю ширину —
   глава распадалась на «шапку» и «список». Теперь колонки выровнены
   по ВЕРХУ, а нижний отступ шапки отрицательный: карточки подтянуты
   под заголовок и читаются его продолжением, а не отдельным блоком. */
/* ГЛАВА СОБРАНА КАК «САЙТЫ» (26.08.2026): одна сетка на всю главу —
   слева колонка текста (заголовок → примеры → панель), справа Гоша во
   всю высоту. Раньше .chain-top держал только шапку, а карточки шли под
   ней во всю ширину: рендер занимал верхнюю треть, под ним была пустота,
   и глава выпадала из ряда двух соседних. */
.chain-main {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(1.5rem, 3.5vw, 3.4rem);
  align-items: center;
}
.chain-col { display: flex; flex-direction: column; }
.chain-main .auto-art { margin: 0; justify-self: end; }
.chain-main .auto-art img { width: min(100%, 560px); }
.chain-main .auto-art::before { width: min(100%, 540px); }
.chain-copy .body { max-width: 46ch; }


.chain-head .body { font-size: .95rem; max-width: 46ch; }

/* КАК ЭТО РАБОТАЕТ — цепочка на светящемся проводе */

/* КОМПОЗИЦИЯ «СИТУАЦИИ + ГОША» (25.08.2026, второй заход по правке
   Георгия «сумбурно, иишные блоки, всё в одной каше»): карточки
   ситуаций слева, рендер справа — зеркально .sites-main. Аккордеоны
   .auto-card, подпись «нажмите, чтобы раскрыть» и три «выгоды» .gains
   удалены: закрытые карточки читались списком заголовков без
   содержания, выгоды дублировали провод. Не возвращать. */
/* (сетка карточек 2×3 и панели .site-card--sm убраны 25.08.2026 —
   ситуации идут одностроками .rows--wide под проводом) */

/* AI — ОДНОЙ СТРОКОЙ внутри «Автоматизации» (решение Георгия 25.08.2026;
   панель и колонки сняты по правке «перегруз»): mono-подпись, одно
   предложение с примером, перечисление видов работы через точки */
/* .ai-line и AI-блок убраны 26.08.2026: панель .chain-extra закрывает
   главу мыслью «это только примеры» */
/* ХВОСТ «АВТОМАТИЗАЦИИ» — ШИРОКАЯ ПАНЕЛЬ В ДВЕ КОЛОНКИ (26.08.2026,
   Георгий: «в таком же стиле, но он больше и крайний — своя изюминка»).
   Общие правила — .sites-extra; здесь только отличия: панель во всю
   ширину главы, слева AI (заголовок, строка видов работы, пример, который
   меняется по наведению на слово), справа — фраза-выход крупнее, чем в
   «Сайтах» и «Приложениях»: она закрывает не главу, а все услуги. Сдвиг
   .is-on вправо снят — широкой панели некуда выезжать, остаётся отсвет. */
.chain-extra {
  display: grid;
  /* одна колонка (26.08.2026): фраза-выход «Один раз настроили…» удалена
     по правке Георгия, вторая колонка опустела — при 1.3fr/.7fr текст
     занимал две трети ширины, а справа оставалась дыра */
  grid-template-columns: 1fr;
  /* панель в той же мере, что у «Сайтов» и «Приложений» (~800px): во всю
     ширину (1581px) она выпадала из ряда трёх глав (26.08.2026) */
  margin-top: clamp(2rem, 3.4vh, 2.8rem);
}
.chain-extra.is-on { transform: none; }
/* текст крупнее базового: это единственная фраза панели и главная мысль
   главы — «перечисленное выше только примеры» */
/* ПАНЕЛЬ КАК У СОСЕДЕЙ (26.08.2026, Георгий: «должен выглядеть так же,
   как два аналогичных сверху»). Свой кегль 21.6px и мера 78ch остались
   от удалённого AI-блока — панель была единственной без заголовка
   .extra-t и с более крупным текстом. Теперь наследует общее правило */
.chain-extra .extra-line { line-height: 1.5; }

/* ============================================================
   КЕЙСЫ — крупные истории
   ============================================================ */


/* ============================================================
   ДВА ЧЕЛОВЕКА
   ============================================================ */

/* ============================================================
   ПРИЛОЖЕНИЯ — под ключ, любой сложности
   ============================================================ */

/* ритм общий (--pad-sec), частное правило снято 26.08.2026 */
/* глава сквозных тезисов — короче остальных: шапка, две панели, кнопка */
.apps-head {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: end;
  margin-bottom: clamp(1.1rem, 2.2vh, 1.8rem);
}
.apps-h { font-size: clamp(2.3rem, 4.2vw, 4.4rem); margin: .85rem 0 1rem; max-width: 14ch; }
/* панель хвоста в «Приложениях» — общие правила .sites-extra (26.08.2026),
   сюда только то, что отличает: хвост стоит в правой колонке, поэтому
   отсвет .is-on тот же, а отрицательный margin-left оставлен — поле
   выходит за левый край текста, как в «Сайтах» */
.apps-col .body { max-width: 46ch; }
.apps-h .solve { text-shadow: 0 0 30px rgba(201,143,134,.5), 0 0 8px rgba(201,143,134,.35); }
.apps-head .body { font-size: .95rem; max-width: 48ch; }

/* слева 3D-сцена, справа типы приложений */
/* ГЛАВА-СЦЕНА (телефон на 100vw, форматы строкой под сценой) ПРОБОВАЛАСЬ
   И ОТВЕРГНУТА 26.08.2026 («как-то вообще не очень получилось»): сцена
   вышла пустой. Раскладка возвращена — не повторять. */
.apps-main {
  display: grid;
  /* сцена слева, весь текст главы справа (шапка + строки + фраза) —
     зеркально «Сайтам», как чередуются шаги «Процесса» */
  grid-template-columns: .95fr 1.05fr;
  gap: clamp(1.5rem, 3.5vw, 3.4rem);
  align-items: center;
  margin-bottom: 0;
}
.apps-stage {
  position: relative;
  width: 100%;
  height: clamp(360px, 54vh, 600px);
}


.apps-types .apps-open { margin-top: clamp(.3rem, .8vh, .8rem); }

/* ============================================================
   СТОИМОСТЬ — стартовые цены по направлениям
   ============================================================ */

/* светлая секция-пауза: тёмный сайт «выдыхает», цены читаются
   как разворот дорогого каталога. Иллюстраций со свечением здесь нет,
   поэтому светлый фон ничего не гасит */
/* Светлая заливка непрозрачна и обрывалась ровно на границе секции —
   это и была видимая склейка. Теперь песок лежит в ::before, который
   выходит ЗА пределы секции и растворяется по краям через mask:
   граница заливки физически не совпадает с границей блока. */

/* СВЕТЛАЯ СЕКЦИЯ-ПАУЗА. Верх без прозрачного края — сверху стоит светлая
   «Кейсы», шов между ними не рисуем; гаснет только НИЗ (стык с тёмным
   «О нас»). Край гаснет в ПРОЗРАЧНОСТЬ, а не в цвет: тогда он совпадает
   с любым фоном под ним. */
#pricing { color: var(--sand-ink); }
#pricing {
  /* ПРОСТОЙ ГРАДИЕНТ (26.08.2026, седьмая правка. ЗАМЕР В БРАУЗЕРЕ решил
     спор: сняли headless-Chrome, декодировали PNG и прошли столбец
     пикселей. Эталон — обычный градиент из 4 стопов: макс скачок Δ2.0,
     идеально. Моя «линейная по яркости» кривая из 60 стопов: Δ3.8, Δ3.1,
     Δ2.1 ПОДРЯД на первых 4 пикселях спада (238→236→234→230→228→225) —
     вот эта ступенька и читалась чёткой линией под кнопкой. Причина: у
     такой кривой alpha в начале меняется рывком, а частые стопы этот
     рывок фиксируют. ВЫВОД: чем МЕНЬШЕ стопов, тем глаже — браузер сам
     интерполирует лучше, чем ручная развёртка. Не возвращать ни
     smootherstep, ни линейную по яркости, ни 60 стопов. */
  background: linear-gradient(180deg,
    var(--sand) 0px,
    var(--sand) calc(100% - 20px),
    rgba(235,226,216,.55) calc(100% - 10px),
    rgba(235,226,216,0) 100%);
}
/* зерно-дизеринг: ломает ровные границы уровней яркости */
#pricing::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 40px;  /* под кромку 20px (26.08.2026) */
  pointer-events: none;
  z-index: 0;
  opacity: .5;
  mix-blend-mode: soft-light;
  /* КРАЙ САМОГО СЛОЯ ЗЕРНА БЫЛ ВИДЕН КАК ЛИНИЯ (26.08.2026, шестая правка
     Георгия). soft-light слой начинался резко: выше зерна нет, ниже есть —
     граница читалась горизонтальной чертой ровно в начале перехода, там
     где песок ещё плотный. Теперь слой гаснет по краям маской. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.15) 14%, rgba(0,0,0,.5) 30%, rgba(0,0,0,.85) 48%, #000 65%, #000 100%);
  mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.15) 14%, rgba(0,0,0,.5) 30%, rgba(0,0,0,.85) 48%, #000 65%, #000 100%);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='npr'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23npr)'/%3E%3C/svg%3E");
}

#pricing .halo { opacity: .22; }

/* ШОВ СХЛОПНУТ (26.08.2026, Георгий: «соединить блоки, чтобы гармонично»):
   общие 90–180px .sec с обеих сторон давали до 360px пустого песка между
   лентой кейсов и вопросом о цене — блоки читались чужими. Обе секции
   светлые, воздух между ними нужен небольшой. */
/* низ короче: под ним сразу «Стоимость», обе секции светлые */
#cases { padding-bottom: clamp(28px, 3.5vw, 48px); }

/* МЕЖДУ «КЕЙСАМИ» И ЦЕНОЙ — ЧИСТЫЙ ВОЗДУХ (26.08.2026, итог четырёх
   правок Георгия: палка → кольца-мишень → точки-многоточие, всё
   отвергнуто). Соединителя нет и не добавлять: обе секции светлые,
   стык бесшовный, связь держат сами отступы. */
/* «Стоимость» идёт сразу за «Кейсами» — верх короче общего ритма */
#pricing { padding-top: clamp(28px, 3.5vw, 48px); }

/* блок по центру, как стоял до правок */
.price-block { max-width: 62ch; margin: 0 auto; text-align: center; }
.pricing-h { margin-left: auto; margin-right: auto; }

/* ШРИФТ (26.08.2026, Георгий: «неприятно читать»). Третью гарнитуру не
   вводим (Caveat закреплён за одной фразой в «О нас») — меняем звучание
   внутри Golos: первый абзац крупный, вес 500, полный контраст; второй —
   обычный, но с воздухом 1.7 и в спокойном сером. */
.price-p--first {
  font-size: clamp(1.22rem, 1.6vw, 1.55rem);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: -.014em;
  max-width: 46ch;
  margin-left: auto;
  margin-right: auto;
  color: var(--sand-ink);
}
.price-p--talk {
  font-size: clamp(1rem, 1.12vw, 1.1rem);
  line-height: 1.7;
  max-width: 54ch;
  margin-left: auto;
  margin-right: auto;
  color: var(--sand-ink-70);
}
.price-p { color: var(--sand-ink-70); }
.price-p + .price-p { margin-top: clamp(.9rem, 1.8vh, 1.3rem); }
/* это уже не про цену, а про следующий шаг — отделено медной чертой */
.price-p--talk {
  position: relative;
  margin-top: clamp(1.6rem, 3.2vh, 2.4rem);
  padding-top: clamp(1.4rem, 2.8vh, 2rem);
}
.price-p--talk::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  width: min(280px, 60%);
  height: 1px;
  background: linear-gradient(90deg, rgba(138,86,72,0), rgba(138,86,72,.32), rgba(138,86,72,0));
}
.price-p--talk b { font-weight: 600; color: var(--cu-deep); }
/* КНОПКА В «СТОИМОСТИ» (26.08.2026, Георгий: «переделал бы на
   „бесплатная консультация“ и чуть изменил дизайн»). Секция СВЕТЛАЯ,
   поэтому медная заливка .btn-main на песке теряла контраст. Здесь
   обратная схема: тёмный уголь с медным кантом — на песке читается
   как оттиск, а не как ещё одна розовая пилюля. Обещание конкретное,
   поэтому кнопка крупнее обычной (min-height 62 против 48) */
.price-cta {
  display: inline-flex; align-items: center; gap: .8em;
  margin-top: clamp(1.6rem, 3vh, 2.3rem);
  min-height: 62px;
  padding: 1.05em 2.4em;
  font-size: clamp(1rem, 1.1vw, 1.1rem);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--sand);
  background: linear-gradient(135deg, #241713 0%, #1A100D 55%, #120B09 100%);
  border: 1px solid rgba(138, 86, 72, .55);
  box-shadow: 0 12px 30px -16px rgba(90, 52, 42, .8);
  transition: transform .4s cubic-bezier(.22,1,.36,1), box-shadow .4s, border-color .4s;
}
.price-cta .ar { color: var(--cu-hi); }
.price-cta:hover {
  transform: translateY(-3px);
  border-color: rgba(201, 143, 134, .9);
  box-shadow: 0 18px 40px -18px rgba(90, 52, 42, .9);
}
.price-cta:active { transform: translateY(-1px); }

.pricing-h {
  font-size: clamp(2rem, 3.8vw, 3.3rem);
  letter-spacing: -.04em;
  color: var(--sand-ink);
  /* воздух под заголовком: без него h2 и первая фраза слипались в одну
     тёмную массу (26.08.2026) */
  margin-bottom: clamp(1.2rem, 2.6vh, 2rem);
}

/* ТЕКСТОВЫЙ БЛОК ВМЕСТО ПРАЙСА (26.08.2026, бриф Георгия: цены убраны,
   секция осталась и объясняет подход). Никаких новых приёмов: колонка
   текста в мере абзаца + существующая кнопка .btn-main. Блок должен
   читаться легко и не выглядеть пустым после удаления трёх групп цен. */
/* блок стоит по центру кадра: колонка текста слева при пустой правой
   половине читалась незавершённой (26.08.2026) */


/* образ команды над блоком «кто мы» — картинка растворяется в фоне секции */
.duo-world {
  position: relative;
  margin: 0 auto clamp(1.6rem, 4vh, 3rem);
  /* высота ограничена вьюпортом: при 880px ширины картинка занимала
     почти весь экран и выдавливала заголовок «Два человека» за край */
  width: min(100%, clamp(460px, 52vw, 720px));
  max-height: 52vh;
  line-height: 0;
}
.duo-world img { max-height: 52vh; width: auto; margin: 0 auto; }

/* лёгкое поле частиц-узлов по бокам — «команда как живая сеть» */
.duo-field {
  /* full-bleed: тянем канвас до края вьюпорта независимо от ширины .duo-world —
     50% - 50vw даёт координату края экрана, т.к. центр .duo-world ≈ центр вьюпорта */
  position: absolute; top: 0;
  height: 100%;
  width: 50vw;
  pointer-events: none;
  z-index: 0;
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
.duo-field--l {
  left: calc(50% - 50vw);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent),
                      linear-gradient(90deg, transparent 0%, #000 10%, #000 92%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent),
              linear-gradient(90deg, transparent 0%, #000 10%, #000 92%, transparent 100%);
}
.duo-field--r {
  right: calc(50% - 50vw);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent),
                      linear-gradient(270deg, transparent 0%, #000 10%, #000 92%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent),
              linear-gradient(270deg, transparent 0%, #000 10%, #000 92%, transparent 100%);
}
.duo-world::before {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 88%; aspect-ratio: 1.6;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse 50% 50% at 50% 50%, rgba(201, 143, 134, .2), rgba(201, 143, 134, .1456) 14.4%, rgba(201, 143, 134, .1074) 25.2%, rgba(201, 143, 134, .0766) 34.56%, rgba(201, 143, 134, .0522) 43.2%, rgba(201, 143, 134, .0336) 50.4%, rgba(201, 143, 134, .02) 56.88%, rgba(201, 143, 134, .0106) 61.92%, rgba(201, 143, 134, .0046) 66.24%, rgba(201, 143, 134, .0015) 69.12%, rgba(201, 143, 134, 0) 72%);
  filter: blur(38px);
  pointer-events: none;
}
.duo-world img {
  position: relative; z-index: 1;
  width: 100%; height: auto;
  /* резерв места под 1536x1024 (2.1 МБ) — крупнейший файл на сайте */
  aspect-ratio: 1536 / 1024;
  /* края уводим в графит, чтобы не читалась рамка прямоугольника */
  -webkit-mask-image: radial-gradient(ellipse 74% 74% at 50% 48%, #000 52%, transparent 100%);
  mask-image: radial-gradient(ellipse 74% 74% at 50% 48%, #000 52%, transparent 100%);
}

/* ШАПКА ПО ОСИ СИММЕТРИИ (26.08.2026, Георгий: «не эстетично относительно
   других объектов»). Сцена ниже симметрична — два портрета, — а шапка
   стояла влево с пустой правой половиной: оси не совпадали. Заголовок и
   лид по центру, ровно между двумя карточками. Лид крупнее и шире —
   раньше рвался на обрывки по 3–5 слов. */
.duo-head {
  display: block;
  text-align: center;
  margin-bottom: clamp(2.4rem, 4.6vh, 3.6rem);
}
.duo-h { font-size: clamp(2rem, 3.8vw, 3.3rem); margin: .8rem auto 0; max-width: 18ch; }
.duo-h .solve { text-shadow: 0 0 30px rgba(201,143,134,.5), 0 0 8px rgba(201,143,134,.35); }
.duo-lead .body {
  font-size: clamp(1.05rem, 1.2vw, 1.2rem);
  line-height: 1.6;
  max-width: 56ch;
  margin: clamp(1rem, 2vh, 1.5rem) auto 0;
  color: var(--ink-70);
}
/* две карточки и дверь между ними */
/* ТЕЛЕГРАМ-КАНАЛ ПОД КАРТОЧКАМИ (26.08.2026): по ЦЕНТРУ секции —
   у левого края строка терялась («вообще не видно»).
   ГЕОМЕТРИЯ ПО КНОПКАМ САЙТА (замер .btn-main: h 56, padding 16/32,
   кегль 15.2, radius 100). Своя капсула была 52px с padding 12/24 и
   кеглем 16.8 — текст крупнее, поля меньше, и элемент читался «почти
   кнопкой», но не ею. Теперь метрики совпадают, отличие только в том,
   что кант медный, а заливки нет: роль тише кнопки.
   ВАЖНО: width: fit-content обязателен — без него flex + margin auto
   схлопывает ширину и текст рвётся на три строки */
.duo-tg {
  display: flex; align-items: center; justify-content: center; gap: .7em;
  width: fit-content; white-space: nowrap;
  margin: clamp(3rem, 5.5vw, 4.6rem) auto 0;
  min-height: 56px;
  padding: .95em 2em;
  border: 1px solid var(--cu-line);
  border-radius: 100px;
  color: var(--ink-70);
  font-size: .95rem;
  letter-spacing: .005em;
  transition: color .3s, border-color .3s, background .3s;
}
.duo-tg img { flex: none; width: 1.35em; height: auto; opacity: .85; transition: opacity .3s; }
.duo-tg:hover {
  color: var(--ink);
  border-color: rgba(233, 188, 169, .55);
  background: rgba(201, 143, 134, .06);
}
.duo-tg:hover img { opacity: 1; }

.duo-cards {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2.5rem, 6vw, 7rem);
  align-items: center;
  margin-bottom: clamp(1.2rem, 2.4vh, 2rem);
}
.duo-card { position: relative; z-index: 1; }
/* тёплая аура за портретом — снимки живут на свечении, как рендеры */
.duo-card::before {
  content: '';
  position: absolute;
  left: -10%;
  top: -8%;
  width: 72%;
  height: 116%;
  background: radial-gradient(50% 50% at 42% 46%, rgba(201, 143, 134, .14), rgba(201, 143, 134, 0) 70%);
  z-index: -1;
  pointer-events: none;
}


/* низ «О нас» ужат — финал стоит следом одной сценой (26.08.2026) */
/* низ короче: финал идёт следом одной сценой */
#duo { padding-bottom: clamp(28px, 3.5vw, 48px); }

/* ЗНАКОМСТВО БЕЗ ПЛАШЕК (26.08.2026, Георгий: «сделать красивым и не
   иишным, тексты не добавлять — вынести смыслы»). Что читалось
   сгенерированным: две тёмные панели со свечением + пилюли-теги — ровно
   паттерн, отвергнутый в услугах («скруглённая карточка + чипы»).
   Теперь плашек нет: главным стал КРУПНЫЙ ПОРТРЕТ, карточка — разворот
   «фото | текст», теги — строка через медные точки (приём .site-skills).
   Пока фото одно (Георгий): колонка без фото остаётся чистой
   типографикой, фото Лизы встанет само — положить в team/liza.jpg
   и раскомментировать <img>. */
.duo-photo { display: none; }
.duo-photo:has(img) { display: block; }
.duo-photo {
  width: 100%;
  aspect-ratio: 4 / 5;
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(160deg, var(--bg-2), var(--bg));
  box-shadow: inset 0 0 0 1px rgba(233, 188, 169, .25),
              0 0 54px -14px rgba(201, 143, 134, .5),
              0 22px 46px -26px rgba(201, 143, 134, .45);
}
.duo-photo img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  /* тёплый кадр слегка сведён к палитре: чуть глушим цвет, greyscale-хвост
     не нужен — фото и так закатное */
  filter: saturate(.86) contrast(1.02);
}

/* визитка-разворот: портрет слева, справа единый блок .duo-info
   (имя → абзац → теги), выровнено по центру вертикали. БЕЗ обёртки
   .duo-info grid раскидывал h3/p/ul по клеткам — имя уезжало к низу
   фото, абзац падал под фото (скриншот Георгия 26.08.2026). */
.duo-card {
  display: grid;
  /* ФИКСИРОВАННАЯ колонка портрета (26.08.2026, Георгий: «блоки стоят
     неровно»). Было minmax(250px,340px) — резиновая колонка делила
     остаток по-разному в зависимости от длины текста, и портреты
     выходили РАЗНОЙ ширины, а правые колонки начинались на разных x. */
  grid-template-columns: clamp(230px, 20vw, 300px) 1fr;
  gap: clamp(1.1rem, 1.8vw, 2rem);
  /* текст от ВЕРХА фото, а не по центру: у Елизаветы фраза короче на
     строку, и при центрировании имена стояли на разной высоте */
  align-items: start;
}
/* имя выровнено по верхней кромке портрета */
.duo-info { padding-top: clamp(.4rem, 1.2vh, 1rem); }
/* ИМЯ БЕЗ НАЕЗДА И БЕЗ ЛИНИИ (26.08.2026, правка Георгия: «текст наезжает
   на картинку, стоит не ровно, убрать линию, приятнее шрифты»). Наезд на
   портрет и медное подчёркивание удалены — не возвращать. Имя спокойное,
   без теней; воздух и вес вместо украшений. */
.duo-card h3 {
  font-size: clamp(1.7rem, 2.3vw, 2.3rem);
  font-weight: 600;
  letter-spacing: -.025em;
  margin: 0 0 .55rem;
}
.duo-card p {
  margin: 0;
  font-size: 1rem; line-height: 1.65; color: var(--ink-70);
  max-width: 34ch;
}

/* ссылки на профили: текстовые, с иконкой, без плашек; медь на hover.
   Пока заглушки href="#" — реальные адреса прикрутим позже. */
.duo-soc {
  display: flex;
  gap: clamp(.9rem, 1.6vw, 1.6rem);
  margin-top: clamp(.8rem, 1.6vh, 1.2rem);
}
/* абзац одной меры в обеих карточках — иначе строки рвутся по-разному
   и ссылки уезжают на разные уровни */
.duo-card p { min-height: 4.95em; }
.duo-soc a {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px; /* кликабельная цель ≥44px — общее правило сайта */
  font-size: .88rem;
  color: var(--ink-70);
  text-decoration: none;
  transition: color .35s;
}
/* иконки в фирменных цветах приложений — CSS их не перекрашивает,
   цвета заданы в самих SVG (просьба Георгия 26.08.2026) */
.duo-soc svg { width: 18px; height: 18px; border-radius: 4px; }
.duo-soc a:hover { color: var(--ink); }
.duo-soc a:hover svg { filter: brightness(1.12); }
.duo-pulse--b { animation-delay: 1.3s; }

@keyframes duoPulseDown {
  0%   { top: 2%;  opacity: 0; }
  8%   { opacity: 1; }
  50%  { top: 50%; opacity: 1; }
  92%  { opacity: 1; }
  100% { top: 98%; opacity: 0; }
}
@keyframes duoPulseAcross {
  0%   { left: 2%;  opacity: 0; }
  8%   { opacity: 1; }
  50%  { left: 50%; opacity: 1; }
  92%  { opacity: 1; }
  100% { left: 98%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
}
:root.is-static .duo-pulse { animation: none; opacity: 0; }

/* итоговая строка */
/* ============================================================
   КЕЙСЫ
   ============================================================ */

/* вторая светлая пауза: портфолио как разворот каталога.
   Края растушёваны в уголь — вход и выход читаются как смена
   света, а не как обрыв встык (тот же приём, что у #pricing) */
/* та же схема, что у #pricing: песок в ::after выходит за пределы
   секции и растворяется по краям — стык не совпадает с границей */
#cases { color: var(--sand-ink); }
/* ПОРЯДОК СЕКЦИЙ ИЗМЕНЁН 26.08.2026: Услуги → Кейсы → Стоимость → О нас.
   «Кейсы» и «Стоимость» встали ПОДРЯД и обе светлые, поэтому гашение
   между ними снято: раньше каждая гасила свой край в прозрачность, между
   ними просвечивал тёмный фон страницы и на стыке была тёмная полоса.
   Теперь у «Кейсов» гаснет только ВЕРХ (стык с тёмной «Автоматизацией»),
   а низ остаётся плотным песком и переходит в «Стоимость» без шва. */
/* «Кейсы» и «Стоимость» — две светлые секции ПОДРЯД. Растушёвку стыка
   делает только одна из двух, иначе между ними проступает тёмная полоса
   фона страницы: у «Кейсов» гаснет только ВЕРХ (стык с тёмной
   «Автоматизацией»), низ — плотный песок до 100%. */
#cases {
  /* верхний край — тот же простой градиент (см. замер выше) */
  background: linear-gradient(180deg,
    rgba(235,226,216,0) 0px,
    rgba(235,226,216,.55) 10px,
    var(--sand) 20px,
    var(--sand) 100%);
}
#cases::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 40px;  /* под кромку 20px (26.08.2026) */
  pointer-events: none;
  z-index: 0;
  opacity: .5;
  mix-blend-mode: soft-light;
  /* КРАЙ САМОГО СЛОЯ ЗЕРНА БЫЛ ВИДЕН КАК ЛИНИЯ (26.08.2026, шестая правка
     Георгия). soft-light слой начинался резко: выше зерна нет, ниже есть —
     граница читалась горизонтальной чертой ровно в начале перехода, там
     где песок ещё плотный. Теперь слой гаснет по краям маской. */
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 35%, rgba(0,0,0,.85) 52%, rgba(0,0,0,.5) 70%, rgba(0,0,0,.15) 86%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 35%, rgba(0,0,0,.85) 52%, rgba(0,0,0,.5) 70%, rgba(0,0,0,.15) 86%, transparent 100%);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='ncs'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23ncs)'/%3E%3C/svg%3E");
}

#cases .halo { opacity: .22; }

/* ШАПКА — ДВЕ КОЛОНКИ, как у #duo: заголовок слева, лид справа по нижнему
   краю. В колонку заголовок стоял один во всю ширину, правая половина
   кадра пустовала, и до ленты карточек оставался провал ~130px. */
.cases-head {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: end;
  margin-bottom: clamp(1.8rem, 3.4vh, 2.8rem);
}
.cases-h { font-size: clamp(2rem, 3.8vw, 3.3rem); letter-spacing: -.04em; color: var(--sand-ink); }
/* ЦВЕТ ОБЯЗАТЕЛЕН (27.08.2026): .body задаёт rgba(241,236,231,.7) —
   молочный текст для ТЁМНЫХ секций, а «Кейсы» светлые. Лид набирался
   почти белым по песку и был не виден ни на телефоне, ни на десктопе
   (замер цвета подтвердил на 390 и 1400). Берём ту же приглушённую
   тёмную краску, что у остальных абзацев светлой секции. */
.cases-lead-col .cases-lead {
  font-size: .95rem; max-width: 48ch; margin-top: 0;
  color: rgba(36, 28, 24, .72);
}

/* КЕЙСЫ — КОМПАКТНАЯ СЕТКА (26.08.2026, Георгий: «может, блоки с кейсами
   поменьше сделать»). Были три карточки во всю ширину по ~700px высотой:
   рядом с такими глыбами любой блок цены читался довеском. Теперь три
   карточки в ряд — работа, что входило, сколько стоило. */
.cases-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.2rem, 2vw, 2rem);
  align-items: stretch;
}
@media (max-width: 1000px) { .cases-list { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .cases-list { grid-template-columns: 1fr; } }

.case-card {
  display: flex;
  flex-direction: column;
  gap: clamp(.9rem, 1.4vw, 1.2rem);
  padding: clamp(.9rem, 1.2vw, 1.1rem);
  border-radius: 20px;
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(201, 143, 134, .1), rgba(201, 143, 134, .0728) 11%, rgba(201, 143, 134, .0537) 19.25%, rgba(201, 143, 134, .0383) 26.4%, rgba(201, 143, 134, .0261) 33%, rgba(201, 143, 134, .0168) 38.5%, rgba(201, 143, 134, .01) 43.45%, rgba(201, 143, 134, .0053) 47.3%, rgba(201, 143, 134, .0023) 50.6%, rgba(201, 143, 134, .0008) 52.8%, rgba(201, 143, 134, 0) 55%),
    linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid rgba(233, 188, 169, .22);
  transition: border-color .45s, box-shadow .45s;
}
.case-card:hover {
  border-color: rgba(233, 188, 169, .55);
  box-shadow: 0 20px 46px -30px rgba(201,143,134,.6);
}
/* карточки на светлой подложке — молочные панели, а не тёмные дыры */
#cases .case-card {
  background: linear-gradient(160deg, var(--sand-panel), #F7F1E9);
  border-color: var(--sand-line);
  box-shadow: 0 18px 40px -34px rgba(26, 19, 16, .5);
}
#cases .case-card:hover {
  border-color: rgba(138, 86, 72, .38);
  box-shadow: 0 24px 50px -30px rgba(138, 86, 72, .45);
}
/* ОДНИ ЯРУСЫ ВО ВСЕХ ТРЁХ КАРТОЧКАХ (26.08.2026): теги занимали 1 или 2
   строки, поэтому заголовки, абзацы и «Ещё скриншоты» стояли на разной
   высоте и ряд читался неровным. Высота задана в строках самого
   элемента — при любой длине текста ярус один. */
#cases .case-body h3 { min-height: 2.48em; }
#cases .case-body h3 { color: var(--sand-ink); }
#cases .case-body > p { color: var(--sand-ink-70); }
#cases .case-media { box-shadow: inset 0 0 0 1px rgba(138, 86, 72, .18); }
/* затемнение поверх скриншота ни к чему на светлой карточке */
#cases .case-media::after { display: none; }


.case-media {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  aspect-ratio: 16/10;
  box-shadow: inset 0 0 0 1px rgba(233,188,169,.2);
}
.case-media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .6s cubic-bezier(.22,1,.36,1);
}
.case-card:hover .case-media img { transform: scale(1.035); }
.case-media::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 60%, rgba(8,9,11,.55));
  pointer-events: none;
}

.case-body { display: flex; flex-direction: column; }
.case-body { flex: 1; display: flex; flex-direction: column; }
.case-body h3 {
  font-size: clamp(1.02rem, 1.15vw, 1.18rem);
  line-height: 1.24; margin: 0 0 .5rem;
}
.case-body > p {
  margin: 0; font-size: .85rem; line-height: 1.5; color: var(--ink-70);
}

/* КНОПКА ОКНА КЕЙСА (26.08.2026): вместо <details>, который растягивал
   карточку и ломал сетку. Не сплошная кнопка — текст с медным кантом:
   в светлой секции сплошная заливка спорила бы с обложкой кейса */
.case-open {
  margin-top: auto;
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .7em 1.25em;
  border: 1px solid var(--sand-line);
  border-radius: 100px;
  font-size: .72rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--cu-deep);
  cursor: pointer;
  transition: color .3s, border-color .3s, background .3s, transform .3s cubic-bezier(.22,1,.36,1);
  min-height: 44px; /* кликабельная цель >=44px — общее правило сайта */
}
.case-open:hover {
  color: #6E4034;
  border-color: rgba(138, 86, 72, .5);
  background: rgba(201, 143, 134, .1);
  transform: translateY(-2px);
}
.case-open-ar { width: 11px; height: 11px; flex: none; }

@media (max-width: 860px) {
  .case-card, .case-card--rev { grid-template-columns: 1fr; }
  .case-card--rev .case-media, .case-card--rev .case-body { order: initial; }
}
/* ============================================================
   ФИНАЛ
   ============================================================ */

.finale {
  position: relative;
  text-align: center;
  /* ВЕРХ УЖАТ (26.08.2026, Георгий: «разделение неорганичное между
     блоками»): свои 110–200px сверху + 90–180px снизу у #duo давали до
     380px пустого поля — знакомство и финал читались как два оторванных
     блока. Теперь верх короткий: финал идёт продолжением сцены, а не
     отдельной главой. Низ прежний — там футер. */
  padding-top: var(--pad-sec);
  padding-bottom: calc(var(--pad-sec) * 1.4);
  /* ВОТ ОНА, ПРИЧИНА ЛИНИИ (26.08.2026): overflow: hidden ОБРЕЗАЛ все
     слои секции ровно по её границе — и ауру #finale::after, и канвас
     искр. Маски на них не помогали: слой физически отсекался по краю,
     и срез читался горизонтальной чертой. Теперь обрезаем только по
     горизонтали (для декора, вылезающего вбок), а сверху и снизу свет
     свободно перетекает в соседние секции. */
  overflow-x: clip;
  /* верх прозрачный — непрозрачная заливка обрывалась на границе
     и давала склейку; темнеет только к низу, перед футером */
  /* ЕДИНЫЙ СТАНДАРТ КРОМКИ (26.08.2026, Георгий: «вот это эталон, сделай
     такое же на всём сайте» — про стык «Автоматизация → Кейсы»). Проценты
     давали растяжку в сотни пикселей; теперь та же короткая мягкая кромка
     в ПИКСЕЛЯХ, что у светлых секций: гаснет на 20px, дальше плотный цвет. */
  /* низ финала плотный: именно он держит черноту перед футером.
     Гасить его в прозрачность нельзя — открывается фон страницы
     и перепад на стыке вырастает до 8.7 пункта (проверено) */
  background: linear-gradient(180deg,
    rgba(18,12,10,0) 0px,
    rgba(18,12,10,.55) 10px,
    rgba(18,12,10,.85) 20px,
    var(--void) 100%);
}

/* поле медленно плывущих искр на весь блок — минималистичный фон вместо двери */
.finale-field {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
  pointer-events: none;
  /* верх канваса гаснет: искры обрывались ровно на границе секции —
     внутри есть, выше нет, и кромка читалась горизонтальной линией
     (26.08.2026, Георгий: «всё равно она осталась») */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.4) 8%, #000 18%, #000 100%);
  mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,.4) 8%, #000 18%, #000 100%);
}

.finale::before {
  content: '';
  position: absolute; left: 50%; bottom: -5%;
  width: 130%; height: 80%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse 38% 55% at 50% 100%, rgba(233, 188, 169, .18), rgba(233, 188, 169, .131) 14%, rgba(233, 188, 169, .0967) 24.5%, rgba(233, 188, 169, .0689) 33.6%, rgba(233, 188, 169, .047) 42%, rgba(233, 188, 169, .0302) 49%, rgba(233, 188, 169, .018) 55.3%, rgba(233, 188, 169, .0095) 60.2%, rgba(233, 188, 169, .0041) 64.4%, rgba(233, 188, 169, .0013) 67.2%, rgba(233, 188, 169, 0) 70%);
  pointer-events: none;
}

/* новый текст CTA длиннее прежнего: кегль чуть меньше общего .big,
   иначе последняя строка наезжает на подзаголовок. Тексту дан воздух,
   а не урезана формулировка */
/* ФИНАЛ — КУЛЬМИНАЦИЯ (26.08.2026): нити от портретов сходятся ровно
   в этот вопрос, поэтому он крупнее заголовков глав (у тех ~3.3rem) и
   набран в один блок с плотным интерлиньяжем. */
.finale .big {
  font-size: clamp(2.2rem, 6vw, 5.4rem);
  line-height: .92;
  letter-spacing: -.045em;
  max-width: 16ch;
  margin: 0 auto 1.6rem;
}
.finale .wrap { position: relative; z-index: 2; }
/* ФИНАЛЬНАЯ КНОПКА КРУПНЕЕ И ЖИВЁТ (26.08.2026, Георгий: «кнопочку бы
   чуть более навязчивую в самом конце»). Правка только для финала —
   в шапке и услугах кнопка остаётся прежней.
   Что добавлено: кегль и поля крупнее (18.4px против 15.2), пульсирующее
   медное гало вокруг (::after, дышит 3.4s) и бегущий блик по заливке
   (::before, раз в 4.5s). Обе анимации — только на десктопе и снимаются
   в статике/reduced-motion, чтобы не тратить кадры зря */
.finale .btn-main {
  font-size: clamp(1rem, 1.15vw, 1.15rem);
  font-weight: 600;
  padding: 1.15em 2.6em;
  min-height: 62px;
  overflow: hidden;
  isolation: isolate;
}
/* пульсирующее гало: тот же медный свет, что у рендеров */
.finale .btn-main::after {
  content: '';
  position: absolute; inset: -3px;
  border-radius: 100px;
  z-index: -1;
  background: radial-gradient(60% 120% at 50% 50%, rgba(233,188,169,.55), rgba(233,188,169,0) 70%);
  opacity: .5;
  animation: ctaPulse 3.4s ease-in-out infinite;
  pointer-events: none;
}
/* блик пробегает по заливке слева направо */
.finale .btn-main::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: 100px;
  background: linear-gradient(105deg,
    rgba(255,255,255,0) 38%,
    rgba(255,255,255,.42) 50%,
    rgba(255,255,255,0) 62%);
  transform: translateX(-120%);
  animation: ctaSheen 4.5s ease-in-out infinite;
  pointer-events: none;
}
@keyframes ctaPulse {
  0%, 100% { opacity: .38; transform: scale(1); }
  50%      { opacity: .75; transform: scale(1.045); }
}
@keyframes ctaSheen {
  0%, 62%  { transform: translateX(-120%); }
  86%, 100%{ transform: translateX(120%); }
}
.finale .btn-main:hover { transform: translateY(-4px) scale(1.035); }
/* в статике и при reduced-motion кнопка просто крупная, без движения */
html.is-static .finale .btn-main::after,
html.is-static .finale .btn-main::before { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .finale .btn-main::after, .finale .btn-main::before { animation: none; }
}

.finale .body {
  margin: 0 auto 2.6rem;
  max-width: 52ch;
  font-size: clamp(1.02rem, 1.15vw, 1.15rem);
  line-height: 1.65;
}

/* ============================================================
   FOOTER
   ============================================================ */

/* футер втекает в финал: заливка встык с границей давала
   самый заметный перепад яркости на странице (11.7 пункта) */
.foot {
  position: relative;
  /* высота: 48–80 → 34–52 → 26–36 → 34–44px (последний шаг —
     чуть больше воздуха по правке Георгия 26.08.2026) */
  padding: clamp(2rem, 2.7vw, 2.75rem) 0 1.4rem;
  /* ЩЕЛЬ ПОД ФУТЕРОМ (26.08.2026): после сжатия футера внизу оставалось
     34px, где просвечивал фон страницы с полем частиц (12.33 против
     6.33 у футера). Причина не в футере: аура .scene::before у #finale
     (inset: -45%) свисает ниже секции и даёт 320px лишней прокрутки,
     до которых футер не достаёт. Лечится обрезкой ауры — см. правило
     #finale ниже. box-shadow и flex на body не помогают: тень рисуется
     под фоном родителя, а флекс не влияет на переполнение потомка */
  /* ФУТЕР ПРОДОЛЖАЕТ ЗАЛИВКУ ФИНАЛА (26.08.2026, итог трёх попыток).
     .finale кончается плотным var(--void), поэтому у футера обязан быть
     ТОТ ЖЕ цвет — иначе на кромке видна граница двух плоскостей.
     Отдельный слой, гаснущий вверх, не годится: он уходит под фон
     страницы (z-index: -1) и футер становится СВЕТЛЕЕ фона на 7.9
     пункта.
     ЦВЕТ ПОДОБРАН ЗАМЕРОМ, а не взят из токенов: .finale приходит
     к своей нижней границе с медианной яркостью 6.00, а var(--void)
     (#060404) даёт 4.67 — перепад 1.33 в один пиксель и читался
     линией. #080605 совпадает с яркостью финала на стыке. */
  background: #080605;
}
/* две колонки: бренд слева, контакты справа. Навигации в футере нет —
   она вся в шапке; юридические ссылки не колонка, а строка внизу
   рядом с копирайтом (26.08.2026) */
.foot-grid {
  display: grid;
  grid-template-columns: 1.5fr 1.15fr;
  gap: clamp(2rem, 4vw, 4.5rem);
  margin-bottom: clamp(1.5rem, 2.1vw, 1.9rem);
}
.foot-brand p {
  font-size: .92rem; line-height: 1.55;
  /* мера расширена дважды: 26ch → 40ch → 52ch. Фраза ложится
     в две строки вместо четырёх — футер ниже на два интерлиньяжа */
  color: var(--ink-45); max-width: 52ch; margin-top: .75rem;
}

/* заголовки колонок — моно-капс, язык меток сайта */
/* метка колонки: ОСНОВНОЙ шрифт, не моно (26.08.2026, Георгий:
   «не красивый шрифт») — JetBrains Mono в капсе с разрядкой читался
   технической меткой. Golos в капсе мягче и садится к остальному тексту */
.foot-col h4 {
  font-size: .72rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--cu); opacity: .8;
  margin-bottom: .9rem;
}
.foot-col ul { list-style: none; display: grid; gap: .1rem; }
.foot-col a {
  display: inline-flex; align-items: center; min-height: 30px;
  font-size: .95rem; color: var(--ink-45);
  transition: color .3s;
}
.foot-col a:hover { color: var(--cu); }

/* телефон — главный контакт, поэтому крупнее и светлее всего в футере.
   Специфичность составная: .foot-col a = (0,2,0) перебивала бы класс */
.foot-contact { display: grid; align-content: start; }
/* телефон — главный элемент футера, но без плаката (26.08.2026,
   Георгий: «очень большой шрифт»): кегль снижен с 23–30px до 19–23px.
   Табличные цифры оставлены — группы номера стоят ровным строем */
.foot-col a.foot-tel {
  font-size: clamp(1.2rem, 1.5vw, 1.4rem);
  font-weight: 600; letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  color: var(--ink); min-height: 0;
  line-height: 1.05;
  margin-bottom: .5rem; width: fit-content;
}
.foot-col a.foot-tel:hover { color: var(--cu-hi); }
/* почта ОСНОВНЫМ шрифтом (26.08.2026, Георгий: «не красивый шрифт»):
   моно давало машинный вид, адрес читается спокойнее в Golos */
.foot-col a.foot-mail {
  font-size: .95rem; letter-spacing: -.005em;
  color: var(--ink-70); width: fit-content;
}
.foot-col a.foot-mail:hover { color: var(--cu); }

/* телеграм-канал: третья строка контактов. Тише почты — это не способ
   связи, а «почитать нас», поэтому мельче и приглушённее (26.08.2026) */
.foot-col a.foot-tg {
  display: inline-flex; align-items: center; gap: .5em;
  font-size: .88rem; color: var(--ink-45);
  width: fit-content; margin-top: .35rem;
}
.foot-col a.foot-tg svg {
  flex: none; width: 1.05em; height: 1.05em;
  fill: none; stroke: var(--cu); stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
  transition: stroke .3s;
}
.foot-col a.foot-tg:hover { color: var(--ink-70); }
.foot-col a.foot-tg:hover svg { stroke: var(--cu-hi); }

/* нижняя строка: копирайт слева, документы справа.
   Черта гаснет вправо — правило палитры «заливка не кончается цветом» */
.foot-base {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .6rem 2.5rem;
  padding-top: 1.05rem; position: relative;
}
.foot-base::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, var(--cu-line), rgba(201,143,134,.10) 60%, rgba(201,143,134,0));
}
/* копирайт ОСНОВНЫМ шрифтом (26.08.2026, Георгий: «не красивый шрифт»):
   моно давало машинный вид. Реквизиты вынесены на отдельную страницу */
.foot-copy {
  font-size: .84rem; color: var(--ink-25);
  letter-spacing: -.005em;
}
.foot-legal {
  list-style: none; display: flex; flex-wrap: wrap;
  gap: .4rem 1.6rem; align-items: center;
}
.foot-legal a {
  font-size: .84rem; color: var(--ink-45);
  letter-spacing: -.005em;
  transition: color .3s;
}
.foot-legal a:hover { color: var(--cu); }

/* ============================================================
   ПОЯВЛЕНИЕ
   ============================================================ */

.rise { opacity: 0; transform: translateY(26px); }

/* на высоких экранах поднимаем сцену: сверху меньше пустоты,
   ноги пары не упираются в нижний край */
@media (min-height: 780px) {
  .hero { padding-bottom: clamp(24px, 13vh, 190px); }
}

/* ультраширокие экраны: сцена уходит вправо, УТП занимает левое поле,
   чтобы сверху не оставалось пустой черноты */
@media (min-width: 1400px) {
  .hero-stage { max-width: 1720px; }
  .hero-actors { left: auto; right: 0; width: min(100%, 1400px); }
  .hero-copy { max-width: min(52%, 840px); }
  .hero-h1 { font-size: clamp(3.2rem, 5vw, 5.6rem); line-height: 1.05; }
  .hero-copy .body { max-width: 46ch; font-size: 1.08rem; }
  .hero-copy .tag { font-size: .8rem; }
}

@media (min-width: 2000px) {
  .hero-stage { max-width: 1880px; }
  .hero-copy { max-width: min(54%, 1020px); }
  .hero-h1 { font-size: 6.4rem; line-height: 1.05; }
  .hero-copy .body { font-size: 1.12rem; max-width: 50ch; }
}

/* низкие окна: сцена мельче, чтобы дверь не лезла под навигацию,
   а ноги пары не уезжали за нижний край. Идёт после блоков min-width,
   иначе перебивается ими */
@media (max-height: 800px) {
  .hero-actors { width: min(100%, 1200px); }
}
@media (max-height: 700px) {
  .hero-actors { width: min(100%, 1040px); }
}
@media (max-height: 620px) {
  .hero-actors { width: min(100%, 900px); }
}

/* ============================================================
   АДАПТИВ
   ============================================================ */

@media (max-width: 1080px) {
  .act { grid-column: span 6; }
}

@media (max-width: 900px) {
  /* СЦЕНА «ПРОЦЕССА» ЛИПКАЯ И НА ТЕЛЕФОНЕ (27.08.2026, Георгий: «нет
     3D-анимаций»). Было: position: relative, height 52vh — холст стоял
     ОДНИМ блоком над списком шагов, показывал первую форму (лупу) и
     уезжал вверх; остальные четыре формы отыгрывались за пределами
     экрана, и на телефоне 3D фактически не существовало.
     Теперь холст прилипает к верхней трети экрана и держится всю
     секцию: шаги проходят под ним снизу вверх, форма перестраивается
     на каждом — та же драматургия, что на десктопе, но по вертикали
     (фигура сверху, текст под ней) вместо «слева/справа».
     44vh — фигура крупная, но под ней остаётся место на заголовок
     шага и абзац; замер: шаг занимает 300–340px из 844. */
  .layers-stage.journey-3d {
    position: sticky;
    top: 0;
    /* 34vh (было 42vh, 27.08.2026 — сжатие «Процесса» по просьбе
       Георгия «лучше сжать, если ничего не потеряется»). Высота сцены
       задаёт минимальную высоту шага: под фигурой должен стоять РОВНО
       ОДИН шаг, иначе форма не успевает смениться. Уменьшив сцену,
       уменьшаем и требуемый шаг — секция ужимается с 3.08 до 2.46
       экрана, а все пять шагов, все тексты и сама фигура остаются. */
    height: 34vh;
    width: 100%;
    margin-left: 0;
    margin-bottom: 0;
    /* СЦЕНА — НАД ТЕКСТОМ, НО СО СВОЕЙ НЕПРОЗРАЧНОЙ ПОЛОСОЙ
       (27.08.2026, Георгий: «3D-фигуры криво работают при свайпе»).
       Липкая сцена держит верх экрана, а шаги едут снизу вверх — и в
       момент, когда шаг доезжает до верха, он оказывается В ЗОНЕ
       ФИГУРЫ: буквы шли прямо сквозь частицы (проверено кадрами
       быстрого свайпа). z-index: 0 не спасал — текст просто рисовался
       поверх, что читалось так же грязно.
       Решение: сцена лежит НАД текстом (z-index 4) и получает
       собственный фон-градиент через ::after — плотный сверху, гаснущий
       в прозрачность к низу. Текст уезжает ПОД неё и растворяется,
       вместо того чтобы пересекаться с рисунком. Градиент, а не
       сплошная заливка: жёсткий край читался бы полосой поперёк
       страницы (см. правило «заливка кончается прозрачностью»). */
    z-index: 4;
  }
  .layers-stage.journey-3d::after {
    content: '';
    position: absolute;
    /* шире и выше своей рамки: край растворяется за пределами кадра,
       поэтому границы полосы не видно ни сверху, ни с боков */
    inset: -20% -10% 0;
    /* ВАЖНО, ловушка из истории проекта: сплошной var(--bg) здесь
       НЕ ГОДИТСЯ. Реальный фон в этом месте подсвечен аурами и светлее
       #090706 — полоса читалась чёрным прямоугольником поверх тёплого
       угля (проверено кадром). Гасим не цветом, а ПРОЗРАЧНОСТЬЮ: чёрный
       с убывающей альфой ложится на любой фон и не даёт видимого края. */
    background: linear-gradient(to bottom,
      rgba(6, 4, 4, .96) 0%,
      rgba(6, 4, 4, .93) 55%,
      rgba(6, 4, 4, .72) 76%,
      rgba(6, 4, 4, .32) 90%,
      rgba(6, 4, 4, 0) 100%);
    z-index: -1;
    pointer-events: none;
  }
  .journey-wrap { margin-top: 0; }
  /* КАЖДЫЙ ШАГ НАЧИНАЕТСЯ ПОД ФИГУРОЙ. Липкая сцена держит верхние
     38vh экрана, поэтому у колонки шагов сверху ровно такой же отступ:
     первый шаг встаёт под фигурой, а не за ней. Дальше шаги проходят
     под неподвижной сценой снизу вверх, форма меняется на каждом. */
  .journey-col {
    margin-top: 0; margin-left: 0; width: 100%;
    padding-top: 34vh;
    position: relative; z-index: 3;
  }
  /* ЭТАЛОН chessfirst: CTA-кнопка в шапке видна ВСЕГДА — заявку можно
     оставить из любой точки страницы. Раньше на мобиле кнопка
     скрывалась вместе с меню; теперь прячется только меню и телефон,
     кнопка остаётся в компактном виде рядом с бургером. */
  .nav-links, .nav-tel { display: none; }
  .nav .btn { font-size: .78rem; padding: .68em 1.1em; min-height: 40px; }
  .nav .btn .ar { display: none; }
  .nav-act { margin-left: auto; margin-right: .8rem; }
  .burger { display: block; }

  /* ═══ HERO — ПЛАКАТ ПО РЕФЕРЕНСУ chess.chessfirst.online (27.08.2026).
     Георгий дал этот сайт эталоном мобильной адаптации. Замер эталона
     (440×860): иллюстрация занимает ВЕСЬ первый экран, заголовок стоит
     ПО ЦЕНТРУ на ней (h1 32px, центр), абзацы 20px на всю ширину.
     Никаких колонок: на телефоне работает плакат, не раскладка.
     История наших попыток (обе отвергнуты Георгием): (1) вертикаль с
     текстом от левого края — «текст уходит в какой-то бок»; (2) две
     колонки как на десктопе — колонка текста 200px, кегль падал до
     22px, «всё ещё криво и некрасиво». Эталон показал третий путь:
     СТЕК ПО ЦЕНТРУ. Портал крупный по центру, под ним центрованный
     заголовок и центрованный абзац — читается постером, как эталон. */
  .hero {
    min-height: 100vh; min-height: 100dvh;
    display: flex; align-items: center;
    padding-block: 84px 40px;
  }
  .hero-stage {
    display: flex; flex-direction: column;
    align-items: center;
    gap: clamp(1.1rem, 2.6vh, 1.8rem);
    width: 100%;
  }
  .hero-copy { max-width: none; text-align: center; }
  .hero-copy .body { margin-inline: auto; }
  .portal { display: block; position: relative; width: min(62vw, 290px); margin: 0 auto; }
  .portal-floor { display: none; }
  .duo-actors { display: block; width: min(62vw, 290px); margin: 0 auto; }
  .hero-actors { display: none; }
  .note { display: none; }

  .acts { grid-template-columns: repeat(6, 1fr); }
  .act { grid-column: span 6; }

  /* на узких экранах блоки в колонку, кабель идёт слева */
  /* padding-left обнулён: в одну колонку он только сдвигал шаги вправо
     относительно картинки и заголовка над ними */
  .journey { padding-left: 1.4rem; }
  .journey-rail { display: none; }
  .journey-runway { display: none; }
  /* min-height 58vh (было 0): шаг занимает свободную полосу под липкой
     сценой, поэтому под фигурой стоит РОВНО ОДИН шаг и форма успевает
     смениться, пока читатель проходит его. При min-height: 0 все пять
     шагов шли сплошным списком, и сцена отыгрывала все формы за один
     экран прокрутки (27.08.2026) */
  .leg, .leg:first-child, .leg:last-child, .leg:nth-child(even) {
    min-height: 40vh; padding: 1.4rem 0; opacity: 1; transform: none;
    width: 100%; margin-left: 0; margin-right: 0;
    /* текст прижат к НИЗУ своей полосы, а не по центру: при центровке
       заголовок в момент подъезда оказывался на уровне фигуры и она
       ложилась на буквы (кадр «Проектируем»). Прижатый вниз текст
       входит в кадр под фигурой и там же останавливается. */
    display: flex; flex-direction: column; justify-content: flex-end;
    align-items: flex-start; text-align: left;
  }
  /* последнему шагу полный экран не нужен: под ним сразу «Сайты», и
     58vh пустоты между «Запускаем» и следующей главой читались провалом
     (замер на 440×956). Хвоста хватает, чтобы ракета успела встать. */
  .leg:last-child { min-height: 34vh; padding-bottom: 0; }
  /* выноска и аура завязаны на рельс и активный шаг — на мобиле их нет */
  .leg h3::before, .leg::after { display: none; }
  .leg-n::before { display: none; }

  .sites-main { grid-template-columns: 1fr; }
  .apps-main { grid-template-columns: 1fr; }
  /* ужато с 38vh: камера теперь отъезжает и вписывает сцену по ширине
     (frameCamera в apps3d.js), поэтому сам объект стал компактнее —
     прежняя высота оставляла под ним пустую полосу */
  /* выше на треть (план «мобильное вау»): при 30vh телефон с орбитами
     был размером с иконку — frameCamera в apps3d.js пересчитает
     отъезд камеры под новый кадр сама */
  .apps-stage { height: clamp(260px, 36vh, 340px); }
  /* зазор между сценой и текстом главы — воздух, а не провал */
  .apps-main, .sites-main, .chain-main { gap: clamp(1rem, 2.5vh, 1.8rem); }
  .sites-art { width: min(86%, 380px); margin-left: 0; }
  .code-rain { display: none; }
  .chain-main { grid-template-columns: 1fr; }
  .chain-main .auto-art { margin-top: clamp(1.4rem, 3vh, 2.6rem); justify-self: center; }
  .chain-main .auto-art img { width: min(80%, 600px); }
  .rows--wide { grid-template-columns: 1fr; }
  /* «один экран на главу» — только десктоп: на телефоне контент и так
     выше экрана, а flex-центровка ломает порядок отступов */
  #sites, #apps, .chain { min-height: 0; display: block; }
  /* сцена «Сайтов» на всю ширину колонки: рендер сверху, голограмма
     под ним в потоке (см. .holo ниже) */
  .sites-scene { justify-self: center; margin-top: 1.5rem; width: 100%; }
  .sites-scene .sites-art { width: min(78%, 340px); margin-inline: auto; }

  /* ГОЛОГРАММА ВОЗВРАЩЕНА НА ТЕЛЕФОН (27.08.2026, Георгий: «нет 3D-анимаций»).
     Была скрыта, потому что абсолютное позиционирование (left: -62%)
     уводило её за левую кромку и на Лизу — свободного поля СБОКУ на
     телефоне действительно нет. Но механика от наведения не зависит:
     siteHolo() и без курсора перебирает варианты каждые 3.6 с и
     подсвечивает соответствующий пункт списка. Поэтому окно не
     скрывается, а переносится ПОД рендер, в поток: место есть внизу,
     а не сбоку. Наклон в перспективе снят — он существовал, чтобы
     панель читалась «ещё одной панелью Лизы», стоящей рядом с ней;
     под рендером фронтальная панель честнее и не съедает ширину. */
  .holo {
    position: static;
    display: block;
    /* уже рендера: голограмма — его спутник, а не второй главный
       объект. При равной ширине они читались двумя картинками подряд */
    width: min(66%, 260px);
    /* прижата к рендеру: между ними воздуха меньше, чем до следующего
       блока, поэтому пара читается одной сценой */
    margin: -6% auto 0;
    transform: none;
    animation: none;
    /* три слоя свечения, как на десктопе (третий возвращён планом
       «мобильное вау»: два слоя читались «следом» приёма, не приёмом) */
    filter:
      drop-shadow(0 0 4px rgba(242, 189, 195, .5))
      drop-shadow(0 0 14px rgba(197, 109, 119, .4))
      drop-shadow(0 0 36px rgba(197, 109, 119, .22));
  }
  /* наведения на телефоне нет — живым словам хвоста незачем держать
     nowrap, он оставлял «нестандартная вёрстка,» одинокой строкой.
     Разбиение на буквы-спаны там же отключено в main.js (см. extraLive):
     без него слово остаётся цельным и переносится по-человечески. */
  .extra-line .live { white-space: normal; display: inline; }

  /* ВАЖНО: nowrap на заголовке «Процесса» снимается уже здесь, а не на
     640px. После склейки двух строк в одну (24.08.2026) строка «Придумать —
     половина дела.» на 641–900px оказывалась шире экрана и распирала
     документ — появлялся горизонтальный скролл на всей странице */
  .journey-head .journey-h { white-space: normal; }

  /* КАПСУЛА ТЕЛЕГРАМА (27.08.2026): white-space: nowrap при
     width: fit-content делал её шире экрана — правый край с концом
     фразы уходил за кромку. На узком экране разрешаем перенос. */
  .duo-tg {
    white-space: normal;
    width: auto;
    max-width: 100%;
    text-align: center;
    padding-inline: 1.3em;
  }

  .duo-head { grid-template-columns: 1fr; align-items: start; }
  .duo-cards { grid-template-columns: 1fr; }

  .foot-grid { grid-template-columns: 1fr 1fr; }
  .foot-brand { grid-column: 1 / -1; }
}

@media (max-width: 640px) {
  /* ВАЖНО: <br> НЕ скрывать (было display: none до 27.08.2026). В
     разметке два <br> стоят вместо пробелов — «...начать?<br>Начнём с
     того...». Скрытый <br> склеивал слова: на телефоне читалось
     «НАЧАТЬ?НАЧНЁМ». Переносы оставлены, кегль подобран так, чтобы
     строки и без того ложились по ширине. */
  .hero-h1 br { display: inline; }
  .foot-grid { grid-template-columns: 1fr; gap: 1.8rem; }
  .foot-base { flex-direction: column; align-items: flex-start; gap: .4rem; }
  .journey-copy .body { padding-left: 0; border-left: 0; }
}

/* ============================================================
   МОБИЛЬНАЯ ТИПОГРАФИЧЕСКАЯ ЛЕСТНИЦА (27.08.2026)
   ПРИЧИНА ПРАВКИ (Георгий: «криво стоят шрифты, всё растянуто»).
   ЗАМЕР на 390×844 показал ПЕРЕВЁРНУТУЮ иерархию: hero-h1 23.4px
   (правило на 640px зажимало его в 1.35–1.75rem), заголовки глав
   36.8px, а рядовой шаг «Процесса» .leg h3 — 41.6px. Главный экран
   был САМЫМ МЕЛКИМ на странице. Причина в том, что почти все кегли
   заданы через vw: на 390px vw-слагаемое схлопывается к нижней
   границе clamp, и у каждого правила эта граница своя (.leg h3 —
   2.6rem, .sites-h — 2.3rem, .hero-h1 — 1.35rem) — лестница
   рассыпается именно на телефоне, хотя на десктопе она верна.
   Плюс интерлиньяж заголовков (.84–.92) МЕНЬШЕ кегля: на широких
   строках это смыкает их в плакат, а на узкой колонке, где слов
   в строке 2–3, строки налезали друг на друга.
   РЕШЕНИЕ: на ≤640px кегли задаются ЯВНО в rem (без vw), одной
   лестницей: hero 40 → главы 33 → шаг «Процесса» 30 → пункт
   списка 22 → текст 16.5. Интерлиньяж заголовков поднят до 1.02–1.1
   (строки перестают наезжать). Десктоп не затронут — весь блок
   живёт внутри max-width: 640px.
   ============================================================ */
@media (max-width: 640px) {

  /* ── 1. ЗАГОЛОВКИ: явные rem, интерлиньяж > 1 ── */

  /* КЕГЛЬ ПОДОБРАН ПО РАЗБИВКЕ СТРОК, А НЕ «НА ГЛАЗ» (27.08.2026,
     Георгий: «текст уходит в какой-то бок»). ЗАМЕР ширин каждой
     визуальной строки при 2.3rem: 208 / 293 / 379 / 82 / 319 / 153px —
     разброс почти впятеро, правый край скачет (остаток справа 214 → 43
     → 340px). Строка «Начнём с того, что» упиралась в кромку и роняла
     «вам» отдельной строкой-сиротой — блок читался рваным клином.
     Перебраны кегли: 2.1 и 1.95rem дают 5 строк с сиротой «нужно.»,
     text-wrap: balance не помогает (жёсткие <br> в разметке не дают
     браузеру балансировать). 1.8rem — единственный, где фраза ложится
     ЦЕЛЫМИ смысловыми кусками в 4 строки, а две нижние почти равны
     (367 и 376px). Плотный плакат вместо клина. */
  .hero-h1 {
    /* ПЛАКАТ ПО ЭТАЛОНУ chessfirst: заголовок по центру на всю ширину
       (эталон: h1 32px по центру кадра). 1.9rem = 30.4px — фраза из
       четырёх строк ложится в 404px без сирот (замер на 1.8rem давал
       строки 163–376px, запас есть). */
    /* 1.9rem — максимум, при котором фраза ложится в 4 строки без
       сироты «нужно.» (перебор 2.15/2.05/2.0/1.95 — все дают 5 строк
       с сиротой; проверено Range-замером). Плакатность hero держит
       uppercase и масса из четырёх строк, а не лишние 4px кегля. */
    font-size: 1.9rem;
    line-height: 1.04;
    letter-spacing: -.04em;
  }
  /* абзац крупный, как у эталона (там 20px): мелкий текст и был
     половиной «нечитаемости» */
  .hero .body { font-size: 1.05rem; line-height: 1.55; max-width: 34ch; }
  .hero-h1 .outline { -webkit-text-stroke-width: 1.3px; }

  /* заголовки глав — ступень ниже hero, как и на десктопе */
  /* ВАЖНО: .finale h2 и .duo h2 несут класс .big с clamp(2.4rem…) —
     его нижняя граница 38.4px перебивала общий кегль глав, и финал
     оказывался вторым по величине на странице после hero (замер:
     35.2px против 24px у глав). Перечисляем .big внутри этих секций
     явно, иначе лестница разъезжается. */
  /* ПЛАКАТ ВЕРНУЛСЯ (27.08.2026, план «мобильное вау», решение
     Георгия). При 1.5rem заголовок был лишь в 1.4 раза крупнее текста
     и читался «жирной строкой» — фирменный плакатный контраст десктопа
     (~4:1) исчезал. Теперь ~2:1 (32px к 16.8px) + контур и медь. */
  .sites-h, .apps-h, .chain-h, .journey-head .journey-h, #cases h2, .price-h,
  .duo h2, .finale h2, .finale .big, .duo .big, #cases .big {
    /* 1.9rem, не 2: при 2rem «Есть идея для приложения?» не влезал в
       строку и ронял «сделаем.» сиротой (перебор fit.js). 30.4px против
       16.8px текста ≈ 1.8:1 + контур + медь — плакат читается. */
    font-size: 1.9rem;
    line-height: 1.03;
    letter-spacing: -.04em;
    max-width: none;
  }
  .journey-head .journey-h { white-space: normal; }
  .sites-h .outline, .apps-h .outline, .chain-h .outline,
  .journey-h .outline { -webkit-text-stroke-width: 1.3px; }

  /* шаг «Процесса» — НИЖЕ глав: на десктопе он равен им по рангу, но
     там у него отдельная половина экрана, а на телефоне он идёт
     сплошным списком и при 42px читался главным блоком страницы */
  .leg h3 {
    font-size: 1.7rem;
    line-height: 1.06;
    letter-spacing: -.04em;
  }

  /* пункты списков услуг */
  .rows h3 { font-size: 1.22rem; line-height: 1.2; }

  /* ── 2. ТЕКСТ: одна мера, один кегль ── */
  .body, .rows p, .leg p, .extra-line, #cases .body {
    /* 1.1rem (17.6px): эталон chessfirst держит абзацы 20px — крупный
       текст и есть его главное отличие от «сгенерированной» мобилки */
    font-size: 1.05rem;
    line-height: 1.55;
  }
  /* меры в ch на узкой колонке ничего не ограничивают, но мешают
     тексту занять всю доступную ширину — снимаем */
  .body, .rows p, .leg p, .extra-line, .sites-open,
  .sites-main .body, .apps-col .body, .hero .body { max-width: none; }
  .sites-open { font-size: 1.2rem; line-height: 1.35; }
  .extra-t { font-size: .82rem; }

  /* ── 3. ОДИН ЛЕВЫЙ КРАЙ У ВСЕЙ СТРАНИЦЫ ──
     Замер: hero стоял в 18px от кромки, шаги «Процесса» — в 40px
     (из-за .journey { padding-left: 1.4rem } на ≤900px), списки
     услуг — в 18px. Три разные вертикали на одной странице и есть
     то, что читается «криво». Теперь у всех одна: 18px от .wrap. */
  .journey { padding-left: 0; }
  .leg, .leg:first-child, .leg:last-child, .leg:nth-child(even) {
    padding-left: 0; margin-left: 0; margin-right: 0;
  }
  .leg p { max-width: none; }
}

/* ============================================================
   МОБИЛЬНАЯ КОМПОЗИЦИЯ — ПЕРЕОСМЫСЛЕНИЕ, А НЕ ПЕРЕНОС (27.08.2026)

   Георгий: «ты пытаешься сделать импорт без переосмысления того, как
   всё должно выглядеть в мобильной версии; блоки классные, визуал
   классный, 3D классное — но расположение относительно друг друга
   это просто ужас».

   ЗАМЕР, который объяснил «ужас» (440×860):
   (1) РВАНЫЙ РИТМ СЕКЦИЙ: 1.14 → 0.12 → 3.58 → 1.61 → 1.17 → 1.89
       экрана. «Процесс» в 30 раз длиннее бегущей строки. При листании
       нет пульса: то мелькает, то тянется бесконечно.
   (2) ОДИН ЗАЗОР НА ВСЁ: у всех секций padding 56px, и ровно столько же
       воздуха стоит ВНУТРИ главы — между её рендером и её заголовком
       (gap 21.5px при padding 56px — рендер визуально ближе к соседней
       главе, чем к своему тексту). Связанное и несвязанное разделено
       одинаково — глаз не может собрать блоки в группы.
   (3) ПРИЧИНА ОБОИХ: на десктопе иерархию держит ГОРИЗОНТАЛЬ (рендер
       слева, текст справа — глаз видит их одним кадром). В одной
       колонке эта связь исчезает, а замены ей не поставили.

   РЕШЕНИЕ — ОДНА СИСТЕМА ВЕРТИКАЛЬНОГО РИТМА:
     --m-in    внутри группы (рендер ↔ заголовок ↔ список) — тесно
     --m-group между группами внутри главы
     --m-out   между главами — вдвое больше внутреннего
   Правило, которое и создаёт композицию: РАССТОЯНИЕ КОДИРУЕТ СВЯЗЬ.
   Что рядом по смыслу — стоит близко; граница главы — крупная пауза.
   Блоки, визуал и 3D НЕ МЕНЯЮТСЯ: меняется только их расстановка.
   ============================================================ */
@media (max-width: 900px) {
  :root {
    --m-in: clamp(.7rem, 2.2vh, 1.1rem);
    --m-group: clamp(1.5rem, 4.5vh, 2.4rem);
    /* 3.25rem = 52px — ровно шаг секций эталона chessfirst: одинаковая
       пауза между главами даёт ровный пульс при листании */
    --m-out: 3.25rem;
  }

  /* ═══ ПРИЁМЫ VEONIX.RU — «ВАУ» НА ТЕЛЕФОНЕ (27.08.2026) ═══
     Георгий дал veonix.ru эталоном: «очень хорошо адаптирован, у нас
     плохо, нужно ВАУ». СРАВНИТЕЛЬНЫЙ ЗАМЕР обоих сайтов на 440×860:
       veonix: медиа во всю ширину 19 блоков, 1 горизонтальная карусель,
               кнопки в среднем 265×152px, радиус 24px
       наш:    медиа во всю ширину 3, каруселей 0,
               кнопки 320×57px, радиус 18px
     ВЫВОД: у veonix работа показана КРУПНО и от края до края — экран
     заполнен целиком, поля не съедают кадр. Карточки услуг едут вбок,
     показывая край следующей, — это приглашает свайпнуть. Кнопки
     крупные, промахнуться нельзя. Три приёма ниже.

     ПРИЁМ 1: МЕДИА ОТ КРАЯ ДО КРАЯ.
     Наши кейсы сидели в контейнере с полями 18px и скруглением — на
     440px картинка выходила 404px и читалась «превьюшкой в рамке».
     Выпускаем изображение на всю ширину экрана: работа занимает кадр
     целиком, как у эталона. Текст кейса остаётся в полях — читать его
     от кромки неудобно. */
  .case-media {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    border-radius: 0;
  }
  .case-media img { width: 100%; border-radius: 0; }
  /* карточка теряет рамку и фон — кадр держит сама работа */
  #cases .case-card, .case-card {
    background: none;
    border: 0;
    padding: 0;
    border-radius: 0;
    overflow: visible;
  }
  .case-body { padding-inline: 18px; padding-top: 1rem; }

  /* ПРИЁМ 1б: КЕЙСЫ — ГОРИЗОНТАЛЬНАЯ ЛЕНТА (у veonix ровно так же).
     Три работы вертикально занимали 3.5 экрана и читались длинным
     списком: чтобы увидеть третью, надо пролистать всё. В ленте видны
     первая целиком и КРАЙ второй — это и приглашает свайпнуть вбок.
     scroll-snap ставит карточку по месту, полоса прокрутки скрыта. */
  .cases-list {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 88vw;
    grid-template-columns: none;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* лента идёт от кромки до кромки, но первая карточка начинается
       по общей левой границе страницы */
    width: 100vw;
    margin-left: calc(50% - 50vw);
    padding-inline: 18px;
    padding-bottom: .5rem;
  }
  .cases-list::-webkit-scrollbar { display: none; }
  .case-card { scroll-snap-align: start; }
  /* внутри ленты медиа не выходит на 100vw — карточка уже своя мера */
  .cases-list .case-media {
    width: 100%;
    margin-left: 0;
    border-radius: 18px;
    overflow: hidden;
  }
  .cases-list .case-media img { border-radius: 18px; }
  .cases-list .case-body { padding-inline: 2px; }
  /* Подсказки «листается» не добавляем: у veonix её тоже нет — видимый
     край следующей карточки сам сообщает, что лента едет вбок.
     (Обёртки .cases-wrap в разметке нет, вешать ::after не на что.) */

  /* ПРИЁМ 2: КРУПНЫЕ КНОПКИ (эталон 265×152, у нас были 320×57).
     На телефоне кнопка — главная цель пальца; мелкая читается ссылкой,
     крупная — приглашением. Поднимаем высоту и кегль. */
  .btn, .case-open {
    min-height: 60px;
    font-size: 1rem;
    border-radius: 100px;
  }
  .btn-main {
    min-height: 64px;
    font-size: 1.05rem;
    padding-inline: 2em;
  }
  /* кнопка в шапке — исключение: она компактная, чтобы не спорить
     с логотипом и бургером */
  .nav .btn { min-height: 40px; font-size: .78rem; }

  /* ПРИЁМ 3: СКРУГЛЕНИЯ КРУПНЕЕ (эталон 24px против наших 18px) —
     на маленьком экране мягкий радиус читается «приложением», острый
     угол — вёрсткой */
  .sites-extra, .apps-extra, .chain-extra, .duo-card,
  .price-box, .lead-form, .duo-photo { border-radius: 24px; }

  /* ═══ ОДНА СИСТЕМА НА ВЕСЬ САЙТ — ПО ЭТАЛОНУ chessfirst ═══
     (27.08.2026, Георгий: «ты только первый блок подогнал под основу?
     нужно чтобы весь сайт был красивый как первый блок»).
     ДА, до этой правки по эталону был переделан ТОЛЬКО hero.
     ЗАМЕР показал разнобой по странице: выравнивание заголовков
     center → start → center (три системы), кегли 30.4 → 24 → 32 → 24px
     (у #pricing и #duo заголовки КРУПНЕЕ глав услуг — иерархия
     перевёрнута). ЗАМЕР ЭТАЛОНА: h1 32px, ВСЕ h2 ровно 24px, заголовки
     и абзацы ПО ЦЕНТРУ — одно правило на все секции без исключений.
     Здесь то же самое: центр везде, единый кегль h2, мера абзаца
     ограничена и центрирована. Плакатная подача первого экрана
     распространяется на всю страницу. */

  /* заголовки всех глав — по центру и в один кегль */
  .sites-h, .apps-h, .chain-h, .journey-head .journey-h,
  #cases h2, .cases-h, .price-h, .duo h2, .finale h2,
  .finale .big, .duo .big, #cases .big, #pricing h2 {
    text-align: center;
    margin-inline: auto;
  }
  /* абзацы-лиды глав — по центру, мера ограничена (эталон центрирует
     текст, а не растягивает его от края до края) */
  .sites-col > .body, .apps-col > .body, .chain-col > .body,
  #cases .cases-lead, .price-p, .price-p--lead, .price-p--talk,
  .duo-lead, .finale .body, .journey-copy .body {
    text-align: center;
    margin-inline: auto;
    max-width: 34ch;
  }
  /* колонки глав центрируют своё содержимое */
  .sites-col, .apps-col, .chain-col { align-items: center; }
  /* СПИСКИ ОСТАЮТСЯ ПО ЛЕВОМУ КРАЮ: центрованный многострочный список
     нечитаем — глаз теряет начало строки. Эталон так же держит
     перечисления по левому краю внутри центрованной секции.
     Центрируем сам БЛОК списка, а текст внутри — слева. */
  .rows { text-align: left; width: 100%; max-width: 34rem; margin-inline: auto; }
  .rows p { max-width: none; }
  /* хвост-панель главы — тоже по центру кадра */
  .sites-extra, .apps-extra, .chain-extra {
    margin-inline: auto; width: 100%; max-width: 34rem;
  }
  /* «Стоимость», «О нас», финал: заголовки были 32px против 24px у
     глав услуг — приводим к общему кеглю (см. правило .big выше, здесь
     только страховка для вложенных случаев) */
  #pricing .big, #duo .big { font-size: 1.9rem; }

  /* карточки «О нас» и кейсов — контент по центру, как везде.
     ВАЖНО: text-align центрирует только ТЕКСТ; блочные потомки (фото,
     теги, соцсети) остаются у левого края — на кадре фото стояли слева
     под центрованной подписью. Центрируем их явно через margin. */
  .duo-card, .case-card { text-align: center; }
  .duo-photo { margin-inline: auto; }
  .duo-card .duo-links, .duo-card .duo-role { justify-content: center; }
  .duo-card .duo-tags, .case-card .case-tags { justify-content: center; }
  /* тексты внутри карточек кейсов оставляем слева — там абзацы длинные */
  .case-card p, .case-card details { text-align: left; }

  /* кнопки — по центру своей секции */
  .hero-cta, .price-cta, .finale .btn, .duo-tg { justify-content: center; }
  .finale .btn, .price-cta .btn { margin-inline: auto; }

  /* ── ГРАНИЦЫ ГЛАВ: крупная пауза вместо одинаковых 56px ──
     ДВЕ ЛОВУШКИ СПЕЦИФИЧНОСТИ, обе проверены через CDP-разбор
     применённых правил:
     (1) селектор по .sec не годится — у #chain и #finale такого класса
         нет, они держали свои 56px, пока остальные ушли на 68;
     (2) `main > section` (вес 0-0-2) СЛАБЕЕ `.sec` (0-1-0), поэтому
         секции с классом .sec игнорировали правило.
     Берём `main > section.sec` И голые секции — так покрыты обе группы,
     и вес выше базового .sec. */
  main > section,
  main > section.sec,
  .chain, .finale { padding-block: var(--m-out); }

  /* ── ГЛАВА УСЛУГ = ОДИН ЭКРАН-КАРТОЧКА ──
     Решение Георгия. Глава складывается в вертикальный кадр:
     сцена сверху, под ней заголовок и список — ОДНОЙ группой,
     без внутренних провалов. min-height не жёсткий (100vh обрезал бы
     длинные списки), но каждая глава стремится занять экран целиком. */
  .sites-main, .apps-main, .chain-main {
    grid-template-columns: 1fr;
    gap: var(--m-group);
    align-content: center;
  }
  /* ОДИН ПОРЯДОК У ВСЕХ ТРЁХ ГЛАВ: СНАЧАЛА СЦЕНА, ПОТОМ ТЕКСТ.
     На десктопе главы чередуют стороны (Лиза справа, телефон слева,
     Гоша справа) — это создаёт ритм при листании. В одной колонке
     чередование превращается в РАЗНЫЙ ПОРЯДОК: у «Сайтов» и
     «Автоматизации» разметка ставит текст первым, и рендер уезжает
     в самый низ главы, оторванный от своего заголовка (проверено
     кадром: Лиза с голограммой стояла после хвоста-панели и читалась
     «непонятной картинкой в конце»). У «Приложений» — наоборот.
     В вертикальном кадре работает другое правило: картинка ОТКРЫВАЕТ
     главу, текст её объясняет. Поэтому у всех трёх сцена идёт первой. */
  .apps-main .apps-stage,
  .sites-main .sites-scene,
  .chain-main .auto-art { order: -1; }

  /* внутри колонки текста — самый тесный шаг: заголовок и список
     читаются одним блоком, а не двумя случайными полосами */
  .sites-col, .apps-col, .chain-col { display: flex; flex-direction: column; gap: var(--m-in); }
  .sites-h, .apps-h, .chain-h { margin: 0; }
  .rows { margin-top: var(--m-in); }
  /* хвост-панель — отдельная мысль, ей нужен шаг группы, не внутренний */
  .sites-extra, .apps-extra, .chain-extra { margin-top: var(--m-group); }

  /* сцены глав: прижаты к своему тексту, а не висят сами по себе */
  .sites-scene { margin-top: 0; }
  .chain-main .auto-art { margin-top: 0; }

  /* ── РАЗМЕР СЦЕН: КАРТИНКА ОТКРЫВАЕТ ГЛАВУ, А НЕ ЗАНИМАЕТ ЕЁ ──
     Замер: сцена «Сайтов» 511px при экране 860 — вместе с голограммой
     она съедала весь первый экран главы, и заголовок уезжал за кромку.
     На десктопе рендер держит СВОЮ ПОЛОВИНУ кадра и может быть крупным;
     в вертикальной колонке он лишь заставка перед текстом. Держим
     сцену в трети экрана — видно и картинку, и заголовок под ней. */
  /* СЦЕНЫ ГЛАВ — ПО ЦЕНТРУ И В ОДНОМ МАСШТАБЕ, как портал в hero.
     Эталон ставит иллюстрацию по центру кадра во всех секциях; у нас
     рендеры стояли каждый в своей ширине (64%/70%) и с разным
     выравниванием. Один размер — один ритм при листании. */
  .sites-scene, .apps-stage, .chain-main .auto-art { margin-inline: auto; }
  /* КРУПНЕЕ (27.08.2026, план «мобильное вау»): 280px на 440-экране —
     это иконка, а у эталонов картинка держит кадр. 84% ширины колонки
     (~340px) — рендер снова главный объект своей главы. */
  .sites-scene .sites-art { width: min(84%, 340px); margin-inline: auto; }
  .chain-main .auto-art img { width: min(84%, 340px); margin-inline: auto; display: block; }
  .holo { width: min(64%, 260px); margin-top: -4%; }

  /* ── HERO: портал и текст — одна группа ── */
  .hero-stage { gap: var(--m-group); }
  .hero-copy .body { margin-bottom: var(--m-group); }
  .hero-copy h1 { margin-bottom: var(--m-in); }

  /* ── «ПРОЦЕСС»: сжать, ничего не потеряв ──
     Георгий: «если не потеряется 3D-фигуры и текст — лучше сжать».
     Секция занимала 3.58 экрана против 1.6 у соседей. Шаг был 58vh —
     это высота, при которой под липкой сценой (42vh) помещается ровно
     один шаг. Уменьшать её нельзя: два шага под фигурой = форма не
     успевает смениться. Сжимаем ЗА СЧЁТ ПАДДИНГОВ секции, а не шагов:
     сцена, все пять шагов и все тексты остаются на месте. */
  main > #journey.sec { padding-top: var(--m-group); padding-bottom: 0; }

  /* ── «О НАС»: карточки людей — группа ── */
  .duo-cards { gap: var(--m-group); }
  .duo-tg { margin-top: var(--m-out); }

  /* ── КЕЙСЫ И ЦЕНА: светлые секции стоят подряд ──
     Между ними не нужна двойная пауза: это одна светлая глава
     «работы → сколько стоит». Внутренний шов вместо границы глав. */
  main > #cases.sec { padding-bottom: var(--m-group); }
  main > #pricing.sec { padding-top: var(--m-group); }
  .cases-list { gap: var(--m-group); }
}

/* ============================================================
   ЛАЙТБОКС КЕЙСОВ — крупный просмотр с пролистыванием
   ============================================================ */

img.lb-open { cursor: zoom-in; }

.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  gap: clamp(.5rem, 2vw, 1.6rem);
  padding: clamp(16px, 4vw, 48px);
  background: rgba(8, 9, 11, .92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0; visibility: hidden;
  transition: opacity .3s ease, visibility 0s linear .3s;
}
.lightbox.open {
  opacity: 1; visibility: visible;
  transition: opacity .3s ease, visibility 0s linear 0s;
}

.lb-stage {
  position: relative;
  margin: 0;
  display: flex; flex-direction: column; align-items: center; gap: .9rem;
  max-width: min(1400px, 88vw);
}
.lb-img {
  display: block;
  max-width: 88vw; max-height: 78vh;
  width: auto; height: auto;
  border-radius: 12px;
  box-shadow: 0 30px 70px -30px rgba(0,0,0,.7), 0 0 0 1px rgba(233,188,169,.22);
  background: var(--bg-2);
  transform: scale(.97); opacity: 0;
  transition: transform .35s cubic-bezier(.22,1,.36,1), opacity .35s ease;
}
.lightbox.open .lb-img.in { transform: scale(1); opacity: 1; }

.lb-count {
  font-family: var(--font-mono); font-size: .72rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink-45);
}

.lb-btn {
  flex: none;
  display: grid; place-items: center;
  width: 46px; height: 46px; border-radius: 50%;
  background: rgba(20, 20, 23, .7);
  border: 1px solid rgba(233, 188, 169, .35);
  color: var(--cu-hi);
  cursor: pointer;
  transition: border-color .3s, background .3s, transform .3s;
}
.lb-btn:hover { border-color: rgba(233, 188, 169, .8); background: rgba(30, 26, 26, .85); }
.lb-btn:active { transform: scale(.92); }
.lb-btn svg { width: 40%; height: 40%; }
.lb-btn[disabled] { opacity: .3; pointer-events: none; }

.lb-close {
  position: absolute; top: clamp(12px, 3vw, 28px); right: clamp(12px, 3vw, 28px);
}

@media (max-width: 720px) {
  .lb-prev, .lb-next { width: 38px; height: 38px; }
  .lb-stage { max-width: 92vw; }
  .lb-img { max-height: 68vh; }
}

/* ============================================================
   REDUCED MOTION
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  .rise { opacity: 1; transform: none; }
}

/* ============================================================
   ФОРМА ЗАЯВКИ — модальное окно (26.08.2026, задача Георгия:
   «нажимает "Обсудить проект" — сайт не листается, открывается форма»).
   Подложка и механика те же, что у лайтбокса кейсов. Плашек-пилюль в
   услугах избегаем, но здесь поля ввода — функциональные элементы,
   а не декор: рамки нужны, чтобы было видно, куда писать.
   ============================================================ */
.modal {
  position: fixed; inset: 0; z-index: 320;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(14px, 4vw, 44px);
  background: rgba(8, 6, 5, .9);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  opacity: 0; visibility: hidden;
  transition: opacity .32s ease, visibility 0s linear .32s;
}
.modal.open {
  opacity: 1; visibility: visible;
  transition: opacity .32s ease, visibility 0s linear 0s;
}
/* ОКНО КЕЙСА (26.08.2026): шире формы — внутри галерея скриншотов.
   ВАЖНО: правило .modal-box идёт ниже по файлу и перебивало ширину,
   поэтому селектор составной */
.modal .case-modal-box { width: min(100%, 980px); }
.case-modal-h {
  font-size: clamp(1.3rem, 2.2vw, 1.9rem);
  line-height: 1.12; letter-spacing: -.03em;
  color: var(--ink); margin: 0 0 .9rem;
  max-width: 24ch;
}
.case-modal-p {
  font-size: 1rem; line-height: 1.6;
  color: var(--ink-70); margin: 0 0 1.5rem;
  max-width: 62ch;
}
/* ссылка на живой сайт — доказательство, что кейс настоящий,
   поэтому единственный акцент в шапке окна */
.case-live {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .8em 1.4em;
  border: 1px solid var(--cu-line);
  border-radius: 100px;
  color: var(--ink-70);
  font-size: .95rem;
  transition: color .3s, border-color .3s, background .3s;
}
.case-live[hidden] { display: none; }
.case-live-t { font-weight: 600; color: var(--ink); }
.case-live-url { color: var(--cu); font-size: .88em; }
.case-live-ar { width: 12px; height: 12px; flex: none; color: var(--cu); }
.case-live:hover {
  border-color: rgba(233, 188, 169, .6);
  background: rgba(201, 143, 134, .08);
  color: var(--ink);
}
/* галерея: две колонки, крупнее чем было в карточке (три в узкой колонке) */
.case-modal-shots {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(.6rem, 1.4vw, 1rem);
  margin-top: clamp(1.4rem, 3vw, 2.2rem);
}
/* ЕДИНЫЙ ФОРМАТ 16:10 (26.08.2026, Георгий: «криво стоят»). Замер показал
   пропорции скриншотов от 1.11 до 2.66 и высоты от 162 до 385px — в сетке
   из двух колонок ряды рвались и появлялись дыры. Обрезка по верхнему
   краю: у макетов сайта смысл в шапке, а низ обычно футер. Целиком
   картинка открывается кликом в лайтбоксе */
.case-modal-shots img {
  width: 100%; aspect-ratio: 16 / 10;
  object-fit: cover; object-position: top center;
  border-radius: 12px;
  border: 1px solid rgba(233, 188, 169, .16);
  cursor: zoom-in;
  transition: transform .35s cubic-bezier(.22,1,.36,1), border-color .35s;
}
.case-modal-shots img:hover {
  transform: scale(1.015);
  border-color: rgba(233, 188, 169, .45);
}
@media (max-width: 640px) {
  .case-modal-shots { grid-template-columns: 1fr; }
}

.modal-box {
  position: relative;
  width: min(100%, 640px);
  max-height: 92vh;
  overflow-y: auto;
  padding: clamp(1.8rem, 4vw, 3.4rem);
  border-radius: 26px;
  background:
    radial-gradient(120% 90% at 0% 0%, rgba(201, 143, 134, .12), rgba(201, 143, 134, 0) 58%),
    linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid rgba(233, 188, 169, .26);
  /* свет живёт по верхней кромке — окно «выходит из темноты», а не лежит
     плоской плашкой (26.08.2026) */
  box-shadow: inset 0 1px 0 rgba(255, 227, 194, .18),
              0 0 70px -18px rgba(201, 143, 134, .45),
              0 50px 110px -45px rgba(0, 0, 0, .95);
  transform: translateY(14px) scale(.985);
  transition: transform .38s cubic-bezier(.22, 1, .36, 1);
}
.modal.open .modal-box { transform: none; }

.modal-close {
  position: absolute; top: 12px; right: 12px;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-70);
  cursor: pointer;
  transition: color .3s, background .3s;
}
.modal-close svg { width: 16px; height: 16px; }
.modal-close:hover { color: var(--cu-hi); background: rgba(233, 188, 169, .1); }

/* ТИПОГРАФИКА ФОРМЫ (26.08.2026, Георгий: «сделать красивее, шрифты не
   очень»). Убраны mono-подписи капсом над каждым полем — тот самый
   «технический» язык, отвергнутый в услугах; они же дробили форму на
   четыре куска. Что писать, говорит placeholder. Поля — не коробки с
   рамками, а строки на тонкой медной линии. */
.lead-h {
  font-size: clamp(1.7rem, 3vw, 2.5rem);
  line-height: 1.02; letter-spacing: -.04em;
  margin: 0 0 .6rem;
}
.lead-sub {
  font-size: 1rem; line-height: 1.5; color: var(--ink-70);
  max-width: 34ch;
  margin: 0 0 clamp(1.6rem, 3.2vh, 2.4rem);
}

.lead-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1rem, 2vw, 1.6rem);
}
.lead-field { display: block; margin-bottom: clamp(1.2rem, 2.4vh, 1.8rem); border: 0; padding: 0; }

/* поля — строки на линии, без коробок */
.lead input[type="text"],
.lead input[type="tel"],
.lead textarea {
  width: 100%;
  padding: .55rem 0 .7rem;
  font: inherit;
  font-size: clamp(1.02rem, 1.2vw, 1.15rem);
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(233, 188, 169, .28);
  border-radius: 0;
  transition: border-color .35s, box-shadow .35s;
}
.lead textarea { resize: vertical; min-height: 76px; line-height: 1.55; }
.lead input::placeholder, .lead textarea::placeholder {
  color: rgba(241, 236, 231, .3);
}
.lead input:focus, .lead textarea:focus {
  outline: none;
  border-bottom-color: rgba(233, 188, 169, .85);
  box-shadow: 0 1px 0 0 rgba(233, 188, 169, .5);
}
.lead .is-bad { border-bottom-color: rgba(224, 122, 106, .9); }

/* подпись над выбором услуг (26.08.2026, Георгий: «шрифт не красивый»).
   Была моно-капсом 10px с разрядкой .22em — техническая метка посреди
   формы, набранной Golos (поля 18px, чипы 14px). Теперь основной шрифт
   без капса и разрядки: обычный вопрос, как плейсхолдеры полей рядом */
.lead-lbl {
  display: block;
  font-size: .95rem; font-weight: 500;
  letter-spacing: -.005em;
  color: var(--ink-70);
  margin-bottom: .8rem;
  padding: 0;
}
.lead-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.lead-chips label { cursor: pointer; }
.lead-chips input { position: absolute; opacity: 0; pointer-events: none; }
.lead-chips span {
  display: inline-block;
  padding: .5em .95em;
  font-size: .88rem;
  color: var(--ink-70);
  border: 1px solid rgba(233, 188, 169, .28);
  border-radius: 100px;
  transition: color .3s, border-color .3s, background .3s, transform .3s;
}
.lead-chips label:hover span {
  border-color: rgba(233, 188, 169, .6);
  color: var(--ink);
  transform: translateY(-1px);
}
.lead-chips input:checked + span {
  color: #1B1411;
  background: linear-gradient(150deg, #F3D2C6, #D29A8C);
  border-color: transparent;
  font-weight: 500;
}
.lead-chips input:focus-visible + span { box-shadow: 0 0 0 3px rgba(201, 143, 134, .3); }

/* свой чекбокс: системный квадрат браузера был чужим элементом */
.lead-agree {
  display: flex; gap: .7rem; align-items: flex-start;
  font-size: .9rem; line-height: 1.5; color: var(--ink-70);
  margin: clamp(.6rem, 1.4vh, 1rem) 0 clamp(1.4rem, 2.8vh, 2rem);
  cursor: pointer;
}
.lead-agree input { position: absolute; opacity: 0; pointer-events: none; }
.lead-tick {
  flex: none;
  width: 20px; height: 20px; margin-top: .1rem;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(233, 188, 169, .38);
  border-radius: 6px;
  color: transparent;
  transition: background .3s, border-color .3s, color .3s;
}
.lead-tick svg { width: 12px; height: 12px; }
.lead-agree:hover .lead-tick { border-color: rgba(233, 188, 169, .7); }
.lead-agree input:checked + .lead-tick {
  background: linear-gradient(150deg, #F3D2C6, #D29A8C);
  border-color: transparent;
  color: #1B1411;
}
.lead-agree input:focus-visible + .lead-tick { box-shadow: 0 0 0 3px rgba(201, 143, 134, .3); }
.lead-agree a { color: var(--cu-hi); text-underline-offset: 3px; }
.lead-agree.is-bad .lead-tick { border-color: rgba(224, 122, 106, .9); }
.lead-agree.is-bad .lead-agree-t { color: #E07A6A; }

.lead-send { width: 100%; justify-content: center; }
.lead-note { min-height: 1.2em; margin: .8rem 0 0; font-size: .86rem; color: #E07A6A; text-align: center; }

/* экран «отправлено» */
.lead-done { text-align: center; padding: clamp(1rem, 3vh, 2rem) 0; }
.lead-done-mark { color: var(--cu-hi); margin-bottom: 1.2rem; }
.lead-done-mark svg { width: 60px; height: 60px; }
.lead-done .lead-h, .lead-done .lead-sub { max-width: none; margin-left: auto; margin-right: auto; }
.lead-done .lead-sub { margin-bottom: 1.6rem; }

@media (max-width: 560px) {
  .lead-row { grid-template-columns: 1fr; }
}

/* ============================================================
   МОБИЛЬНАЯ ВЕРСИЯ — ПОЛНЫЙ ПРОХОД (27.08.2026)
   Замер headless-браузером на 390px показал: документ 743px (страница
   ездила вбок), 48 элементов за кромкой, 12 кликабельных целей ниже
   44px. Ниже — правила по этим замерам, от крупного к мелкому.
   ============================================================ */

/* --- 1. КЛИКАБЕЛЬНЫЕ ЦЕЛИ >=44px (правило доступности проекта) --- */
/* специфичность .foot-col a.foot-* выше — повторяем её, иначе правило
   не применяется (замер 27.08.2026: цели были 20–30px) */
.foot-col a.foot-tel,
.foot-col a.foot-mail,
.foot-col a.foot-tg {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.lb-btn, .modal-close { min-width: 44px; min-height: 44px; }
.modal-close { width: 44px; height: 44px; }

/* юридические ссылки в футере — inline-текст, но зона касания должна
   быть удобной на телефоне (замер: 16px) */
.foot-legal a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding-block: 2px;
}
/* ссылка в согласии формы: увеличиваем зону, не ломая строку */
.lead-agree a { display: inline-block; padding-block: 6px; }

/* --- 2. ПЛАНШЕТ И УЗКИЙ ЛЭПТОП: 901–1100px --- */
/* шапке нужно ~1100px на 7 пунктов + логотип + кнопку; бургер включался
   только на 900px, и в промежутке меню налезало на кнопку */
@media (max-width: 1180px) and (min-width: 901px) {
  .nav-links { gap: clamp(10px, 1.4vw, 18px); }
  .nav-links a { font-size: .68rem; letter-spacing: .12em; }
  .nav-in > .btn-main { padding: .7em 1.1em; font-size: .82rem; }
}

/* --- 3. ТЕЛЕФОНЫ: <=560px --- */
@media (max-width: 560px) {
  /* «О нас»: фиксированная колонка фото 230px не оставляла тексту места */
  .duo-card {
    grid-template-columns: 1fr;
    gap: clamp(.9rem, 3vw, 1.3rem);
    justify-items: start;
  }
  .duo-photo { width: min(64vw, 240px); }
  .duo-card h3 { font-size: clamp(1.5rem, 7vw, 1.9rem); }
  .duo-card p { min-height: 0; max-width: none; }
  .duo-soc { flex-wrap: wrap; }

  /* форма заявки: два поля в строке не помещаются */
  .lead-row { grid-template-columns: 1fr; }
  .modal-box { padding: clamp(1.2rem, 5vw, 1.8rem); border-radius: 18px; }
  .lead-h { font-size: clamp(1.4rem, 6.5vw, 1.8rem); }

  /* шапки глав и хвосты — в одну колонку без жёстких мер */
  .cases-head { display: block; }
  .cases-lead-col .cases-lead { margin-top: .8rem; max-width: none; }
  .price-block { max-width: none; }
  .price-p--first, .price-p--talk { max-width: none; }

  /* «Стоимость» и «Кейсы»: воздух по краям вместо жёстких отступов */
  .sites-extra { margin-left: 0; padding: clamp(1rem, 4vw, 1.4rem); }

  /* таблица кейсов в одну колонку уже есть; ужимаем внутренности */
  .case-card { padding: clamp(.7rem, 3vw, 1rem); }
}

/* --- 4. УЗКИЕ ТЕЛЕФОНЫ: <=380px --- */
@media (max-width: 380px) {
  body { font-size: 16px; }
  .wrap { padding-inline: 14px; }
  .duo-photo { width: min(70vw, 220px); }
  .lead-chips span { font-size: .8rem; padding: .45em .8em; }
}

/* ============================================================
   МОБИЛЬНОЕ «ВАУ» — АТМОСФЕРА (27.08.2026, план по инвентарю)
   Диагноз: до телефона доживало ~30% декоративного слоя десктопа.
   Единый механизм отказа: выживает заданное в %/vw, умирает заданное
   в px (все 5 .halo — инлайн-px при margin в %; радиусы аур
   body::before — 1400px, на 440px градиент вырождается в заливку).
   Здесь всё переопределяется В ОТНОСИТЕЛЬНЫХ единицах.
   Блок стоит В КОНЦЕ файла намеренно: перекрывает по каскаду и
   секционные ауры, и инлайн-стили (через !important только там,
   где иначе не перебить инлайн).
   ============================================================ */
@media (max-width: 900px) {

  /* ── ФОНОВЫЕ АУРЫ: радиусы в vw, свет снова читается пятнами ── */
  body::before {
    background:
      radial-gradient(140vw 90vh at 20% 6%, rgba(201, 143, 134, .075), rgba(201, 143, 134, .052) 16%, rgba(201, 143, 134, .034) 28%, rgba(201, 143, 134, .02) 40%, rgba(201, 143, 134, .01) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%),
      radial-gradient(120vw 80vh at 85% 44%, rgba(138, 86, 72, .068), rgba(138, 86, 72, .047) 16%, rgba(138, 86, 72, .03) 28%, rgba(138, 86, 72, .017) 40%, rgba(138, 86, 72, .008) 52%, rgba(138, 86, 72, .003) 62%, rgba(138, 86, 72, 0) 72%),
      radial-gradient(120vw 70vh at 30% 90%, rgba(201, 143, 134, .055), rgba(201, 143, 134, .038) 16%, rgba(201, 143, 134, .024) 28%, rgba(201, 143, 134, .013) 40%, rgba(201, 143, 134, .006) 52%, rgba(201, 143, 134, .002) 62%, rgba(201, 143, 134, 0) 72%),
      linear-gradient(180deg, #080605 0%, #0A0807 28%, #0C0908 58%, #0A0807 74%, #080605 88%, #070505 95%, #060404 100%);
  }

  /* ── HALO: одно правило поверх пяти инлайн-стилей ──
     Инлайн задаёт px-размеры и left в % — на 440px пятна #top и
     #journey уезжали за кадр (центры 619px и 77px, замер разведки).
     !important нужен именно против инлайна. Все пять пятен встают
     по центру своей секции размером 130vw. */
  .halo {
    width: 130vw !important;
    height: 130vw !important;
    left: 50% !important;
    right: auto !important;
    margin: 0 0 0 -65vw !important;
  }

  /* ── АУРЫ СЕКЦИЙ: интенсивность ×~1.5, свет ближе к центру ──
     Точки света 8%…94% на 440px почти сливались (разброс 380px),
     а альфы .04–.06, рассчитанные на большие площади свечения, на
     маленьком кадре не читались. Ритм «свет качается влево-вправо»
     сохранён: чередуются 30% и 70%. #chain не трогаем — у него своя
     драматургия затемнения центра под 3D, и альфы уже высокие. */
  #top::before {
    background:
      radial-gradient(95% 70% at 50% 40%, rgba(201, 143, 134, .085), rgba(201, 143, 134, .059) 16%, rgba(201, 143, 134, .038) 28%, rgba(201, 143, 134, .022) 40%, rgba(201, 143, 134, .011) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%),
      radial-gradient(120% 80% at 50% 125%, rgba(8, 6, 5, .15), rgba(8, 6, 5, .1) 16%, rgba(8, 6, 5, .06) 30%, rgba(8, 6, 5, .03) 44%, rgba(8, 6, 5, .01) 55%, rgba(8, 6, 5, 0) 62%);
  }
  #acts::before {
    background: radial-gradient(95% 75% at 30% 30%, rgba(201, 143, 134, .082), rgba(201, 143, 134, .057) 16%, rgba(201, 143, 134, .037) 28%, rgba(201, 143, 134, .021) 40%, rgba(201, 143, 134, .01) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%);
  }
  #journey::before {
    background: radial-gradient(100% 70% at 70% 35%, rgba(201, 143, 134, .09), rgba(201, 143, 134, .063) 16%, rgba(201, 143, 134, .04) 28%, rgba(201, 143, 134, .023) 40%, rgba(201, 143, 134, .011) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%);
  }
  #sites::before {
    background: radial-gradient(100% 70% at 30% 32%, rgba(201, 143, 134, .085), rgba(201, 143, 134, .059) 16%, rgba(201, 143, 134, .038) 28%, rgba(201, 143, 134, .022) 40%, rgba(201, 143, 134, .011) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%);
  }
  #apps::before {
    background: radial-gradient(95% 65% at 70% 35%, rgba(201, 143, 134, .16), rgba(201, 143, 134, .11) 16%, rgba(201, 143, 134, .07) 28%, rgba(201, 143, 134, .04) 40%, rgba(201, 143, 134, .02) 52%, rgba(201, 143, 134, .008) 62%, rgba(201, 143, 134, 0) 72%);
  }
  #duo::before {
    background:
      radial-gradient(90% 60% at 30% 30%, rgba(201, 143, 134, .09), rgba(201, 143, 134, .063) 16%, rgba(201, 143, 134, .04) 28%, rgba(201, 143, 134, .023) 40%, rgba(201, 143, 134, .011) 52%, rgba(201, 143, 134, .004) 62%, rgba(201, 143, 134, 0) 72%),
      radial-gradient(90% 60% at 70% 60%, rgba(233, 188, 169, .06), rgba(233, 188, 169, .042) 16%, rgba(233, 188, 169, .027) 28%, rgba(233, 188, 169, .015) 40%, rgba(233, 188, 169, .007) 52%, rgba(233, 188, 169, .003) 62%, rgba(233, 188, 169, 0) 72%);
  }

  /* ── СВЕЧЕНИЕ ПОД РЕНДЕРАМИ: рендер не висит в пустоте ──
     Многостопный radial БЕЗ blur-фильтра (правило производительности
     из CLAUDE.md: blur дорог, мягкость даёт кривая затухания). */
  .hero-stage { position: relative; }
  .hero-stage::before {
    content: '';
    position: absolute;
    left: 50%; top: 24%;
    width: 120vw; aspect-ratio: 1;
    transform: translate(-50%, -50%);
    background: radial-gradient(circle, rgba(201, 143, 134, .13), rgba(201, 143, 134, .09) 16%, rgba(201, 143, 134, .055) 28%, rgba(201, 143, 134, .03) 40%, rgba(201, 143, 134, .014) 52%, rgba(201, 143, 134, .005) 62%, rgba(201, 143, 134, 0) 72%);
    pointer-events: none;
    z-index: 0;
  }
  .hero-stage > * { position: relative; z-index: 1; }
  .sites-scene::before {
    content: '';
    position: absolute;
    left: 50%; top: 34%;
    width: 110vw; aspect-ratio: 1;
    transform: translate(-50%, -50%);
    background: radial-gradient(circle, rgba(197, 109, 119, .12), rgba(197, 109, 119, .083) 16%, rgba(197, 109, 119, .052) 28%, rgba(197, 109, 119, .028) 40%, rgba(197, 109, 119, .013) 52%, rgba(197, 109, 119, .005) 62%, rgba(197, 109, 119, 0) 72%);
    pointer-events: none;
    z-index: 0;
  }
  .sites-scene > * { position: relative; z-index: 1; }
  /* ЛОВУШКА (27.08.2026): строка выше делает голограмму relative — и
     оживает её ДЕСКТОПНЫЙ left: -62% (окно улетало за левую кромку,
     проверено кадром). На мобиле голограмма стоит в потоке по центру. */
  .sites-scene .holo { left: 0; }
  /* у Гоши аура уже есть (.auto-art::before) — снимаем только дорогой
     blur(30px): кривая затухания и так мягкая, а фильтр на телефоне
     жжёт батарею */
  .auto-art::before { filter: none; width: min(120%, 460px); }

  /* ── CODE-RAIN ВОЗВРАЩЁН (был display:none) ──
     «Машинное отделение» Гоши — фирменный вау «Автоматизации».
     Обе колонки узкие и приглушённые: код виден за рендером, но не
     спорит с текстом. JS уже работал вхолостую (chapterEntrances
     анимировал скрытый элемент) — теперь анимация попадает в цель. */
  .code-rain { display: block; width: clamp(90px, 26vw, 140px); opacity: .6; }

  /* ── АУРА ЗА АКТИВНЫМ ШАГОМ «ПРОЦЕССА» ──
     На десктопе за читаемым тезисом загорается тёплое пятно
     (.leg::after) — на мобиле оно было display:none, и шаги стояли
     на голой черноте. Возвращаем по центру кадра: подсветка шага
     синхронна с .is-on (механика setOn в main.js жива на мобиле,
     проверено инвентаризацией). Правило стоит в конце файла и
     перекрывает display:none из раннего мобильного блока. */
  .leg::after {
    display: block;
    content: '';
    position: absolute;
    left: 50% !important;
    right: auto !important;
    top: 55%;
    width: 120vw; aspect-ratio: 1.3;
    transform: translate(-50%, -50%);
    background: radial-gradient(ellipse 50% 50% at 50% 50%, rgba(201, 143, 134, .13), rgba(201, 143, 134, .09) 16%, rgba(201, 143, 134, .056) 28%, rgba(201, 143, 134, .031) 40%, rgba(201, 143, 134, .015) 52%, rgba(201, 143, 134, .006) 62%, rgba(201, 143, 134, 0) 72%);
    opacity: 0;
    transition: opacity .8s ease;
    pointer-events: none;
    z-index: -1;
  }
  .leg.is-on::after { opacity: 1; }
}

/* ============================================================
   РЕЖИМ «ДЕСКТОП В МАСШТАБЕ» НА ТЕЛЕФОНЕ (27.08.2026).
   Решение Георгия после четырёх отвергнутых мобильных пересборок:
   «сделать всё так же, как в веб-версии, только масштабы изменить».
   Скрипт в index.html ставит layout-вьюпорт 980px — телефон рисует
   НАСТОЯЩУЮ десктопную версию и вписывает её в экран (масштаб ~0.45).
   Мобильные @media ≤900 при этом не срабатывают вовсе.
   ЕДИНСТВЕННАЯ поправка режима — ВЫСОТЫ: экран телефона (1:2.17)
   по пропорции вдвое «выше» десктопного окна, поэтому 100vh-секции
   и шаги «Процесса» в vh раздувались в пустые пролёты (замер: hero
   2130px при контенте ~700). Композицию НЕ трогаем — только высоты.
   ============================================================ */
html.is-scaled .hero { min-height: 0; padding-block: 130px 90px; }
html.is-scaled #sites,
html.is-scaled #apps,
html.is-scaled .chain { min-height: 0; }
/* шаги «Процесса»: та же драматургия, но кадр телефона вмещает два
   десктопных экрана — шаги ужаты пропорционально, чтобы плотность
   ВИДИМОГО кадра совпала с десктопной */
html.is-scaled .leg { min-height: 26vh; }
html.is-scaled .leg:first-child { min-height: 40vh; }
html.is-scaled .leg:last-child { min-height: 22vh; }
html.is-scaled .journey-runway { height: 16vh; }
/* h1 hero на 980px давал сироту «ВАМ» (строка «НАЧНЁМ С ТОГО, ЧТО ВАМ»
   при 43px не влезала в колонку 510px) — в масштабном режиме кегль
   чуть ниже, фраза ложится как на широком десктопе */
html.is-scaled .hero-h1 { font-size: 2.55rem; }

/* ============================================================
   КОНЦЕПТ «КИНО» — ПРОБА НА ДВУХ ГЛАВАХ (29.08.2026, ?mob=kino)
   Седьмой заход по мобиле, впервые СЛОЁНЫЙ: рендер занимает кадр,
   текст лежит ПОВЕРХ него на скриме (как замок у chessfirst).
   Все шесть прошлых версий клали текст ПОД или РЯДОМ — «лента» и
   «миниатюра»; эталоны Георгия делают наоборот.
   Режим включается только с ?mob=kino на экранах <700 (см. скрипт
   в <head>); боевой режим и десктоп не затронуты. Раскатка на
   остальные главы — после «да» Георгия по этим двум.
   ВАЖНО: параллакс mobileParallax пишет transform целиком, поэтому
   центрирование рендеров здесь — только left+margin, БЕЗ transform.
   ============================================================ */
html.is-kino .hero {
  position: relative;
  min-height: 100vh; min-height: 100dvh;
  display: block;
  padding: 0;
  overflow: hidden;
}
html.is-kino .hero .wrap,
html.is-kino .hero-stage { position: static; display: block; }
/* рендер портала с парой — ВЕСЬ кадр: 104vw (1024×1536 → ~686px высоты
   на 440-экране, ~75% кадра). Кропа нет — бока рендера чуть выходят за
   экран, там только свечение. */
html.is-kino .hero-stage .portal {
  position: absolute;
  left: 50%; top: max(70px, 6vh);
  width: 104vw; max-width: none;
  margin: 0 0 0 -52vw;
}
/* аура за порталом — на весь кадр */
html.is-kino .hero-stage::before { top: 38%; width: 150vw; }
/* текст — слоем поверх нижней части рендера, на скриме */
html.is-kino .hero-copy {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  max-width: none;
  /* верхний паддинг меньше: при 120px заголовок съедал пару по пояс —
     теперь текст перекрывает только ноги/пол рендера (~90px) */
  padding: 80px 20px calc(28px + env(safe-area-inset-bottom, 0px));
  text-align: center;
}
html.is-kino .hero-copy::before {
  content: '';
  position: absolute; inset: 0;
  z-index: -1;
  /* скрим гаснет вверх в прозрачность — ноги пары видны сквозь верх,
     плотность набирается только под текстом */
  background: linear-gradient(to top,
    rgba(6, 4, 4, .94) 0%,
    rgba(6, 4, 4, .9) 38%,
    rgba(6, 4, 4, .66) 62%,
    rgba(6, 4, 4, .3) 82%,
    rgba(6, 4, 4, 0) 100%);
}
html.is-kino .hero-h1 {
  /* 1.9rem — единственный кегль с 4 чистыми строками (перебор Range-
     методом ранее; 2.3rem ронял «ВАМ» сиротой прямо на постере).
     Постерность в этом кадре даёт РЕНДЕР на весь экран, не кегль. */
  font-size: 1.9rem;
  line-height: 1.05;
  /* тень-отсечка от рендера позади */
  text-shadow: 0 2px 26px rgba(6, 4, 4, .9), 0 0 8px rgba(6, 4, 4, .6);
}
html.is-kino .hero-copy .body {
  font-size: 1.02rem;
  max-width: 34ch;
  margin-inline: auto;
  color: rgba(241, 236, 231, .88);
}

/* ── «САЙТЫ»-КАДР ── */
html.is-kino #sites {
  position: relative;
  padding-top: 0;
  min-height: 100vh; min-height: 100dvh;
}
html.is-kino .sites-main { display: block; position: static; }
/* Лиза — верх кадра, крупнее, чем когда-либо: 106vw (чернила рендера
   начинаются с 2.1% ширины — больше 106 порежет предметы по бокам) */
html.is-kino .sites-scene {
  position: absolute;
  top: 3vh; left: 50%;
  width: 106vw; max-width: none;
  margin: 0 0 0 -53vw;
}
html.is-kino .sites-scene .sites-art { width: 100%; max-width: none; }
/* голограмма остаётся спутником — чуть крупнее и глубже под Лизу */
html.is-kino .sites-scene .holo { width: min(70%, 300px); margin-top: -10%; }
/* колонка текста стартует в нижней трети кадра, ПОВЕРХ низа сцены */
html.is-kino .sites-col {
  position: relative;
  z-index: 2;
  margin-top: calc(100vh - 310px);
  margin-top: calc(100dvh - 310px);
  padding-top: 120px;
}
html.is-kino .sites-col::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  width: 100vw; height: 500px;
  margin-left: -50vw;
  z-index: -1;
  /* оба конца скрима прозрачны: сверху — чтобы рендер гас плавно,
     снизу — чтобы не было шва с фоном страницы (правило «заливка
     кончается прозрачностью») */
  background: linear-gradient(to bottom,
    rgba(6, 4, 4, 0) 0%,
    rgba(6, 4, 4, .62) 26%,
    rgba(6, 4, 4, .9) 46%,
    rgba(6, 4, 4, .9) 72%,
    rgba(6, 4, 4, .4) 90%,
    rgba(6, 4, 4, 0) 100%);
}
html.is-kino .sites-h {
  font-size: 2.05rem;
  text-shadow: 0 2px 24px rgba(6, 4, 4, .9);
}

/* ── РАСКАТКА «КИНО» (29.08.2026, после «первый блок очень хороший»
   от Георгия): те же слои для «Приложений» и «Автоматизации».
   «Процесс» не трогаем — его липкая сцена уже кино по природе;
   «О нас»/финал/кейсы остаются веткой ≤900 (фото и full-bleed). ── */

/* «ПРИЛОЖЕНИЯ»: 3D-телефон с орбитами держит верхние 2/3 кадра,
   текст поверх низа сцены. Кап камеры в apps3d.js не даёт аппарату
   стать точкой на портретном кадре. */
html.is-kino #apps {
  position: relative;
  min-height: 100vh; min-height: 100dvh;
  padding-top: 0;
}
html.is-kino .apps-main { display: block; position: static; }
html.is-kino .apps-stage {
  position: absolute;
  top: 40px; left: 0; right: 0;
  /* глубже под скрим: при 70dvh низ орбит не доставал до текста и
     слоёности не было — сцена и текст жили отдельно */
  height: 78vh; height: 78dvh;
  margin: 0; max-width: none;
}
html.is-kino .apps-col {
  position: relative;
  z-index: 2;
  margin-top: calc(100vh - 320px);
  margin-top: calc(100dvh - 320px);
  padding-top: 110px;
}
html.is-kino .apps-col::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  width: 100vw; height: 480px;
  margin-left: -50vw;
  z-index: -1;
  background: linear-gradient(to bottom,
    rgba(6, 4, 4, 0) 0%,
    rgba(6, 4, 4, .62) 26%,
    rgba(6, 4, 4, .9) 46%,
    rgba(6, 4, 4, .9) 72%,
    rgba(6, 4, 4, .4) 90%,
    rgba(6, 4, 4, 0) 100%);
}
html.is-kino .apps-h { font-size: 2.05rem; text-shadow: 0 2px 24px rgba(6, 4, 4, .9); }

/* «АВТОМАТИЗАЦИЯ»: Гоша с падающим кодом — верх кадра, текст поверх */
html.is-kino .chain {
  position: relative;
  min-height: 100vh; min-height: 100dvh;
  padding-top: 0;
}
html.is-kino .chain-main { display: block; position: static; }
html.is-kino .chain-main .auto-art {
  position: absolute;
  top: 2vh; left: 50%;
  width: 108vw; max-width: none;
  margin: 0 0 0 -54vw;
  justify-self: auto;
}
html.is-kino .chain-main .auto-art img { width: 100%; max-width: none; }
html.is-kino .chain-col {
  position: relative;
  z-index: 2;
  margin-top: calc(100vh - 320px);
  margin-top: calc(100dvh - 320px);
  padding-top: 110px;
}
html.is-kino .chain-col::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  width: 100vw; height: 480px;
  margin-left: -50vw;
  z-index: -1;
  background: linear-gradient(to bottom,
    rgba(6, 4, 4, 0) 0%,
    rgba(6, 4, 4, .62) 26%,
    rgba(6, 4, 4, .9) 46%,
    rgba(6, 4, 4, .9) 72%,
    rgba(6, 4, 4, .4) 90%,
    rgba(6, 4, 4, 0) 100%);
}
html.is-kino .chain-h { font-size: 2.05rem; text-shadow: 0 2px 24px rgba(6, 4, 4, .9); }

/* ── СПИСКИ = ОКНА, РАСКРЫВАЮЩИЕСЯ ПРИ ПРОКРУТКЕ (29.08.2026)
   Георгий: «они сильно прижаты в левый бок, это выглядит некрасиво —
   сдвинуть на середину и сделать в виде открывающихся окон, только
   на мобильной версии». Первая попытка (титры-подсветка) решала не ту
   проблему: дело было в РАСКЛАДКЕ, а не в цвете.
   Окно закрыто → виден только заголовок по центру; доехало до центра
   экрана (.is-hot от kinoRows) → раскрывается: рамка светлеет, поле
   теплеет, описание выезжает. Это ЕДИНСТВЕННОЕ место, где в услугах
   разрешена плашка: запрет касался статичных карточек-плашек, а здесь
   окно — механика раскрытия, живущая только на телефоне в кино-режиме.
   Приёмы .rows li::before/::after (штрих и аура) в этом виде не нужны —
   их роль взяли рамка и фон окна. ── */
html.is-kino .rows {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 380px;
  margin-inline: auto;
  text-align: center;
}
html.is-kino .rows li {
  position: relative;
  padding: 20px 22px;
  border-radius: 20px;
  border: 1px solid rgba(201, 143, 134, .18);
  background: linear-gradient(160deg, rgba(28, 20, 18, .5), rgba(12, 9, 8, .34));
  opacity: .72;
  transition: opacity .55s ease, border-color .55s ease, background .55s ease,
              transform .55s cubic-bezier(.22, 1, .36, 1);
}
/* штрих и аура старого списка в окне лишние */
html.is-kino .rows li::before,
html.is-kino .rows li::after { display: none; }
html.is-kino .rows h3 {
  font-size: 1.34rem;
  margin: 0;
  transition: color .45s ease, text-shadow .45s ease;
}
/* описание — закрыто, пока окно не в центре кадра */
html.is-kino .rows p {
  font-size: 1.02rem;
  max-width: none;
  margin: 0;
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transform: translateY(-6px);
  transition: max-height .6s cubic-bezier(.22, 1, .36, 1),
              opacity .45s ease, transform .5s ease, margin-top .5s ease;
}
/* РАСКРЫТОЕ ОКНО */
html.is-kino .rows li.is-hot {
  opacity: 1;
  transform: scale(1.03);
  border-color: rgba(233, 188, 169, .45);
  background: linear-gradient(160deg, rgba(46, 30, 27, .72), rgba(18, 13, 11, .5));
}
html.is-kino .rows li.is-hot h3 {
  color: var(--cu-hi);
  text-shadow: 0 0 26px rgba(233, 188, 169, .5);
}
html.is-kino .rows li.is-hot p {
  max-height: 220px;
  opacity: .88;
  transform: none;
  margin-top: 10px;
}
/* сетка «Автоматизации» на телефоне — в одну колонку окон */
html.is-kino .rows--wide { grid-template-columns: 1fr; }
html.is-kino .rows--wide li { padding: 20px 22px; }
/* связь с голограммой в кадре не видна — её глушение снимаем */
html.is-kino .rows.is-linked li { opacity: .72; }
html.is-kino .rows.is-linked li.is-hot { opacity: 1; }
html.is-kino .rows li.is-on { transform: none; }
html.is-kino .rows li.is-hot.is-on { transform: scale(1.03); }

/* колонки глав в кино-кадре центрируются целиком: заголовок, окна и
   хвост-панель стоят по одной оси, левый прижим уходит */
html.is-kino .sites-col,
html.is-kino .apps-col,
html.is-kino .chain-col { text-align: center; }
html.is-kino .sites-h,
html.is-kino .apps-h,
html.is-kino .chain-h { margin-inline: auto; }
html.is-kino .sites-col > .body,
html.is-kino .apps-col > .body,
html.is-kino .chain-col > .body { margin-inline: auto; }
html.is-kino .sites-extra,
html.is-kino .apps-extra,
html.is-kino .chain-extra {
  max-width: 380px;
  margin-inline: auto;
  text-align: left;
}

/* ПУСТОТА ПОСЛЕ ХВОСТА ГЛАВЫ (29.08.2026): кино-кадр держит 100dvh, но
   под ним ещё идут хвост-панель и нижний паддинг секции — между главами
   зиял пустой экран (проверено кадром после «Сайтов»). Низ секций-кадров
   ужат: воздух даёт сам полноэкранный кадр следующей главы. */
html.is-kino #sites,
html.is-kino #apps,
html.is-kino .chain { padding-bottom: clamp(1.5rem, 4vh, 2.5rem); }
